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()])