【笔记】动手学深度学习v2(全73讲)李沐

  1. 00预告
  2. 01课程安排
    1. 目标
    2. 内容
    3. 你将学到什么
    4. 资源
  • 02深度学习介绍
  • 03安装
  • 05线性代数
    1. 代码
  • 06矩阵计算
  • 07 自动求导
  • 08线性回归 + 基础优化算法
    1. 一个简化模型
    2. 线性模型
    3. 线性模型可以看做是单层神经网络
    4. 神经网络源于神经科学
    5. 衡量预估质量
    6. 训练数据
    7. 参数学习
    8. 显示解
    9. 总结
    10. 梯度下降
    11. 选择学习率
    12. 小批量随机梯度下降
    13. 选择批量大小
    14. 总结
    15. 线性回归的从零开始实现
  • 09 Softmax 回归 + 损失函数 + 图片分类数据集
    1. 回归 vs 分类
    2. Kaggle上的分类问题
    3. 从回归到多类分类
    4. 从回归到多类分类——均方损失
    5. Softmax和交叉熵损失
    6. 总结
    7. 损失函数
    8. softmax回归的从零开始实现
  • 10多层感知机
    1. 感知机
      1. 训练感知机
      2. 收敛定理
      3. XOR问题(Minsky & Papert,1969)
      4. 总结
    2. 多层感知机
      1. 学习XOR
      2. 单隐藏层
      3. 单隐藏层——单分类
      4. Sigmoid激活函数
      5. Tanh激活函数
      6. ReLU激活函数
      7. 多类分类
      8. 多隐藏层
      9. 总结
    3. 代码
  • 11模型选择 + 过拟合和欠拟合
    1. 训练误差和泛化误差
      1. 验证数据集和测试数据集
      2. K-则交叉验证
    2. 过拟合和欠拟合
      1. 模型容量
      2. 模型容量的影响
      3. 估计模型容量
      4. VC维
      5. 线性分类器的VC维
      6. VC维的用处
      7. 数据复杂度
      8. 总结
    3. 代码
  • 12权重衰退
    1. 使用均方范数作为硬性限制
    2. 使用均方范数作为柔性限制
    3. 演示对最优解的影响
    4. 参数更新法则
    5. 总结
    6. 代码
  • 13丢弃法
    1. 动机
    2. 无偏差的加入噪音
    3. 使用丢弃法
    4. 推理中的丢弃法
    5. 总结
    6. 代码
  • 14数值稳定性 + 模型初始化和激活函数
  • 19卷积层
    1. 两个原则
    2. 重新考察全连接层
    3. 原则1—平移不变性
    4. 原则2—局部性5
    5. 卷积层
    6. 二维交叉相关
    7. 二维卷积层
    8. 交叉相关vs卷积
    9. 一维和三维交叉相关
  • 68 Transformer
    1. Transformer架构
    2. 多头注意力
  • 00预告

    学习深度学习关键是动手

    01课程安排

    目标

    • 介绍深度学习经典和最新模型
      • LeNet, ResNet, LSTM, BERT, …
    • 机器学习
      • 损失函数、目标函数、 过拟合、 优化
    • 实践
      • 使用Pytorch实现介绍的知识点
      • 在真实数据上体验算法效果

    内容

    • 深度学习基础——线性神经网络,多层感知机
    • 卷积神经网络——LeNet, AlexNet, VGG, Inception, ResNet
    • 循环神经网络——RNN, GRU, LSTM, seq2seq
    • 注意力机制——Attention, Transformer
    • 优化算法——SGD, Momentum, Adam
    • 高性能计算——并行,多GPU,分布式
    • 计算机视觉——目标检测,语义分割
    • 自然语言处理——词嵌入,BERT

    你将学到什么

    • What
      • 深度学习里有那些技术
    • How
      • 如何实现和调参
    • Why
      • 背后的原因(直觉、数学)

    资源

    02深度学习介绍

    03安装

    pip install d2l -i http://pypi.douban.com/simple –trusted-host pypi.douban.com –user

    05线性代数

    代码

    标量由只有一个元素的张量表示

    1
    2
    3
    4
    5
    6
    import torch

    x = torch.tensor([3.0])
    y = torch.tensor([2.0])

    x + y, x * y, x / y, x**y

    你可以将向量视为标量值组成的列表

    1
    2
    x = torch.arange(4)
    x

    通过张量的索引来访问任一元素

    1
    x[3]

    06矩阵计算

    07 自动求导

    08线性回归 + 基础优化算法

    线性回归

    一个简化模型

    ![](https://cdn.jsdelivr.net/gh/YangQingHui66/CDN/blog-img/limu/8-1 .png)

    线性模型

    线性模型可以看做是单层神经网络

    神经网络源于神经科学

    衡量预估质量

    训练数据

    参数学习

    显示解

    总结


    基础优化方法

    梯度下降

    选择学习率

    小批量随机梯度下降

    选择批量大小

    总结

    线性回归的从零开始实现

    我们将从零开始实现整个方法,包括数据流水线、模型、损失函数和小批量随机梯度下降优化器

    1
    2
    3
    4
    5
    6
    7
    %matplotlib inline
    import math
    import time
    import numpy as np
    import torch

    from d2l import torch as d2l

    09 Softmax 回归 + 损失函数 + 图片分类数据集


    Softmax 回归是机器学习中非常经典、重要的模型,虽然它名字里带着回归,但它其实是个分类问题

    回归 vs 分类

    • 回归估计一个连续值
    • 分类预测一个离散类别
      MNIST:手写数字识别(10类)

      ImgeNet:自然物体分类(1000类)

    Kaggle上的分类问题



    从回归到多类分类

    回归

    • 单连续数值输出
    • 自然区间R
    • 跟真实值的区别作为损失

      分类
    • 通常多个输出
    • 输出i是预测为第i类的置信度

    从回归到多类分类——均方损失



    Softmax和交叉熵损失

    总结

    • Softmax回归是一个多类分类模型
    • 使用Softmax操作得到每个类的预测置信度
    • 使用交叉熵来衡量预测和标号的区别

    损失函数

    用来衡量预测值和真实值之间的区别

    1. 均方损失函数

      蓝色的线——当y=0时,变换预测值后y’的函数
      绿色的线——似然函数
      橙色的线——损失函数的梯度

    2. 绝对值损失函数

    softmax回归的从零开始实现

    就像我们从零开始实现线性回归一样, 你应该知道实现softmax的细节

    1
    2
    3
    4
    5
    6
    7
    import torch
    from IPython import display
    from d2l import torch as d2l

    batch_size = 256 #每次随机读取256张图片
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
    #返回训练集和测试集的迭代器

    将展平每个图像,把它们看作长度为784的向量。 因为我们的数据集有10个类别,所以网络输出维度为 10

    1
    2
    3
    4
    5
    6
    7
    8
    #图片的长和宽都为28,28*28=784
    #对于softmax函数而言,输入必须是一个向量,需要把整个图片拉长,拉成一个向量
    num_inputs = 784
    num_outputs = 10

    #定义权重w,初始成一个高斯随机分布的值,均值为0,方差为0.01,形状是行数等于输入的个数、列数等于输出的个数,计算梯度requires_grad=True
    W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)
    b = torch.zeros(num_outputs, requires_grad=True) #对于每一个输出都需要一个偏移

    给定一个矩阵X,我们可以对所有元素求和

    1
    2
    3
    4
    #定义一个2*3的矩阵
    X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
    #如果按照维度=0来求和的话
    X.sum(0, keepdim=True), X.sum(1, keepdim=True)

    实现softmax

    1
    2
    3
    4
    def softmax(X):
    X_exp = torch.exp(X) #对每个元素做指数计算
    partition = X_exp.sum(1, keepdim=True) #按照维度为1来求和
    return X_exp / partition #广播机制:X_exp的每一行除以partition对应行的那个数

    我们将每个元素变成一个非负数。此外,依据概率原理,每行总和为1

    1
    2
    3
    X = torch.normal(0, 1, (2, 5)) #创建一个随机的均值为0,方差为1的两行五列的矩阵X
    X_prob = softmax(X) #将X放入softmax函数
    X_prob, X_prob.sum(1)

    实现softmax回归模型

    1
    2
    def net(X):
    return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)

    创建一个数据y_hat,其中包含2个样本在3个类别的预测概率, 使用y作为y_hat中概率的索引

    1
    2
    3
    y = torch.tensor([0, 2])
    y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]])
    y_hat[[0, 1], y]

    10多层感知机

    感知机

    • 给定输入x,权重w,和偏移b,感知机输出:
      (其中x,w为向量,b为标量)

      输入w和权重x做内积,加上偏移b

    • 二分类:-1或1

      • VS 回归输出实数
      • VS Softmax回归输出概率

    训练感知机


    预测和真实值如果准确就是同号,预测错误就是异号
    等价于使用批量大小为1的梯度下降,并使用如下的损失函数:

    收敛定理

    XOR问题(Minsky & Papert,1969)

    感知机不能拟合XOR函数,它智能产生线性分割面

    总结

    • 感知机是一个二分类模型,是最早的AI模型之一
    • 它的求解算法等价于使用批量大小为1的梯度下降
    • 它不能拟合XOR函数,导致的第一次AI寒冬

    多层感知机

    学习XOR

    单隐藏层

    单隐藏层——单分类

    Sigmoid激活函数


    Tanh激活函数


    ReLU激活函数


    多类分类


    多隐藏层


    总结

    • 多层感知机使用隐藏层和激活函数来得到非线性模型
    • 常用激活函数是Sigmoid,Tanh,ReLU
    • 使用Softmax来处理多类分类
    • 超参数为隐藏层数,和各个隐藏层大小

    代码

    多层感知机的从零开始实现

    1
    2
    3
    4
    5
    6
    import torch
    from torch import nn
    from d2l import torch as d2l

    batch_size = 256
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)

    实现一个具有单隐藏层的多层感知机,它包含256个隐藏单元

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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激活函数

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

    实现我们的模型

    1
    2
    3
    4
    5
    6
    def net(X):
    X = X.reshape((-1, num_inputs))
    H = relu(X @ W1 + b1)
    return (H @ W2 + b2)

    loss = nn.CrossEntropyLoss()

    多层感知机的训练过程与softmax回归的训练过程完全相同

    1
    2
    3
    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)

    在一些测试数据上应用这个模型

    1
    d2l.predict_ch3(net, test_iter)

    11模型选择 + 过拟合和欠拟合

    训练误差和泛化误差

    • 训练误差:模型在训练数据上的误差
    • 泛化误差:模型在新数据上的误差
    • 例子:根据摸考成绩来预测未来考试分数
      • 在过去的考试中表现很好(训练误差)不代表未来考试一定会好(泛化误差)
      • 学生A通过背书在摸考中拿到很好成绩
      • 学生B知道答案后面的原因

    验证数据集和测试数据集

    • 验证数据集:一个用来评估模型好坏的数据集
      • 例如拿出50%的训练数据
      • 不要跟训练数据混在一起(常犯错误)
    • 测试数据集:只用一次的数据集。例如
      • 未来的考试
      • 我出价的房子的实际成交价
      • 用在Kaggle私有排行榜中的数据集

    K-则交叉验证

    • 在没有足够多数据时使用((这是常态)
    • 算法:
      • 将训练数据分割成K块-
      • For i= 1,…,K
        • 使用第i块作为验证数据集,其余的作为训练数据集
      • 报告K个验证集误差的平均
    • 常用:K=5或10

    过拟合和欠拟合


    模型容量

    • 拟合各种函数的能力
    • 低容量的模型难以拟合训练数据
    • 高容量的模型可以记住所有的训练数据

    模型容量的影响

    估计模型容量

    • 难以在不同的种类算法之间比较
      • 例如树模型和神经网络
    • 给定一个模型种类,将有两个主要因素
      • 参数的个数
      • 参数值的选择范围

    VC维

    • 统计学习理论的一个核心思想
    • 对于一个分类模型,VC等于一个最大的数据集的大小,不管如何给定标号,都存在一个模型来对它进行完美分类

    线性分类器的VC维

    • 2维输入的感知机,VC维=3
      • 能够分类任何三个点,但不是4个(xor)

    • 支持N维输入的感知机的VC维是N+1
    • —些多层感知机的VC维O(N $log_2$ N)

    VC维的用处

    • 提供为什么一个模型好的理论依据
      • 它可以衡量训练误差和泛化误差之间的间隔
    • 但深度学习中很少使用
      • 衡量不是很准确
      • 计算深度学习模型的VC维很困难

    数据复杂度

    • 多个重要因素
      • 样本个数
      • 个样本的元素个数
      • 时间、空间结构多样性

    总结

    • 模型容量需要匹配数据复杂度,否则可能导致欠拟合和过拟合
    • 统计机器学习提供数学工具来衡量模型复杂度
    • 实际中一般靠观察训练误差和验证误差

    代码

    模型选择、欠拟合和过拟合
    通过多项式拟合来交互地探索这些概念

    1
    2
    3
    4
    5
    import math
    import numpy as np
    import torch
    from torch import nn
    from d2l import torch as d2l

    使用以下三阶多项式来生成训练和测试数据的标签:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    max_degree = 20
    n_train, n_test = 100, 100
    true_w = np.zeros(max_degree)
    true_w[0:4] = np.array([5, 1.2, -3.4, 5.6])

    features = np.random.normal(size=(n_train + n_test, 1))
    np.random.shuffle(features)
    poly_features = np.power(features, np.arange(max_degree).reshape(1, -1))
    for i in range(max_degree):
    poly_features[:, i] /= math.gamma(i + 1)
    labels = np.dot(poly_features, true_w)
    labels += np.random.normal(scale=0.1, size=labels.shape)

    看一下前2个样本

    1
    2
    3
    4
    5
    true_w, features, poly_features, labels = [
    torch.tensor(x, dtype=torch.float32)
    for x in [true_w, features, poly_features, labels]]

    features[:2], poly_features[:2, :], labels[:2]

    实现一个函数来评估模型在给定数据集上的损失

    1
    2
    3
    4
    5
    6
    7
    8
    9
    def evaluate_loss(net, data_iter, loss):  
    """评估给定数据集上模型的损失。"""
    metric = d2l.Accumulator(2)
    for X, y in data_iter:
    out = net(X)
    y = y.reshape(out.shape)
    l = loss(out, y)
    metric.add(l.sum(), l.numel())
    return metric[0] / metric[1]

    定义训练函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    def train(train_features, test_features, train_labels, test_labels,
    num_epochs=400):
    loss = nn.MSELoss()
    input_shape = train_features.shape[-1]
    net = nn.Sequential(nn.Linear(input_shape, 1, bias=False))
    batch_size = min(10, train_labels.shape[0])
    train_iter = d2l.load_array((train_features, train_labels.reshape(-1, 1)),
    batch_size)
    test_iter = d2l.load_array((test_features, test_labels.reshape(-1, 1)),
    batch_size, is_train=False)
    trainer = torch.optim.SGD(net.parameters(), lr=0.01)
    animator = d2l.Animator(xlabel='epoch', ylabel='loss', yscale='log',
    xlim=[1, num_epochs], ylim=[1e-3, 1e2],
    legend=['train', 'test'])
    for epoch in range(num_epochs):
    d2l.train_epoch_ch3(net, train_iter, loss, trainer)
    if epoch == 0 or (epoch + 1) % 20 == 0:
    animator.add(epoch + 1, (evaluate_loss(
    net, train_iter, loss), evaluate_loss(net, test_iter, loss)))
    print('weight:', net[0].weight.data.numpy())

    三阶多项式函数拟合(正态)

    1
    2
    train(poly_features[:n_train, :4], poly_features[n_train:, :4],
    labels[:n_train], labels[n_train:])


    线性函数拟合(欠拟合)

    1
    2
    train(poly_features[:n_train, :2], poly_features[n_train:, :2],
    labels[:n_train], labels[n_train:])


    高阶多项式函数拟合(过拟合)

    1
    2
    train(poly_features[:n_train, :], poly_features[n_train:, :],
    labels[:n_train], labels[n_train:], num_epochs=1500)

    12权重衰退

    使用均方范数作为硬性限制

    使用均方范数作为柔性限制

    演示对最优解的影响

    参数更新法则

    总结

    • 权重衰退通过L2正则项使得模型参数不会过大,从而控制模型复杂度
    • 正则项权重是控制模型复杂度的超参数

    代码

    权重衰减是最广泛使用的正则化的技术之一

    1
    2
    3
    4
    %matplotlib inline
    import torch
    from torch import nn
    from d2l import torch as d2l

    像以前一样生成一些数据

    1
    2
    3
    4
    5
    6
    n_train, n_test, num_inputs, batch_size = 20, 100, 200, 5
    true_w, true_b = torch.ones((num_inputs, 1)) * 0.01, 0.05
    train_data = d2l.synthetic_data(true_w, true_b, n_train)
    train_iter = d2l.load_array(train_data, batch_size)
    test_data = d2l.synthetic_data(true_w, true_b, n_test)
    test_iter = d2l.load_array(test_data, batch_size, is_train=False)

    初始化模型参数

    1
    2
    3
    4
    def init_params():
    w = torch.normal(0, 1, size=(num_inputs, 1), requires_grad=True)
    b = torch.zeros(1, requires_grad=True)
    return [w, b]

    定义L2范数惩罚

    1
    2
    def l2_penalty(w):
    return torch.sum(w.pow(2)) / 2

    定义训练代码实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def train(lambd):
    w, b = init_params()
    net, loss = lambda X: d2l.linreg(X, w, b), d2l.squared_loss
    num_epochs, lr = 100, 0.003
    animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
    xlim=[5, num_epochs], legend=['train', 'test'])
    for epoch in range(num_epochs):
    for X, y in train_iter:
    with torch.enable_grad():
    l = loss(net(X), y) + lambd * l2_penalty(w)
    l.sum().backward()
    d2l.sgd([w, b], lr, batch_size)
    if (epoch + 1) % 5 == 0:
    animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
    d2l.evaluate_loss(net, test_iter, loss)))
    print('w的L2范数是:', torch.norm(w).item())

    忽略正则化直接训练

    1
    train(lambd=0)


    使用权重衰减

    1
    train(lambd=3)


    简洁实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    def train_concise(wd):
    net = nn.Sequential(nn.Linear(num_inputs, 1))
    for param in net.parameters():
    param.data.normal_()
    loss = nn.MSELoss()
    num_epochs, lr = 100, 0.003
    trainer = torch.optim.SGD([{
    "params": net[0].weight,
    'weight_decay': wd}, {
    "params": net[0].bias}], lr=lr)
    animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log',
    xlim=[5, num_epochs], legend=['train', 'test'])
    for epoch in range(num_epochs):
    for X, y in train_iter:
    with torch.enable_grad():
    trainer.zero_grad()
    l = loss(net(X), y)
    l.backward()
    trainer.step()
    if (epoch + 1) % 5 == 0:
    animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss),
    d2l.evaluate_loss(net, test_iter, loss)))
    print('w的L2范数:', net[0].weight.norm().item())

    这些图看起来和我们从零开始实现权重衰减时的图相同

    1
    train_concise(0)

    1
    train_concise(3)

    13丢弃法

    动机

    • 一个好的模型需要对输入数据的扰动鲁棒
      • 使用有噪音的数据等价于Tikhonov正则
      • 丢弃法:在层之间加入噪音

    无偏差的加入噪音

    使用丢弃法

    通常将丢弃法作用在隐藏全连接层的输出上

    推理中的丢弃法

    • 正则项只在训练中使用:他们影响模型参数的更新
    • 在推理过程中,丢弃法直接返回输入h = dropout(h)
      • 这样也能保证确定性的输出

    总结

    • 丢弃法将一些输出项随机置0来控制模型复杂度
    • 常作用在多层感知机的隐藏层输出上
    • 丢弃概率是控制模型复杂度的超参数

    代码

    我们实现dropout_layer函数,该函数以dropout的概率丢弃张量输入X中的元素

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import torch
    from torch import nn
    from d2l import torch as d2l

    def dropout_layer(X, dropout):
    assert 0 <= dropout <= 1
    if dropout == 1:
    return torch.zeros_like(X)
    if dropout == 0:
    return X
    mask = (torch.Tensor(X.shape).uniform_(0, 1) > dropout).float()
    return mask * X / (1.0 - dropout)

    测试dropout_layer函数

    1
    2
    3
    4
    5
    X = torch.arange(16, dtype=torch.float32).reshape((2, 8))
    print(X)
    print(dropout_layer(X, 0.))
    print(dropout_layer(X, 0.5))
    print(dropout_layer(X, 1.))


    定义具有两个隐藏层的多层感知机,每个隐藏层包含256个单元

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    num_inputs, num_outputs, num_hiddens1, num_hiddens2 = 784, 10, 256, 256

    dropout1, dropout2 = 0.2, 0.5

    class Net(nn.Module):
    def __init__(self, num_inputs, num_outputs, num_hiddens1, num_hiddens2,
    is_training=True):
    super(Net, self).__init__()
    self.num_inputs = num_inputs
    self.training = is_training
    self.lin1 = nn.Linear(num_inputs, num_hiddens1)
    self.lin2 = nn.Linear(num_hiddens1, num_hiddens2)
    self.lin3 = nn.Linear(num_hiddens2, num_outputs)
    self.relu = nn.ReLU()

    def forward(self, X):
    H1 = self.relu(self.lin1(X.reshape((-1, self.num_inputs))))
    if self.training == True:
    H1 = dropout_layer(H1, dropout1)
    H2 = self.relu(self.lin2(H1))
    if self.training == True:
    H2 = dropout_layer(H2, dropout2)
    out = self.lin3(H2)
    return out

    net = Net(num_inputs, num_outputs, num_hiddens1, num_hiddens2)

    训练和测试

    1
    2
    3
    4
    5
    num_epochs, lr, batch_size = 10, 0.5, 256
    loss = nn.CrossEntropyLoss()
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
    trainer = torch.optim.SGD(net.parameters(), lr=lr)
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)


    简洁实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    net = nn.Sequential(nn.Flatten(), nn.Linear(784, 256), nn.ReLU(),
    nn.Dropout(dropout1), nn.Linear(256, 256), nn.ReLU(),
    nn.Dropout(dropout2), 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);

    对模型进行训练和测试

    1
    2
    trainer = torch.optim.SGD(net.parameters(), lr=lr)
    d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)

    14数值稳定性 + 模型初始化和激活函数

    19卷积层

    分类猫和狗

    • 使用一个还不错的相机采集图片(12M像素)
    • RGB图片有36M元素
    • 使用100大小的单隐藏层MLP,模型有3.6B元素
      • 远多于世界上所有猫和狗总算(900M狗,600M猫)


    回顾:单隐藏层MLP

    两个原则

    • 平移不变性
    • 局部性

    重新考察全连接层

    原则1—平移不变性

    原则2—局部性5


    总结
    对全连接层使用平移不变性和局部性得到卷积层

    卷积层

    二维交叉相关

    二维卷积层


    例子

    交叉相关vs卷积

    一维和三维交叉相关


    总结

    • 卷积层将输入和核矩阵进行交叉相关,加上偏移后得到输出
    • 核矩阵和偏移是可学习的参数
    • 核矩阵的大小是超参数

    68 Transformer

    Transformer架构

    • 基于编码器-解码器架构来处理序列对
    • 跟使用注意力的seq2seq不同,Transformer是纯基于注意力



    多头注意力

    • 对同一Key,value,query,希望抽取不同的信息
      • 例如短距离关系和长距离关系
    • 多头注意力使用h个独立的注意力池化
      • 合并各个头(head)输出得到最终输出