深度学习原理与框架-猫狗图像识别-卷积神经网络(代码) 1.cv2.resize(图片压缩) 2..get_shape()[1:4].num_elements(获得最后三维度之和) 3.saver.save(训练参数的保存) 4.tf.train.import_meta_graph(加载模型结构) 5.saver.restore(训练参数载入)

1.cv2.resize(image, (image_size, image_size), 0, 0, cv2.INTER_LINEAR)

参数说明:image表示输入图片,image_size表示变化后的图片大小,0, 0表示dx和dy, cv2.INTER_LINEAR表示插值的方式为线性插值

2.image.get_shape[1:4].num_elements() 获得最后三个维度的大小之和

参数说明:image表示输入的图片

3. saver.save(sess, path, global_step=i) 进行sess的加载

参数说明:sess表示输入,path表示保存路径, global_step表示路径的结尾

4.saver = tf.train.import_meta_graph('./dog-cats-model/dog-cat.ckpt-3700.meta')  # 加载训练好的模型的meta值

参数说明:./dog-cats-model/dog-cat.ckpt-3700.meta表示meta 的路径

5.saver.restore(sess, ckpt_path) # 加载训练好的参数模型

参数说明:sess表示执行函数,ckpt_path表示ckpt的路径

6.graph = tf.get_defualt_graph 获得训练好的参数图

7.graph.get_tensor_by_name('x:0') 获得模型的占位参数,以便进行模型的预测

