深度学习代码实践(六)- 使用神经网络来逼近任意函数

问题提出

在前面 “深度学习代码实践(四)- 从0搭建一个神经网络:感知机与激活函数”的博文分享中,提到, 神经网络的本质是:通过参数与激活函数来拟合特征与目标之间的真实函数关系。单层网络只能做线性分类任务,两层神经网络可以无限逼近任意连续函数。

这里提到的“用两层神经网络可以无限逼近任意连续函数”。 那么神经网络是不是真的能够逼近任何函数?

我用 Tensorflow 做了一个实验, 以一个已知函数 z = x^2 + y*2 的 80000个随机的 (x,y) 点作为输入,计算得到函数的 z 值。 然后用这 80000个 (x, y) -> (z) 作为神经网络的训练数据, 训练得到一个模型。 然后使用这个模型对于新的输入值进行预测。 最后计算预测值跟实际值的差异。

函数:z = x*x + y*2

训练数据:80000个随机的 (x,y) 点, 以及计算出来的 z 值。

测试数据:任意给定 (x,y)

使用训练数据来训练神经网络, 然后使用训练得到的神经网络来预测预估的 z 值, 比较跟函数计算得到的期望值的差异。 从而验证神经网络是否能够准确地逼近这个函数 z。

1.准备训练集

首先构造随机的 输入值, 以及 期望的输出值,构造 80000 组数据。

import numpy as np
import matplotlib.pyplot as plt

## 函数 z = x*x + 2*y, 生成 80000 个样本, x是从 0-100 之间均匀分布的8000个数字,y是<1000的80000个数字 ;
total = 80000
x = np.linspace(0, 100, total)
y = np.random.randint(1000,size=total)
z = x**2 + 2*y

然后, 使用80000 组数据的 (x,y) , (z) 构造神经网络的输入, 输出

import numpy as np
import matplotlib.pyplot as plt

input = np.zeros([total,2])
print(input.shape)

output = np.zeros(total)

for i in range(total):
    input[i] = (x[i], y[i])
    output[i] = z[i]

print(input.shape)
print(output.shape)

2.训练神经网络

接着,以这个函数的 80000 个点作为训练机,训练神经网络

import tensorflow as tf
(x_train, y_train) = (input,output)

model = tf.keras.models.Sequential([
  tf.keras.Input(shape=(2,)),
  tf.keras.layers.Dense(24, activation='relu'),
  tf.keras.layers.Dense(12, activation='relu'),
  tf.keras.layers.Dense(1)
])

model.compile(optimizer=tf.keras.optimizers.RMSprop(0.02),
              loss='mean_squared_error', metrics=['mae','mse'])

#训练模型
history = model.fit(x_train, y_train, epochs=15)

到这里, 实际上对于其他的需要预测的问题,也可以使用上面的步骤来构造训练集的数据。

注意, 这里使用了 MSE 均方差作为损失函数,激活函数使用的 Relu。对于回归问题,通常使用 Relu 作为激活函数,使用 MSE 作为损失函数; 对于分类问题,通常使用 Softmax 作为激活函数, 使用 交叉墒作为损失函数。 不同的场景选择不同的函数,会有更好的效果。

下面是训练过程的输出,可以看到损失函数值越来越小。

Metal device set to: Apple M1

