动手学习深度学习笔记(李沐)
2026/9/15 7:23:22 网站建设 项目流程
模块日期学习内容
深度学习基础9.13深度学习介绍
安装
数据操作
数据预处理
9.14线性代数、[补充] 按特定轴求和、矩阵计算、自动求导
9.15线性回归、基础优化方法、线性回归的从零开始实现、线性回归的简洁实现
Softmax 回归、损失函数、图像分类数据集、Softmax 回归的从零开始实现、Softmax 回归的简洁实现
感知机、多层感知机、多层感知机的从零开始实现、多层感知机的简洁实现
4 月 11 日模型选择、欠拟合和过拟合
4 月 17 日权重衰减、Dropout
4 月 18 日数值稳定性、模型初始化和激活函数、实战 Kaggle 比赛:预测房价、预测房价
卷积神经网络4 月 24 日模型构造、参数管理、自定义层、读写文件、GPU
5 月 15 日预测房价竞赛总结
5 月 15 日从全连接层到卷积、图像卷积
5 月 16 日填充和步幅、多输入多输出通道
5 月 22 日池化层、卷积神经网络(LeNet)
5 月 23 日深度卷积神经网络(AlexNet)、使用块的网络(VGG)
5 月 29 日网络中的网络(NiN)、含并行连结的网络(GoogLeNet)
5 月 30 日批量归一化、残差网络(ResNet)、图片分类
计算机视觉6 月 5 日硬件:CPU 和 GPU
6 月 6 日更多的专有硬件、多 GPU 训练
6 月 19 日多 GPU 训练的实现、分布式训练
6 月 20 日图像增广、微调
6 月 26 日实战 Kaggle 比赛:图像分类(CIFAR-10)、实战 Kaggle 比赛:狗的品种识别
6 月 27 日物体检测、边缘框实现、物体检测数据集、锚框、树叶分类竞赛总结
7 月 3 日区域卷积神经网络(R-CNNs)、单发多框检测(SSD)、你只看一次(YOLO)
7 月 4 日多尺度物体检测实现、SSD 实现
7 月 10 日语义分割、语义分割数据集、转置卷积、转置卷积是一种卷积
7 月 11 日全连接卷积神经网络(FCN)、样式迁移、目标检测
循环神经网络7 月 17 日序列模型、文本预处理
7 月 18 日语言模型和数据集、循环神经网络
7 月 24 日循环神经网络的从零开始实现、循环神经网络的简洁实现
7 月 25 日门控循环单元(GRU)、长短期记忆网络(LSTM)、深层循环神经网络、双向循环神经网络
8 月 7 日机器翻译与数据集、编码器 - 解码器结构、序列到序列学习(seq2seq)、束搜索
注意力机制8 月 8 日注意力机制、注意力分数、使用注意力机制的 seq2seq
8 月 14 日自注意力和位置编码、Transformer
8 月 15 日BERT、BERT 预训练数据集、预训练 BERT、微调 BERT、自然语言推理和数据集、自然语言推理:微调 BERT、目标检测总结
8 月 21 日优化算法、课程总结和进阶学习

05线性代数

标量

就是单个数字,在 PyTorch 里用只有 1 个元素的张量来代表标量。

import torch # 创建标量张量(每个张量中仅包含一个元素) x = torch.tensor([3.0]) y = torch.tensor([2.0]) # 执行四则运算和幂运算 addition = x + y # 加法:3.0 + 2.0 multiplication = x * y # 乘法:3.0 * 2.0 division = x / y # 除法:3.0 / 2.0 power = x ** y # 幂运算:3.0 的 2.0 次方 # 输出结果 print("加法:", addition) print("乘法:", multiplication) print("除法:", division) print("幂运算:", power)
加法: tensor([5.]) 乘法: tensor([6.]) 除法: tensor([1.5000]) 幂运算: tensor([9.])

向量

= 标量组成的一维列表,在 PyTorch 里就是 1 维张量

x = torch.arange(4)
tensor([0, 1, 2, 3])
# In[3]:索引取值(Python从0开始编号!) x[3] # Out[3]: tensor(3)
# In[4]:len() 获取向量元素总数 len(x) # Out[4]: 4
# In[5]:.shape 查看张量形状 x.shape # Out[5]: torch.Size([4])

矩阵

通过指定两个分量m和n来创建一个形状为mXn的矩阵

