TensorFlow迁移学习的识别花试验
最近學(xué)習(xí)了TensorFlow,發(fā)現(xiàn)一個(gè)模型叫vgg16,然后搭建環(huán)境跑了一下,覺(jué)得十分神奇,而且準(zhǔn)確率十分的高。又上了一節(jié)選修課,關(guān)于人工智能,老師讓做一個(gè)關(guān)于人工智能的試驗(yàn),于是覺(jué)得vgg16很不錯(cuò),可以直接用。
但發(fā)現(xiàn)vgg16是訓(xùn)練好的模型,拿來(lái)直接用太沒(méi)水平,于是網(wǎng)上發(fā)現(xiàn)說(shuō)可以用vgg16進(jìn)行遷移學(xué)習(xí)。
我理解的遷移學(xué)習(xí):
遷移學(xué)習(xí)符合人們學(xué)習(xí)的過(guò)程,如果要學(xué)習(xí)一樣新東西,我們肯定會(huì)運(yùn)用或是借鑒之前的學(xué)習(xí)經(jīng)驗(yàn),這樣能夠快速的把握要點(diǎn),能夠快速的學(xué)習(xí)。遷移學(xué)習(xí)也是如此。
vgg16模型是前人訓(xùn)練出的能夠識(shí)別1000種物品的模型,而且識(shí)別率很高,它的模型如圖:
可以數(shù)出綠色的模塊一共有16層,通過(guò)多層的卷積和池化,會(huì)提取圖片特征值,然后把圖片壓縮成一個(gè)一維數(shù)組輸入到全連接層中,圖中有三層全連接層fc1,fc2,fc3,再經(jīng)過(guò)softmax輸出概率分布的預(yù)測(cè)結(jié)果。
進(jìn)過(guò)試驗(yàn),這個(gè)模型能夠很好的識(shí)別花,但是如果要在此基礎(chǔ)上識(shí)別多種花,還需要在此基礎(chǔ)上進(jìn)行訓(xùn)練,但是訓(xùn)練的過(guò)程將簡(jiǎn)化很多。接下來(lái)通過(guò)代碼來(lái)講解
項(xiàng)目:
Transfer_learning:
? --checkpoint? ? #用來(lái)保存模型
? ? ? --? ?#自動(dòng)生成的四個(gè)文件
? --flower_photos? ?#圖片
? ? ? ?--daisy
--dandeline
--roses
--sunflowers
--tulips
? ? ? ? #vgg16模型
? --utils.py
?--vgg16.npy
?--vgg16.py
? --app.py
? --ftrain.py
? --get_features.py
? --transfer_test.py
? --transfer_train.py
? --codes.npy #存儲(chǔ)圖片特征值
? --labels #存儲(chǔ)圖片的標(biāo)簽
? --1.jpg? #檢測(cè)圖片
? --.......
第一步獲取圖片的特征,對(duì)于vgg16模型,fc1層之前所做的就是提取圖片特征,我們無(wú)需再費(fèi)事去訓(xùn)練模型去提取圖片的特征,而是直接使用它提供的完善的模型去提取特征,并且它能夠很好的把握?qǐng)D片的特征,然后它這些特征存儲(chǔ)起來(lái),用于下面的訓(xùn)練。
get_features.py
#coding=utf-8 import os import numpy as np import tensorflow as tf import vgg16 import utils#接下來(lái)我們將 flower_photos 文件夾中的花朵圖片都載入到進(jìn)來(lái),并且用圖片所在的子文件夾作為標(biāo)簽值。 data_dir = 'flower_photos/' contents = os.listdir(data_dir) classes = [each for each in contents if os.path.isdir(data_dir + each)]#利用vgg16計(jì)算得到特征值 # 首先設(shè)置計(jì)算batch的值,如果運(yùn)算平臺(tái)的內(nèi)存越大,這個(gè)值可以設(shè)置得越高 batch_size = 10 # 用codes_list來(lái)存儲(chǔ)特征值 codes_list = [] # 用labels來(lái)存儲(chǔ)花的類(lèi)別 labels = [] # batch數(shù)組用來(lái)臨時(shí)存儲(chǔ)圖片數(shù)據(jù) batch = []codes = Nonewith tf.Session() as sess:# 構(gòu)建VGG16模型對(duì)象vgg = vgg16.Vgg16()input_ = tf.placeholder(tf.float32, [None, 224, 224, 3])with tf.name_scope("content_vgg"):# 載入VGG16模型 vgg.build(input_)# 對(duì)每個(gè)不同種類(lèi)的花分別用VGG16計(jì)算特征值for each in classes:print ("Starting {} images".format(each))class_path = data_dir + eachfiles = os.listdir(class_path)for ii, file in enumerate(files, 1):# 載入圖片并放入batch數(shù)組中img = utils.load_image(os.path.join(class_path, file))batch.append(img.reshape((1, 224, 224, 3)))labels.append(each)# 如果圖片數(shù)量到了batch_size則開(kāi)始具體的運(yùn)算if ii % batch_size == 0 or ii == len(files):images = np.concatenate(batch)feed_dict = {input_: images}# 計(jì)算特征值codes_batch = sess.run(vgg.relu6, feed_dict=feed_dict)# 將結(jié)果放入到codes數(shù)組中if codes is None:codes = codes_batchelse:codes = np.concatenate((codes, codes_batch))# 清空數(shù)組準(zhǔn)備下一個(gè)batch的計(jì)算batch = []print ('{} images processed'.format(ii)) #code is a two-dimensional array including features of all pictures #這樣我們就可以得到一個(gè) codes 數(shù)組,和一個(gè) labels 數(shù)組,分別存儲(chǔ)了所有花朵的特征值和類(lèi)別。 #可以用如下的代碼將這兩個(gè)數(shù)組保存到硬盤(pán)上: #with open('codes', 'w') as f: np.save("codes.npy",codes)#codes.tofile(f)#not good size of file is too big#pickle.dump(codes,f)import csv with open('labels', 'w') as f:writer = csv.writer(f, delimiter='\n')writer.writerow(labels)#pickle.dump(labels,f)進(jìn)過(guò)上面代碼我們已經(jīng)得到了圖片的特征值和標(biāo)簽,接下來(lái),我們需要設(shè)置一個(gè)全連接層來(lái)訓(xùn)練,下面代碼中增加了一層256個(gè)節(jié)點(diǎn)和5個(gè)節(jié)點(diǎn)的全連接層。
ftrain.py
#coding=utf-8 import os import numpy as np import tensorflow as tf import matplotlib.pyplot as plt from sklearn.preprocessing import LabelBinarizer import vgg16 import utils from sklearn.model_selection import StratifiedShuffleSplit#模型保存的路徑和名稱 MODEL_SAVE_PATH="./checkpoints/" MODEL_NAME="flowers.ckpt" LABELS = "labels" CODES = "codes.npy" codes = None label = [] labels = []if CODES:codes = np.load(CODES) else:print ("No such file,please run get_feature.py first")if LABELS:with open(LABELS,"r") as f: label = f.readlines()for line in label:line = line.strip()labels.append(line) else:print ("No such file,please run get_feature.py first") #準(zhǔn)備訓(xùn)練集,驗(yàn)證集和測(cè)試集 #首先我把 labels 數(shù)組中的分類(lèi)標(biāo)簽用 One Hot Encode 的方式替換 lb = LabelBinarizer() lb.fit(labels) labels_vecs = lb.transform(labels) #return codes,labels,labels_vecs''' 接下來(lái)就是抽取數(shù)據(jù),因?yàn)椴煌?lèi)型的花的數(shù)據(jù)數(shù)量并不是完全一樣的, 而且 labels 數(shù)組中的數(shù)據(jù)也還沒(méi)有被打亂, 所以最合適的方法是使用 StratifiedShuffleSplit 方法來(lái)進(jìn)行分層隨機(jī)劃分。 假設(shè)我們使用訓(xùn)練集:驗(yàn)證集:測(cè)試集 = 8:1:1,那么代碼如下: ''' ss = StratifiedShuffleSplit(n_splits=1, test_size=0.2)train_idx, val_idx = next(ss.split(codes, labels))half_val_len = int(len(val_idx)/2) val_idx, test_idx = val_idx[:half_val_len], val_idx[half_val_len:]train_x, train_y = codes[train_idx], labels_vecs[train_idx] val_x, val_y = codes[val_idx], labels_vecs[val_idx] test_x, test_y = codes[test_idx], labels_vecs[test_idx]print ("Train shapes (x, y):", train_x.shape, train_y.shape) print ("Validation shapes (x, y):", val_x.shape, val_y.shape) print ("Test shapes (x, y):", test_x.shape, test_y.shape)#訓(xùn)練網(wǎng)絡(luò) ''' 分好了數(shù)據(jù)集之后,就可以開(kāi)始對(duì)數(shù)據(jù)集進(jìn)行訓(xùn)練了, 假設(shè)我們使用一個(gè) 256 維的全連接層, 一個(gè) 5 維的全連接層(因?yàn)槲覀円诸?lèi)五種不同類(lèi)的花朵), 和一個(gè) softmax 層。當(dāng)然,這里的網(wǎng)絡(luò)結(jié)構(gòu)可以任意修改, 你可以不斷嘗試其他的結(jié)構(gòu)以找到合適的結(jié)構(gòu)。 ''' # 輸入數(shù)據(jù)的維度# 標(biāo)簽數(shù)據(jù)的維度 labels_ = tf.placeholder(tf.int64, shape=[None, labels_vecs.shape[1]]) inputs_ = tf.placeholder(tf.float32, shape=[None, codes.shape[1]]) # 加入一個(gè)256維的全連接的層 fc = tf.contrib.layers.fully_connected(inputs_, 256)# 加入一個(gè)5維的全連接層 logits = tf.contrib.layers.fully_connected(fc, labels_vecs.shape[1], activation_fn=None)# 得到最后的預(yù)測(cè)分布 predicted = tf.nn.softmax(logits)# 計(jì)算cross entropy值 cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=labels_, logits=logits)# 計(jì)算損失函數(shù) cost = tf.reduce_mean(cross_entropy)# 采用用得最廣泛的AdamOptimizer優(yōu)化器 optimizer = tf.train.AdamOptimizer().minimize(cost) correct_pred = tf.equal(tf.argmax(predicted, 1), tf.argmax(labels_, 1)) accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))#為了方便把數(shù)據(jù)分成一個(gè)個(gè) batch 以降低內(nèi)存的使用,還可以再用一個(gè)函數(shù)專(zhuān)門(mén)用來(lái)生成 batch。 def get_batches(x, y, n_batches=10):""" 這是一個(gè)生成器函數(shù),按照n_batches的大小將數(shù)據(jù)劃分了小塊 """batch_size = len(x)//n_batchesfor ii in range(0, n_batches*batch_size, batch_size):# 如果不是最后一個(gè)batch,那么這個(gè)batch中應(yīng)該有batch_size個(gè)數(shù)據(jù)if ii != (n_batches-1)*batch_size:X, Y = x[ii: ii+batch_size], y[ii: ii+batch_size] # 否則的話,那剩余的不夠batch_size的數(shù)據(jù)都湊入到一個(gè)batch中else:X, Y = x[ii:], y[ii:]# 生成器語(yǔ)法,返回X和Yyield X, Y經(jīng)過(guò)上面的代碼,已經(jīng)把圖片集分成三部分,而且也設(shè)置好全連接成,接下來(lái)需要把圖片特征喂入,開(kāi)始訓(xùn)練模型。
transfer_train.py
import os import numpy as np import tensorflow as tf import matplotlib.pyplot as plt import vgg16 import utils import ftrain#運(yùn)行 # 運(yùn)行多少輪次 epochs = 20 # 統(tǒng)計(jì)訓(xùn)練效果的頻率 iteration = 0 # 保存模型的保存器 saver = tf.train.Saver()with tf.Session() as sess:sess.run(tf.global_variables_initializer())coord = tf.train.Coordinator()#4threads = tf.train.start_queue_runners(sess=sess, coord=coord)#5for e in range(epochs):for x, y in ftrain.get_batches(ftrain.train_x, ftrain.train_y):feed = {ftrain.inputs_: x,ftrain.labels_: y}# 訓(xùn)練模型 loss, _ = sess.run([ftrain.cost, ftrain.optimizer], feed_dict=feed)print ("Epoch: {}/{}".format(e+1, epochs),"Iteration: {}".format(iteration),"Training loss: {:.5f}".format(loss))iteration += 1if iteration % 5 == 0:feed = {ftrain.inputs_: ftrain.val_x,ftrain.labels_: ftrain.val_y}val_acc = sess.run(ftrain.accuracy, feed_dict=feed)# 輸出用驗(yàn)證機(jī)驗(yàn)證訓(xùn)練進(jìn)度print ("Epoch: {}/{}".format(e, epochs),"Iteration: {}".format(iteration),"Validation Acc: {:.4f}".format(val_acc))# 保存模型saver.save(sess, os.path.join(ftrain.MODEL_SAVE_PATH, ftrain.MODEL_NAME))在控制臺(tái)的輸出結(jié)果中,我們可以看到隨著迭代次數(shù)的增加,損失值在不斷的降低,精確性也在提高。把訓(xùn)練好的模型保存起來(lái),接下來(lái)用測(cè)試集來(lái)測(cè)試模型。
?
transfer_test.py
#coding=utf-8 import os import numpy as np import tensorflow as tf import ftrain import vgg16 import utils#用測(cè)試集來(lái)測(cè)試模型效果 saver = tf.train.Saver() with tf.Session() as sess:saver.restore(sess,tf.train.latest_checkpoint(ftrain.MODEL_SAVE_PATH))feed = {ftrain.inputs_: ftrain.test_x,ftrain.labels_: ftrain.test_y} test_acc = sess.run(ftrain.accuracy,feed_dict=feed)print ("Test accuracy: {:.4f}".format(test_acc))測(cè)試代碼,加載訓(xùn)練好的模型,然后把測(cè)試集代碼喂入,計(jì)算精確度,控制臺(tái)可以看到結(jié)果,我的結(jié)果達(dá)到90%以上
然后可以應(yīng)用這個(gè)模型,來(lái)識(shí)別圖片了,這個(gè)模型可以識(shí)別5中話,可以自己增加。
app.py
#coding=utf-8 import numpy as np import tensorflow as tf import matplotlib.pyplot as plt import vgg16 import utils import ftraindef per_picture():#deal with picturetestPicArr = []img_path = input('Input the path and image name:')img_ready = utils.load_image(img_path) testPicArr.append(img_ready.reshape((1,224,224,3)))images = np.concatenate(testPicArr)return imageslabels_vecs = ['daisy','dandelion','roses','sunflower','tulips'] labels_vecs = np.array(labels_vecs) fig=plt.figure(u"Top-5 預(yù)測(cè)結(jié)果") saver = tf.train.Saver() with tf.Session() as sess:#圖片預(yù)處理images = per_picture()#輸入vgg16中計(jì)算特征值vgg = vgg16.Vgg16()input_ = tf.placeholder(tf.float32, [None, 224, 224, 3])with tf.name_scope("content_vgg"):# 載入VGG16模型 vgg.build(input_)feed_dict = {input_: images}# 計(jì)算特征值codes_batch = sess.run(vgg.relu6, feed_dict=feed_dict)#返回y矩陣中最大值的下標(biāo),如果是二維的加1preValue = tf.argmax(ftrain.predicted, 1) #加載訓(xùn)練好的新模型 saver.restore(sess, tf.train.latest_checkpoint(ftrain.MODEL_SAVE_PATH))#計(jì)算預(yù)測(cè)值preValue = sess.run(preValue, feed_dict={ftrain.inputs_:codes_batch})print ("The prediction flower is:", labels_vecs[preValue])probability = sess.run(ftrain.predicted, feed_dict={ftrain.inputs_:codes_batch})top5 = np.argsort(probability[0])print ("top5:",top5)values = []bar_label = []for n, i in enumerate(top5): print ("n:",n)print ("i:",i)values.append(probability[0][i]) bar_label.append(labels_vecs[i]) print (i, ":", labels_vecs[i], "----", utils.percent(probability[0][i])) ax = fig.add_subplot(111) ax.bar(range(len(values)), values, tick_label=bar_label, width=0.5, fc='g')ax.set_ylabel(u'probabilityit') ax.set_title(u'Top-5') for a,b in zip(range(len(values)), values):ax.text(a, b+0.0005, utils.percent(b), ha='center', va = 'bottom', fontsize=7) plt.show()上面代碼過(guò)程是,首先要通過(guò)vgg16提取該圖片的特征值,然后進(jìn)行圖片預(yù)處理,加載訓(xùn)練好的模型,輸入進(jìn)去,獲得結(jié)果。
結(jié)果展示如下:
? ? ? ?
可以看到準(zhǔn)確率很高,我每種圖片只訓(xùn)練了144張,數(shù)據(jù)集有800多張。
以上代碼可以在windows 下python3的環(huán)境運(yùn)行。
代碼和數(shù)據(jù)集參考自:https://cosx.org/2017/10/transfer-learning/
?
對(duì)于實(shí)現(xiàn)以上過(guò)程遇到的問(wèn)題:
?(1)首先對(duì)遷移學(xué)習(xí)的理解
對(duì)于這個(gè)簡(jiǎn)單的試驗(yàn),遷移學(xué)習(xí)主要體現(xiàn)在使用訓(xùn)練好的vgg16模型(存儲(chǔ)在vgg16.npy中)提取圖片的特征值,然后再對(duì)這些特征值訓(xùn)練。
(2)模型的保存和加載
為了避免反復(fù)的去提取圖片特征值(這個(gè)很耗時(shí)間),把特征值保存在codes.npy,把圖片的標(biāo)簽存儲(chǔ)在labels中。還有就是存儲(chǔ)訓(xùn)練模型,這里因?yàn)閷?duì)TensorFlow模型不太了解,所以出一個(gè)問(wèn)題
存儲(chǔ)模型后,在另一個(gè)文件中加載模型發(fā)現(xiàn)訓(xùn)練的模型和沒(méi)訓(xùn)練的模型一樣
原因是因?yàn)樵诹硪粋€(gè)文件中使用的不是同一個(gè)saver,我又對(duì)saver進(jìn)行了初始化,導(dǎo)致使用了一個(gè)嶄新的模型。
(3)模型保存優(yōu)化部分:
如果你不給tf.train.Saver()傳入任何參數(shù),那么saver將處理graph中的所有變量。其中每一個(gè)變量都以變量創(chuàng)建時(shí)傳入的名稱被保存。
有時(shí)候在檢查點(diǎn)文件中明確定義變量的名稱很有用。舉個(gè)例子,你也許已經(jīng)訓(xùn)練得到了一個(gè)模型,其中有個(gè)變量命名為"weights",你想把它的值恢復(fù)到一個(gè)新的變量"params"中。
有時(shí)候僅保存和恢復(fù)模型的一部分變量很有用。再舉個(gè)例子,你也許訓(xùn)練得到了一個(gè)5層神經(jīng)網(wǎng)絡(luò),現(xiàn)在想訓(xùn)練一個(gè)6層的新模型,可以將之前5層模型的參數(shù)導(dǎo)入到新模型的前5層中。
你可以通過(guò)給tf.train.Saver()構(gòu)造函數(shù)傳入Python字典,很容易地定義需要保持的變量及對(duì)應(yīng)名稱:鍵對(duì)應(yīng)使用的名稱,值對(duì)應(yīng)被管理的變量。
轉(zhuǎn)載于:https://www.cnblogs.com/zhxuxu/p/9689778.html
總結(jié)
以上是生活随笔為你收集整理的TensorFlow迁移学习的识别花试验的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java自学小段 产生随机数
- 下一篇: 返回json格式