参数说明:’x:0‘ 表示模型在训练过程中,tf.placeholder(name=’x') 输入数据设置的名字

代码中的学习点:1. 使用cv2.resize对图片的维度进行压缩

                             2.使用np.zeros(num_classes)构造标签,lable[index] = 1 构造标签

                             3.使用image.get_shape[1:4].num_elements获得最后三个维度的大小

                              4. saver.save(sess, path, global_step=i) 进行模型参数的存储

                              5.save.restore(sess, path)  进行模型的加载

猫狗识别的代码:主要分为3个部分,

                             第一部分:数据的准备

                             第二部分:构造卷积神经网络,进行模型的训练

                             第三部分:使用saver.restore加载训练好的参数,进行模型的预测。

第一部分:数据的准备,构建read_train_data函数

第一步:输入的参数是文件的地址,图片的大小(进行图像的矩阵变换),标签,验证集的比例

第二步:对构造一个类dataset, 用于存储训练集和验证集

第三步:对标签进行循环,对输入的文件与标签值进行拼接,获得图片文件的地址,使用glob.glob获得每张图片的地址。

第四步:循环图片地址,读入图片

              第一步:使用cv2.imread() 读入图片

              第二步: 使用cv2.resize(img, (img_size, img_size), 0, 0, cv2.Inter) 进行图片的维度变换

              第三步: 使用.astype('float32') 对图片进行数据类型的转换

              第四步: 使用np.multiply(img, 1.0/255.0) 进行图片数值归一化操作, 并将图片加到列表中

              第五步:使用np.zeros(num_classes) 构造标签的零矩阵

              第六步:使用index = classes.index(filed) 获得标签值对应的索引,label[index] = 1 将索引位置赋值为1 

              第七步: 将标签加到列表中

              第八步:使用os.path.basename(file) 获得图片的名字,添加到列表中,获得标签的名字,添加到列表中

第五步:对图片和标签使用np.array转换为数组类型,并返回图片,标签,名字,类别名

第六步:使用sklearn.utils 中的shuffle,对图片,标签,名字和类别名进行清洗

第七步:使用val_size,验证集的比例对训练集和验证集进行分割

第八步:创建类别DataSet,实例化dataset.train和dataset.val,创建.next_batch函数,

第九步:next_batch函数说明:使用一个变量self._epoch_index 对start和end进行递增循环,如果end > self._num_image, 将start置为0, self._epoch_index置为batch_size。

 代码:dataset.py 

import numpy as np
import tensorflow as tf
import os
import glob
import cv2
from sklearn.utils import shuffle



def load_image(file_path, image_size, classes):

    num_classes = len(classes)
    images = []
    labels = []
    names = []
    cls = []
    # 第三步:循环标签,将路径和标签名进行拼接,获得图片文件路径,使用glob.glob获得图片路径
    for filed in classes:
        index = classes.index(filed)
        path = os.path.join(file_path, filed, '*g')
        files = glob.glob(path)
        # 第四步:循环图片路径,进行图片的读取
        for file in files:
            # cv2.imread图片的读取
            image = cv2.imread(file)
            # cv2.resize进行图片维度的重构
            image = cv2.resize(image, (image_size, image_size), 0, 0, cv2.INTER_LINEAR)
            # .astype进行图片的数据类型的变换
            image = image.astype('float32')
            # 使用np.multipy进行图片的归一化操作
            image = np.multiply(image, 1.0/255.0)
            # 将图片添加到列表中
            images.append(image)
            # 标签零值初始化
            label = np.zeros(num_classes)
            # 对于类别位置与标签位置对应,即设置为1
            label[index] = 1
            # 将标签进行添加
            labels.append(label)
            # 获得图片的名字,使用os.path.basename
            name = os.path.basename(file)
            # 将名字进行添加
            names.append(name)
            # 将类别名进行添加
            cls.append(filed)
    # 第五步: 将图片和标签名都转换为array格式, 并返回图片,标签,名字和类别
    images = np.array(images)
    labels = np.array(labels)


    return images, labels, names, cls



class DataSet(object):


    def __init__(self, images, labels, names, cls):

        self._num_image = images.shape[0]
        self._images = images
        self._labels = labels
        self._names = names
        self._cls = cls
        self._epoch_index = 0
    # 私有属性,返回实际的函数值
    @property
    def images(self):
        return self._images
    @property
    def labels(self):
        return self._labels
    @property
    def names(self):
        return self._names
    @property
    def cls(self):
        return self._cls
    @property
    def num_image(self):
        return self._num_image
    # next_batch函数,使用self._epoch_index用来创建初始索引和结束索引,返回batch图像,标签,名字和类别
    def next_batch(self, batch_size):
        start = self._epoch_index
        self._epoch_index += batch_size
        if self._epoch_index > self._num_image:
            start = 0
            self._epoch_index = batch_size
            assert batch_size < self._num_image
        end = self._epoch_index
        return self._images[start:end], self._labels[start:end], self._names[start:end], self._cls[start:end]


# 第一步:输入文件名,图片大小,标签,验证集的比例
def read_train_data(file_path, image_size, classes, val_size):
    # 第二步:构造类,实例化dataset用于存储训练集和验证集
     class DataSets(object):
         pass
     dataset = DataSets()
     # 第三步:载入图片,标签, 名字,类别名
     images, labels, names, cls = load_image(file_path, image_size, classes)
     # 第六步:对图片,标签,名字和类别名进行清洗
     images, labels, names, cls = shuffle(images, labels, names, cls)
     # 第七步:使用val_size 对训练集和验证集图片进行分开
     val_num = int(images.shape[0] * val_size)

     val_images = images[0:val_num]
     val_labels = labels[0:val_num]
     val_names = names[0:val_num]
     val_cls = cls[0:val_num]

     train_images = images[val_num:]
     train_labels = labels[val_num:]
     train_names = names[val_num:]
     train_cls = cls[val_num:]
     # 第八步:创建类别DataSet,实例化train和val数据集,并创建next_batch 
     dataset.train = DataSet(train_images, train_labels, train_names, train_cls)
     dataset.val = DataSet(val_images, val_labels, val_names, val_cls)

     return dataset

 第二步:模型的训练

第一步:参数设置,一二三层卷积的大小和个数,以及全连接层的隐藏层的个数

第二步:使用tf.placeholder设置初始的输入参数x和y_pred,并命名为x和y_pred, 使用np.argmax获得预测的索引值

第三步:构建生成卷积过程中参数的函数, tf.Variable(tf.truncate_normal(shape, stddev=0.05))

第四步:构建进行卷积的函数,使用tf.nn.conv2(x, w, stride=[1, 2, 2, 1], padding='SAME'),再加上偏置项b, 使用激活层tf.nn.relu构建, 使用tf.nn.max_pool构建池化层

第五步:构建进行维度变换的函数,用于进行第一次全连接层的卷积到全连接的维度变换,使用image.get_shape()[1:4].num_elements获得后3个维度的个数之和,即乘积

第六步:构造进行全连接的函数,使用tf.matmul构造全连接函数,这里的话,需要使用tf.nn.dropout进行dropout防止过拟合

第七步:开始进行卷积过程

              第一步:第一层卷积

              第二步:第二层卷积

              第三步:第三次卷积

              第四步:第一次全连接,使用conv.get_shape[1:4].num_elements获得维度,构造参数

               第五步:第二次全连接

第八步:y_pred = tf.nn.softmax构造y_pred, 使用tf.argmax(y_pred, 1)输出索引值

第九步:使用tf.nn.softmax_logits构造损失值loss, logits=score, labels= y_true

第十步:使用tf.train.Adaoptimer().minimize自适应梯度下降降低损失值

第十一步:使用tf.equal(y_pred_cls, y_true_cls) ,tf.reduce_mean构造准确率

第十二步:构建train函数, 开始进行训练,首先使用data.train.next_batch获得batch训练样本,使用sess.run训练trainopt降低损失值,进行参数的训练

第十三步:每一个epoch值,获得train 的batch,获得val_batch,对训练集和验证集的准确率进行展示

代码:train.py

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import dataset


from numpy.random import  seed

seed(0)

from tensorflow import  set_random_seed

set_random_seed(20)


image_size = 60
val_size = 0.2
file_path = 'training_data'
classes = ['cats', 'dogs']
num_channel = 3
num_classes = len(classes)

# 第一部分数据的载入
data = dataset.read_train_data(file_path, image_size, classes, val_size)

image_num = data.train.images.shape[0]
# 第二部分:数据的实际训练


# 第一步参数设置,卷积层的维度和filter的个数
# 第一层卷积大小
filter1_size = 3
filter1_num = 32
# 第二层卷积大小
filter2_size = 3
filter2_num = 32
# 第三层卷积大小
filter3_size = 3
filter3_num = 64
# 隐含层大小
fc1_num = 1024
# 第二步:使用tf.placeholder设置初始输入参数
# 输入参数大小, [图片的数目,图片的宽度, 图片的长度, 图片的通道数]
x = tf.placeholder(tf.float32, [None, image_size, image_size, num_channel], name='x')
# 输入图片标签值,大小为[N, num_classes] 这里为N*2
y_true = tf.placeholder(tf.float32, [None, num_classes], name='y_true')
#真实类别对应的索引值,即1所在的位置
y_true_cls = tf.argmax(y_true, 1)

# 第三步:生成卷积过程中所需要的函数
def create_weight(shape):
    # 生成正态分布的初始值
    return tf.Variable(tf.truncated_normal(shape, stddev=0.05))

def create_bias(size):
    # 生成常数分布的初始值
    return tf.Variable(tf.constant(0.05, shape=[size]))
# 第四步:构造进行卷积的函数
def create_convolution_layers(input, input_channel, filter_size, filter_num):
    # 生成卷积使用的W,[3, 3, 3, 32]第一层卷积核大小
    W = create_weight([filter_size, filter_size, input_channel, filter_num])
    # 生成偏置项b [32]
    b = create_bias(filter_num)
    # 进行卷积操作
    conv_layer = tf.nn.conv2d(input, W, strides=[1, 1, 1, 1], padding='SAME') + b
    # 进行激活操作
    conv_layer = tf.nn.relu(conv_layer)
    # 使用tf.nn.max_pool进行池化操作
    max_pool = tf.nn.max_pool(conv_layer, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding='SAME')
    # 返回池化的结果
    return max_pool
# 第五步:构造图像变换的函数
def create_flatten_conv(input):
    # 获得图片的后3个维度的大小
    input_shape = input.get_shape()[1:4].num_elements()
    # 对图像进行维度的变化,即[-1, input_shape] 以便用于后续的全连接操作
    out = tf.reshape(input, shape=[-1, input_shape])

    return out
# 第六步:构造进行全连接变化的函数
def create_fc_layer(input, num_input, fc1_num, relu_true = True):
    # 构造全连接的函数,即后三个维度的大小和第一个全连接的大小
    W = create_weight([num_input, fc1_num])
    # 构造偏置项b
    b = create_bias(fc1_num)
    # 构造线性变化,即x * w + b
    layer = tf.matmul(input, W) + b
    # 对全连接层进行dropout变化
    layer = tf.nn.dropout(layer, keep_prob=0.7)
    # 如果需要进行激活层
    if relu_true:
        # 就进行激活变化
        layer = tf.nn.relu(layer)
    # 返回结果
    return layer
# 第七步:进行正式的卷积过程
# 第一层卷积,输入为x, 通道数,卷积核的大小,卷积的个数
conv_h1 = create_convolution_layers(x, num_channel, filter1_size, filter1_num)
# 第二层卷积
conv_h2 = create_convolution_layers(conv_h1, filter1_num, filter2_size, filter2_num)
# 第三层卷积
conv_h3 = create_convolution_layers(conv_h2, filter2_num, filter3_size, filter3_num)
# 获得第三层卷积后的后3个维度的大小
flatten_shape = conv_h3.get_shape()[1:4].num_elements()
# 对图像进行维度变化
flatten_conv = create_flatten_conv(conv_h3)
# 进行全连接操作,输入的是变换后的图像,全连接的第一个维度和第二个维度
fc_h1 = create_fc_layer(flatten_conv, flatten_shape, fc1_num)
# 进行第二次全连接,输出预测的得分值
out = create_fc_layer(fc_h1, fc1_num, num_classes, relu_true=False)
# 第八步:使用tf.nn.softmax获得输入得分的概率值
y_pred = tf.nn.softmax(out, name='y_pred')
# 使用tf.agrmax获得对应的最大索引的大小
y_pred_cls = tf.argmax(y_pred, 1)
# 第九步:使用tf.reduce_mean获得softmax的损失值
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y_true, logits=out))
# 第十步:使用自适应梯度下降,进行损失值的下降
train_op = tf.train.AdamOptimizer(0.0001).minimize(cost)
# 第十一步:使用tf.equal表示类别是否相同
correct_pred = tf.equal(y_true_cls, y_pred_cls)
accur = tf.reduce_mean(tf.cast(correct_pred, 'float'))