# In[6] 创建 m×n 的矩阵:5行4列 A = torch.arange(20).reshape(5, 4) A
[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19]]
# In[7] A.T
[[ 0, 4, 8, 12, 16], [ 1, 5, 9, 13, 17], [ 2, 6, 10, 14, 18], [ 3, 7, 11, 15, 19]]
  • 原 A:5 行 4 列
  • 转置后 A.T:4 行 5 列

✅ 规则:矩阵的列数必须等于向量的行数,才能相乘。

✅ 输出向量行数 = 矩阵的行数

✅ 相乘前提:A 的列数 = B 的行数(这里都是 4) ✅ 输出矩阵维度:A 的行数 × B 的列数

✅ 输出矩阵维度:A 的行数 × B 的列数

import torch # 构造3×3对称矩阵 B = torch.tensor([[1, 2, 3], [2, 0, 4], [3, 4, 5]]) B
tensor([[1, 2, 3], [2, 0, 4], [3, 4, 5]])
# 判断矩阵是否等于自身转置,验证对称 B == B.T
tensor([[True, True, True], [True, True, True], [True, True, True]])

就像向量是标量的推广,矩阵是向量的推广一样,我们可以构建具有更多轴的数据结构

import torch # 3维张量,shape=(2, 3, 4) X = torch.arange(24).reshape(2, 3, 4) X
tensor([[[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]])

理解:可以看作2 个 3×4 的矩阵堆叠在一起。在深度学习里,常用三维张量:(样本数, 行数, 列数)或者(通道, 高, 宽)(图像)。

X.shape # torch.Size([2, 3, 4])

给定具有相同形状的任何两个张量任何按元素二元运算的结果都将是相同形状的张量

import torch # In[11] A = torch.arange(20, dtype=torch.float32).reshape(5, 4) B = A.clone() # 通过分配新内存,将A的一个副本分配给B A, A + B
(tensor([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.], [12., 13., 14., 15.], [16., 17., 18., 19.]]), tensor([[ 0., 2., 4., 6.], [ 8., 10., 12., 14.], [16., 18., 20., 22.], [24., 26., 28., 30.], [32., 34., 36., 38.]]))

# In[12] 哈达玛积(按元素相乘) A * B
# A * B 的输出 tensor([[ 0., 1., 4., 9.], [ 16., 25., 36., 49.], [ 64., 81., 100., 121.], [144., 169., 196., 225.], [256., 289., 324., 361.]])
# In[13] 标量与三维张量广播运算 a = 2 X = torch.arange(24).reshape(2, 3, 4) a + X, (a * X).shape
# a + X, (a * X).shape 的输出 (tensor([[[ 2, 3, 4, 5], [ 6, 7, 8, 9], [10, 11, 12, 13]], [[14, 15, 16, 17], [18, 19, 20, 21], [22, 23, 24, 25]]]), torch.Size([2, 3, 4]))

  • .sum()不带参数:把张量里面所有元素全部加起来,不管是几维,最后得到一个标量张量。
  • 一维向量[0,1,2,3]总和 = 0+1+2+3 = 6
  • 之前的 A 是 5×4 矩阵(0~19),全部元素相加结果是 190。
# In[5] 三维张量全部元素求和 A = torch.arange(20*2).reshape(2, 5, 4) A.shape, A.sum()
# In[6] 在第0维(axis=0)求和 A_sum_axis0 = A.sum(axis=0) A_sum_axis0, A_sum_axis0.shape
# In[7] 在第1维(axis=1)求和 A_sum_axis1 = A.sum(axis=1) A_sum_axis1, A_sum_axis1.shape
# In[8] 同时对axis0和axis1两个维度求和 A.sum(axis=[0, 1])
# In[5] (torch.Size([2, 5, 4]), tensor(780))
# In[6] (tensor([[20, 22, 24, 26], [28, 30, 32, 34], [36, 38, 40, 42], [44, 46, 48, 50], [52, 54, 56, 58]]), torch.Size([5, 4]))
# In[7] (tensor([[ 40, 45, 50, 55], [140, 145, 150, 155]]), torch.Size([2, 4]))

✅ A.sum(axis=0)

沿着第 0 维求和,压缩 / 消掉 axis=0axis=0 是 2 个矩阵块,把对应位置元素两两相加: 第 1 块 [0,,] + 第 2 块 [1,,]

原来 shape(2,5,4)→ 消掉第 0 维 → 结果 shape(5,4)

