(十九)多层网络与非线性
如果每一层都只做线性变换,连在一起仍可以合并成一次线性变换。写成两个步骤:,,展开后为 。增加这样的层数没有改变可表达的关系类型。
以异或为例,(0,0)、(1,1) 属于类别零,另外两个角属于类别一,不能用同一条直线把这两组角分开。可以先把输入转换成几个中间特征,每个特征再经过非线性函数,然后组合它们。
先手工构造两项:、,再输出 。输入和为零、一、二时,中间项分别是 (0,0)、(1,0)、(2,1),最后得到 0、1、0,正好区分四个角。这里的非线性就是把负数截为零。
接着让网络通过训练寻找一组可用中间特征:
# 项目文件:demos/xor_network.py
import torch
from torch import nn
torch.set_num_threads(1)
torch.manual_seed(7)
x = torch.tensor([[0.0, 0.0], [0.0, 1.0], [1.0, 0.0], [1.0, 1.0]])
y = torch.tensor([0, 1, 1, 0])
model = nn.Sequential(nn.Linear(2, 4), nn.Tanh(), nn.Linear(4, 2))
optimizer = torch.optim.Adam(model.parameters(), lr=0.05)
for _ in range(200):
# 中间层的非线性让四个角不必由同一条直线分开。
optimizer.zero_grad(set_to_none=True)
loss = nn.CrossEntropyLoss()(model(x), y)
loss.backward()
optimizer.step()
model.eval()
with torch.inference_mode():
print("四个输入的类别", model(x).argmax(1).tolist())nn.Linear(2,4) 产生四个中间特征,Tanh 将各项按双曲正切函数压到 -1 与 1 之间,再用 Linear(4,2) 输出两个类别分数。nn.Sequential 按登记次序调用各层,训练后四个输入预测为 [0,1,1,0]。
常用的 ReLU 是 ,负数变零,正数保留;Tanh 在两端逐渐变平。它们使中间变换不再能够简单合并成一层线性式。这个四点实验展示网络表达异或的过程,完整分类项目随后使用单独的验证和测试图。