Skip to content

1. 神经网络解决非线性问题

1.1 三好学生评选问题

修改问题条件

  • 家长得知三项分数成绩,但不知道总分
  • 家长知道自己的孩子是否是三好学生,三好学生要求总分大于等于 9595
  • 家长想知道计算总分的方法

这个问题现在是一个二分类问题,评选的结果只有两种,是或否。

1.2 设计模型

激活函数 sigmoid\mathrm{sigmoid} 可以用来解决二分问题。

sigmoid(x)=11+ex \mathrm{sigmoid}(x) = \frac{1}{1 + \mathrm{e}^{-x}}

将线性关系转化为非线性关系的函数叫 激活函数(activation function)。

现在我们的网络多一个 隐藏层 2,内容是将求和的值代入激活函数 sigmoid\mathrm{sigmoid}

1.3 模型实现

py
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

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)

1.4 随机数

注意,如果您需要快速获得大量且高质量的随机数,使用 numpy

Python 的伪随机数生成器:

py
import random
# 设定随机种子
random.seed()
# 生成随机数
print(random.random())

后面我们使用随机数来检验神经网络的性能:

py
import random

import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

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 _ in range(5):
    xData = [int(random.random() * 8) + 93
             for _ in range(3)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    yTrainData = 0
    if xAll >= 95:
        yTrainData = 1
    result = sess.run([train, x, yTrain, n2, y, loss],
                      feed_dict={x: xData, yTrain: yTrainData})
    print(result)
    xData = [int(random.random() * 41) + 60
             for _ in range(3)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    yTrainData = 0
    if xAll >= 95:
        yTrainData = 1
    result = sess.run([train, x, yTrain, n2, y, loss],
                      feed_dict={x: xData, yTrain: yTrainData})
    print(result)

经过训练,我们得到如下结果

py
[None, array([99., 94., 93.], dtype=float32), array(1., dtype=float32), 95.333336, 1.0, 0.0]
[None, array([ 91.,  98., 100.], dtype=float32), array(0., dtype=float32), 96.333336, 1.0, 1.0]
[None, array([99., 97., 99.], dtype=float32), array(1., dtype=float32), 98.333336, 1.0, 0.0]
[None, array([100.,  87.,  65.], dtype=float32), array(0., dtype=float32), 84.0, 1.0, 1.0]
[None, array([95., 97., 94.], dtype=float32), array(1., dtype=float32), 95.333336, 1.0, 0.0]
[None, array([82., 71., 77.], dtype=float32), array(0., dtype=float32), 76.66667, 1.0, 1.0]
[None, array([100.,  98.,  94.], dtype=float32), array(1., dtype=float32), 97.333336, 1.0, 0.0]
[None, array([62., 96., 74.], dtype=float32), array(0., dtype=float32), 77.333336, 1.0, 1.0]
[None, array([93., 94., 97.], dtype=float32), array(0., dtype=float32), 94.66667, 1.0, 1.0]
[None, array([61., 67., 82.], dtype=float32), array(0., dtype=float32), 70.0, 1.0, 1.0]

我们发现,损失值并没有明显下降,原因是总分 n2n_2 的值一般在 7010070 \sim 100 左右,这个区间内进行 sigmoid\mathrm{sigmoid} 操作,总是得到 11

这个时候我们就需要线性模型 y=wx+by = wx + b 的偏置参数 bb 了:

py
import random
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()

random.seed()

x = tf.placeholder(dtype=tf.float32)
yTrain = tf.placeholder(dtype=tf.float32)
w = tf.Variable(tf.zeros((3,)), dtype=tf.float32)
# 增加参数 b
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 _ in range(5000):
    xData = [int(random.random() * 8) + 93
             for _ in range(3)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    yTrainData = 0
    if xAll >= 95:
        yTrainData = 1
    result = sess.run([train, x, yTrain, wn, b, n2, y, loss],
                      feed_dict={x: xData, yTrain: yTrainData})
    xData = [int(random.random() * 41) + 60
             for _ in range(3)]
    xAll = xData[0] * 0.6 + xData[1] * 0.3 + xData[2] * 0.1
    yTrainData = 0
    if xAll >= 95:
        yTrainData = 1
    result = sess.run([train, x, yTrain, wn, b, n2, y, loss],
                      feed_dict={x: xData, yTrain: yTrainData})
print(result)

输出如下:

py
[None, array([99., 97., 85.], dtype=float32), array(1., dtype=float32), array([0.71742696, 0.25420287, 0.02837014], dtype=float32), 94.43411, 3.6350937, 0.9742966, 0.02570337]

5000050000 次循环的结果如下:

py
[None, array([71., 83., 70.], dtype=float32), array(0., dtype=float32), array([0.5261445 , 0.37374046, 0.10011504], dtype=float32), 92.99498, -17.610214, 2.248957e-08, 2.248957e-08]

可见其非常接近随机时使用的数据 [0.6,  0.3,  0.1][0.6,\;0.3,\;0.1]

1.5 numpy

numpy 提供了多维数组(np.ndarray),也包括了随机数生成器 np.random.random() 。后续我们将讨论这个随机数生成器。