1. 程式人生 > 其它 >CH5 用神經網路解決線性問題

CH5 用神經網路解決線性問題

  • 瞭解非線性問題、分類問題
  • 掌握神經網路解決二分類問題
  • 掌握隨機生成訓練資料的方法

非線性問題

三好學生問題:家長們再次湊到一起,但這次情況不一樣了,孩子們的總分不知道,僅知道是否評選上三好學生的結果。

計算總分的規則仍然是:總分 = 德育分*60% + 智育分*30% + 體育分*10%
評選三好學生的標準是:總分 ≥ 95

家長不知道這兩條規則。

這是一個典型的分類問題。學校一定是以德育分、智育分和體育分三項分數為依據,把學生們分成兩類:三好學生和非三好學生。因此,這是一個常見的二分類問題。下圖是用神經網路簡述二分類問題。

分類問題一般是非線性的。

  • 可以看出,當總分達到95之後,y值有一個跳變,並非線性的(一條直線)
  • y=f(xA),跳變函式/階躍函式
  • “一票否決制”

設計神經網路模型

總分(0~100)= 德育分60% + 智育分30% + 體育分*10% -> 評選結果(0、1)

啟用函式:把線性關係轉換成非線性關係的函式。啟用函式 sigmoid 函式的作用是把引數轉換成為 0 到 1 之間的一個小數。

使用啟用函式後的神經網路模型:

實現該網路模型的程式碼:

# import tensorflow as tf
import tensorflow.compat.v1 as tf

tf.compat.v1.disable_eager_execution()

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)

準備訓練資料

使用 random 產生隨機數

import random

random.seed() # 初始化隨機數種子,增加隨機性
random.random() # 產生一個 [0,1) 範圍內的小數

r = random.random() * 10 # 通過乘以一個整數,使產生的隨機數的範圍增大,此處範圍為 [0,10)

產生隨機訓練資料

import random

random.seed()

# 產生一個 [0,100] 範圍內的整數代表某一科分數
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: %s" %xData)
print("yTrainData: %s" %yTrainData)

優化產生的訓練資料,產生一個[60,101) 範圍內的更合理的分數:

xData = [
    int(random.random() * 41 + 60),
    int(random.random() * 41 + 60),
    int(random.random() * 41 + 60)
]

產生更多結果為 1 的訓練資料,產生一個[93,101)範圍內的符合三好學生要求的分數:

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

為什麼要使用隨機資料來訓練神經網路:

  • 並非“劇透”,用於演示和驗證
  • 符合人工收集的規貝
  • 滿足神經網路大規模訓練的需要

訓練

# import tensorflow as tf
import tensorflow.compat.v1 as tf
import random

tf.compat.v1.disable_eager_execution()

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)

觀察訓練結果:

增加偏移量 b 來加速訓練:

+ b = tf.Variable(80, dtype=tf.float32)
- n2 = tf.reduce_sum(n1)
+ n2 = tf.reduce_sum(n1) - b
# import tensorflow as tf
import tensorflow.compat.v1 as tf
import random

tf.compat.v1.disable_eager_execution()

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(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)
- b = tf.Variable(80, dtype=tf.float32)
+ b = tf.Variable(95, dtype=tf.float32)

批量產生隨機訓練資料:

import random
import numpy as np

tf.compat.v1.disable_eager_execution()

random.seed()

rowCount = 5

xData = np.full(
    shape=(rowCount, 3),
    fill_value=0,
    dtype=np.float32
)

yTrainData = np.full(
    shape=rowCount,
    fill_value=0,
    dtype=np.float32
)

for i in range(rowCount):
    xData[i][0] = int(random.random() * 11 + 90)
    xData[i][1] = int(random.random() * 11 + 90)
    xData[i][2] = int(random.random() * 11 + 90)

    xAll = xData[i][0] * 0.6 + xData[i][0] * 0.3 + xData[i][2] * 0.1
  • numpy 是常用於數學計算的類庫
  • npful 函式用於向陣列中填充初始數值
  • 使用迴圈來生成批量的資料
# import tensorflow as tf
import tensorflow.compat.v1 as tf
import random
import numpy as np

tf.compat.v1.disable_eager_execution()

random.seed()

rowCount = 5

xData = np.full(
    shape=(rowCount, 3),
    fill_value=0,
    dtype=np.float32
)

yTrainData = np.full(
    shape=rowCount,
    fill_value=0,
    dtype=np.float32
)

goodCount = 0

for i in range(rowCount):
    xData[i][0] = int(random.random() * 11 + 90)
    xData[i][1] = int(random.random() * 11 + 90)
    xData[i][2] = 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=%s" %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)

可以看到,xData 是一個二維陣列,其中包含了 5 條資料,每條是 3 項符合定義範圍的分數。tTrainData 中包含 3 個 1,也就是說有 3 位學生符合三好學生的條件,接下來輸出的 goodCount 也確實等於 3,再往下的訓練也一切正常。