【d2l】4.1-2.多层感知机及实现

【d2l】4.1-2.多层感知机及实现

多层感知机

隐藏层

此前已经对仿射变换进行了深入的研究,但是仿射变换对应的是线性关系,而线性关系是一种很强的假设

在这样的情况下,线性模型可能会不适用

假设一个猫狗分类的场景,我们需要决定某一个像素对于结果的权重,但是这个像素的强度对于判断为猫/狗的似然很难是一个简单的线性(单调)关系。而且就算是单调的,同样的图片反色之后势必会产生相反的结果

因此可以发现如果网络只有仿射变换的化,模型的泛化能力会受到限制,这时候就出现了隐藏层

我们可以通过在输入层和输出层中间加入一个或多个层级,把最后一层视作线性映射,这样或许能够突破线性的限制。这种架构通常称为"多重感知机(multilayer perceptron, MLP)"

多层感知机的基础上,假设隐藏层中做了\(\mathbf{H^{(k-1)}W^{(k)} + b}\),这个时候加入一个非线性函数\(\sigma\)使得\(\mathbf{H^{(k)}} = \sigma(\mathbf{H^{(k-1)}W^{(k)} + b})\)

就这样通过网络的堆叠,能够让模型的表达力变得更强

激活函数

下面是一些常用的非线性函数\(\sigma(\cdot)\)

ReLU函数

\[\text{ReLU}(x) = \max(x, 0) \]

这个函数是修正线性单元(recitified linear unit, ReLU),它实现起来简单,并且在各种预测任务中表现良好

这个函数在0处不可导,因此在工程中一般使用0处导数为0,视作忽略了输入为0的情况

在ReLU基础上还有参数化ReLU(paarameterized ReLU, pReLU),加上了一个线性的项,可以让某些负数信息被激活

\[\text{pReLU}(x) = \max(0, x) + \alpha \min(0, x) \]

sigmoid函数

\[\text{sigmoid}(x) = \frac{1}{1 + \exp (-x)} \]

这个函数的数值特点是可以将\((-\infty,+\infty)\)的数据压缩到\((0, 1)\),并且是平滑可微的

\[\frac{\text d}{\text dx} \text{sigmoid} (x) = \text{sigmoid} (x) [1 - \text{sigmoid}(x)] \]

tanh函数

\[\tanh (x) = \frac{1 - \exp(-2x)}{1 + \exp{-2x}} \]

导数如下

\[\frac{\text d}{\text dx}\tanh(x) = 1 - \tanh^2(x) \]

多层感知机从零开始实现

初始化模型参数

网络单元分配如下

28×28 --> 256 --> 10

接着对于这个三层结构,有两组\((\mathbf{W, b})\)

num_inputs, num_outputs, num_hiddens = 784, 10, 256

W1 = nn.Parameter(torch.randn(
    num_inputs, num_hiddens, requires_grad = True
) * 0.01)
b1 = nn.Parameter(torch.zeros(num_hiddens, requires_grad = True))
W2 = nn.Parameter(torch.randn(
    num_hiddens, num_outputs, requires_grad = True
) * 0.01)
b2 = nn.Parameter(torch.zeros(num_outputs, requires_grad = True))

params = [W1, b1, W2, b2]

基本函数

激活函数选取ReLU

def relu(X):
    a = torch.zeros_like(X)
    return torch.max(X, a)

每个单元都被压平成了向量,因此模型的计算不难写

def net(X):
    X = X.reshape(-1, num_inputs)
    H = relu(X @ W1 + b1) # @为矩阵乘法
    return (H @ W2 + b2)

损失函数依旧采用softmax和交叉熵损失

loss = nn.CrossEntropyLoss(reduction = 'none')

训练

此前已经写过了训练的代码,结果也与之前相似,就不附图片了

num_epochs, lr = 10, 0.1
updater = torch.optim.SGD(params, lr = lr)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, updater)
d2l.predict_ch3(net, test_iter)

多层感知机的简洁实现

MLP已经完全可以通过torch内置的函数实现

net = nn.Sequential(
    nn.Flatten(),
    nn.Linear(784, 256),
    nn.ReLU(),
    nn.Linear(256, 10)
)

def init_weights(m):
    if type(m) == nn.Linear:
        nn.init.normal_(m.weight, std = 0.01)

net.apply(init_weights)

batch_size, lr, num_epochs = 256, 0.1, 10
loss = nn.CrossEntropyLoss(reduction = 'none')
trainer = torch.optim.SGD(net.parameters(), lr = lr)

train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
posted @ 2026-02-07 15:36  R4y  阅读(10)  评论(0)    收藏  举报