今天我們來實現(xiàn)一個神經(jīng)網(wǎng)絡(luò),其中部分內(nèi)容參考
http://www.itdecent.cn/p/596a30d46f34
如有冒犯請私信我或者留言,希望一些小小的工作能為大家的學(xué)習(xí)和工作帶來便利。
一、神經(jīng)網(wǎng)絡(luò)
我在看Michael Nielsen 大神的 《Neural Networks and Deep Learning》這本書時第一次接觸到神經(jīng)網(wǎng)絡(luò)這個概念。這本書由淺入深,講述得細致而不失深度。有興趣的朋友可以看看,下面是中文版鏈接。
http://www.liuxiao.org/wp-content/uploads/2016/10/nndl-ebook.pdf
那么什么是神經(jīng)網(wǎng)絡(luò)?神經(jīng)網(wǎng)絡(luò)又能干什么呢?我相信有不少同學(xué)聽過這句話“神經(jīng)網(wǎng)絡(luò)可以計算任何函數(shù)”。神經(jīng)網(wǎng)絡(luò)擁有一種普遍性。這非常非常有吸引力。關(guān)于這點的證明(說是“解釋”可能更好)可以參考Approximation by superpositions of a sigmoidal function這篇文章?,F(xiàn)在我們更關(guān)心怎么實現(xiàn)一個神經(jīng)網(wǎng)絡(luò)。
二、實現(xiàn)步驟
先簡單說明一下待擬合的函數(shù)。畢竟咱們得先找個目標(biāo)嘛!先從擬合簡單的函數(shù)來說明下大概流程,后面再逐步復(fù)雜起來。
我們需要擬合的函數(shù)非常簡單——y = x^2 - 0.5,對!就是我們之前演示過的函數(shù)。我們通過numpy來生產(chǎn)模擬數(shù)據(jù)。
def createdata():
x_data = np.linspace(-1,1,300)[:,np.newaxis]
noise = np.random.normal(0,0.05,x_data.shape).astype(np.float32)
y_data = np.square(x_data) - 0.5 + noise
return x_data,y_data
我們需要關(guān)注的就是返回值,這個函數(shù)返回x_data,y_data。x_data相當(dāng)于原始inputs,y_data相當(dāng)于我們需要擬合的對象targets。至此數(shù)據(jù)便有了。
接下來我們需要做什么?是不是好多時候去實現(xiàn)一個東西的時候一臉懵逼?其實,覺得困惑是因為我們沒有理清思路。我們得多問問自己一些問題。
我們首先問問自己一個問題:
我們知不知道,這是 一個什么樣的函數(shù),我們有沒有先驗的知識?
我們?yōu)槭裁匆P(guān)注函數(shù)形態(tài)?因為這關(guān)系到我們需要怎么設(shè)置參數(shù)。比如y=kx+b只需要設(shè)置兩個函數(shù)擬合,而y=sin(kx)+b就需要三個。
我們再問一個問題:
我們怎么來擬合一個函數(shù)?或者說,函數(shù)怎么就三下兩下就出結(jié)果了?
其實我和大家一樣,一開始也很困惑,讀完梯度下降算法之后,稍微好了一些,但還是有些不太理解。
關(guān)于第一個問題,我們其實可以先通過假設(shè)的方式來解決一下,后面我們可以通過更高級的方式來探索“這可能是一個什么函數(shù)?”
第二個問題很關(guān)鍵:神經(jīng)網(wǎng)絡(luò)的普適性。
Michael Nielsen的書中提到了這個問題,在第四章講到了“神經(jīng)網(wǎng)絡(luò)可以計算任何函數(shù)的可視化證明”
下面我們簡單探討一下這個問題。有兩點需要注意:
一、一個網(wǎng)絡(luò)并不能準(zhǔn)確地計算任何函數(shù)。而是說,我們可以獲得盡可能好的一個近似。通過增加隱藏元的數(shù)量,可以提升近似的精度
二、近似的函數(shù)類是連續(xù)函數(shù),對于階躍函數(shù),我們使用連續(xù)函數(shù)進行模擬。
大家都學(xué)過微積分吧!對于任意函數(shù)我們都可以用一個個小方塊來擬合,對吧?那么在神經(jīng)網(wǎng)絡(luò)中我們的小方塊又是什么呢?先看下圖,這是一個特殊的sigmod函數(shù),w=999 幾乎就是個階躍函數(shù)了。

現(xiàn)在我們有兩個參數(shù)w,b實際上我們可以用s = ?b/w簡化我們描述隱藏神經(jīng)元的方式,這就是階躍位置。

越來越接近我們的目標(biāo)了.
下邊的繪圖是隱藏層的加權(quán)輸出 w1a1 + w2a2 。這里 a1 和 a2 各自是頂部和底部神經(jīng)元的輸出。這些輸出由a表示,是因為它們通常被稱為神經(jīng)元的 激活值(activations)。

我們再看一張圖,我相信看完這張圖,你就會發(fā)現(xiàn)"小方塊"在哪里了。

詳細內(nèi)容可以參考上文提到的資料。這里不多說了,再說下去大家可能沒興致看了。
我們回到正題。先用tensorflow構(gòu)建一個簡單的層,輸入的參數(shù)是該層輸入,輸入數(shù)據(jù)的大小,輸出數(shù)據(jù)的大小,以及使用的激活函數(shù),激活函數(shù)在默認(rèn)情況下是None,即不適用激活函數(shù):
def add_layer(inputs,in_size,out_size,activation_function=None):
Weights = tf.Variable(tf.random_normal([in_size,out_size]))
biases = tf.Variable(tf.zeros([1,out_size])+0.1)
Wx_plus_b = tf.add(tf.matmul(inputs,Weights),biases)
if activation_function is None:
outputs = Wx_plus_b
else:
outputs = activation_function(Wx_plus_b)
return outputs
這里,我們定義輸入層-隱藏層-輸出層的三層神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu),其中輸入層和輸出層僅有一個神經(jīng)元,而隱藏層有10個神經(jīng)元。同時,我們定義我們的損失是平方損失函數(shù),通過梯度下降法來最小化我們的損失。
def createnet():
xs = tf.placeholder(tf.float32,[None,1])
ys = tf.placeholder(tf.float32,[None,1])
l1 = add_layer(xs,1,10,activation_function=tf.nn.relu)
prediction = add_layer(l1,10,1,activation_function=None)
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction),
reduction_indices = [1]))
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init = tf.global_variables_initializer()
x_data,y_data = createdata()
with tf.Session() as sess:
sess.run(init)
for i in range(1000):
sess.run(train_step,feed_dict={xs:x_data,ys:y_data})
if i % 50 == 0:
print(sess.run(loss,feed_dict={xs:x_data,ys:y_data}))
非常簡單的一個例子動手敲一下就會明白了,有些內(nèi)容在之前的博客里做了記錄,比如reduce_sum的用法等等。不多做贅述了。
完整代碼如下
import tensorflow as tf
import numpy as np
def add_layer(inputs,in_size,out_size,activation_function=None):
Weights = tf.Variable(tf.random_normal([in_size,out_size]))
biases = tf.Variable(tf.zeros([1,out_size])+0.1)
Wx_plus_b = tf.add(tf.matmul(inputs,Weights),biases)
if activation_function is None:
outputs = Wx_plus_b
else:
outputs = activation_function(Wx_plus_b)
return outputs
def createdata():
x_data = np.linspace(-1,1,300)[:,np.newaxis]
noise = np.random.normal(0,0.05,x_data.shape).astype(np.float32)
y_data = np.square(x_data) - 0.5 + noise
return x_data,y_data
def createnet():
xs = tf.placeholder(tf.float32,[None,1])
ys = tf.placeholder(tf.float32,[None,1])
l1 = add_layer(xs,1,10,activation_function=tf.nn.relu)
prediction = add_layer(l1,10,1,activation_function=None)
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction),
reduction_indices = [1]))
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)
init = tf.global_variables_initializer()
x_data,y_data = createdata()
with tf.Session() as sess:
sess.run(init)
for i in range(1000):
sess.run(train_step,feed_dict={xs:x_data,ys:y_data})
if i % 50 == 0:
print(sess.run(loss,feed_dict={xs:x_data,ys:y_data}))
createnet()