人工智能(AI)庫TensorFlow 踩坑日記之二

上次 踩坑日誌之一 遺留的問題終於解決了,因此做者(也就是我)終於有臉出來寫第二篇了。html

   首先仍是貼上 卷積算法的示例代碼地址 :https://github.com/tensorflow/modelspython

    這個庫裏面主要是一些經常使用的模型用tensorflow實現以後的代碼。其中我用的是git

    models/tree/master/tutorials/image/cifar10 這個示例,上一篇也大體講過了。github

   關於上次遇到問題是:算法

雖然訓練了不少次,可是每次實際去用時都是相同的結果。這個問題主要緣由是api

在覈心代碼文件cifar10.py裏 瀏覽器

tf.app.flags.DEFINE_integer('batch_size', 128,
                            """Number of images to process in a batch.""")

  

被我改爲 batch_size =1app

一開始我誤覺得這個batch要跟訓練文件的.bin 文件裏面的圖片數量對應,其實否則。這個batch_size 是爲了用分佈式

cifar10_input.py
images, label_batch = tf.train.batch( [image, label], batch_size=batch_size, num_threads=num_preprocess_threads, capacity=min_queue_examples + 3 * batch_size)

 

建立一個圖片跟標籤的隊列,每一個隊列128個元素,便於分佈式處理。性能

因爲改爲1以後多是影響是訓練效果。致使總體的loss很高,因此識別率不好。有待進一步驗證。

 2018-03-11 修正

batch_size 做用就是一次性訓練這麼屢次以後纔開始作梯度降低,這樣loss 的波動不會太大。

2018-06-19 補充

https://blog.csdn.net/ycheng_sjtu/article/details/49804041

看完這篇文章以後終於對batch_size 有了一個更深入的理解。就是越小的batch會致使局部的梯度波動大,難以收斂。

 

另一個緣由極可能是最致命的

上一篇講到label的對應方式是

# Create a queue that produces the filenames to read.
    filename_queue = tf.train.string_input_producer(filenames)

 

 label 也是用string_input_producer 作了另一條字符串隊列

由於label 是分類名稱,也是圖片所在文件夾的名稱,因此我在外面把圖片文件夾名稱都丟到一個label的string隊列裏,而後裏面作出隊 depuqeue。

這實際上是錯誤的,由於兩條隊列要完美保持一致,並且還不能加shuffle 參數 這個參數能夠隨機獲取圖片文件,以便訓練模型效果更具有泛化能力。

# Create a queue that produces the filenames to read.
    filename_queue = tf.train.string_input_producer(filenames,name="filename_queue_hcq",shuffle=True)

 shuffle=true 仍是要加的。

label的獲取方式就得另外想辦法。

把 cifar10_input.py 方法 read_cifar10 改造以下:

def read_cifar10(filename_queue): class CIFAR10Record(object): pass    reader = tf.WholeFileReader() key, value = reader.read(filename_queue) image0 = tf.image.decode_jpeg(value,3) esized_image = tf.image.resize_images(image0, [32, 32], method=tf.image.ResizeMethod.AREA) result = ImageNetRecord() re2=splitfilenames(tf.constant( filenames),len(filenames)) key=splitfilenames(tf.reshape(key,[1],name="key_debug"),1) label=diff(re2,key)

 

其中 splitilenames ,diff 方法是我新增的,主要是爲了把文件所在目錄的路勁切出來

def splitfilenames(inputs,allstringlen): a = tf.string_split(inputs, "/\\") bigin = tf.cast(tf.size(a.values) / allstringlen -2, tf.int32) slitsinglelen = tf.cast(tf.size(a.values) / allstringlen, tf.int32) val = tf.reshape(a.values, [allstringlen, slitsinglelen]) re2 = tf.cast(tf.slice(val, [0, bigin], [allstringlen, 1]),tf.string) re2 =tf.reshape(re2,[allstringlen]) re2 =tf.unique(re2).y return re2

好比」H:\imagenet\fortest\n01440764「 切出來 「n01330764」。 這個方法是支持批量處理的。

之因此寫的這麼麻煩。是由於輸入量是tensor,因此全部操做都必須按照tensorflow的api寫。

diff方法(代碼在下面) 是爲了斷定key 的分類名在全部分類裏面的文件排序位置(數字0-1000之內)。用這個位置做爲label。

這裏 讀者估計有一個疑問

「爲啥不直接用分類名‘n01330764’做爲label標籤去訓練呢?」

