前言
先上最終結(jié)果圖,就是根據(jù)輸入的身高和體重來判斷胖瘦。這個程序使用TensorFlow創(chuàng)建模型和訓(xùn)練,然后導(dǎo)出.pb模型文件,最后利用CoreML導(dǎo)入iPhone中來進(jìn)行識別。



不是有個BMI可以計算體型么?我知道,不是要聯(lián)系一下機(jī)器學(xué)習(xí)相關(guān)內(nèi)容么,不要在意那些細(xì)節(jié)。而且,機(jī)器預(yù)測的跟平常我們的認(rèn)知都差不多。
TensorFlow端
下面潛入細(xì)節(jié)。首先從TensorFlow端說起。訓(xùn)練一個模型首先需要的就是數(shù)據(jù),我利用的是自己生成的.csv文件。何為.csv文件?其實就是許多特征值通過逗號連接而已,我用的bmi.csv文件中有20000條數(shù)據(jù),特征有3個,分別是身高、體重和胖瘦狀態(tài)。
因為身高、體重是處于線性回歸的狀態(tài),即y=x*w+b的狀態(tài),那么我們就可以利用TensorFlow來創(chuàng)建一個線性回歸的模型,關(guān)鍵代碼如下:
import tensorflow as tf
w=tf.Variable(tf.Zero([2,3]))
b=tf.Variable(tf.Zero([3]))
相當(dāng)于定義一個原始的w,b,然后交由神經(jīng)網(wǎng)絡(luò)迭代解出最佳的w和b的值。請注意w的shape為[2,3],這代表w為2*3的矩陣,為什么是2*3呢,首先讓我們先定義容納輸入的容器:
x=tf.placeholder(tf.float32,[None,2],name="x_input")
因為我們需要輸入的變量為身高和體重,所以肯定是2列,行數(shù)隨著數(shù)據(jù)數(shù)量而定,所以設(shè)為None,意思是看數(shù)據(jù)而定。因為x*w是矩陣運(yùn)算,第一個矩陣的列數(shù)一定要和第二個矩陣的行數(shù)相等,所以x的列數(shù)為2,那么w的行數(shù)一定也要為2,那么列數(shù)為什么是3呢?因為輸出是瘦、正常、胖的各自的概率,所以肯定是3列,所以這個3,包括b的shape為3,都是為了輸出y服務(wù)的.
再定義一個y_來容納真實標(biāo)簽(胖、瘦、正常)輸出,這個用來稍后計算損失函數(shù)的
y_=tf.placeholder(tf.float32,name="y_predict")
現(xiàn)在就可以寫線性回歸的表達(dá)式了
y=tf.nn.Softmax(tf.matmul(x*w)+b)
其中tf.matmul代表兩個矩陣相乘,Softmax多用于多分類問題中,用來說明一個數(shù)據(jù)在各個分類中的概率。
因為考慮到損失最小化,這樣才能使網(wǎng)絡(luò)預(yù)測的和真實值相差最小,所以定義交叉熵?fù)p失函數(shù):
cross_encropy=-tf.reduce_mean(y_*tf.log(y))
因為目的是使這個交叉熵值最小,tensorflow為我們提供了優(yōu)化器。
train_step=tf.train.AdamOptimizer(0.01).minimize(cross_encropy)
其中0.01代表學(xué)習(xí)率,就是每次迭代的步長。
模型已經(jīng)定義好了,下面就是訓(xùn)練了,我這個模型訓(xùn)練100000次
for i in range(100000):
? ? sess.run(train_step,feed_dict={x_input=訓(xùn)練的特征值,y_predict=訓(xùn)練的標(biāo)簽值})
然后留出一部分?jǐn)?shù)據(jù)作為測試集,驗證模型正確率,得到了上圖的97.98%。
correct_prediction=tf.equal(tf.max(y,1,name="output"),tf.max(y_,1))
請注意加粗的這一句,一會在導(dǎo)入CoreML中,這句話至關(guān)重要。上面這句代碼就體現(xiàn)了網(wǎng)絡(luò)預(yù)測的和真實值相差的多少。
TensorFlow導(dǎo)入.pb文件
constant_graph = graph_util.convert_variables_to_constants(sess, sess.graph_def, ["output"])?
with tf.gfile.FastGFile(pb_file_path, mode='wb') as f: ? ? ? ? ? ? ? ? ? ?f.write(constant_graph.SerializeToString())
這個output就是剛才我們定義的名字,相當(dāng)于我們把y=w*x+b,也就是整個模型的最終形態(tài)寫入了pb文件
iOS端
這個在我的上一篇(盡管有兩個多月了)中有過介紹,就不過多介紹怎么把pb文件轉(zhuǎn)換成CoreML識別的.mlmodel文件了。轉(zhuǎn)換完成后,謝謝界面代碼,就可以實現(xiàn)開頭那些圖片的效果了。
謝謝。已經(jīng)是午夜了,趕緊睡了。生命不息,編碼不止!