Epoch 1/15
2500/2500 [==============================] - 10s 4ms/step - loss: 905062.1250 - mae: 697.3808 - mse: 905062.1250
Epoch 2/15
2500/2500 [==============================] - 10s 4ms/step - loss: 411992.3750 - mae: 451.8226 - mse: 411992.3750
Epoch 3/15
2500/2500 [==============================] - 10s 4ms/step - loss: 320328.5625 - mae: 392.1287 - mse: 320328.5625
Epoch 4/15
2500/2500 [==============================] - 10s 4ms/step - loss: 262819.8438 - mae: 349.4919 - mse: 262819.8438
Epoch 5/15
2500/2500 [==============================] - 10s 4ms/step - loss: 217462.3281 - mae: 308.5135 - mse: 217462.3281
Epoch 6/15
2500/2500 [==============================] - 10s 4ms/step - loss: 181991.8594 - mae: 271.8238 - mse: 181991.8594
Epoch 7/15
2500/2500 [==============================] - 10s 4ms/step - loss: 157704.9062 - mae: 253.4466 - mse: 157704.9062
Epoch 8/15
2500/2500 [==============================] - 10s 4ms/step - loss: 141173.7344 - mae: 240.9149 - mse: 141173.7344
Epoch 9/15
2500/2500 [==============================] - 10s 4ms/step - loss: 129727.2656 - mae: 232.2946 - mse: 129727.2656
Epoch 10/15
2500/2500 [==============================] - 10s 4ms/step - loss: 124203.8594 - mae: 227.3699 - mse: 124203.8594
Epoch 11/15
2500/2500 [==============================] - 10s 4ms/step - loss: 120373.8438 - mae: 225.3336 - mse: 120373.8438
Epoch 12/15
2500/2500 [==============================] - 10s 4ms/step - loss: 118525.2812 - mae: 226.8641 - mse: 118525.2812
Epoch 13/15
2500/2500 [==============================] - 10s 4ms/step - loss: 114596.7188 - mae: 225.6951 - mse: 114596.7188
Epoch 14/15
2500/2500 [==============================] - 10s 4ms/step - loss: 112954.1172 - mae: 221.1882 - mse: 112954.1172
Epoch 15/15
2500/2500 [==============================] - 10s 4ms/step - loss: 109493.3672 - mae: 221.7279 - mse: 109493.3672

3.使用构建的神经网络预测未知的输入点

这个神经网络模型逼近的函数:  z = x^2 + y*2

我们使用 (45, 100), (10,20), (30,50), (60,80) 这4组 (x,y ) 来作为输入点,

使用神经网络进行预测, 看一下预测值跟实际值的差距:

model.predict([[45,100],[10,20],[30,50],[60,80]])

输出

array([[2271.7625],
       [ 336.1219],
       [1132.2782],
       [3892.6077]], dtype=float32)

实际函数的准确值:

z1 = [[45*45 + 2*100],[10*10 + 2*20],[30*30 + 2*50],[60*60 + 2*80]]

z1
函数对于这 4组输入的准确的输出是:
[[2225], [140], [1000], [3760]]

使用前面的神经网络, 预测值 除了第二组(预测值:336.1219,  期望值:140)相差比较大, 其他的差别都比较小。 

下面,调整一下 网络层级, 以及优化函数,再做一次实验

4.优化神经网络

增加1层神经网络,使用 3个 relu 函数,同时改用 nadam 作为优化函数改进神经网络

import tensorflow as tf
(x_train, y_train) = (input,output)

model = tf.keras.models.Sequential([
  tf.keras.layers.Dense(40, input_dim=2, activation='relu'),
  tf.keras.layers.Dense(24, activation='relu'),
  tf.keras.layers.Dense(12, activation='relu'),
  tf.keras.layers.Dense(1)
])

model.compile(optimizer=tf.keras.optimizers.Nadam(learning_rate=0.02),
              loss='mean_squared_error', metrics=['mae','mse'])

#训练模型
history = model.fit(x_train, y_train, epochs=15, batch_size=50)

model.predict([[45,100],[10,20],[30,50],[60,80]])

可以看到损失和均方差误差小了很多

Epoch 1/15
   8/1600 [..............................] - ETA: 12s - loss: 25706038.0000 - mae: 4003.6877 - mse: 25706038.0000 
