TensorFlow 用神經網絡解決非線性問題


本節涉及點:

  1. 激活函數 sigmoid
  2. 產生隨機訓練數據
  3. 使用隨機訓練數據訓練
  4. 加入偏移量b加快訓練過程
  5. 進階:批量生產隨機訓練數據

 

在前面的三好學生問題中,學校改變了評三好的標准 —— 總分>= 95,即可當三好。計算總分公式不變 —— 總分 = 德*0.6+智*0.3+體*0.1

但學校沒有公布這些規則,家長們希望通過神經網絡計算出學校的上述規則

 

這個問題顯然不是線性問題,也就是無法用一個類似 y = w*x + b 的公式來從輸入數據獲得結果

雖然總分和各項成績是線性關系,但總分與是否評比上三好並不是線性關系,而是一個階躍函數

 

 

# 如果在一連串的線性關系中有一個非線性關系出現,整個問題都將成為非線性的問題

一、激活函數 sigmoid

把評選結果 是不是三好學生 定義為 1 / 0

那么由總分 ——>  評選結果的過程 就是 0~100的數字得出1 或 0 的計算過程 ——>   sidmoid 函數

  e 為自然底數

(1)sigmoid 函數

可以把任意數字變成 0 - 1 范圍內的數字

在圖中可以觀察到,-5~5 的范圍是個快速的從0 變1的過程,非常像這個問題出現的階躍函數 ————>    常常用來進行 二分類

 

 

# 在神經網絡中,像sigmoid 這種把線性化的關系轉化為非線性化關系的函數叫做 激活函數

 

(2)使用sigmoid 函數后的神經網絡模型

 

 隱藏層中的節點 n11,n12,n13 分別接收來自輸入層節點 x1 x2 x3的輸入數據,與權重 w1 w2 w3 分別相乘后都送到 隱藏層 2 的節點 n2 ,n2將這些數據匯總求和后再 送到輸出層,輸出層節點將來自n2 的數據使用激活函數 sigmoid 處理后面作為神經網絡最后輸出的計算結果

 

用代碼實現這個模型:

import tensorflow as tf

x = tf.placeholder(dtype=tf.float32)
yTrain = tf.placeholder(dtype=tf.float32)

w = tf.Variable(tf.zeros([3]),dtype=tf.float32)

n1 = w* x
n2 = tf.reduce_sum(n1)

y = tf.nn.sigmoid(n2)

 

上面的代碼中 使用了以向量來組織數據的簡單的實現方法 x —— [x1,x2,x3]

輸出層節點則是 調用了tf.nn.sigmoid() 函數  

 

 

二、產生隨機訓練數據

隨機數:

import random
random.seed()
r = random.random() * 10
print(r)
x = int (r)
print(x)
6.999030147748621
6

random包 提供的函數 random 產生 [0,1) 范圍內的隨機小數

int (r)  ————   對小數r 向下取

計算機產生的隨機數都是偽隨機數,隨機性並不好,最好運行函數 random.seed() 來產生新的 隨機數種子

 

產生隨機訓練數據:

import random
random.seed()

xData = [int (random.random() * 101),int (random.random() * 101),int(random.random() * 101)]
xAll = xData[0]* 0.6 + xData[1] * 0.3 + xData[2]*0.1

if xAll >= 95:
    yTrainData = 1
else:
    yTrainData = 0
print(xData)
print(yTrainData)

 

我們用xData 來存放隨機產生的某個學生的三個分數 ————  這是一個 一維數組來存放的三維向量

xAll 用來存放 總分

接着 用條件判斷語句生成目標值,滿足 總分 >= 95 時為1, 否則為0

 

結果:

[52, 70, 7]
0

雖然該數據理論上是正確的,但一名學生一科7分,有點不正常,所以優化下

import random
random.seed()

xData = [int (random.random() * 41+60),int (random.random() *41+60),int(random.random() *41+60)]
xAll = xData[0]* 0.6 + xData[1] * 0.3 + xData[2]*0.1

if xAll >= 95:
    yTrainData = 1
else:
    yTrainData = 0
print(xData)
print(yTrainData)

 

產生隨機數在 [60,100],是數據更合理

但符合三好學生的條件的數據太少,不利於神經網絡的訓練,所以更大概率的產生一些 符合三好學生調節的數據

