1. 程式人生 > >Tensorflow 搭建自己的神經網路(一)

Tensorflow 搭建自己的神經網路(一)

神經網路的輸入只能是數值型:BP神經網路反向的誤差傳播過程中有求導運算的,必須是連續可導的函式才能進行此運算,所以輸入也必須是數值型的資料(向量或者矩陣)。

優化問題:梯度下降法;牛頓法;最小二乘法

Tensorflow中的資料型別基本都是float32

一.Tensorflow的簡單使用

一個簡單的例子:

import tensorflow as tf
import numpy as np

# 建立資料
x_data = np.random.rand(100).astype(np.float32)
y_data = x_data*0.1 + 0.3

# 搭建模型
Weights = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
biases = tf.Variable(tf.zeros([1]))
y = Weights*x_data + biases

# 計算誤差
loss = tf.reduce_mean(tf.square(y-y_data))

# 優化    學習率為0.5
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)

# 初始化所有之前定義的Variable
init = tf.global_variables_initializer()

# 建立會話 Session
sess = tf.Session()
sess.run(init)         

for step in range(201):
    sess.run(train)
    if step % 20 == 0:
        print(step, sess.run(Weights), sess.run(biases))

sess.close()

Session的兩種開啟模式:

import tensorflow as tf

# create two matrixes
matrix1 = tf.constant([[3,3]])
matrix2 = tf.constant([[2],
                       [2]])
product = tf.matmul(matrix1,matrix2)  # 矩陣乘法,相當於numpy中的np.dot()

# method 1
sess = tf.Session()
result = sess.run(product)
print(result)
sess.close()
# [[12]]

# method 2
with tf.Session() as sess:
    result2 = sess.run(product)
    print(result2)
# [[12]]

Variable 變數:

import tensorflow as tf

# 定義變數
state = tf.Variable(0, name='counter')

# 定義常量
one = tf.constant(1)

# 定義加法步驟 (注: 此步並沒有直接計算)
new_value = tf.add(state, one)

# 將 state 更新成 new_value
update = tf.assign(state, new_value)

# 如果定義 Variable, 就一定要 initialize
init = tf.global_variables_initializer()
 
# 使用 Session
with tf.Session() as sess:
    sess.run(init)
    for _ in range(3):
        sess.run(update)
        print(sess.run(state))
# 直接 print(state) 不起作用,一定要把 sess 的指標指向 state 再進行 print 才能得到想要的結果

如果在 Tensorflow 中設定了變數(Variable),那麼初始化變數是最重要的!!所以定義了變數以後, 一定要定義 init = tf.global_variables_initializer()

placeholder 傳入值:

placeholder 是 Tensorflow 中的佔位符,暫時儲存變數.Tensorflow 如果想要從外部傳入data, 那就需要用到 tf.placeholder(), 然後以這種形式傳輸資料: sess.run(***, feed_dict={input: **}).

import tensorflow as tf

#在 Tensorflow 中需要定義 placeholder 的 type ,一般為 float32 形式
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)

# 將input1和input2 做乘法運算,並輸出為 output 
ouput = tf.multiply(input1, input2)

# 傳值的工作交給了 sess.run() , placeholder 與 feed_dict={} 是繫結在一起出現的。
with tf.Session() as sess:
    print(sess.run(ouput, feed_dict={input1: [7.], input2: [2.]}))
# [ 14.]

啟用函式(激勵函式):

層數較少時,選擇哪個啟用函式都可以;層數較多時,為避免梯度消失和梯度爆炸,需要慎重選擇啟用函式

在卷積神經網路的卷積層中,推薦使用relu;在迴圈神經網路中,推薦使用relu或tanh

激勵函式執行時啟用神經網路中某一部分神經元,將啟用資訊向後傳入下一層的神經系統。激勵函式的實質是非線性方程。 Tensorflow 的神經網路裡面處理較為複雜的問題時都需要運用激勵函式 activation function 

二.搭建一個神經網路

新增層 def add_layer():

在 Tensorflow 裡定義一個新增層的函式可以很容易的新增神經層,為之後的新增省下不少時間.神經層裡常見的引數通常有weightsbiases和激勵函式。

import tensorflow as tf

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)
    # 在機器學習中,biases的推薦值不為0,所以這裡是在0向量的基礎上又加了0.1
    Wx_plus_b = tf.matmul(inputs, Weights) + biases

    if activation_function is None:
        outputs = Wx_plus_b
    else:
        outputs = activation_function(Wx_plus_b)
    
    return outputs

搭建神經網路:

import numpy as np

# 構建所需的資料。這裡的x_data和y_data並不是嚴格的一元二次函式的關係,因為我們多加了一個noise,這樣看起來會更像真實情況。
x_data = np.linspace(-1,1,300, dtype=np.float32)[:, np.newaxis]
noise = np.random.normal(0, 0.05, x_data.shape).astype(np.float32)
y_data = np.square(x_data) - 0.5 + noise

# 利用佔位符定義我們所需的神經網路的輸入。tf.placeholder()就是代表佔位符,這裡的None代表無論輸入有多少都可以,因為輸入只有一個特徵,所以這裡是1。
xs = tf.placeholder(tf.float32, [None, 1])
ys = tf.placeholder(tf.float32, [None, 1])

# 開始定義神經層。通常神經層都包括輸入層、隱藏層和輸出層。這裡的輸入層只有一個屬性,所以我們就只有一個輸入;隱藏層我們可以自己假設,這裡我們假設隱藏層有10個神經元;輸出層和輸入層的結構是一樣的,所以我們的輸出層也是隻有一層。所以,我們構建的是——輸入層1個、隱藏層10個、輸出層1個的神經網路。

# 開始定義隱藏層,利用之前的add_layer()函式,這裡使用 Tensorflow 自帶的激勵函式tf.nn.relu。
l1 = add_layer(xs, 1, 10, activation_function=tf.nn.relu)
# 接著,定義輸出層。此時的輸入就是隱藏層的輸出——l1,輸入有10層(隱藏層的輸出層),輸出有1層。
prediction = add_layer(l1, 10, 1, activation_function=None)

loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction),
                     reduction_indices=[1]))  # reduction_indices=[1]即axis=1

train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

init = tf.global_variables_initializer()

# 定義Session,並用 Session 來執行 init 初始化步驟(注意:在tensorflow中,只有session.run()才會執行我們定義的運算)
sess = tf.Session()
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}))
# 如果誤差是在逐漸減小,則說明機器學習是有積極的效果的。

sess.close()

視覺化:

import matplotlib.pyplot as plt

# plot the real data
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x_data, y_data)
plt.ion()# 用於連續顯示,否則只顯示初始的狀態
plt.show()

for i in range(1000):
    # training
    sess.run(train_step, feed_dict={xs: x_data, ys: y_data})
    if i % 50 == 0:
        # to visualize the result and improvement
        try:
            ax.lines.remove(lines[0])
        except Exception:
            pass
        prediction_value = sess.run(prediction, feed_dict={xs: x_data})
        # plot the prediction
        lines = ax.plot(x_data, prediction_value, 'r-', lw=5)
        plt.pause(0.1)
# 每隔50次訓練重新整理一次圖形,用紅色、寬度為5的線來顯示我們的預測資料和輸入之間的關係,每次顯示暫停0.1s。

加速神經網路訓練:

  • Stochastic Gradient Descent (SGD)  隨機梯度下降
  • Momentum  動量法
  • AdaGrad
  • RMSProp
  • Adam  最常用 比較好用

優化器:

Tensorflow提供了7種優化器:

視覺化工具:Tensorboard

三.高階內容

分類問題(mnist手寫體數字識別):

相當於一個多分類問題,二分類使用邏輯迴歸(sigmoid函式作啟用函式),多分類使用邏輯迴歸的變種(softmax函式作啟用函式)

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

# 定義add_layer函式

def compute_accuracy(v_xs,v_ys):
    global prediction
    y_pre = sess.run(prediction,feed_dict={xs:v_xs})
    correct_prediction = tf.equal(tf.argmax(y_pre,1),tf.argmax(v_ys,1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
    # tf.cast(x,dtype,name=None):將x的資料格式轉化為dtype
    result = sess.run(accuracy,feed_dict={xs:v_xs,ys:v_ys})
    return result

xs = tf.placeholder(tf.float32,[None,784]) # 28*28
ys = tf.placeholder(tf.float32,[None,10])

prediction = add_layer(xs,784,10,activation_function=tf.nn.softmax)

cross_entropy = tf.reduce_mean(-tf.reduce_sum(
    ys * tf.log(prediction),reduction_indices=[1]))

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(1000):
    # 開始train,每次只取100張圖片,免得資料太多訓練太慢
    batch_xs,batch_ys = mnist.train.next_batch(100)
    sess.run(train_step,feed_dict={xs:batch_xs,ys:batch_ys})
    if i % 50 == 0:
        print(compute_accuracy(mnist.test.images,mnist.test.labels))
sess.close()

dropout正則化:

有一種專門用在神經網路的正規化的方法, 叫作 dropout. 在訓練的時候, 我們隨機忽略掉一些神經元和神經聯結 , 使這個神經網路變得”不完整”. 用一個不完整的神經網路訓練一次.

到第二次再隨機忽略另一些, 變成另一個不完整的神經網路. 有了這些隨機 drop 掉的規則, 我們可以想象其實每次訓練的時候, 我們都讓每一次預測結果都不會依賴於其中某部分特定的神經元. 像l1, l2正規化一樣, 過度依賴的 W , 也就是訓練引數W的數值會很大, l1, l2會懲罰這些大的引數. Dropout 的做法是從根本上讓神經網路沒機會過度依賴.

keep_prob = tf.placeholder(tf.float32)

Wx_plus_b = tf.nn.dropout(Wx_plus_b, keep_prob)
...
...

sess.run(train_step, feed_dict={xs: X_train, ys: y_train, keep_prob: 0.5})

keep_prob是保留概率,即我們要保留的結果所佔比例,它作為一個placeholder,在run時傳入, 當keep_prob=1的時候,相當於100%保留,也就是dropout沒有起作用。