在上一章已經(jīng)了解了tensorflow的工作原理抡砂,那么今天來學(xué)習(xí)一下神經(jīng)網(wǎng)絡(luò)。
(一)首先看一下最簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò):
?????和圖中表示的一樣这弧,最左邊是我們的數(shù)據(jù)集欠肾,然后中間使我們的神經(jīng)網(wǎng)絡(luò),包括輸入層骑晶、隱層痛垛、和輸出層。
?????輸入層是特征向量(這個(gè)特征向量需要我們一個(gè)特征提取的過程桶蛔,書上說用于描述實(shí)體的數(shù)字的組合成為一個(gè)實(shí)體的特征向量匙头,比如一個(gè)零件可用【0.5,1.6】來描述他0.5m長(zhǎng)和1.6kg重的特征)。這個(gè)部分通過圖中可以看到他可以簡(jiǎn)單的輸入x1仔雷、x2兩個(gè)數(shù)據(jù)蹂析,也可以輸入他們的平方,相乘等多種輸入形式碟婆。我認(rèn)為神經(jīng)網(wǎng)路就是把輸入的數(shù)據(jù)進(jìn)行一個(gè)函數(shù)擬合的過程电抚,說白了就是建立一個(gè)函數(shù),根據(jù)輸入的值得到一個(gè)輸出竖共,這里的輸入和輸出都為一個(gè)多維數(shù)組蝙叛,當(dāng)然也可以是單一的一個(gè)數(shù)字。所以只要能包含輸入特征的運(yùn)算過程都可以作為輸入肘迎,當(dāng)然這只是我自己的理解甥温。
? ? ?接下來就是神經(jīng)元了。神經(jīng)元到底是什么妓布!這個(gè)其實(shí)很重要姻蚓,面試的時(shí)候有可能會(huì)問。神經(jīng)元匣沼,說白了我認(rèn)為就是一個(gè)函數(shù)狰挡!左面是輸入、右邊是輸出。他的具體結(jié)構(gòu)如下圖:
? ? ?OK~就是一堆輸入的線性組合加上一個(gè)非線性的函數(shù)加叁,某軟面試官居然特么跟我說神經(jīng)元里沒有非線性函數(shù)倦沧,真是各位選好公司很重要!那么一個(gè)神經(jīng)元的輸出只能是一個(gè)值它匕,但是可以輸出到多個(gè)不同的神經(jīng)元展融。也就是說,神經(jīng)元的輸出可以有多條線豫柬,但是每條線輸出的值是一樣的告希!
? ? ?經(jīng)過了多層隱層以后便得到了輸出層,這個(gè)輸出層輸出的不是上圖中那個(gè)圖烧给,而就是簡(jiǎn)簡(jiǎn)單單的一個(gè)值燕偶。這個(gè)值如果大于0就是藍(lán)色,小于0就是橘黃色础嫡,所以根據(jù)不同的輸入值就將兩種顏色的點(diǎn)點(diǎn)分離開來指么!真神奇。
(二)前向傳播算法
? ? ?看完這部分我也是服了榴鼎,這也叫算法呀---所謂前向傳播伯诬,就是輸入通過權(quán)重和神經(jīng)元的函數(shù)后,計(jì)算得出結(jié)果的這一個(gè)過程巫财。如下圖所示:
? ? ?而由于在TensorFlow中矩陣的乘法是非常容易實(shí)現(xiàn)的姑廉,所以前向傳播的過程常表示為矩陣乘法。這里主要是矩陣之間的乘法翁涤,行向量乘以列,然后再相加的這個(gè)過程萌踱。
(三)神經(jīng)網(wǎng)絡(luò)參數(shù)與TensorFlow變量
? ? ?在TensorFlow中葵礼,tf.Variable的作用就是保存和更新神經(jīng)網(wǎng)絡(luò)的參數(shù)。? ??
weight?=?tf.Variable(tf.random_normal([2,3],stddev=2))
? ? ?上面一行代碼就是參數(shù)初始化的過程并鸵,初始化一個(gè)2*3的參數(shù)矩陣鸳粉,均值為0,標(biāo)準(zhǔn)差為2.當(dāng)然园担,此外還有很多初始化變量的方法届谈。? ??
OK,接下來我們看一下如何用代碼實(shí)現(xiàn)前向傳播算法:
import?tensorflowas?tf
w1?=?tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2?=?tf.Variable(tf.random_normal([3,1],stddev=1,seed=2))
x?=?tf.constant([[0.7,0.9]])
a?=?tf.matmul(x,w1)
y?=?tf.matmul(a,w2)
sess?=?tf.Session()
init_op?=?tf.global_variables_initializer()
sess.run(init_op)
print(sess.run(y))
sess.close()
要寫一段tf代碼弯汰,我認(rèn)為就是需要寫出每個(gè)神經(jīng)元和每條邊艰山。首先定義變量(Variable),也就是邊(權(quán)重)咏闪。然后定義每次層的神經(jīng)元曙搬,第一層為輸入神經(jīng)元,所以定義為常量輸入,第二層和第三層分別進(jìn)行了矩陣的乘法纵装,也就是簡(jiǎn)單的線性組合征讲。以上便定義好了張量,和計(jì)算圖橡娄,然后我們定義會(huì)話诗箍,首先需要初始化所有的張量,而后如下這兩句便完成了所有張量的初始化
init_op?=?tf.global_variables_initializer()
sess.run(init_op)
最后打印了y挽唉,然后關(guān)閉會(huì)話滤祖!
(四)訓(xùn)練網(wǎng)絡(luò)模型
那么,在一個(gè)神經(jīng)網(wǎng)絡(luò)里我們有大量的輸入(比如訓(xùn)練集)橱夭,那么如果我們用之前定義constant的方式氨距,那么需要定義大量的計(jì)算節(jié)點(diǎn),這樣是不可取的棘劣。那么tensor里定義了 一個(gè)placeholder俏让,他作為一個(gè)計(jì)算節(jié)點(diǎn),可以源源不斷的幫我們傳入輸入值茬暇。
import?tensorflowas?tf
w1?=?tf.Variable(tf.random_normal([2,3],stddev=1,seed=1))
w2?=?tf.Variable(tf.random_normal([3,1],stddev=1,seed=2))
#x?=?tf.constant([[0.7,0.9]])
x?=?tf.placeholder(tf.float32,shape=(3,2),name="input")
a?=?tf.matmul(x,w1)
y?=?tf.matmul(a,w2)
sess?=?tf.Session()
init_op?=?tf.global_variables_initializer()
sess.run(init_op)
print(sess.run(y,feed_dict={x:[[0.7,0.9],[0.1,0.4],[0.5,0.8]]}))
sess.close()
上圖中我們定義了placeholder首昔,然后再run里的feed_dict中輸入我們的x。
那么接下來就是反向傳播的調(diào)參過程糙俗。
?反向傳播的整體思路是這樣的:我們根據(jù)設(shè)置的參數(shù)得到的輸出結(jié)果與真實(shí)結(jié)果的差勒奇,我們稱之為損失函數(shù)(代表的就是我們的輸出與真實(shí)的差距),反向傳播的過程就是想辦法使損失函數(shù)降低到一個(gè)最小值巧骚。
Loss = (w1*x1 + w2*x2 + b) - y 括號(hào)里的當(dāng)然不只是線性的組合赊颠,還有各種非線性的組合。x1劈彪,x2等是我們的輸入竣蹦,y是標(biāo)簽的值,所以這些都是常數(shù)沧奴,所以Loss函數(shù)就是關(guān)于各種w和b的多元函數(shù)痘括。
OK,那么現(xiàn)在這個(gè)調(diào)參的過程變成了一個(gè)多元函數(shù)的求最小值的問題滔吠。那么為了讓這個(gè)損失函數(shù)變小的最快纲菌,這里使用了“梯度下降法”(又稱最速下降法)。 我們知道多元函數(shù)關(guān)于在任何方向上都有變化疮绷,那么這個(gè)就叫做方向?qū)?shù)翰舌。然而這個(gè)函數(shù)的值變化最快的方向,就叫做梯度4@ⅰT钪ァVT!R固椤(這個(gè)稍微有些難理解)那么這個(gè)梯度的求解方法就是各個(gè)方向的偏導(dǎo)數(shù)乘當(dāng)前方向的單位向量再相加犯犁。
所以就可以把所有的參數(shù)都從他們的偏導(dǎo)數(shù)方向上減少:
其中n就是他們的學(xué)習(xí)率。而求偏導(dǎo)的過程就使用了鏈?zhǔn)揭?guī)則:
當(dāng)然女器,這個(gè)過程在tf中不需要這么復(fù)雜酸役,只需要使用封裝好的代碼就可以。具體的代碼明天上驾胆。