xData = [int (random.random() * 8+93),int (random.random() *8+93),int(random.random() *8+93)]

 

使數據介於[93,100]

但為了避免出現太多符合三好學生條件的數據,會交替使用這兩種方法產生更平衡的訓練數據

 

 

 

三、使用隨機數據訓練

 本段代碼一共循環執行 5 輪,每一輪兩次訓練,第一次是 三好學生概率大的一些隨機分數,第二次使用一般的隨機分數

import tensorflow as tf
import random
random.seed()
x = tf.placeholder(dtype=tf.float32)
yTrain = tf.placeholder(dtype=tf.float32)
w = tf.Variable(tf.zeros([3]), dtype=tf.float32)
wn = tf.nn.softmax(w)
n1 = wn * x
n2 = tf.reduce_sum(n1)
y = tf.nn.sigmoid(n2)
loss = tf.abs(yTrain - y)
optimizer = tf.train.RMSPropOptimizer(0.1)
train = optimizer.minimize(loss)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(5):
    xData = [int(random.random() * 8 + 93), int(random.random() * 8 + 93), int(random.random() * 8 + 93)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    if xAll >= 95:
        yTrainData = 1
    else:
        yTrainData = 0
    result = sess.run([train, x, yTrain, w, n2, y, loss], feed_dict={x: xData, yTrain: yTrainData})
    print(result)
    xData = [int(random.random() * 41 + 60), int(random.random() * 41 + 60), int(random.random() * 41 + 60)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    if xAll >= 95:
        yTrainData = 1
    else:
        yTrainData = 0
    result = sess.run([train, x, yTrain, w, n2, y, loss], feed_dict={x: xData, yTrain: yTrainData})
    print(result)
[None, array([96., 98., 95.], dtype=float32), array(1., dtype=float32), array([0., 0., 0.], dtype=float32), 96.33334, 1.0, 0.0]
[None, array([85., 91., 61.], dtype=float32), array(0., dtype=float32), array([0., 0., 0.], dtype=float32), 79.0, 1.0, 1.0]
[None, array([95., 96., 94.], dtype=float32), array(1., dtype=float32), array([0., 0., 0.], dtype=float32), 95.0, 1.0, 0.0]
[None, array([94., 87., 68.], dtype=float32), array(0., dtype=float32), array([0., 0., 0.], dtype=float32), 83.0, 1.0, 1.0]
[None, array([99., 93., 95.], dtype=float32), array(1., dtype=float32), array([0., 0., 0.], dtype=float32), 95.66667, 1.0, 0.0]
[None, array([98., 75., 63.], dtype=float32), array(0., dtype=float32), array([0., 0., 0.], dtype=float32), 78.66667, 1.0, 1.0]
[None, array([99., 95., 95.], dtype=float32), array(1., dtype=float32), array([0., 0., 0.], dtype=float32), 96.33334, 1.0, 0.0]
[None, array([83., 89., 74.], dtype=float32), array(0., dtype=float32), array([0., 0., 0.], dtype=float32), 82.0, 1.0, 1.0]
[None, array([ 98., 100.,  95.], dtype=float32), array(1., dtype=float32), array([0., 0., 0.], dtype=float32), 97.66667, 1.0, 0.0]
[None, array([62., 79., 61.], dtype=float32), array(0., dtype=float32), array([0., 0., 0.], dtype=float32), 67.333336, 1.0, 1.0]

 

 

 

加入偏移量b加快訓練過程

import tensorflow as tf
import random
random.seed()
x = tf.placeholder(dtype=tf.float32)
yTrain = tf.placeholder(dtype=tf.float32)
w = tf.Variable(tf.zeros([3]), dtype=tf.float32)
b = tf.Variable(80, dtype=tf.float32)
wn = tf.nn.softmax(w)
n1 = wn * x
n2 = tf.reduce_sum(n1) - b
y = tf.nn.sigmoid(n2)
loss = tf.abs(yTrain - y)
optimizer = tf.train.RMSPropOptimizer(0.1)
train = optimizer.minimize(loss)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(500):
    xData = [int(random.random() * 8 + 93), int(random.random() * 8 + 93), int(random.random() * 8 + 93)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    if xAll >= 95:
        yTrainData = 1
    else:
        yTrainData = 0
    result = sess.run([train, x, yTrain, wn, b, n2, y, loss], feed_dict={x: xData, yTrain: yTrainData})
    print(result)
    xData = [int(random.random() * 41 + 60), int(random.random() * 41 + 60), int(random.random() * 41 + 60)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    if xAll >= 95:
        yTrainData = 1
    else:
        yTrainData = 0
    result = sess.run([train, x, yTrain, wn, b, n2, y, loss], feed_dict={x: xData, yTrain: yTrainData})
    print(result)

 

程序中,我們讓 n2 在計算總分的 基礎上 - b,目的是為了讓 n2向[-5,5]這個區間范圍靠攏。

根據前面代碼的輸出,我們隨便預估了 b 的取值,80

輸出:

 

 參數w 和 b 的值明顯變化,n2的值也在 0 附近跳動,誤差也出現了小數上的調整,這說明神經網絡的訓練已經進入良性的循環了

 嘗試增加訓練次數,並把輸出結果信息中的w 改為 wn,最后幾次的輸出結果如下:

import tensorflow as tf
import random
random.seed()
x = tf.placeholder(dtype=tf.float32)
yTrain = tf.placeholder(dtype=tf.float32)
w = tf.Variable(tf.zeros([3]), dtype=tf.float32)
b = tf.Variable(80, dtype=tf.float32)
wn = tf.nn.softmax(w)
n1 = wn * x
n2 = tf.reduce_sum(n1) - b
y = tf.nn.sigmoid(n2)
loss = tf.abs(yTrain - y)
optimizer = tf.train.RMSPropOptimizer(0.1)
train = optimizer.minimize(loss)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(500):
    xData = [int(random.random() * 8 + 93), int(random.random() * 8 + 93), int(random.random() * 8 + 93)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    if xAll >= 95:
        yTrainData = 1
    else:
        yTrainData = 0
    result = sess.run([train, x, yTrain, wn, b, n2, y, loss], feed_dict={x: xData, yTrain: yTrainData})
    print(result)
    xData = [int(random.random() * 41 + 60), int(random.random() * 41 + 60), int(random.random() * 41 + 60)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    if xAll >= 95:
        yTrainData = 1
    else:
        yTrainData = 0
    result = sess.run([train, x, yTrain, wn, b, n2, y, loss], feed_dict={x: xData, yTrain: yTrainData})
    print(result)

 

可以看到, 三項分數的權重變量wn 非常接近於期待值 [0.6,0.3,0.1] ,可變參數b 非常接近這個問題中判斷是否是 三好學生的門檻 95 ——— 總分門檻95分,會有一個評選結果從 0-1的跳變,,而 sigmoid 函數的輸入值在 [-5,5] 之間時,會有一個從  0 到 1 的巨變,那么總分減去偏移量 b 就可以得到引起模型輸出結果巨變的數值,顯然可以看出,偏移量b 為 95

b 的值為95左右時,優化器可以“感受到” 調整可變參數 w 后對輸出結果的影響,因而能夠有效的調整可變參數,使誤差越來越小

 

b 為啥不等於95? ————  sigmoid函數比較不是從0直接跳變成1,是連續的,這個漸變的過程中,輸出的數值會導致優化器判斷出現誤判,這是正常的。可以通過增加大量在這個邊界附近的訓練數據,可以有效的減少誤差

 

 

 

 

四、進階:批量生產隨機訓練數據

在訓練前 一次性 批量生成 一批訓練數據以備訓練

 

import tensorflow as tf
import random
import numpy as np
random.seed()
rowCount = 5
#np.full 生成一個多維數組,並用預定的值來填充
xData = np.full(shape=(rowCount, 3), fill_value=0, dtype=np.float32)#生成了一個形態為 (rowCount,3)的多維數組,並全部用0填充
#rowCount 是准備生成的訓練數據的條數
yTrainData = np.full(shape=rowCount, fill_value=0, dtype=np.float32)
goodCount = 0#符合三好學生條件的數據的個數
# 生成隨機訓練數據的循環
for i in range(rowCount):
    xData[i] = [int(random.random() * 11 + 90), int(random.random() * 11 + 90), int(random.random() * 11 + 90)]
    xAll = xData[i][0] * 0.6 + xData[i][1] * 0.3 + xData[i][2] * 0.1
    if xAll >= 95:
        yTrainData[i] = 1
        goodCount = goodCount + 1
    else:
        yTrainData[i] = 0
print("xData=%s" % xData)
print("yTrainData=%s" % yTrainData)
print("goodCount=%d" % goodCount)
x = tf.placeholder(dtype=tf.float32)
yTrain = tf.placeholder(dtype=tf.float32)
w = tf.Variable(tf.zeros([3]), dtype=tf.float32)
b = tf.Variable(80, dtype=tf.float32)
wn = tf.nn.softmax(w)
n1 = wn * x
n2 = tf.reduce_sum(n1) - b
y = tf.nn.sigmoid(n2)
loss = tf.abs(yTrain - y)
optimizer = tf.train.RMSPropOptimizer(0.1)
train = optimizer.minimize(loss)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(2):
    for j in range(rowCount):
        result = sess.run([train, x, yTrain, wn, b, n2, y, loss], feed_dict={x: xData[j], yTrain: yTrainData[j]})
        print(result)

#最后,在訓練的時候,每一輪訓練會訓練rowCount 次,也就是5次,每次訓練會把 xData yTrainData 中對應小標序號的數據“喂”給神經網絡

結果如下:

xData=[[ 96.  90.  97.]
 [ 95. 100.  98.]
 [ 97.  91.  94.]
 [ 96.  92.  95.]
 [100.  97. 100.]]
yTrainData=[0. 1. 0. 0. 1.]
goodCount=2
[None, array([96., 90., 97.], dtype=float32), array(0., dtype=float32), array([0.33333334, 0.33333334, 0.33333334], dtype=float32), 80.0, 14.333336, 0.9999994, 0.9999994]
[None, array([ 95., 100.,  98.], dtype=float32), array(1., dtype=float32), array([0.33333334, 0.33333337, 0.33333334], dtype=float32), 80.0, 17.666672, 1.0, 0.0]
[None, array([97., 91., 94.], dtype=float32), array(0., dtype=float32), array([0.33333334, 0.33333337, 0.33333334], dtype=float32), 80.0, 14.000008, 0.99999917, 0.99999917]
[None, array([96., 92., 95.], dtype=float32), array(0., dtype=float32), array([0.33333328, 0.33333337, 0.33333328], dtype=float32), 80.0, 14.333328, 0.9999994, 0.9999994]
[None, array([100.,  97., 100.], dtype=float32), array(1., dtype=float32), array([0.33333325, 0.3333334 , 0.3333333 ], dtype=float32), 80.0, 19.0, 1.0, 0.0]
[None, array([96., 90., 97.], dtype=float32), array(0., dtype=float32), array([0.33333325, 0.3333334 , 0.3333333 ], dtype=float32), 80.0, 14.333328, 0.9999994, 0.9999994]
[None, array([ 95., 100.,  98.], dtype=float32), array(1., dtype=float32), array([0.33333325, 0.33333346, 0.33333328], dtype=float32), 80.0, 17.666672, 1.0, 0.0]
[None, array([97., 91., 94.], dtype=float32), array(0., dtype=float32), array([0.33333325, 0.33333346, 0.33333328], dtype=float32), 80.0, 14.0, 0.99999917, 0.99999917]
[None, array([96., 92., 95.], dtype=float32), array(0., dtype=float32), array([0.33333322, 0.3333335 , 0.33333328], dtype=float32), 80.0, 14.333336, 0.9999994, 0.9999994]
[None, array([100.,  97., 100.], dtype=float32), array(1., dtype=float32), array([0.3333332 , 0.33333352, 0.33333328], dtype=float32), 80.0, 19.0, 1.0, 0.0]

 

 

 

 隨時生成數據的方法能夠最大限度地提高神經網絡訓練的覆蓋范圍(因為每一次 訓練都是使用新產生的隨機數據),進而最大限度地提高它的准確性,缺點是訓練速度相對較慢;

一次性生成一批隨機數據的方法則反之, 訓練速度會很快,因為每輪訓練都是同一批數據, 神經網絡中的參數可以很快地被調節到合適的取值,但是這樣訓練出來的神經網絡會比較“依賴”於這批數據,換一批數據時 會發現准確度明顯下降

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM