在上一章已經(jīng)了解了tensorflow的工作原理,那么今天來(lái)學(xué)習(xí)一下神經(jīng)網(wǎng)絡(luò)。
(一)首先看一下最簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò):
?????和圖中表示的一樣,最左邊是我們的數(shù)據(jù)集,然后中間使我們的神經(jīng)網(wǎng)絡(luò),包括輸入層、隱層、和輸出層。

?????輸入層是特征向量(這個(gè)特征向量需要我們一個(gè)特征提取的過(guò)程,書(shū)上說(shuō)用于描述實(shí)體的數(shù)字的組合成為一個(gè)實(shí)體的特征向量,比如一個(gè)零件可用【0.5,1.6】來(lái)描述他0.5m長(zhǎng)和1.6kg重的特征)。這個(gè)部分通過(guò)圖中可以看到他可以簡(jiǎn)單的輸入x1、x2兩個(gè)數(shù)據(jù),也可以輸入他們的平方,相乘等多種輸入形式。我認(rèn)為神經(jīng)網(wǎng)路就是把輸入的數(shù)據(jù)進(jìn)行一個(gè)函數(shù)擬合的過(guò)程,說(shuō)白了就是建立一個(gè)函數(shù),根據(jù)輸入的值得到一個(gè)輸出,這里的輸入和輸出都為一個(gè)多維數(shù)組,當(dāng)然也可以是單一的一個(gè)數(shù)字。所以只要能包含輸入特征的運(yùn)算過(guò)程都可以作為輸入,當(dāng)然這只是我自己的理解。
? ? ?接下來(lái)就是神經(jīng)元了。神經(jīng)元到底是什么!這個(gè)其實(shí)很重要,面試的時(shí)候有可能會(huì)問(wèn)。神經(jīng)元,說(shuō)白了我認(rèn)為就是一個(gè)函數(shù)!左面是輸入、右邊是輸出。他的具體結(jié)構(gòu)如下圖:

? ? ?OK~就是一堆輸入的線性組合加上一個(gè)非線性的函數(shù),某軟面試官居然特么跟我說(shuō)神經(jīng)元里沒(méi)有非線性函數(shù),真是各位選好公司很重要!那么一個(gè)神經(jīng)元的輸出只能是一個(gè)值,但是可以輸出到多個(gè)不同的神經(jīng)元。也就是說(shuō),神經(jīng)元的輸出可以有多條線,但是每條線輸出的值是一樣的!
? ? ?經(jīng)過(guò)了多層隱層以后便得到了輸出層,這個(gè)輸出層輸出的不是上圖中那個(gè)圖,而就是簡(jiǎn)簡(jiǎn)單單的一個(gè)值。這個(gè)值如果大于0就是藍(lán)色,小于0就是橘黃色,所以根據(jù)不同的輸入值就將兩種顏色的點(diǎn)點(diǎn)分離開(kāi)來(lái)!真神奇。
(二)前向傳播算法
? ? ?看完這部分我也是服了,這也叫算法呀---所謂前向傳播,就是輸入通過(guò)權(quán)重和神經(jīng)元的函數(shù)后,計(jì)算得出結(jié)果的這一個(gè)過(guò)程。如下圖所示:

? ? ?而由于在TensorFlow中矩陣的乘法是非常容易實(shí)現(xiàn)的,所以前向傳播的過(guò)程常表示為矩陣乘法。這里主要是矩陣之間的乘法,行向量乘以列,然后再相加的這個(gè)過(guò)程。

(三)神經(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ù)初始化的過(guò)程,初始化一個(gè)2*3的參數(shù)矩陣,均值為0,標(biāo)準(zhǔn)差為2.當(dāng)然,此外還有很多初始化變量的方法。? ??

OK,接下來(lái)我們看一下如何用代碼實(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()
要寫(xiě)一段tf代碼,我認(rèn)為就是需要寫(xiě)出每個(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。
那么接下來(lái)就是反向傳播的調(diào)參過(guò)程。
?反向傳播的整體思路是這樣的:我們根據(jù)設(shè)置的參數(shù)得到的輸出結(jié)果與真實(shí)結(jié)果的差,我們稱(chēng)之為損失函數(shù)(代表的就是我們的輸出與真實(shí)的差距),反向傳播的過(guò)程就是想辦法使損失函數(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)參的過(guò)程變成了一個(gè)多元函數(shù)的求最小值的問(wèn)題。那么為了讓這個(gè)損失函數(shù)變小的最快,這里使用了“梯度下降法”(又稱(chēng)最速下降法)。 我們知道多元函數(shù)關(guān)于在任何方向上都有變化,那么這個(gè)就叫做方向?qū)?shù)。然而這個(gè)函數(shù)的值變化最快的方向,就叫做梯度?。。。。。ㄟ@個(gè)稍微有些難理解)那么這個(gè)梯度的求解方法就是各個(gè)方向的偏導(dǎo)數(shù)乘當(dāng)前方向的單位向量再相加。

所以就可以把所有的參數(shù)都從他們的偏導(dǎo)數(shù)方向上減少:

其中n就是他們的學(xué)習(xí)率。而求偏導(dǎo)的過(guò)程就使用了鏈?zhǔn)揭?guī)則:

當(dāng)然,這個(gè)過(guò)程在tf中不需要這么復(fù)雜,只需要使用封裝好的代碼就可以。具體的代碼明天上。