深度學習原理與框架-貓狗圖像識別-卷積神經網絡(代碼) 1.cv2.resize(圖片壓縮) 2..get_shape()[1:4].num_elements(得到最後三維度之和) 3.saver.s

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

相關文章
相關標籤/搜索