1.cv2.resize(image, (image_size, image_size), 0, 0, cv2.INTER_LINEAR)git
參數說明:image表示輸入圖片,image_size表示變化後的圖片大小,0, 0表示dx和dy, cv2.INTER_LINEAR表示插值的方式爲線性插值數組
2.image.get_shape[1:4].num_elements() 得到最後三個維度的大小之和網絡
參數說明:image表示輸入的圖片session
3. saver.save(sess, path, global_step=i) 進行sess的加載app
參數說明:sess表示輸入,path表示保存路徑, global_step表示路徑的結尾dom
4.saver = tf.train.import_meta_graph('./dog-cats-model/dog-cat.ckpt-3700.meta') # 加載訓練好的模型的meta值ide
參數說明:./dog-cats-model/dog-cat.ckpt-3700.meta表示meta 的路徑函數
5.saver.restore(sess, ckpt_path) # 加載訓練好的參數模型學習
參數說明:sess表示執行函數,ckpt_path表示ckpt的路徑spa
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()])