# 构造session函数
session = tf.Session()
# 构造存储函数
saver = tf.train.Saver()
# 进行初始化操作
session.run(tf.global_variables_initializer())

batch_size = 32

def show_progress(data, lost, epoch, i):
    
    tr_image_batch, tr_label_batch = data.train.next_batch(batch_size)[0:2]
    val_image_batch, val_label_batch = data.val.next_batch(batch_size)[0:2]
    # 输出训练样本的准确率
    tr_accur = session.run(accur, feed_dict={x:tr_image_batch, y_true:tr_label_batch})
    # 输出验证样本的准确率
    val_accur = session.run(accur, feed_dict={x:val_image_batch, y_true:val_label_batch})
    # 打印epoch值,训练集和验证集准确率,训练的损失值,迭代的次数
    content = ('train_epoch {0} tr_accur {1:>6.1%} val_accur {2:6.1%} train_loss {3:.3f} iteration_num {4}')
    print(content.format(epoch, tr_accur, val_accur, lost, i))
def train(num_iteration):
    start_epoch = 0
    for i in range(num_iteration):
        # 第十二步:构造函数进行参数的实际代入,使用data.train.next_batch获得模型的训练样本和验证集样本,进行模型训练
        batch_image, batch_labels, batch_nams, batch_cls = data.train.next_batch(batch_size)
        session.run(train_op, feed_dict={x:batch_image, y_true:batch_labels})
        #第十三步:每一个epoch进行模型的准确率的输出
        if i % int(data.train.num_image / batch_size) == 0:
            # 计算模型的损失值
            loss = session.run(cost, feed_dict={x:batch_image, y_true:batch_labels})
            # 展示模型的训练集和验证集的准确率
            show_progress(data, loss, start_epoch, i)
            start_epoch += 1
            # 第十四步:使用saver.save(session, './dog-cats-model/dog-cat.ckpt', global_step)进行模型的参数保存
            saver.save(session, './dog-cats-model/dog-cat.ckpt', global_step=i)


