目录
GGNet是于ICLR 2015(International Conference on Learning Representations, 2015)上展示的一种新的卷积神经网络,在ImageNet上达到了非常高的辨识率,且能够在以DCNN(Deep Convolutional Network, 深度卷积神经网络)为基础的工程上达到很好的效果,可以广泛的在其后使用Fine-tuning(微调)。VGGNet是在AlexNet基础上添加更多隐藏层(一般为16层或19层)的卷积神经网络,该网络参数是AlexNet的3倍左右。
VGGNet共包含5组卷积层,3组全连接层,层与层间通过maxpool分隔(结构如下图)。具体程序实现见第一小节(面向对象思想编程,编程语言python)
1.卷积层实现
卷积层包含:卷积层+激活函数层。在定义域中定义了卷积层名称,这样做的好处是可以根据不同的局基层对变量进行命名,并且根据命名规则,所属不同,命名域中的变量也会自动标记上不同的名称。
tf.variable_scope(name):定义变量域
name_scope与variable_scope均会为创建的变量加上词头,而tf.name_scope对tf.get_variable创建的变量没有词头影响。同时,tf.variable_scope与tf.get_variable搭配使用可以实现tensorflow中的“变量共享机制”。在共享机制当中,是否使用之前创建的变量要看tf.variable_scope中 “reuse”参数是不是为True,如果为True则使用之前变量,不是True则创建变量,如果变量已存在会抱错。
def conv(self, name, input_data, out_channel):
"""
定义卷积组
:param name:
:param input_data:
:param out_channel:
:return:
"""
in_channel = input_data.get_shape()[-1]
# 定义变量命名空间
with tf.variable_scope(name):
kernel = tf.get_variable("weights", [3, 3, in_channel, out_channel], dtype=tf.float32, trainable=False)
biases = tf.get_variable("biases", [out_channel], dtype=tf.float32, trainable=False)
conv_res = tf.nn.conv2d(input_data, kernel, [1, 1, 1, 1], padding="SAME")
res = tf.nn.bias_add(conv_res, biases)
out = tf.nn.relu(res, name=name)
return out
2.全连接层实现
全连接层与一般的卷积神经网络层定义相似。需要注意的是,全连接层是对数据进行一个展开操作,因此第一步需要获取输入展开后的全部维度,即判断输入数据是卷积层要求的[-1, width, height, dim]还是已经展开的数组数据。
def fc(self, name, input_data, out_channel, trainable=True):
"""
定义全连接组(展开图像数据)
:param name:
:param input_data:
:param out_channel:
:return:
"""
shape = input_data.get_shape().as_list()
# 获取img纬度
if len(shape) == 4:
size = shape[-1]*shape[-2]*shape[-3]
else:
size = shape[1]
input_data_flat = tf.reshape(input_data, [-1, size])
# 定义变量命名空间
with tf.variable_scope(name):
weights = tf.get_variable("weights", [size, out_channel], dtype=tf.float32, trainable=trainable)
biases = tf.get_variable("biases", [out_channel], dtype=tf.float32, trainable=trainable)
res = tf.nn.bias_add(tf.matmul(input_data_flat, weights), biases)
out = tf.nn.relu(res, name=name)
return out
3.卷积组实现
卷机组包含5大卷积层,第1卷积层:2卷积+1池化;第2卷积层:2卷积+1池化;第3卷积层:3卷积+1池化;第4卷积层:3卷积+1池化;第5卷积层:3卷积+1池化
def convlayers(self):
"""
定义卷积模型
:return:
"""
# conv1
self.conv1_1 = self.conv("conv1_1", self.imgs, 64)
self.conv1_2 = self.conv("conv1_2", self.conv1_1, 64)
self.pool1 = self.maxpool("pool1", self.conv1_2)
# conv2
self.conv2_1 = self.conv("conv2_1", self.pool1, 128)
self.conv2_2 = self.conv("conv2_2", self.conv2_1, 128)
self.pool2 = self.maxpool("pool2", self.conv2_2)
# conv3
self.conv3_1 = self.conv("conv3_1", self.pool2, 256)
self.conv3_2 = self.conv("conv3_2", self.conv3_1, 256)
self.conv3_3 = self.conv("conv3_3", self.conv3_2, 256)
self.pool3 = self.maxpool("pool3", self.conv3_3)
# conv4
self.conv4_1 = self.conv("conv4_1", self.pool3, 512)
self.conv4_2 = self.conv("conv4_2", self.conv4_1, 512)
self.conv4_3 = self.conv("conv4_3", self.conv4_2, 512)
self.pool4 = self.maxpool("pool4", self.conv4_3)
# conv5
self.conv5_1 = self.conv("conv5_1", self.pool4, 512)
self.conv5_2 = self.conv("conv5_2", self.conv5_1, 512)
self.conv5_3 = self.conv("conv5_3", self.conv5_2, 512)
self.pool5 = self.maxpool("pool5", self.conv5_3)
4.全连接组实现
全连接组包含3次全连接层。n_class为最终的分类个数。
def fclayers(self):
"""
定义全连接模型
:return:
"""
self.fc6 = self.fc("fc6", self.pool5, 4096, trainable=False)
self.fc7 = self.fc("fc7", self.fc6, 4096, trainable=False)
self.fc8 = self.fc("fc8", self.fc7, n_class)
5.完整代码
import tensorflow as tf
import time
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
n_class = 10
class Vgg16(object):
def __init__(self, imgs):
self.parameters = []
self.imgs = imgs
self.convlayers()
self.fclayers()
self.probs = tf.nn.softmax(self.fc8)
def saver(self):
"""
定义模型存储器
:return:
"""
return tf.train.Saver()
def variable_summaries(self, var, name):
"""
生成变量监控信息并定义生成监控信息日志的操作
:param var: 输入变量
:param name: 变量名称
:return:
"""
with tf.name_scope('summaries'):
tf.summary.histogram(name, var)
mean = tf.reduce_mean(var)
tf.summary.scalar('mean/' + name, mean)
stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
tf.summary.scalar('stddev/' + name, stddev)
def conv(self, name, input_data, out_channel):
"""
定义卷积组
:param name:
:param input_data:
:param out_channel:
:return:
"""
in_channel = input_data.get_shape()[-1]
# 定义变量命名空间
with tf.variable_scope(name):
kernel = tf.get_variable("weights", [3, 3, in_channel, out_channel], dtype=tf.float32, trainable=False)
biases = tf.get_variable("biases", [out_channel], dtype=tf.float32, trainable=False)
self.variable_summaries(biases, "biases") # +++
conv_res = tf.nn.conv2d(input_data, kernel, [1, 1, 1, 1], padding="SAME")
res = tf.nn.bias_add(conv_res, biases)
out = tf.nn.relu(res, name=name)
self.parameters += [kernel, biases]
return out
def fc(self, name, input_data, out_channel, trainable=True):
"""
定义全连接组(展开图像数据)
:param name:
:param input_data:
:param out_channel:
:return:
"""
shape = input_data.get_shape().as_list()
# 获取img纬度
if len(shape) == 4:
size = shape[-1]*shape[-2]*shape[-3]
else:
size = shape[1]
input_data_flat = tf.reshape(input_data, [-1, size])
# 定义变量命名空间
with tf.variable_scope(name):
weights = tf.get_variable("weights", [size, out_channel], dtype=tf.float32, trainable=trainable)
self.variable_summaries(weights, "weights") # +++
biases = tf.get_variable("biases", [out_channel], dtype=tf.float32, trainable=trainable)
self.variable_summaries(biases, "biases") # +++
res = tf.nn.bias_add(tf.matmul(input_data_flat, weights), biases)
out = tf.nn.relu(res, name=name)
self.parameters += [weights, biases]
return out
def maxpool(self, name, input_data):
"""
定义池化层
:param name:
:param input_data:
:return:
"""
with tf.variable_scope(name):
out = tf.nn.max_pool(input_data, [1, 2, 2, 1], [1, 2, 2, 1], padding="SAME", name=name)
return out
def convlayers(self):
"""
定义卷积模型
:return:
"""
# conv1
self.conv1_1 = self.conv("conv1_1", self.imgs, 64)
self.conv1_2 = self.conv("conv1_2", self.conv1_1, 64)
self.pool1 = self.maxpool("pool1", self.conv1_2)
# conv2
self.conv2_1 = self.conv("conv2_1", self.pool1, 128)
self.conv2_2 = self.conv("conv2_2", self.conv2_1, 128)
self.pool2 = self.maxpool("pool2", self.conv2_2)
# conv3
self.conv3_1 = self.conv("conv3_1", self.pool2, 256)
self.conv3_2 = self.conv("conv3_2", self.conv3_1, 256)
self.conv3_3 = self.conv("conv3_3", self.conv3_2, 256)
self.pool3 = self.maxpool("pool3", self.conv3_3)
# conv4
self.conv4_1 = self.conv("conv4_1", self.pool3, 512)
self.conv4_2 = self.conv("conv4_2", self.conv4_1, 512)
self.conv4_3 = self.conv("conv4_3", self.conv4_2, 512)
self.pool4 = self.maxpool("pool4", self.conv4_3)
# conv5
self.conv5_1 = self.conv("conv5_1", self.pool4, 512)
self.conv5_2 = self.conv("conv5_2", self.conv5_1, 512)
self.conv5_3 = self.conv("conv5_3", self.conv5_2, 512)
self.pool5 = self.maxpool("pool5", self.conv5_3)
def fclayers(self):
"""
定义全连接模型
:return:
"""
self.fc6 = self.fc("fc6", self.pool5, 4096, trainable=False)
self.fc7 = self.fc("fc7", self.fc6, 4096, trainable=False)
self.fc8 = self.fc("fc8", self.fc7, n_class)
def load_weight(self, weight_file, sess):
weights = np.load(weight_file)
keys = sorted(weights.keys())
for i, k in enumerate(keys):
sess.run(self.parameters[i].assign(weights[k]))
print("--------------------all done--------------------")
if "__main__" == __name__:
mnist = input_data.read_data_sets("./mnist", one_hot=True)
x = tf.placeholder("float32", [None, 784])
y_ = tf.placeholder(tf.float32, [None, 10])
imgs = tf.reshape(x, [-1, 28, 28, 1])
vgg = Vgg16(imgs)
y = vgg.probs
with tf.name_scope("cross_entropy"):
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
with tf.name_scope("train_step"):
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(cross_entropy)
# 模型评价
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
with tf.name_scope("accuracy"):
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
# 模型保存
saver = vgg.saver()
merged = tf.summary.merge_all()
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
# TODO
writer = tf.summary.FileWriter("./log", sess.graph)
iters = 5
for i in range(iters):
batch_xs, batch_ys = mnist.train.next_batch(200)
acc = sess.run(accuracy, feed_dict={x: batch_xs, y_: batch_ys})
print(acc)
summary, _ = sess.run([merged, train_step], feed_dict={x: batch_xs, y_: batch_ys})
# sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
writer.add_summary(summary, i)
saver.save(sess, "./train/VGG16.ckpt")
6.模型参数复用及模型存储
权重下载链接:www.cs.toronto.edu/~frossard/vgg16/vgg16_weights.npz
分类文件下载链接:www.cs.toronto.edu/~frossard/vgg16/imagenet_classes.py
模型文件:上边代表保存到VGG16_model.py脚本中
# 训练权重复用
import tensorflow as tf
import numpy as np
from scipy.misc import imread, imresize
from imagenet_classes import class_names
from VGG16_model import Vgg16
n_class = 1000
if "__main__" == __name__:
# 定义输入图像占位符
imgs = tf.placeholder(tf.float32, [None, 224, 224, 3])
vgg = Vgg16(imgs)
prob = vgg.probs
# =====模型存储
saver = vgg.saver()
with tf.Session() as sess:
# 加载训练好的vgg16权重文件
vgg.load_weight("./vgg16_weights.npz", sess)
saver.save(sess, "./model/vgg.ckpt")
# =====模型恢复
saver = vgg.saver()
with tf.Session() as sess:
saver.restore(sess, "./model/vgg.ckpt")
# 加载图像文件
img1 = imread("001.jpg", mode="RGB")
img1 = imresize(img1, (224, 224))
# 预测
prob = sess.run(vgg.probs, feed_dict={vgg.imgs: [img1]})[0]
# 生成一系列key值和对应的概率值,选择最有可能的前5个
preds = (np.argsort(prob)[::-1])[0:5]
for p in preds:
# 输出类名称及对应概率
print(class_names[p], prob[p])
7.模型Finetuning(微调)复用
7.1 基本概念
在实际的问题当中,并不能泛化的使用VGGNet在本身模型参数所带的1000个类别中判断所属或者近似的类别,而是对其更进一步的需求专精一项分类,这是一项非常重要的工作,需要对模型进行重新的Finetuning复用。(AlexNet, VGGNet, ResNet)
Finetuning指的是对已训练好的模型进行微调,相当于使用别人的模型的前基层来提取浅层特征,从而让其所在需要针对的训练集上的判别能力更强、更加适合所需要的判断。例如:Vgg16可对1000中物体进行分类,但实际用不了这么多,此时可选择某些针对性物体对已有网络进行微调,重新训练,使其更具有针对性。
另外,之所以会通过对现有网络进行微调,主要是考虑:某一类别物体图像数据收集难度、模型训练成本和参数调整难度等因素,能够有效的节省模型训练成本且对数据集不是很大的情况下Finetuning是一个较高的选择。
数据集大小 与旧数据集相似程度 是否合适Finetuning 较小 相似 过拟合;高层特征 大 相似 可Finetuning整个网络 较小 不相似 非Finetuning整个网络;非高层特征 大 不相似 可重新训练;可Finetuning整个网络
7.2 猫狗大战(Finetuning使用VGG)
1.修改输出层的全连接数据,即分类数目;
2.weights,biases定义过程中将trainable=False(确保其在训练过程中不会修改已经训练好的权重)
3.权重加载函数修改:权重的载入文件“*.npz”,是以键值对的字典模型进行保存。而Python对字典的使用可以根据其标记序列号的形式对其进行读取,因此可以剔除不需要的序号而对模型进行有针对性的载入。由于最后的全连接层进行了调整,因此不加载最后全连接层的“权重”和“偏执项”。
4.定义“数据路径加载函数”——get_file(file_dir)
5.定义“图片读取函数”get_batch(image_list, label_list, img_width, img_height, batch_size, caplacity):按照指定批量
6.对labels进行“标签编码”(Durex编码)
7.模型的“重新训练与存储”
8.模型的“复用”
VGG16_model.py
# 训练模型
import tensorflow as tf
import time
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
import os
import create_and_read_TFRecord2 as reader2
import time
n_class = 2
# trainable参数:在进行Finetuning对模型进行重新训练时,对于部分不需要训练的层可通过设置trainable=False
# 来确保其在训练过程中不会因为训练而修改权值
class Vgg16(object):
def __init__(self, imgs):
self.parameters = []
self.imgs = imgs
self.convlayers()
self.fclayers()
self.probs = tf.nn.softmax(self.fc8)
def saver(self):
"""
定义模型存储器
:return:
"""
return tf.train.Saver()
def variable_summaries(self, var, name):
"""
生成变量监控信息并定义生成监控信息日志的操作
:param var: 输入变量
:param name: 变量名称
:return:
"""
with tf.name_scope('summaries'):
tf.summary.histogram(name, var)
mean = tf.reduce_mean(var)
tf.summary.scalar('mean/' + name, mean)
stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
tf.summary.scalar('stddev/' + name, stddev)
def conv(self, name, input_data, out_channel):
"""
定义卷积组
:param name:
:param input_data:
:param out_channel:
:return:
"""
in_channel = input_data.get_shape()[-1]
# 定义变量命名空间
with tf.variable_scope(name):
kernel = tf.get_variable("weights", [3, 3, in_channel, out_channel], dtype=tf.float32, trainable=False)
biases = tf.get_variable("biases", [out_channel], dtype=tf.float32, trainable=False)
conv_res = tf.nn.conv2d(input_data, kernel, [1, 1, 1, 1], padding="SAME")
res = tf.nn.bias_add(conv_res, biases)
out = tf.nn.relu(res, name=name)
self.parameters += [kernel, biases]
return out
def fc(self, name, input_data, out_channel, trainable=True):
"""
定义全连接组(展开图像数据)
:param name:
:param input_data:
:param out_channel:
:return:
"""
shape = input_data.get_shape().as_list()
# 获取img纬度
if len(shape) == 4:
size = shape[-1]*shape[-2]*shape[-3]
else:
size = shape[1]
input_data_flat = tf.reshape(input_data, [-1, size])
# 定义变量命名空间
with tf.variable_scope(name):
weights = tf.get_variable("weights", [size, out_channel], dtype=tf.float32, trainable=trainable)
biases = tf.get_variable("biases", [out_channel], dtype=tf.float32, trainable=trainable)
res = tf.nn.bias_add(tf.matmul(input_data_flat, weights), biases)
out = tf.nn.relu(res, name=name)
self.parameters += [weights, biases]
return out
def maxpool(self, name, input_data):
"""
定义池化层
:param name:
:param input_data:
:return:
"""
with tf.variable_scope(name):
out = tf.nn.max_pool(input_data, [1, 2, 2, 1], [1, 2, 2, 1], padding="SAME", name=name)
return out
def convlayers(self):
"""
定义卷积模型
:return:
"""
# conv1
self.conv1_1 = self.conv("conv1_1", self.imgs, 64)
self.conv1_2 = self.conv("conv1_2", self.conv1_1, 64)
self.pool1 = self.maxpool("pool1", self.conv1_2)
# conv2
self.conv2_1 = self.conv("conv2_1", self.pool1, 128)
self.conv2_2 = self.conv("conv2_2", self.conv2_1, 128)
self.pool2 = self.maxpool("pool2", self.conv2_2)
# conv3
self.conv3_1 = self.conv("conv3_1", self.pool2, 256)
self.conv3_2 = self.conv("conv3_2", self.conv3_1, 256)
self.conv3_3 = self.conv("conv3_3", self.conv3_2, 256)
self.pool3 = self.maxpool("pool3", self.conv3_3)
# conv4
self.conv4_1 = self.conv("conv4_1", self.pool3, 512)
self.conv4_2 = self.conv("conv4_2", self.conv4_1, 512)
self.conv4_3 = self.conv("conv4_3", self.conv4_2, 512)
self.pool4 = self.maxpool("pool4", self.conv4_3)
# conv5
self.conv5_1 = self.conv("conv5_1", self.pool4, 512)
self.conv5_2 = self.conv("conv5_2", self.conv5_1, 512)
self.conv5_3 = self.conv("conv5_3", self.conv5_2, 512)
self.pool5 = self.maxpool("pool5", self.conv5_3)
def fclayers(self):
"""
定义全连接模型
:return:
"""
self.fc6 = self.fc("fc6", self.pool5, 4096, trainable=False)
self.fc7 = self.fc("fc7", self.fc6, 4096, trainable=False)
self.fc8 = self.fc("fc8", self.fc7, n_class)
def load_weight(self, weight_file, sess):
weights = np.load(weight_file)
keys = sorted(weights.keys())
for i, k in enumerate(keys):
# 获取全连接层的权重与偏执项
# <class 'list'>: ['conv1_1_W', 'conv1_1_b', 'conv1_2_W', 'conv1_2_b',
# 'conv2_1_W', 'conv2_1_b', 'conv2_2_W', 'conv2_2_b', 'conv3_1_W',
# 'conv3_1_b', 'conv3_2_W', 'conv3_2_b', 'conv3_3_W', 'conv3_3_b',
# 'conv4_1_W', 'conv4_1_b', 'conv4_2_W', 'conv4_2_b', 'conv4_3_W',
# 'conv4_3_b', 'conv5_1_W', 'conv5_1_b', 'conv5_2_W', 'conv5_2_b',
# 'conv5_3_W', 'conv5_3_b', 'fc6_W', 'fc6_b', 'fc7_W', 'fc7_b', 'fc8_W',
# 'fc8_b']
if i not in [30, 31]:
sess.run(self.parameters[i].assign(weights[k]))
print("-------------------- all done --------------------")
# ==========模型的重新训练与存储
if "__main__" == __name__:
# 加载训练集
X_train, y_train = reader2.get_file(".\\cat_and_dog_r")
image_batch, label_batch = reader2.get_batch(X_train, y_train, 224, 224, 25, 256)
# 定义模型输入
x_imgs = tf.placeholder(tf.float32, [None, 224, 224, 3])
y_imgs = tf.placeholder(tf.int32, [None, 2])
# 定义模型
vgg = Vgg16(x_imgs)
fc3_cat_and_dog = vgg.probs # 模型预测值
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=fc3_cat_and_dog, labels=y_imgs))
optimizer = tf.train.GradientDescentOptimizer(0.0001).minimize(loss)
# 定义会话
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
# 加载权重
vgg.load_weight(".\\vgg16_weights.npz", sess)
# 定义模型存储器
saver = vgg.saver()
# 创建线程协调器
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
# 记录模型时间
start_time = time.time()
for i in range(1000):
image, label = sess.run([image_batch, label_batch])
labels = reader2.onehot(label)
# *打印模型损失值*
sess.run(optimizer, feed_dict={x_imgs: image, y_imgs: labels})
res = sess.run(loss, feed_dict={x_imgs: image, y_imgs: labels})
print("now the loss is: ", res)
# *打印模型耗时*
end_time = time.time()
print("time:", (end_time-start_time))
start_time = time.time()
print("--------------------epoch %d is finished--------------------")
saver.save(sess, ".\\vgg_finetuning_model\\")
print("Optimization Finished!")
coord.request_stop()
coord.join(threads=threads)
create_and_read_TFRecord2.py
import numpy as np
import os
import tensorflow as tf
img_width = 224
img_height = 224
def get_file(file_dir):
"""
数据的输入
:param file_dir: 数据文件地址
:return:
"""
images = []
temp = []
# 遍历文件树:第一次遍历(i=0)时,files = []
for root, sub_folders, files in os.walk(file_dir):
for name in files:
images.append(os.path.join(root, name))
for name in sub_folders:
temp.append(os.path.join(root, name))
labels = []
for one_folder in temp:
n_img = len(os.listdir(one_folder))
letter = one_folder.split("\\")[-1] # 获取“分类”名称
if "cat" == letter:
labels = np.append(labels, n_img*[0]) # “猫”
else:
labels = np.append(labels, n_img*[1]) # “狗”
# 重排
temp = np.array([images, labels])
temp = temp.transpose()
np.random.shuffle(temp)
image_list = list(temp[:, 0])
label_list = list(temp[:, 1])
label_list = [int(float(i)) for i in label_list]
return image_list, label_list
def get_batch(image_list, label_list, img_width, img_height, batch_size, capacity):
"""
加载对应图片和标签
:param image_list:
:param label_list:
:param img_width:
:param img_height:
:param batch_size:
:param capacity:
:return:
"""
image = tf.cast(image_list, tf.string)
label = tf.cast(label_list, tf.int32)
input_queue = tf.train.slice_input_producer([image, label])
label = input_queue[1]
image_contents = tf.read_file(input_queue[0])
# 将图像编码为“unit8” and “3通道”tensor
image = tf.image.decode_jpeg(image_contents, channels=3)
# 裁剪/填充图片为指定大小
image = tf.image.resize_image_with_crop_or_pad(image, img_width, img_height)
# 图像标准化
image = tf.image.per_image_standardization(image)
image_batch, label_batch = tf.train.batch([image, label], batch_size=batch_size, num_threads=64, capacity=capacity)
label_batch = tf.reshape(label_batch, [batch_size])
return image_batch, label_batch
def onehot(labels):
"""
标签编码
:param labels:
:return:
"""
n_sample = len(labels)
n_class = max(labels) + 1
# 生成标签矩阵,并赋值
onehot_labels = np.zeros((n_sample, n_class))
onehot_labels[np.arange(n_sample), labels] = 1
return onehot_labels
main.py
# Finetuning使用VGGNet进行猫狗大战
import tensorflow as tf
import numpy as np
from VGG16_model import Vgg16
from imagenet_classes import class_names
import os
from scipy.misc import imread, imresize
if "__main__" == __name__:
imgs = tf.placeholder(tf.float32, [None, 224, 224, 3])
sess = tf.Session()
vgg = Vgg16(imgs)
fc3_cat_and_dog = vgg.probs
saver = vgg.saver()
saver.restore(sess, ".\\vgg_finetuning_model\\")
for root, sub_folders, files in os.walk(".\\cat_and_dog_t"):
i = 0
cat = 0
dog = 0
for name in files:
i += 1
filepath = os.path.join(root, name)
try:
img1 = imread(filepath, mode="RGB")
img1 = imresize(img1, (224, 224))
except:
print("remove", filepath)
pred = sess.run(fc3_cat_and_dog, feed_dict={vgg.imgs: [img1]})[0]
max_index = np.argmax(pred)
if 0 == max_index:
cat += 1
else:
dog += 1
if i % 50 == 0:
acc = (dog * 1.) / (cat + dog)
print(acc)
print("---------- img number is %d ----------" % i)