日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)

發布時間:2024/4/15 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用自己的數據集訓練GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)

【尊重原創,轉載請注明出處】https://blog.csdn.net/guyuealian/article/details/81560537

新增博客《使用自己的數據集訓練MobileNet、ResNet圖像識別(TensorFlow)》https://panjinquan.blog.csdn.net/article/details/88252699


一、前言

1、網上已有對GoogLenet模型原理詳盡分析了,因此本博客并不打算詳細分析GoogLenet,而主要談及GoogLenet代碼實現方面。誠然,網上已經有很多使用TensorFlow實現GoogLenet模型,但很尷尬的是,代碼基本上都是你抄我,我復制你。原型代碼貌似都是來自黃文堅著作《TensorFlow實戰》-第六章的《6.3TensorFlow 實現 GooglelnceptionNet》。要想改動為實際可用的、可訓練、可測試的圖像分類模型,還是要花很大的力氣的。

2、本博客,將使用TensorFlow實現GoogLenet V1和GoogLenet V3的圖像分類,其中GoogLenet V3的源碼也是參考黃文堅著作《TensorFlow實戰》,注意該文的源碼僅僅是對Inception V3進行運算性能的測試,并未做圖像分類的測試。實質上,官網TensorFlow已經使用TF-slim實現了InceptionNet?V1,V2,V3,V4等模型,為什么不用呢?因此鄙人在此基礎上,完成訓練和測試的封裝。

3、為了方便大家,這里會提供

  • (1)訓練和測試的圖片數據集
  • (2)提供制作tfrecords數據格式的Python文件
  • (3)GoogLenet訓練和測試的完整代碼,包含inception v1 v2 v3的訓練方法
  • (4)干脆整個工程的項目都放在Github,老鐵要是覺得不錯,記得給個“star”哈
  • (5)新增《使用自己的數據集訓練MobileNet、ResNet圖像識別(TensorFlow)https://panjinquan.blog.csdn.net/article/details/88252699
  • Github源碼:https://github.com/PanJinquan/tensorflow_models_learning
  • 預訓練模型下載地址:https://download.csdn.net/download/guyuealian/10610847
  • 關于其他模型MobileNet和ResNet模型訓練方法,請參考另一篇博客:使用自己的數據集訓練MobileNet、ResNet圖像識別(TensorFlow)https://panjinquan.blog.csdn.net/article/details/88252699

目錄

使用自己的數據集訓練GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)

一、前言

1、googlenet 的網絡示意圖:

2、Inception 模塊

二、項目文件結構說明

三、訓練模型過程

1、訓練和測試的圖片數據集

2、制作tfrecords數據格式

3、GoogLenet網絡結構

4、訓練方法實現過程

5、模型預測

四、其他模型訓練方法?

五、將ckpt轉pb文件


? ? InceptionNet,是 Google 的研究人員提出的網絡結構(所以也叫做`GoogLeNet`),在當時取得了非常大的影響,因為網絡的結構變得前所未有,它顛覆了大家對卷積網絡的串聯的印象和固定做法,采用了一種非常有效的 inception 模塊,得到了比 VGG 更深的網絡結構,但是卻比 VGG 的參數更少,因為其去掉了后面的全連接層,所以參數大大減少,同時有了很高的計算效率。


1、googlenet 的網絡示意圖:


2、Inception 模塊

? ? 在上面的網絡中,我們看到了多個四個并行卷積的層,這些四個卷積并行的層就是 inception 模塊,可視化如下

一個 inception 模塊的四個并行線路如下:

1.一個 1 x 1 的卷積,一個小的感受野進行卷積提取特征
2.一個 1 x 1 的卷積加上一個 3 x 3 的卷積,1 x 1 的卷積降低輸入的特征通道,減少參數計算量,然后接一個 3 x 3 的卷積做一個較大感受野的卷積
3.一個 1 x 1 的卷積加上一個 5 x 5 的卷積,作用和第二個一樣
4.一個 3 x 3 的最大池化加上 1 x 1 的卷積,最大池化改變輸入的特征排列,1 x 1 的卷積進行特征提取

最后將四個并行線路得到的特征在通道這個維度上拼接在一起


二、項目文件結構說明

tensorflow_models_nets:

|__dataset???#數據文件

????|__record #里面存放record文件

????|__train????#train原始圖片

????|__val??????#val原始圖片

|__models??#保存訓練的模型

|__slim????????#這個是拷貝自slim模塊:https://github.com/tensorflow/models/tree/master/research/slim

|__test_image #存放測試的圖片

|__create_labels_files.py #制作trian和val TXT的文件

|__create_tf_record.py #制作tfrecord文件

|__inception_v1_train_val.py #inception V1的訓練文件

|__inception_v3_train_val.py # inception V3訓練文件

|__mobilenet_train_val.py#mobilenet訓練文件

|__resnet_v1_train_val.py#resnet訓練文件

|__predict.py # 模型預測文件


三、訓練模型過程

1、訓練和測試的圖片數據集

? ? 下面是我下載的數據集,共有五類圖片,分別是:flower、guitar、animal、houses和plane,每組數據集大概有800張左右。為了照顧網友,下面的數據集,都已經放在Github項目的文件夾dataset上了,記得給個“star”哈

