本文主要介绍神经网络万能逼近理论 , 并且通过PyTorch展示了两个案例来说明神经网络的函数逼近功能 。
大多数人理解"函数"为高等代数中形如"f(x)=2x"的表达式 , 但是实际上 , 函数只是输入到输出的映射关系 , 其形式是多样的 。

文章插图
拿个人衣服尺寸预测来说 , 我们用机器学习来实现这个功能 , 就是将个人身高、体重、年龄作为输入 , 将衣服尺寸作为输出 , 实现输入-输出映射 。
具体来说 , 需要以下几个步骤:
· 收集关键数据(大量人口的身高/体重/年龄 , 已经对应的实际服装尺寸) 。
· 训练模型来实现输入-输出的映射逼近 。
· 对未知数据进行预测来验证模型 。
如果输出是输入特征的线性映射 , 那么模型的训练往往相对简单 , 只需要一个线性回归就可以实现;size = a*height + b*weight + c*age + d 。
但是 , 通常假设输出是输入特征的线性映射是不够合理和不完全准确的 。现实情况往往很复杂 , 存在一定的特例和例外 。常见的问题(字体识别、图像分类等)显然涉及到复杂的模式 , 需要从高维输入特征中学习映射关系 。
但是根据万能逼近理论 , 带有单隐藏的人工神经网络就能够逼近任意函数 , 因此可以被用于解决复杂问题 。
人工神经网络本文将只研究具有输入层、单个隐藏层和输出层的完全连接的神经网络 。在服装尺寸预测器的例子中 , 输入层将有三个神经元(身高、体重和年龄) , 而输出层只有一个(预测尺寸) 。在这两者之间 , 有一个隐藏层 , 上面有一些神经元(下图中有5个 , 但实际上可能更大一些 , 比如1024个) 。

文章插图
网络中的每个连接都有一些可调整的权重 。训练意味着找到好的权重 , 使给定输入集的预测大小与实际大小之间存在微小差异 。
每个神经元与下一层的每个神经元相连 。这些连接都有一定的权重 。每个神经元的值沿着每个连接传递 , 在那里它乘以权重 。然后所有的神经元都会向前反馈到输出层 , 然后输出一个结果 。训练模型需要为所有连接找到合适的权重 。万能逼近定理的核心主张是 , 在有足够多的隐藏神经元的情况下 , 存在着一组可以近似任何函数的连接权值 , 即使该函数不是像f(x)=x²那样可以简洁地写下来的函数 。即使是一个疯狂的 , 复杂的函数 , 比如把一个100x100像素的图像作为输入 , 输出"狗"或"猫"的函数也被这个定理所覆盖 。
非线性关系神经网络之所以能够逼近任意函数 , 关键在于将非线性关系函数整合到了网络中 。每层都可以设置激活函数实现非线性映射 , 换言之 , 人工神经网络不只是进行线性映射计算 。常见的非线性激活函数有 ReLU, Tanh, Sigmoid等 。

文章插图
ReLU是一个简单的分段线性函数-计算消耗小 。另外两个都涉及到指数运算 , 因此计算成本更高
为了展示人工神经网络的万能逼近的能力 , 接下来通过PyTorch实现两个案例 。
案例一:任意散点曲线拟合神经网络可能面临的最基本的情况之一就是学习两个变量之间的映射关系 。例如 , 假设x值表示时间 , y坐标表示某条街道上的交通量 。在一天中的不同时间点都会出现高峰和低谷 , 因此这不是一种线性关系 。
下面的代码首先生成符合正态分布的随机点 , 然后训练一个网络 , 该网络将x坐标作为输入 , y坐标作为输出 。有关每个步骤的详细信息 , 请参见代码注释:
import torchimport plotly.graph_objects as goimport numpy as np# Batch Size, Input Neurons, Hidden Neurons, Output NeuronsN, D_in, H, D_out = 16, 1, 1024, 1# Create random Tensors to hold inputs and outputsx = torch.randn(N, D_in)y = torch.randn(N, D_out)# Use the nn package to define our model# Linear (Input -> Hidden), ReLU (Non-linearity), Linear (Hidden-> Output)model = torch.nn.Sequential(torch.nn.Linear(D_in, H),torch.nn.ReLU(),torch.nn.Linear(H, D_out),)# Define the loss function: Mean Squared Error# The sum of the squares of the differences between prediction and ground truthloss_fn = torch.nn.MSELoss(reduction='sum')# The optimizer does a lot of the work of actually calculating gradients and# Applying backpropagation through the network to update weightslearning_rate = 1e-4optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)# Perform 30000 training stepsfor t in range(30000):# Forward pass: compute predicted y by passing x to the model.y_pred = model(x)# Compute loss and print it periodicallyloss = loss_fn(y_pred, y)if t % 100 == 0:print(t, loss.item())# Update the network weights using gradient of the lossoptimizer.zero_grad()loss.backward()optimizer.step()# Draw the original random points as a scatter plotfig = go.Figure()fig.add_trace(go.Scatter(x=x.flatten().numpy(), y=y.flatten().numpy(), mode="markers"))# Generate predictions for evenly spaced x-values between minx and maxxminx = min(list(x.numpy()))maxx = max(list(x.numpy()))c = torch.from_numpy(np.linspace(minx, maxx, num=640)).reshape(-1, 1).float()d = model(c)# Draw the predicted functions as a line graphfig.add_trace(go.Scatter(x=c.flatten().numpy(), y=d.flatten().detach().numpy(), mode="lines"))fig.show()
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 刹车|车主曝特斯拉“踩刹车”前进掉河!网友:车尾车贴已说明原因
- 外星人探索 人类为什么要寻找外星生命
- 为什么叫臭宝 臭宝是什么意思要怎么回答
- 鲨鱼不断游泳是因为 鲨鱼为什么要不停地游泳
- Mysql索引为什么使用B+树而不使用跳表?
- 黎族纹身的起因是什么 黎族为什么要纹身
- 河北蚩尤古墓 蚩尤墓为什么不挖
- 你听说了吗?福鼎白茶是糖尿病的克星![养生茶]
- 恒星为什么会坍塌成黑洞
- 怀孕后出汗多怎么回事
