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,再往下的训练也一切正常。
练习
-
编程生成 5
[-20,20)
范围内的随机数,并用 TensorFlow 设法求出这些数字进行 sigmoid 操作后的结果。import tensorflow as tf import random a = tf.placeholder(dtype=tf.float32) b = tf.nn.sigmoid(a) sess = tf.Session() for i in range(5): print(sess.run(b, feed_dict={a: random.random() * 40 - 20}))
-
编程解决下述非线性问题
- 输入数据
[1,1,1]
,输出目标值:2 - 输入数据
[1,0,1]
,输出目标值:1 - 输入数据
[1,2,3]
,输出目标值:3
import tensorflow as tf x = tf.placeholder(shape=[3], dtype=tf.float32) yTrain = tf.placeholder(shape=[], dtype=tf.float32) w = tf.Variable(tf.zeros([3]), dtype=tf.float32) b = tf.Variable(0, dtype=tf.float32) y = tf.reduce_sum(tf.nn.sigmoid(x * w + b)) loss = tf.abs(y - yTrain) optimizer = tf.train.RMSPropOptimizer(0.1) train = optimizer.minimize(loss) sess = tf.Session() sess.run(tf.global_variables_initializer()) for i in range(1000): print(sess.run([train, y, yTrain, loss], feed_dict={x: [1, 1, 1], yTrain: 2})) print(sess.run([train, y, yTrain, loss], feed_dict={x: [1, 0, 1], yTrain: 1})) print(sess.run([train, y, yTrain, loss], feed_dict={x: [1, 2, 3], yTrain: 3}))
- 输入数据