animal:http://www.robots.ox.ac.uk/~vgg/data/pets/
flower:http://www.robots.ox.ac.uk/~vgg/data/flowers/
plane:http://www.robots.ox.ac.uk/~vgg/data/airplanes_side/airplanes_side.tar
house:http://www.robots.ox.ac.uk/~vgg/data/houses/houses.tar
guitar:http://www.robots.ox.ac.uk/~vgg/data/guitars/guitars.tar

? ? 下載圖片數據集后,需要劃分為train和val數據集,前者用于訓練模型的數據,后者主要用于驗證模型。這里提供一個create_labels_files.py腳本,可以直接生成訓練train和驗證val的數據集txt文件。

#-*-coding:utf-8-*- """@Project: googlenet_classification@File : create_labels_files.py@Author : panjq@E-mail : pan_jinquan@163.com@Date : 2018-08-11 10:15:28 """import os import os.pathdef write_txt(content, filename, mode='w'):"""保存txt數據:param content:需要保存的數據,type->list:param filename:文件名:param mode:讀寫模式:'w' or 'a':return: void"""with open(filename, mode) as f:for line in content:str_line = ""for col, data in enumerate(line):if not col == len(line) - 1:# 以空格作為分隔符str_line = str_line + str(data) + " "else:# 每行最后一個數據用換行符“\n”str_line = str_line + str(data) + "\n"f.write(str_line) def get_files_list(dir):'''實現遍歷dir目錄下,所有文件(包含子文件夾的文件):param dir:指定文件夾目錄:return:包含所有文件的列表->list'''# parent:父目錄, filenames:該目錄下所有文件夾,filenames:該目錄下的文件名files_list = []for parent, dirnames, filenames in os.walk(dir):for filename in filenames:# print("parent is: " + parent)# print("filename is: " + filename)# print(os.path.join(parent, filename)) # 輸出rootdir路徑下所有文件(包含子文件)信息curr_file=parent.split(os.sep)[-1]if curr_file=='flower':labels=0elif curr_file=='guitar':labels=1elif curr_file=='animal':labels=2elif curr_file=='houses':labels=3elif curr_file=='plane':labels=4files_list.append([os.path.join(curr_file, filename),labels])return files_listif __name__ == '__main__':train_dir = 'dataset/train'train_txt='dataset/train.txt'train_data = get_files_list(train_dir)write_txt(train_data,train_txt,mode='w')val_dir = 'dataset/val'val_txt='dataset/val.txt'val_data = get_files_list(val_dir)write_txt(val_data,val_txt,mode='w')

? ? 注意,上面Python代碼,已經定義每組圖片對應的標簽labels:

flower ? ->labels=0
guitar ? ->labels=1
animal ?->labels=2
houses ->labels=3
plane ? ?->labels=4

2、制作tfrecords數據格式

? ? ?有了 train.txt和val.txt數據集,我們就可以制作train.tfrecords和val.tfrecords文件了,項目提供一個用于制作tfrecords數據格式的Python文件:create_tf_record.py,鄙人已經把代碼放在另一篇博客:《Tensorflow生成自己的圖片數據集TFrecords》https://blog.csdn.net/guyuealian/article/details/80857228?,代碼有詳細注釋了,所以這里不貼出來了.

注意:

(1)create_tf_record.py將train和val數據分別保存為單個record文件,當圖片數據很多時候,會導致單個record文件超級巨大的情況,解決方法就是,將數據分成多個record文件保存,讀取時,只需要將多個record文件的路徑列表交給“tf.train.string_input_producer”即可。

(2)如何將數據保存為多個record文件呢?請參考鄙人的博客:《Tensorflow生成自己的圖片數據集TFrecords》https://blog.csdn.net/guyuealian/article/details/80857228