train(8000)

第三部分:进行模型的预测

第一步:图片的输入,对于输入的图片需要进行与训练样本输入时相同的处理

              第一步:使用cv2.imread()进行样本的读取

              第二步:使用cv2.resize进行图片的维度变换

              第三步:.astype对样本的类型进行变换

              第四步:使用np.multipy对样本进行归一化操作

              第五步:将图片的维度进行变换,因为是一张图片,维度变化为[1, 60, 60, 3]

           

第二步:将训练好的模型进行加载

              第一步:构建sess = tf.Session() 
              第二步:使用saver = tf.train.import_meta_graph 加载模型的meta 

              第三步:使用saver.restore() 加载模型的ckpt-3750

              第四步:graph = tf.get_default_graph()获得参数结构图

              第五步:使用graph.get_tensor_by_name('y_pred:0') 获得预测y_pred

               第五步:使用graph.get_tensor_by_name('x:0') 获得输入x

               第六步:使用graph.get_tensor_by_name('y_pred:0') 获得输入标签y_true 

               第七步:使用np.zeros((1, 2))构造输入值得标签

               第八步:使用sess.run(y_pred, feed_dict={x:x_batch, y_pred:y_test_img}) 进行结果的预测

               第九步:使用tf.argmax获得标签的索引,使用标签名获得最终的预测结果

 代码:predict.py 