2021-11-07 18:23:34.976596: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:112] Plugin optimizer for device_type GPU is enabled.
1600/1600 [==============================] - 13s 8ms/step - loss: 969170.8125 - mae: 680.8398 - mse: 969170.8125
Epoch 2/15
1600/1600 [==============================] - 13s 8ms/step - loss: 296651.6250 - mae: 361.7083 - mse: 296651.6250
Epoch 3/15
1600/1600 [==============================] - 13s 8ms/step - loss: 169997.9688 - mae: 255.5428 - mse: 169997.9688
Epoch 4/15
1600/1600 [==============================] - 12s 8ms/step - loss: 125974.0703 - mae: 217.3686 - mse: 125974.0703
Epoch 5/15
1600/1600 [==============================] - 13s 8ms/step - loss: 74774.6953 - mae: 165.8670 - mse: 74774.6953
Epoch 6/15
1600/1600 [==============================] - 13s 8ms/step - loss: 59363.4922 - mae: 144.4705 - mse: 59363.4922
Epoch 7/15
1600/1600 [==============================] - 13s 8ms/step - loss: 42491.9805 - mae: 123.6978 - mse: 42491.9805
Epoch 8/15
1600/1600 [==============================] - 12s 8ms/step - loss: 39725.0352 - mae: 115.9161 - mse: 39725.0352
Epoch 9/15
1600/1600 [==============================] - 12s 8ms/step - loss: 31136.7441 - mae: 103.5909 - mse: 31136.7441
Epoch 10/15
1600/1600 [==============================] - 12s 8ms/step - loss: 25983.8066 - mae: 94.0297 - mse: 25983.8066
Epoch 11/15
1600/1600 [==============================] - 13s 8ms/step - loss: 24997.7109 - mae: 87.9649 - mse: 24997.7109
Epoch 12/15
1600/1600 [==============================] - 13s 8ms/step - loss: 18597.2383 - mae: 79.3321 - mse: 18597.2383
Epoch 13/15
1600/1600 [==============================] - 13s 8ms/step - loss: 18474.7168 - mae: 75.2394 - mse: 18474.7168
Epoch 14/15
1600/1600 [==============================] - 12s 8ms/step - loss: 14886.6836 - mae: 68.3936 - mse: 14886.6836
Epoch 15/15
1600/1600 [==============================] - 13s 8ms/step - loss: 16632.0352 - mae: 73.1809 - mse: 16632.0352

再使用新的模型对同样的4组数据进行预测:

model.predict([[45,100],[10,20],[30,50],[60,80]])

z1 = [[45*45 + 2*100],[10*10 + 2*20],[30*30 + 2*50],[60*60 + 2*80]]
print(z1)

得到预测的结果, 以及期望的结果:

array([[2239.2454 ],
       [ 185.3527 ],
       [ 997.70325],
       [3800.0837 ]], dtype=float32)
[[2225], [140], [1000], [3760]]

这个模型的误差,相比前面的模型小了很多。

再做3组输入数据, 对期望的结果进行预测:

p = model.predict([[200,2000],[300,4000],[50,300]])
print(p)

输出的预测值:

[[30548.871 ]
 [47872.543 ]
 [ 3054.8225]]

同样, 计算出期望的值:

z2= [200*200 + 2000*2, 300*300 + 4000*2, 50*50 + 300*2]
print(z2)
[44000, 98000, 3100]

看得出, 这里对于前面两组 (200, 2000), (300, 4000) 的预测值, 跟期望值的差距很大。

而第三组, (50,300) 的预测值, 3050.8225 跟期望值 3100 的差距就很小了。

是什么使得对于不同输入预测值的准确度差异这么大? 回顾一下 前面初始化训练集的代码

x = np.linspace(0, 100, total)
y = np.random.randint(1000,size=total)
z = x**2 + 2*y

能够看出, 训练集合的 x 的范围是 (0,100) , y 的范围是 (0,1000) 的整数。

从前面的几组测试数据, 能够看出, 对于训练集数据范围内的未知点的预测, 预测值的准确度可以很高, 而对于训练集数据范围外的数据的预测, 准确度差的很多。

所以可以得出来的结论,神经网络可以用来模拟连续函数,较高准确度的前提是预测的数据点在训练集的数据范围之内。 神经网络对于没有见过的数据,识别度比较差,实际上也是神经网络在实际的应用中遇到的一个很大的挑战。 需要足够多的输入数据,在一定的条件下能够工作得很好,出了一定的限定条件, 结果可能不堪设想。

前面实验的 Jupyter Notebook 代码可以参考:

https://github.com/davideuler/beauty-of-math-in-deep-learning/blob/main/function_approximation.ipynb

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值