tensor([[20, 22, 24, 26], [28, 30, 32, 34], [36, 38, 40, 42], [44, 46, 48, 50], [52, 54, 56, 58]])

✅ A.sum(axis=1)

沿着第 1 维求和,压缩 / 消掉 axis=1axis=1 是 5 行,在每一个矩阵内部,按列累加 5 行

原来 shape(2,5,4)→ 消掉第 1 维 → 结果 shape(2,4)

tensor([[ 40, 45, 50, 55], [140, 145, 150, 155]])

✅ A.sum(axis=[0,1])

同时压缩 axis0 和 axis1,只剩下 axis2。shape(2,5,4)(4,)相当于把所有元素求和,等价A.sum()


通俗记忆口诀

sum(axis = n)沿着 n 这个轴去叠加,把这个维度 “压扁删掉”

  • axis=0:上下叠加(最外层)
  • axis=1:在行方向叠加
  • axis=2:在列方向叠加
# In[19] 全局平均值(整个张量所有元素的均值) A.mean(), A.sum() / A.numel()
  • A.mean():直接求张量 A全部元素的平均值
  • A.numel():numel = number of elements,返回张量里元素总个数
  • 数学等价:平均值 = 总和 ÷ 元素总数,所以两个式子结果完全一样tensor(9.5)
# In[20] 沿着axis=0维度求均值 A.mean(axis=0), A.sum(axis=0) / A.shape[0]
  • A.mean(axis=0)沿着第 0 维求平均
  • A.shape[0]:取出 axis=0 这个维度的长度(这里等于 2)
  • 等价:先沿 axis=0 求和,再除以 axis0 上元素数量,两个表达式结果一样
# In[21] keepdims=True 保持维度不消失 sum_A = A.sum(axis=1, keepdims=True) sum_A
  • axis=1:沿着第 1 维求和
  • keepdims=True核心作用:求和之后,被求和压缩的那一维不会删掉,保留为长度 = 1 的维度

假设原张量A.shape = (5,4)

  • 不加 keepdims:A.sum(axis=1)→ shape(5,)(一维向量)
  • keepdims=TrueA.sum(axis=1, keepdims=True)→ shape(5,1)输出:
tensor([[ 6.], [22.], [38.], [54.], [70.]])

可以看到结果依然是二维矩阵,不是一维数组。

# In[22] A / sum_A 利用广播做归一化 A / sum_A
  • Ashape(5,4)sum_Ashape(5,1)
  • 触发广播:sum_A的 (5,1) 会在第 1 维复制扩展成 (5,4),然后逐元素相除
  • 含义:每一行的每个元素 ÷ 该行所有元素的总和,得到每行的占比(每行所有数相加 = 1)

✅ keepdims 一句话总结

  • keepdims=False(默认):求和后,被计算的维度直接删掉,维度变少
  • keepdims=True:求和后,被计算的维度保留,变成大小为 1,总维数不变

为什么需要 keepdims?

就是为了方便广播运算! 如果不写keepdims,sum_A 变成 shape(5,),和 A(5,4)做除法会广播失败 / 出错; 保留(5,1)形状,就能直接做每行归一化,这是深度学习里归一化非常常用写法。

# In[23] 在axis=0维度,计算累积和 A.cumsum(axis=0)

cumsum=cumulative sum 累积求和

.sum()不一样:

  • .sum():直接算出一个最终总和,维度会压缩消失
  • .cumsum()不压缩维度!输出 shape 和原张量完全一样,保存每一步累加中间结果

这里axis=0:沿着行方向(纵向)累加

原矩阵 A(5 行 4 列)

行0:[0, 1, 2, 3] 行1:[4, 5, 6, 7] 行2:[8, 9,10,11] 行3:[12,13,14,15] 行4:[16,17,18,19]

按列纵向逐行累加:

  • 输出第 0 行 = 原第 0 行:[0, 1, 2, 3]
  • 输出第 1 行 = 原行 0 + 原行 1:[0+4,1+5,2+6,3+7] = [4,6,8,10]
  • 输出第 2 行 = 行 0 + 行 1 + 行 2:[0+4+8,1+5+9,2+6+10,3+7+11] = [12,15,18,21]
  • 输出第 3 行 = 前 4 行累加
  • 输出第 4 行 = 全部 5 行累加

输出结果:

tensor([[ 0., 1., 2., 3.], [ 4., 6., 8., 10.], [12., 15., 18., 21.], [24., 28., 32., 36.], [40., 45., 50., 55.]])