import tensorflow as tf
import numpy as np
import cv2

# 第一步图片的载入
image_size = 60
# 图片的文件名
path = 'cat.4.jpg'
# 读取图片
image = cv2.imread(path)
# 改变图片的大小
image = cv2.resize(image, (image_size, image_size), 0, 0, cv2.INTER_LINEAR)
# 图片类型的转换
image = image.astype('float32')
# 进行图像的归一化
image = np.multiply(image, 1.0/255.0)
# 对图像进行维度的变化
x_batch = image.reshape(1, image_size, image_size, 3)

# 加载模型,对图片进行预测
# 初始化sess
sess = tf.Session()
# 载入saver,获得模型的结果saver
saver = tf.train.import_meta_graph('./dog-cats-model/dog-cat.ckpt-3700.meta')
# 使用saver加载sess
saver.restore(sess, './dog-cats-model/dog-cat.ckpt-3700')
# 获得模型的结构图
graph = tf.get_default_graph()
# 使用结构图获得模型参数y_pred
y_pred = graph.get_tensor_by_name('y_pred:0')
# 获得模型参数x
x = graph.get_tensor_by_name('x:0')
# 获得模型参数y_true
y_true = graph.get_tensor_by_name('y_true:0')
# 构造真实的标签值,初始化
y_test_images = np.zeros((1, 2))
# 输入的样本参数
feed_dict_testing = {x:x_batch, y_pred:y_test_images}
# 获得模型的预测结果,使用sess.run 
result = sess.run(y_pred, feed_dict=feed_dict_testing)
# 根据预测得分,获得最大值的标签索引做为标签索引,获得最终的预测结果
res_label = ['cat', 'dog']
print(res_label[result.argmax()])

          

原文地址:https://www.cnblogs.com/my-love-is-python/p/10541030.html