python3__深度学习__卷积神经网络(CNN):VGGNet / Finetuning

目录

1.卷积层实现

2.全连接层实现

3.卷积组实现

4.全连接组实现

5.完整代码

6.模型参数复用及模型存储

7.模型Finetuning(微调)复用

7.1 基本概念

7.2 猫狗大战(Finetuning使用VGG)

VGG16_model.py

create_and_read_TFRecord2.py

main.py


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)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章