✅一句话区分

  • sum(axis=0):5 行叠加,只输出 1 行结果,shape 从(5,4)(4,)
  • cumsum(axis=0):保存每一步累加,仍然输出 5 行,shape 不变(5,4)

拓展:如果写A.cumsum(axis=1),就是横向按列累积求和,每行内部从左往右累加。

# In[24] 向量点积 dot y = torch.ones(4, dtype=torch.float32) x, y, torch.dot(x, y)
  • x = tensor([0., 1., 2., 3.])
  • y = tensor([1., 1., 1., 1.])
  • torch.dot(x,y):一维向量的点积

点积定义:对应位置元素相乘,再全部加起来

输出:tensor(6.)

# In[25] 等价写法:先按元素相乘 *,再sum求和 torch.sum(x * y)
  1. x * y按元素乘法(哈达玛积),得到[0*1,1*1,2*1,3*1] = [0,1,2,3]
  2. torch.sum(...):把上面数组全部相加,结果同样 = 6

结论:一维向量点积 = 按元素相乘后求和torch.dot(x,y)等价torch.sum(x*y)

A.shape, x.shape, torch.mv(A, x)
  • torch.mv=matrix-vector multiply矩阵 × 向量乘法
  • A是矩阵:shape [5,4](5 行 4 列)
  • x是一维向量:shape [4](长度 4)

矩阵向量乘法规则: 结果里第 i 个元素 = A 的第 i 行 和向量 x 的点积,也就是 \(a_i^\top x\) 输出向量长度等于矩阵的行数 → 输出 shape[5]

代入我们之前的数据

A = [ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9,10,11], [12,13,14,15], [16,17,18,19] ] x = tensor([0.,1.,2.,3.])

逐行做点积:

输出结果:tensor([14., 38., 62., 86., 110.])和幻灯片完全一致 ✅

重要知识点

  1. 维度匹配要求:矩阵的列数 必须等于向量长度A (5,4),x (4),A 的列 = 4,x 长度 = 4,满足条件。
  2. 等价写法:A @ x@是 PyTorch 矩阵乘法运算符,推荐)
    A @ x # 和 torch.mv(A,x) 效果一模一样
  3. 区分:
    • torch.mv矩阵 × 一维向量
    • torch.mm矩阵 × 矩阵(两个都必须 2D)
    • *:逐元素哈达玛积,不是矩阵乘法

一句话总结

torch.mv(A,x):拿矩阵每一行,分别和向量x点积,所有点积结果拼成输出向量。

B = torch.ones(4, 3) # 4行3列,全部元素=1 torch.mm(A, B)

torch.mm=matrix × matrix 矩阵乘法(只接受二维张量)

代入当前例子

B 的 3 个列向量全是[1,1,1,1]A 矩阵:

行0:[0, 1, 2, 3] → 和[1,1,1,1]点积 = 0+1+2+3 = 6 行1:[4, 5, 6, 7] → 点积=4+5+6+7=22 行2:[8, 9,10,11] → 点积=8+9+10+11=38 行3:[12,13,14,15] → 点积=12+13+14+15=54 行4:[16,17,18,19] → 点积=16+17+18+19=70

因为 B 三列全部是 1,三次矩阵向量积结果完全一样,所以输出矩阵每一行三个数字相同

tensor([[ 6., 6., 6.], [22., 22., 22.], [38., 38., 38.], [54., 54., 54.], [70., 70., 70.]])

✅ 等价写法

A @ B效果完全等同于torch.mm(A,B)

u = torch.tensor([3.0, -4.0]) torch.norm(u)

05[补充] 按特定轴求和

06 矩阵计算

07自动求导

向量链式法则

自动求导

计算图

自动求导的两种模式

反向累积

复杂度

自动求导的实现

# In[2] x.requires_grad_(True) # 开启张量x的梯度追踪,Pytorch会预留x.grad存储梯度 x.grad # 还没反向传播,默认是 None # In[3] y = 2 * torch.dot(x, x) # torch.dot是向量点积 y

def f(a): b = a * 2 # while循环:不断把b×2,直到b的范数≥1000 while b.norm() < 1000: b = b * 2 # if判断分支 if b.sum() > 0: c = b else: c = 100 * b return c

norm()用来计算张量的 L2 范数(向量模长),衡量这个张量整体的 “大小”。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询