? ? create_tf_record.py提供幾個重要的函數:

  • create_records():用于制作records數據的函數,
  • read_records():用于讀取records數據的函數,
  • get_batch_images():用于生成批訓練數據的函數
  • get_example_nums:統計tf_records圖像的個數(example個數)
  • disp_records():?解析record文件,并顯示圖片,主要用于驗證生成record文件是否成功
  • 3、GoogLenet網絡結構

    ? ? ? ? GoogLenet InceptionNet有很多的變體, 比如`InceptionV1`,`V2`, `V3`, `V4`版本,網上已經有很多使用TensorFlow實現的,但很尷尬的是,代碼基本上都是你抄我,我復制你。原型代碼貌似都是來自黃文堅著作《TensorFlow實戰》-第六章的《6.3TensorFlow 實現 GooglelnceptionNet》。要想改動為實際可用的、可訓練、可測試的圖像分類模型,還是要花很大的力氣的。

    ? ? ? ? 本人一開始就想把黃文堅第六章的《6.3TensorFlow 實現 GooglelnceptionNet》的源碼封裝成可訓練的過程,但訓練過程發現模型一直不收斂,識別率一直在0.2-0.3%浮動,不知道是我參數設置問題,還是我訓練代碼出錯了,反正就是不行!!!

    ? ? ? ? 官網TensorFlow已經提供了使用TF-slim實現的InceptionNet?V1,V2,V3,V4模型。TF-Slim是tensorflow中定義、訓練和評估復雜模型的輕量級庫。tf-slim中的組件可以輕易地和原生tensorflow框架以及例如tf.contrib.learn這樣的框架進行整合。

    1、官網模型地址:https://github.com/tensorflow/models/tree/master/research/slim/nets

    2、slim/nets下的模型都是用TF-slim實現的網絡結構,關系TF-slim的用法,可參考:

    《tensorflow中slim模塊api介紹》:https://blog.csdn.net/guvcolie/article/details/77686555

    4、訓練方法實現過程

    ? ? inception_v3要求訓練數據height, width = 299, 299(親測用224也是可以的),項目使用create_tf_record.py制作了訓練train299.tfrecords和驗證val299.tfrecords數據,下面是inception_v3_train_val.py文件代碼說明:

    from datetime import datetime import slim.nets.inception_v3 as inception_v3 from create_tf_record import * import tensorflow.contrib.slim as slimlabels_nums = 5 # 類別個數 batch_size = 16 # resize_height = 299 # 指定存儲圖片高度 resize_width = 299 # 指定存儲圖片寬度 depths = 3 data_shape = [batch_size, resize_height, resize_width, depths]

    下面就一步一步實現訓練過程:

    (1)先占幾個坑用來填數據:

    ? tf.placeholder()是TensorFlow的占位符節點,由placeholder方法創建,其也是一種常量,但是由用戶在調用run方法時傳遞的,可以簡單理解為形參,用于定義過程,在執行的時候再賦具體的值。利用tf.placeholder(),代碼就可以很方便的實現:is_training=True時,填充train數據進行訓練過程,is_training=False時,填充val數據進行驗證過程

    # 定義input_images為圖片數據 input_images = tf.placeholder(dtype=tf.float32, shape=[None, resize_height, resize_width, depths], name='input') # 定義input_labels為labels數據 # input_labels = tf.placeholder(dtype=tf.int32, shape=[None], name='label') input_labels = tf.placeholder(dtype=tf.int32, shape=[None, labels_nums], name='label')# 定義dropout的概率 keep_prob = tf.placeholder(tf.float32,name='keep_prob') is_training = tf.placeholder(tf.bool, name='is_training')

    (2)定義一個訓練函數train():

    def train(train_record_file,train_log_step,train_param,val_record_file,val_log_step,labels_nums,data_shape,snapshot,snapshot_prefix):''':param train_record_file: 訓練的tfrecord文件:param train_log_step: 顯示訓練過程log信息間隔:param train_param: train參數:param val_record_file: 驗證的tfrecord文件:param val_log_step: 顯示驗證過程log信息間隔:param val_param: val參數:param labels_nums: labels數:param data_shape: 輸入數據shape:param snapshot: 保存模型間隔:param snapshot_prefix: 保存模型文件的前綴名:return:'''

    (3)讀取訓練和驗證數據

    ? ? create_tf_record.py文件提供了讀取records數據的函數read_records(),以及獲得批訓練的數據get_batch_images()。一般而言,訓練時需要打亂輸入數據,因此函數get_batch_images()提供了shuffle=True參數可以打亂輸入數據,但該函數僅僅對一個批次的數據進行打亂的,并未達到隨機打亂所有訓練數據的要求,鄙人建議是:在制作records數據時就打亂訓練數據,即設置create_records()函數的參數shuffle=True,而對val數據,不要求打亂數據。

    [base_lr,max_steps]=train_param[batch_size,resize_height,resize_width,depths]=data_shape# 獲得訓練和測試的樣本數train_nums=get_example_nums(train_record_file)val_nums=get_example_nums(val_record_file)print('train nums:%d,val nums:%d'%(train_nums,val_nums))# 從record中讀取圖片和labels數據# train數據,訓練數據一般要求打亂順序shuffle=Truetrain_images, train_labels = read_records(train_record_file, resize_height, resize_width, type='normalization')train_images_batch, train_labels_batch = get_batch_images(train_images, train_labels,batch_size=batch_size, labels_nums=labels_nums,one_hot=True, shuffle=True)# val數據,驗證數據可以不需要打亂數據val_images, val_labels = read_records(val_record_file, resize_height, resize_width, type='normalization')val_images_batch, val_labels_batch = get_batch_images(val_images, val_labels,batch_size=batch_size, labels_nums=labels_nums,one_hot=True, shuffle=False)

    (4)定義inception_v3網絡模型

    ? ? TensorFlow的inception_v3是用tf.contrib.slim寫的。slim.arg_scope用于為tensorflow里的layer函數提供默認參數值,以使構建模型的代碼更加緊湊苗條(slim)。inception_v3已經定義好了默認的參數值:inception_v3_arg_scope(),因此,需要在定義inception_v3模型之前,設置默認參數。

    # Define the model:with slim.arg_scope(inception_v3.inception_v3_arg_scope()):out, end_points = inception_v3.inception_v3(inputs=input_images, num_classes=labels_nums, dropout_keep_prob=keep_prob, is_training=is_training)

    (5)指定損失函數和準確率(重點)

    ? ? inception_v3模型的默認參數inception_v3.inception_v3_arg_scope()已經定義了L2正則化項(你可以看一下源碼:weights_regularizer=slim.l2_regularizer(weight_decay)),因此定義損失函數時,需要把L2正則化項的損失也加進來優化。這里就需要特別特別……說明一下:

    • 若使用 tf.losses自帶的loss函數,則都會自動添加到loss集合中,不需要add_loss()了:如:tf.losses.softmax_cross_entropy()
    • 如使用tf.nn的自帶的損失函數,則必須手動添加,如:? ? tf.nn.sparse_softmax_cross_entropy_with_logits()和?tf.nn.softmax_cross_entropy_with_logits()
    • 特別的,若自定義myloss損失函數,若myloss損失函數中使用了tf.losses中的loss函數,并將該loss添加到slim.losses.add_loss()中,?這時使用tf.losses.get_total_loss()函數時相當于累加兩次myloss,因為tf.losses中的loss值都會自動添加到slim.losses接合中。因此若使用tf.losses中自帶的loss函數,則不需要add_loss()了,否則相當于重復添加了

    ? ? ?本項目源碼使用交叉熵損失函數tf.losses.softmax_cross_entropy()和L2正則項add_regularization_losses=True!僅僅兩條語句就Ok了,簡單了吧,不得不驚嘆tf.contrib.slim庫的強大,大大簡化網絡代碼的定義。若你使用原生的tf定義損失函數,你會發現計算L2正則項的損失,特別麻煩。

    # Specify the loss function: tf.losses定義的loss函數都會自動添加到loss函數,不需要add_loss()了tf.losses.softmax_cross_entropy(onehot_labels=input_labels, logits=out)#添加交叉熵損失loss=1.6# slim.losses.add_loss(my_loss)loss = tf.losses.get_total_loss(add_regularization_losses=True)#添加正則化損失loss=2.2accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(out, 1), tf.argmax(input_labels, 1)), tf.float32))

    (6)定義優化方案

    ? ? 這里使用GradientDescentOptimizer梯度下降法,當然也可以選擇MomentumOptimizer或者AdadeltaOptimizer其他優化方法。由于inception_v3使用了batch_norm層,需要更新每一層的`average`和`variance`參數,?更新的過程不包含在正常的訓練過程中, 需要我們去手動更新,并通過`tf.get_collection`獲得所有需要更新的`op`。

    ???slim.batch_norm里有moving_mean和moving_variance兩個量,分別表示每個批次的均值和方差。當training時候,參數moving_mean和moving_variance的都需要update。看官網教程的解釋和用法:

    ??Note: when training, the moving_mean and moving_variance need to be updated.
    ??By default the update ops are placed in `tf.GraphKeys.UPDATE_OPS`, so they
    ??need to be added as a dependency to the `train_op`. For example:
    ??```python
    ????update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
    ????with tf.control_dependencies(update_ops):
    ????????train_op = optimizer.minimize(loss)

    ??```

    一個不確定的說明:

    (1)若使用train_op = optimizer.minimize(loss)函數時,則需要手動更新每一層的`average`和`variance`參數,并通過`tf.get_collection`獲得所有需要更新的`op`

    (2)若使用slim.learning.create_train_op()產生訓練的op,貌似會自動更新每一層的參數,這個不確定!主要是我發現即使沒有tf.get_collection,使用slim.learning.create_train_op()時,訓練也是收斂的。

    # Specify the optimization scheme:optimizer = tf.train.GradientDescentOptimizer(learning_rate=base_lr)# 在定義訓練的時候, 注意到我們使用了`batch_norm`層時,需要更新每一層的`average`和`variance`參數,# 更新的過程不包含在正常的訓練過程中, 需要我們去手動像下面這樣更新# 通過`tf.get_collection`獲得所有需要更新的`op`update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)# 使用`tensorflow`的控制流, 先執行更新算子, 再執行訓練with tf.control_dependencies(update_ops):# create_train_op that ensures that when we evaluate it to get the loss,# the update_ops are done and the gradient updates are computed.# train_op = slim.learning.create_train_op(total_loss=loss,optimizer=optimizer)train_op = slim.learning.create_train_op(total_loss=loss, optimizer=optimizer)

    (7)訓練迭代訓練

    ? ? ?TF-Slim自帶了非常強大的訓練工具?slim.learning.train()函數,下面是該函數的簡單用法

    g = tf.Graph()# Create the model and specify the losses... ...total_loss = slim.losses.get_total_loss() optimizer = tf.train.GradientDescentOptimizer(learning_rate)# create_train_op ensures that each time we ask for the loss, the update_ops # are run and the gradients being computed are applied too. train_op = slim.learning.create_train_op(total_loss, optimizer) logdir = ... # Where checkpoints are stored.slim.learning.train(train_op,logdir,number_of_steps=1000,save_summaries_secs=300,save_interval_secs=600):

    ? ? ?不過啦~本人在循環迭代過程并未使用?slim.learning.train()函數,而是使用原生普通的tensorflow代碼。主要是因為我想根據自己的需要控制迭代過程,顯示log信息和保存模型:

    說明:

    1、step_train()函數可以實現測試trian的準確率(這里僅測試訓練集的一個batch),而val的數據數據是全部都需要測試的

    2、可以設置模型保存間隔,源碼還實現保存val準確率最高的模型

    def step_train(train_op,loss,accuracy,train_images_batch,train_labels_batch,train_nums,train_log_step,val_images_batch,val_labels_batch,val_nums,val_log_step,snapshot_prefix,snapshot):'''循環迭代訓練過程:param train_op: 訓練op:param loss: loss函數:param accuracy: 準確率函數:param train_images_batch: 訓練images數據:param train_labels_batch: 訓練labels數據:param train_nums: 總訓練數據:param train_log_step: 訓練log顯示間隔:param val_images_batch: 驗證images數據:param val_labels_batch: 驗證labels數據:param val_nums: 總驗證數據:param val_log_step: 驗證log顯示間隔:param snapshot_prefix: 模型保存的路徑:param snapshot: 模型保存間隔:return: None'''saver = tf.train.Saver()max_acc = 0.0with tf.Session() as sess:sess.run(tf.global_variables_initializer())sess.run(tf.local_variables_initializer())coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)for i in range(max_steps + 1):batch_input_images, batch_input_labels = sess.run([train_images_batch, train_labels_batch])_, train_loss = sess.run([train_op, loss], feed_dict={input_images: batch_input_images,input_labels: batch_input_labels,keep_prob: 0.5, is_training: True})# train測試(這里僅測試訓練集的一個batch)if i % train_log_step == 0:train_acc = sess.run(accuracy, feed_dict={input_images: batch_input_images,input_labels: batch_input_labels,keep_prob: 1.0, is_training: False})print "%s: Step [%d] train Loss : %f, training accuracy : %g" % (datetime.now(), i, train_loss, train_acc)# val測試(測試全部val數據)if i % val_log_step == 0:mean_loss, mean_acc = net_evaluation(sess, loss, accuracy, val_images_batch, val_labels_batch, val_nums)print "%s: Step [%d] val Loss : %f, val accuracy : %g" % (datetime.now(), i, mean_loss, mean_acc)# 模型保存:每迭代snapshot次或者最后一次保存模型if (i % snapshot == 0 and i > 0) or i == max_steps:print('-----save:{}-{}'.format(snapshot_prefix, i))saver.save(sess, snapshot_prefix, global_step=i)# 保存val準確率最高的模型if mean_acc > max_acc and mean_acc > 0.7:max_acc = mean_accpath = os.path.dirname(snapshot_prefix)best_models = os.path.join(path, 'best_models_{}_{:.4f}.ckpt'.format(i, max_acc))print('------save:{}'.format(best_models))saver.save(sess, best_models)coord.request_stop()coord.join(threads)

    ? ? 有木有覺得step_train()函數,跟Caffe的solver.prototxt的參數設置很像,比如snapshot_prefix、snapshot等參數,沒錯,我就是學Caffe轉學TensorFlow的。因為習慣了Caffe的訓練方式,所以啦,我把循環迭代改成類似于Caffe的形式,娃哈哈!

    ? ? 其中net_evaluation為評價函數:

    def net_evaluation(sess,loss,accuracy,val_images_batch,val_labels_batch,val_nums):val_max_steps = int(val_nums / batch_size)val_losses = []val_accs = []for _ in xrange(val_max_steps):val_x, val_y = sess.run([val_images_batch, val_labels_batch])# print('labels:',val_y)# val_loss = sess.run(loss, feed_dict={x: val_x, y: val_y, keep_prob: 1.0})# val_acc = sess.run(accuracy,feed_dict={x: val_x, y: val_y, keep_prob: 1.0})val_loss,val_acc = sess.run([loss,accuracy], feed_dict={input_images: val_x, input_labels: val_y, keep_prob:1.0, is_training: False})val_losses.append(val_loss)val_accs.append(val_acc)mean_loss = np.array(val_losses, dtype=np.float32).mean()mean_acc = np.array(val_accs, dtype=np.float32).mean()return mean_loss, mean_acc

    ? ? 完整的inception_v3_train_val.py代碼:

    #coding=utf-8import tensorflow as tf import numpy as np import pdb import os from datetime import datetime import slim.nets.inception_v3 as inception_v3 from create_tf_record import * import tensorflow.contrib.slim as slimlabels_nums = 5 # 類別個數 batch_size = 16 # resize_height = 299 # 指定存儲圖片高度 resize_width = 299 # 指定存儲圖片寬度 depths = 3 data_shape = [batch_size, resize_height, resize_width, depths]# 定義input_images為圖片數據 input_images = tf.placeholder(dtype=tf.float32, shape=[None, resize_height, resize_width, depths], name='input') # 定義input_labels為labels數據 # input_labels = tf.placeholder(dtype=tf.int32, shape=[None], name='label') input_labels = tf.placeholder(dtype=tf.int32, shape=[None, labels_nums], name='label')# 定義dropout的概率 keep_prob = tf.placeholder(tf.float32,name='keep_prob') is_training = tf.placeholder(tf.bool, name='is_training')def net_evaluation(sess,loss,accuracy,val_images_batch,val_labels_batch,val_nums):val_max_steps = int(val_nums / batch_size)val_losses = []val_accs = []for _ in xrange(val_max_steps):val_x, val_y = sess.run([val_images_batch, val_labels_batch])# print('labels:',val_y)# val_loss = sess.run(loss, feed_dict={x: val_x, y: val_y, keep_prob: 1.0})# val_acc = sess.run(accuracy,feed_dict={x: val_x, y: val_y, keep_prob: 1.0})val_loss,val_acc = sess.run([loss,accuracy], feed_dict={input_images: val_x, input_labels: val_y, keep_prob:1.0, is_training: False})val_losses.append(val_loss)val_accs.append(val_acc)mean_loss = np.array(val_losses, dtype=np.float32).mean()mean_acc = np.array(val_accs, dtype=np.float32).mean()return mean_loss, mean_accdef step_train(train_op,loss,accuracy,train_images_batch,train_labels_batch,train_nums,train_log_step,val_images_batch,val_labels_batch,val_nums,val_log_step,snapshot_prefix,snapshot):'''循環迭代訓練過程:param train_op: 訓練op:param loss: loss函數:param accuracy: 準確率函數:param train_images_batch: 訓練images數據:param train_labels_batch: 訓練labels數據:param train_nums: 總訓練數據:param train_log_step: 訓練log顯示間隔:param val_images_batch: 驗證images數據:param val_labels_batch: 驗證labels數據:param val_nums: 總驗證數據:param val_log_step: 驗證log顯示間隔:param snapshot_prefix: 模型保存的路徑:param snapshot: 模型保存間隔:return: None'''saver = tf.train.Saver()max_acc = 0.0with tf.Session() as sess:sess.run(tf.global_variables_initializer())sess.run(tf.local_variables_initializer())coord = tf.train.Coordinator()threads = tf.train.start_queue_runners(sess=sess, coord=coord)for i in range(max_steps + 1):batch_input_images, batch_input_labels = sess.run([train_images_batch, train_labels_batch])_, train_loss = sess.run([train_op, loss], feed_dict={input_images: batch_input_images,input_labels: batch_input_labels,keep_prob: 0.5, is_training: True})# train測試(這里僅測試訓練集的一個batch)if i % train_log_step == 0:train_acc = sess.run(accuracy, feed_dict={input_images: batch_input_images,input_labels: batch_input_labels,keep_prob: 1.0, is_training: False})print "%s: Step [%d] train Loss : %f, training accuracy : %g" % (datetime.now(), i, train_loss, train_acc)# val測試(測試全部val數據)if i % val_log_step == 0:mean_loss, mean_acc = net_evaluation(sess, loss, accuracy, val_images_batch, val_labels_batch, val_nums)print "%s: Step [%d] val Loss : %f, val accuracy : %g" % (datetime.now(), i, mean_loss, mean_acc)# 模型保存:每迭代snapshot次或者最后一次保存模型if (i % snapshot == 0 and i > 0) or i == max_steps:print('-----save:{}-{}'.format(snapshot_prefix, i))saver.save(sess, snapshot_prefix, global_step=i)# 保存val準確率最高的模型if mean_acc > max_acc and mean_acc > 0.7:max_acc = mean_accpath = os.path.dirname(snapshot_prefix)best_models = os.path.join(path, 'best_models_{}_{:.4f}.ckpt'.format(i, max_acc))print('------save:{}'.format(best_models))saver.save(sess, best_models)coord.request_stop()coord.join(threads)def train(train_record_file,train_log_step,train_param,val_record_file,val_log_step,labels_nums,data_shape,snapshot,snapshot_prefix):''':param train_record_file: 訓練的tfrecord文件:param train_log_step: 顯示訓練過程log信息間隔:param train_param: train參數:param val_record_file: 驗證的tfrecord文件:param val_log_step: 顯示驗證過程log信息間隔:param val_param: val參數:param labels_nums: labels數:param data_shape: 輸入數據shape:param snapshot: 保存模型間隔:param snapshot_prefix: 保存模型文件的前綴名:return:'''[base_lr,max_steps]=train_param[batch_size,resize_height,resize_width,depths]=data_shape# 獲得訓練和測試的樣本數train_nums=get_example_nums(train_record_file)val_nums=get_example_nums(val_record_file)print('train nums:%d,val nums:%d'%(train_nums,val_nums))# 從record中讀取圖片和labels數據# train數據,訓練數據一般要求打亂順序shuffle=Truetrain_images, train_labels = read_records(train_record_file, resize_height, resize_width, type='normalization')train_images_batch, train_labels_batch = get_batch_images(train_images, train_labels,batch_size=batch_size, labels_nums=labels_nums,one_hot=True, shuffle=True)# val數據,驗證數據可以不需要打亂數據val_images, val_labels = read_records(val_record_file, resize_height, resize_width, type='normalization')val_images_batch, val_labels_batch = get_batch_images(val_images, val_labels,batch_size=batch_size, labels_nums=labels_nums,one_hot=True, shuffle=False)# Define the model:with slim.arg_scope(inception_v3.inception_v3_arg_scope()):out, end_points = inception_v3.inception_v3(inputs=input_images, num_classes=labels_nums, dropout_keep_prob=keep_prob, is_training=is_training)# Specify the loss function: tf.losses定義的loss函數都會自動添加到loss函數,不需要add_loss()了tf.losses.softmax_cross_entropy(onehot_labels=input_labels, logits=out)#添加交叉熵損失loss=1.6# slim.losses.add_loss(my_loss)loss = tf.losses.get_total_loss(add_regularization_losses=True)#添加正則化損失loss=2.2accuracy = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(out, 1), tf.argmax(input_labels, 1)), tf.float32))# Specify the optimization scheme:optimizer = tf.train.GradientDescentOptimizer(learning_rate=base_lr)# global_step = tf.Variable(0, trainable=False)# learning_rate = tf.train.exponential_decay(0.05, global_step, 150, 0.9)## optimizer = tf.train.MomentumOptimizer(learning_rate, 0.9)# # train_tensor = optimizer.minimize(loss, global_step)# train_op = slim.learning.create_train_op(loss, optimizer,global_step=global_step)# 在定義訓練的時候, 注意到我們使用了`batch_norm`層時,需要更新每一層的`average`和`variance`參數,# 更新的過程不包含在正常的訓練過程中, 需要我們去手動像下面這樣更新# 通過`tf.get_collection`獲得所有需要更新的`op`update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)# 使用`tensorflow`的控制流, 先執行更新算子, 再執行訓練with tf.control_dependencies(update_ops):# create_train_op that ensures that when we evaluate it to get the loss,# the update_ops are done and the gradient updates are computed.# train_op = slim.learning.create_train_op(total_loss=loss,optimizer=optimizer)train_op = slim.learning.create_train_op(total_loss=loss, optimizer=optimizer)# 循環迭代過程step_train(train_op, loss, accuracy,train_images_batch, train_labels_batch, train_nums, train_log_step,val_images_batch, val_labels_batch, val_nums, val_log_step,snapshot_prefix, snapshot)if __name__ == '__main__':train_record_file='dataset/record/train299.tfrecords'val_record_file='dataset/record/val299.tfrecords'train_log_step=100base_lr = 0.01 # 學習率max_steps = 10000 # 迭代次數train_param=[base_lr,max_steps]val_log_step=200snapshot=2000#保存文件間隔snapshot_prefix='models/model.ckpt'train(train_record_file=train_record_file,train_log_step=train_log_step,train_param=train_param,val_record_file=val_record_file,val_log_step=val_log_step,labels_nums=labels_nums,data_shape=data_shape,snapshot=snapshot,snapshot_prefix=snapshot_prefix)

    OK啦,運行啟動訓練看看log信息:

    2018-08-16 10:08:57.107124: Step [0] ?train Loss : 2.762746, training accuracy : ?0.3125
    2018-08-16 10:09:19.281263: Step [0] ?val Loss : 2.931877, val accuracy : ?0.215726
    2018-08-16 10:10:33.807865: Step [100] ?train Loss : 1.849171, training accuracy : ?0.375
    2018-08-16 10:11:56.997064: Step [200] ?train Loss : 2.248142, training accuracy : ?0.0625
    2018-08-16 10:12:22.684584: Step [200] ?val Loss : 163.246002, val accuracy : ?0.200941
    2018-08-16 10:13:44.102429: Step [300] ?train Loss : 1.785683, training accuracy : ?0.25
    ……

    2018-08-16 10:48:24.938470: Step [2500] ?train Loss : 0.732916, training accuracy : ?0.3125
    2018-08-16 10:49:45.958701: Step [2600] ?train Loss : 0.749750, training accuracy : ?0.25
    2018-08-16 10:50:10.845769: Step [2600] ?val Loss : 9.741004, val accuracy : ?0.387769
    2018-08-16 10:51:31.777861: Step [2700] ?train Loss : 1.074746, training accuracy : ?0.4375
    2018-08-16 10:52:52.909256: Step [2800] ?train Loss : 0.814188, training accuracy : ?0.125
    2018-08-16 10:53:17.725089: Step [2800] ?val Loss : 9.216277, val accuracy : ?0.368952
    2018-08-16 10:54:38.721697: Step [2900] ?train Loss : 0.762590, training accuracy : ?0.375
    2018-08-16 10:55:59.860650: Step [3000] ?train Loss : 0.733000, training accuracy : ?0.1875
    2018-08-16 10:56:24.746242: Step [3000] ?val Loss : 13.225746, val accuracy : ?0.237903
    2018-08-16 10:57:45.828758: Step [3100] ?train Loss : 0.833523, training accuracy : ?0.5625
    2018-08-16 10:59:06.822897: Step [3200] ?train Loss : 0.710151, training accuracy : ?0.625

    ……

    2018-08-16 12:40:31.923101: Step [9500] ?train Loss : 0.700521, training accuracy : ?1
    2018-08-16 12:41:53.206480: Step [9600] ?train Loss : 0.782273, training accuracy : ?1
    2018-08-16 12:42:17.757492: Step [9600] ?val Loss : 1.299307, val accuracy : ?0.860887
    2018-08-16 12:43:38.987012: Step [9700] ?train Loss : 0.700440, training accuracy : ?0.9375
    2018-08-16 12:45:00.040759: Step [9800] ?train Loss : 0.702021, training accuracy : ?0.75
    2018-08-16 12:45:25.000334: Step [9800] ?val Loss : 1.402472, val accuracy : ?0.836021
    2018-08-16 12:46:46.077850: Step [9900] ?train Loss : 0.701689, training accuracy : ?1
    2018-08-16 12:48:07.302272: Step [10000] ?train Loss : 0.703496, training accuracy : ?1
    2018-08-16 12:48:32.193206: Step [10000] ?val Loss : 1.131343, val accuracy : ?0.889113
    -----save:models/model.ckpt-10000
    ------save:models/best_models_10000_0.8891.ckpt

    ? ? ? 可以看到,前2000次迭代,不管是train還是val的識別率都很低,徘徊在20%-30%,但到了2000次以上,識別率一步一步往上蹭,到10000步時,train的識別率達到100%啦,而val的識別率穩定在80%以上,對于只訓練了10000次,其效果還是不錯的~有需要的話,可自行訓練十萬次以上哈

    5、模型預測

    ? ? 模型預測代碼,比較簡單,這里直接貼出源碼:

    #coding=utf-8import tensorflow as tf import numpy as np import pdb import cv2 import os import glob import slim.nets.inception_v3 as inception_v3from create_tf_record import * import tensorflow.contrib.slim as slimdef predict(models_path,image_dir,labels_filename,labels_nums, data_format):[batch_size, resize_height, resize_width, depths] = data_formatlabels = np.loadtxt(labels_filename, str, delimiter='\t')input_images = tf.placeholder(dtype=tf.float32, shape=[None, resize_height, resize_width, depths], name='input')with slim.arg_scope(inception_v3.inception_v3_arg_scope()):out, end_points = inception_v3.inception_v3(inputs=input_images, num_classes=labels_nums, dropout_keep_prob=1.0, is_training=False)# 將輸出結果進行softmax分布,再求最大概率所屬類別score = tf.nn.softmax(out)class_id = tf.argmax(score, 1)sess = tf.InteractiveSession()sess.run(tf.global_variables_initializer())saver = tf.train.Saver()saver.restore(sess, models_path)images_list=glob.glob(os.path.join(image_dir,'*.jpg'))for image_path in images_list:im=read_image(image_path,resize_height,resize_width,normalization=True)im=im[np.newaxis,:]#pred = sess.run(f_cls, feed_dict={x:im, keep_prob:1.0})pre_score,pre_label = sess.run([score,class_id], feed_dict={input_images:im})max_score=pre_score[0,pre_label]print "{} is: pre labels:{},name:{} score: {}".format(image_path,pre_label,labels[pre_label], max_score)sess.close()if __name__ == '__main__':class_nums=5image_dir='test_image'labels_filename='dataset/label.txt'models_path='models/model.ckpt-10000'batch_size = 1 #resize_height = 299 # 指定存儲圖片高度resize_width = 299 # 指定存儲圖片寬度depths=3data_format=[batch_size,resize_height,resize_width,depths]predict(models_path,image_dir, labels_filename, class_nums, data_format)

    預測結果:

    test_image/flower.jpg is: pre labels:[0],name:['flower'] score: [ 0.99865556]
    test_image/houses.jpg is: pre labels:[3],name:['houses'] score: [ 0.99899763]
    test_image/animal.jpg is: pre labels:[2],name:['animal'] score: [ 0.96808302]
    test_image/guitar.jpg is: pre labels:[1],name:['guitar'] score: [ 0.99999511]


    四、其他模型訓練方法?

    ? ? 上面的程序inception_v3_train_val.py是實現googLenet inception V3訓練的過程,實質上,稍微改改就可以支持訓練 inception V1,V2 啦,改動方法也很簡單,以 inception V1為例:

    (1)import 改為:

    # 將 import slim.nets.inception_v3 as inception_v3 # 改為 import slim.nets.inception_v1 as inception_v1

    (2)record數據

    ? ? inception V1要求輸入的數據是224*224,因此制作record數據時,需要設置:

    resize_height = 224 ?# 指定存儲圖片高度
    resize_width = 224 ?# 指定存儲圖片寬度

    (3)定義模型和默認參數修改:

    # 將with slim.arg_scope(inception_v3.inception_v3_arg_scope()):out, end_points = inception_v3.inception_v3(inputs=input_images, num_classes=labels_nums, dropout_keep_prob=keep_prob, is_training=is_training)# 改為with slim.arg_scope(inception_v1.inception_v1_arg_scope()):out, end_points = inception_v1.inception_v1(inputs=input_images, num_classes=labels_nums, dropout_keep_prob=keep_prob, is_training=is_training)

    (4)修改優化方案

    ? ? inception V3中使用的優化方案是:?optimizer = tf.train.GradientDescentOptimizer(learning_rate=base_lr),但在V1中,我發現訓練不收斂,后來我改為??optimizer = tf.train.MomentumOptimizer(learning_rate=base_lr,momentum= 0.9),又可以正常收斂了。總之,要是發現訓練不收斂,請嘗試修改幾個參數:

    1、增大或減小學習率參數:base_lr

    2、改變優化方案:如使用MomentumOptimizer或者AdadeltaOptimizer等優化方法

    3、是否有設置默認的模型參數:如slim.arg_scope(inception_v1.inception_v1_arg_scope())

    4、計算損失時,增加或去掉正則項:tf.losses.get_total_loss(add_regularization_losses=False)

    ……最后,就可以Train了!是的,就是那么簡單~

    五、將ckpt轉pb文件:

    ? ? tensorflow實現將ckpt轉pb文件的方法,請參考:

    https://blog.csdn.net/guyuealian/article/details/82218092


    如果你覺得該帖子幫到你,還望貴人多多支持,鄙人會再接再厲,繼續努力的~

    總結

    以上是生活随笔為你收集整理的使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。