這裏也是迫於無奈,由於原始代碼cifar10的後續功能有2個限制,1,label必須是int型,2label最大值不能大於分類總數。因此不能簡單把「n」刪除而後轉成數字 1330764 。

不然會出各類錯。修正這2個問題明顯比我新增一個diff方法改動更大。

雖然不太優雅,各位看官輕拍。

def diff(re2,key): keys = tf.fill([tf.size(re2)],key[0]) numpoi= tf.cast(tf.equal(re2, keys),tf.int32) numpoi=tf.argmax(numpoi) return numpoi

2018-06-19 修正

後來這裏取label的方法仍是換成文件夾按字母排序後的位置做爲label了。這樣保險不少,並且性能也好一些。

 

好了,到止爲止,train(訓練過程)的代碼就改完了,能夠開始訓練了。

cifar10_eval.py 這邊須要改個地方。
if len(sys.argv)==1: SinglePicPath = "/tmp/8.jpg"
else: SinglePicPath =sys.argv[1]

經過參數傳入 單圖片的地址,用來放到生產環境執行識別程序。

先跑一下8.jpg 測試一下

得出來結果是0 之因此有這麼多,是由於

cifar10_eval 原來的代碼用了一部分跟訓練代碼一致的過程,其中訓練代碼中batchsize=128,致使雖然輸入只有1張圖,輸出的結果仍是有128個。有點多餘,不過取其中一個做爲結果就能夠了。
(這裏能夠在把batchsize改成1,只在運行時用1)

而後我用C# MVC寫了一個頁面。用來上傳圖片,而後輸出中文結果。

 

主要核心代碼是(C#):

 Thumbnails.Of(file).ZoomMethod(Thumbnails.ThumbnailZoomMethod.CUT).Resize(32, 32).ToFiles(imagepath); var p = new Process(); //C:\Users\Administrator\AppData\Local\Programs\Python\Python35\python.exe
            p.StartInfo.FileName = @"C:\Users\Administrator\AppData\Local\Programs\Python\Python35\python.exe"; p.StartInfo.Arguments = @"H:\tensorflow_cnn\tensorflow_cnn\tutorials\image\cifar10\cifar10_runsingle.py " + imagepath; p.StartInfo.WorkingDirectory = @"H:\"; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.StartInfo.UseShellExecute = false; p.Start(); string output = p.StandardOutput.ReadToEnd(); string errmsg = p.StandardError.ReadToEnd(); p.WaitForExit(); p.Close(); var num = Regex.Replace(output, @".*\[array\(\[(\d+),.*\].*", "$1", RegexOptions.Singleline); string    result;

主要是把圖片改成 32*32 而後用Process 拉起python 去執行 cifar10_runsingle.py (這個是cifar10_eval.py 改造後的)。

而後用正則把 結果的數字切出來。

剩下就是把位置好比 0替換成「n01330764」

「n01330764」 再替換成中文,上一篇有下載中文的連接。

測試一下

------------------------------------------

--------------------------------------

 

-------------------

由於把eval(評估代碼)改爲執行代碼了,因此eval 測試集(在imagenet下載自帶的)反而沒應用上了。暫時不能判斷識別率高低。這是下一步要改造的地方。

不過imagenet 的數量級太大,正正經經訓練一次,估計要好久好久好久。

另外還要切換成GPU模式,估計不太難。有教程。

期待踩坑日誌之三吧,燒年們。

另外說一點關於tensorboard的,這東西真是厲害。安裝方便。直接命令行 

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple tensorflow-tensorboard

 

-i 地址是用了清華的pip鏡像 這樣安裝比較快不容易出錯。

 

而後

 

 logdir 指向

 wt = tf.summary.FileWriter("/tmp/broaddata3")

代碼中設置的 summary的地址。

而後打開瀏覽器查看。

這裏有個坑須要注意, tensorboard的運行盤符必須跟log所在盤符一致,不然一直提示拿不到文件。

這裏能夠看到我新增了一個label_sum 的曲線圖,能夠看到確實拿到不一樣的label了,並且最小是從0開始的。

此致敬禮。

 

 

更新:

2019-03-22

因爲以前的例子都是一張一張讀取圖片,最後我仍是修改成打包進Bin文件,而後訓練時再一次性讀取

源碼路徑以下 使用方法查看項目 ReadME

https://github.com/g7rhythm/MYcifar255

相關文章
相關標籤/搜索