
动手学深度学习第二张卡片我是边学边写的之前已经啃完了第一张的入门部分现在回头梳理第二章“数据预处理与线性代数”发现这一章的厚度远超我的预期。很多初学者会把它当成“工具书”直接跳过也有人卡在 pandas 数据处理和矩阵乘法就泄气了。实际上这一章是整本书的分水岭吃透了它后面看卷积、循环网络、Transformer 的公式至少能看懂七成。今天把我的学习笔记和踩坑记录整理出来聊得细一点尽量讲人话。这一章书里分成两大块一块是数据预处理的实操套路另一块是线性代数概念和 PyTorch 张量操作的对照。两者看似独立其实都在解决同一个问题让原始数据变成模型能吃、能算、能反向传播的数值结构。数据预处理管“喂进去之前的事”线性代数管“喂进去之后怎么算的事”。适合谁看呢如果你是正在刷《动手学深度学习》的初学者或者做了几个 demo 但总在数据加载和维度变换上翻车的人这一篇可以当作同步笔记来用。1. 章节定位与整体设计思路1.1 为什么这一章要把数据预处理和线性代数放在一起先从书的编排逻辑说起。李沐老师这套书有个特点它不跟你扯太多抽象的数学定义而是把数学概念直接落到张量操作上。第二章先讲数据预处理再讲线性代数这个顺序是刻意安排的。数据预处理部分解决的是“现实世界的数据怎么转化”的问题。现实中的数据大概率是一张 CSV 表格里面有缺失值、有离散文本、有取值范围差异巨大的列。你得先把这些脏数据清理干净、标准化再把它变成 PyTorch 能处理的torch.Tensor。不做这一步模型训练根本跑不起来。线性代数部分解决的是“张量怎么运算”的问题。一旦数据变成了张量后面所有的事——矩阵乘法、范数计算、转置、拼接——都是线性代数的活。神经网络说白了就是一堆矩阵乘法和非线性变换的堆叠。你如果不理解矩阵形状和乘法规则后面看任何模型结构的代码都会懵。两章合在一起正好是“先准备数据再让数据流动起来”的完整链路。1.2 我读这章时最大的认知升级张量就是“带维度的数组”在读这一章之前我对“张量”这个词一直有点畏惧感总觉得它是什么高深的数学对象。书里的定义特别直接张量就是 n 维数组标量是 0 维张量向量是 1 维张量矩阵是 2 维张量再往上就是 n 维数组。从这个视角看深度学习模型里到处流动的数据不过是在不同维度之间做变换的数组而已。这给了我两个启发。第一维度概念比数学符号重要。书里反复强调shape、numel()、reshape()核心是让你时刻清楚数据是几维的、每个维度有多少个元素。第二运算的合法性取决于维度是否匹配。两个矩阵能不能相乘看的是“左矩阵的列数是否等于右矩阵的行数”这句话看似简单调试代码时一半的报错都出在这里。1.3 适合的学习节奏和配套环境我建议这一章至少要动手敲三遍代码。第一遍跟着书里的代码走先跑通再说第二遍拿一份自己的小数据比如自己编一个成绩表、订单表做预处理体会 pandas 和 torch 之间的衔接第三遍再回头看概念把线性代数名词和张量操作一一对应起来。环境方面我是用 PyTorch 2.x 加 pandas 2.x在 Jupyter Notebook 里跑的。如果还没装环境用pip install torch pandas numpy一条命令就行。个人强烈推荐用 Notebook 而不是脚本文件因为这一章全是中间结果展示一个个 cell 跑下来你对数据形态的变化会特别有感觉。2. 数据预处理核心操作解析2.1 从 CSV 到 DataFrame一切从读文件开始书里用的是一个人造的小 CSV 文件存的是房屋价格数据。我实际学习中换成了自己攒的一份“学生成绩与平时表现”数据来练手结构和书里的类似有两列数值、一列离散文本、一个缺失值。预处理的第一步没有任何花活就是把 CSV 读进pandas.DataFrame。import pandas as pd import os os.makedirs(os.path.join(.., data), exist_okTrue) data_file os.path.join(.., data, house_tiny.csv) # 模拟真实文件的写入实际使用中直接指向已有文件即可 with open(data_file, w) as f: f.write(NumRooms,Alley,Price\n) f.write(NA,Pave,127500\n) f.write(2,NA,106000\n) f.write(4,NA,178100\n) f.write(NA,NA,140000\n) data pd.read_csv(data_file) print(data)运行结果就是一张 4 行 3 列的表格里面有NaN。这一步看起来简单但有几个隐藏细节值得注意。文件路径最好用os.path.join拼接别写死一个带反斜杠的 Windows 路径不然换机器跑就炸。CSV 里NA和空字符串读进来都会被识别成缺失值这是 pandas 的默认行为但你要心里有数别以为数据真的丢了。热词里我看到有人在搜“数据预处理 pandas 头歌”应该是课程作业里要做类似任务。其实本质就是这几件事加载、清洗、转换、构造特征。把这四点吃透什么平台的作业都能应付。2.2 缺失值处理不要一删了之书里给出了两个办法删除缺失值或者用插值法填充。我特别认同这章反复强调的一点处理缺失值没有标准答案要看你后续想做什么。来看实际代码。以NumRooms这一列为例缺失值只有两个直接扔掉会影响样本量更稳妥的方式是取该列的平均值来填# 处理缺失值对数值列用均值填充 data[NumRooms] data[NumRooms].fillna(data[NumRooms].mean()) print(data)这里有个非常容易翻车的细节data[NumRooms].mean()返回的是标量直接fillna没问题但如果你做分组填充得用transform加 lambda否则会报长度不匹配的错。至于Alley这一列它是离散的字符串类型书里处理手法是用pd.get_dummies做独热编码。独热编码的本质是把“类别”变成一串 0/1 的向量这样模型才能把它当作数值输入来算。# 独热编码把类型列变成多列0/1 data pd.get_dummies(data, columns[Alley], dummy_naTrue) print(data)dummy_naTrue的意思是缺失值也单独生成一列这样缺失值本身成为了一种“信息”而不是直接被抹掉。这个细节在真实的特征工程里非常常见比如用户收入未知、职业未知这些“未知”往往有特殊的业务含义。2.3 标准化与数值稳定性为什么不能直接扔给模型数据里NumRooms的数量级一般在个位数但Price动辄十万、百万级。如果这两列直接拼成一个矩阵丢给模型数值范围大的那一列会在梯度下降中占据绝对主导地位模型几乎学不到NumRooms的特征。书里没有在这一章展开太多标准化理论但我在后续实战中确认了标准化是深度学习的隐形地基。实际操作上最常用的方式是 z-score 标准化公式是(x - mean) / std处理完后数据均值为 0、标准差为 1。PyTorch 里没有直接给你写好的“标准化”函数但用张量自带的方法就能轻松搞定# 转为张量后手动做z-score标准化仅演示数值列 import torch # 假设这是你最终构造成的数值矩阵 features torch.tensor([ [3.0, 127500.0], [2.0, 106000.0], [4.0, 178100.0], [3.0, 140000.0], ]) mean features.mean(dim0) std features.std(dim0) features_normalized (features - mean) / std print(features_normalized)注意这里dim0表示按列计算均值方差。很多新手一上来就features.mean()把整个矩阵的均值搞成一个数然后再广播去减结果每列都没有被正确中心化训练出来效果差还找不到原因。2.4 从 DataFrame 到 Tensor最后一公里的类型坑书里用一行代码就把 pandas DataFrame 转成了 PyTorch 张量torch.tensor(data.to_numpy(dtypefloat))但这里有两个容易忽略的坑。第一个是to_numpy(dtypefloat)的作用。如果 DataFrame 里混有字符串、数值、布尔值直接转 numpy 会得到 object 类型的数组再转 torch tensor 就直接报错。先统一成 float 类型是因为后面的张量运算要求数值类型一致。第二个坑是缺失值必须处理完才能转。如果你漏了fillna或dropna转出来的 tensor 还是带着NaN训练的时候损失函数直接变成nan整个梯度传播就废了。我自己在实际跑的时候遇到过类型是torch.int64但模型权重默认是torch.float32的情况矩阵乘法直接报 type mismatch。后面养成了习惯凡是从文件读进来的数据在转 tensor 后立刻加一行.float()看似多余实际能省一个小时的排查时间。3. 线性代数核心概念回顾3.1 标量、向量、矩阵、张量从符号到代码书里的线性代数部分写得特别“实用导向”基本上每个数学概念都配套了一个 PyTorch 函数。这一节必须先理清基础概念。标量一个单独的数代码里就是 0 维张量用torch.tensor(2.0)表示。向量一组数1 维张量torch.arange(4)就是长度为 4 的向量。矩阵二维表格2 维张量比如torch.arange(6).reshape(2, 3)。张量n 维数组n 大于 2 的情况统一叫张量。书里有句描述我印象很深张量就像一栋房子向量是走廊矩阵是房间高维张量是整栋楼的每一层。虽然是个很简化的类比但对建立直觉非常有用。在实际写代码时最需要关注的是shape。我用这段时间最大的一条经验就是每写一行张量操作先打印.shape确认结果和自己想的是否一致。3.2 矩阵运算的底层逻辑逐元素运算 vs 矩阵乘法这是整个线性代数章节里最容易混淆的地方。书里特别强调了两者的区别import torch A torch.arange(6, dtypetorch.float32).reshape(2, 3) B A.clone() # 副本 # 逐元素相乘Hadamard积 print(A * B) # 矩阵乘法点积推广 print(torch.matmul(A, B.T))很多人在初学的时候会把*当成数学里的矩阵乘法。实际上PyTorch 的*默认是逐元素相乘也叫 Hadamard 积要求两个张量的形状一致而真正的矩阵乘法要用torch.matmul也就是运算符它要求左边的列数等于右边的行数。这个坑我在写全连接网络时踩过不止一次全连接层其实是做矩阵乘法X W结果我用*去乘形状对不上梯度传播算出来全是乱的。书里用 Softmax 回归的模型举例时torch.matmul(X, w)看到的就是最原始、最本质的深度学习计算方式。理解了这一步后面看多层感知机、CNN 的线性层就只是规模放大而已。3.3 维度变换reshape、transpose、广播机制一次讲清维度变换是深度学习代码里出现频率最高的操作之一。我统计过自己在写模型时用到最多的函数reshape、view、permute、transpose、squeeze、unsqueeze几乎每隔几行就会出现一个。书里重点讲了reshape其中“按行读入按行填充”的理解方式非常有效。你看下面这个例子x torch.arange(12, dtypetorch.float32) X x.reshape(3, 4) print(X)输出的矩阵第一行是 0、1、2、3第二行是 4、5、6、7这符合直觉。但真正容易出问题的是高维张量的 reshape。比如一个形状为(2, 3, 4)的张量你想把它变成(4, 6)除非你透彻理解元素顺序否则很容易得到奇怪的结果。我的经验是reshape 之前先用reshape(-1, 某个数)过渡一下把中间形状打印出来看看再继续操作。再聊广播机制。PyTorch 里两个形状不同的张量做逐元素运算时会自动扩展较小的张量。比如形状(3, 1)的张量加形状(1, 4)的张量会分别广播成(3, 4)再相加。这个机制让代码变得非常简洁a torch.tensor([[1.0], [2.0], [3.0]]) b torch.tensor([[10.0, 20.0, 30.0, 40.0]]) print(a b)但广播机制也带来了隐藏风险。如果两个张量形状“部分匹配但不完全匹配”系统不会直接报错而是会按广播规则默默扩展结果可能不是你想要的。比如形状(3, 1)和(3,)相加PyTorch 会把后者当成(1, 3)来处理产生(3, 3)矩阵。我在写样本特征和偏置相加时就因为这个规则吃过亏损失数值一直下不去。3.4 范数衡量向量大小的标尺书里还讲了范数的概念主要涉及 L1 范数和 L2 范数。简单理解范数就是把向量映射成一个非负标量表示这个向量的“大小”。L2 范数所有元素平方和的平方根就是常见的“欧几里得距离”。L1 范数所有元素绝对值之和对离群点更鲁棒。PyTorch 里一行代码搞定u torch.tensor([3.0, -4.0]) print(torch.norm(u)) # L2范数输出5.0 print(torch.abs(u).sum()) # L1范数输出7.0深度学习里范数最重要的应用是在损失函数加正则化项。你在很多模型的代码里看到的weight_decay参数本质上就是往损失函数里加 L2 范数的平方用来抑制权重过大、防止过拟合。书里讲线性回归那一节会再次用到这个概念现在看确实是在为后面做铺垫。3.5 特殊矩阵与特征分解建立“现实世界是矩阵变换”的直觉第二章后面还提了一些更抽象的概念转置矩阵、对称矩阵、正交矩阵以及特征向量与特征值。书里写得比较简略但我在配合读论文时发现这些概念在深度学习里无处不在。对称矩阵就是转置等于自身的矩阵。为什么要关心它协方差矩阵就是典型代表主成分分析 PCA 的核心就是对这个对称矩阵做特征分解。正交矩阵满足A.T A I几乎所有好的表示学习都希望学到接近正交的权重矩阵因为它能保持信息不退化。我自己的体会是第二章不要求你把特征分解的推导过程全部弄懂但至少要有“矩阵可以从几何上理解为一种变换”的意识。如果你把矩阵看成一种对向量的缩放和旋转操作那么神经网络本质上就是一连串的矩阵变换加非线性激活最终把输入数据变换到一个任务友好的空间。有了这个视角后面理解损失曲面、梯度方向、注意力机制都会有豁然开朗的感觉。4. 用 PyTorch 实操从小张量到模型的关键运算4.1 创建张量的几种姿势哪些常用、哪些别踩坑PyTorch 里创建张量的方式太多新手容易看花眼。我把我实际用过的、认为最重要的列成一个表方式代码示例适用场景注意点类似 Python 列表torch.tensor([1.0, 2.0])小数据、参数初始化注意加dtypetorch.float32等差数列torch.arange(start, end, step)构造序列、位置编码步长支持浮点全 0 / 全 1torch.zeros(2, 3)torch.ones(2, 3)初始化掩码、偏置默认是 float32够用均匀分布随机torch.rand(2, 3)初始化小规模权重范围 [0, 1)需要映射时再变换标准正态随机torch.randn(2, 3)初始化权重深度学习中很多默认初始化用它单位矩阵torch.eye(4)验证矩阵逆、PCA 相关操作只支持二维从 numpy 转换torch.from_numpy(np_array)和 pandas / numpy 联动会共享内存改一个另一个也会变这里最容易被忽略的是torch.tensor和torch.Tensor的区别。torch.tensor是普通函数会根据传入数据推断类型torch.Tensor是类构造器它会无脑用torch.FloatTensor如果你传入整数列表最终得到的是 float 数组但值是一样的类型默认是 float32。所以在训练模型的时候torch.tensor([1, 2])得到的是 int64而torch.Tensor([1, 2])得到的是 float32。很多跨框架切换的人比如从 NumPy 转过来会在这上面卡好久我建议统一用torch.tensor记得给数值列加.float()。4.2 矩阵乘法实操理解、matmul、mm的差别PyTorch 里矩阵乘法相关的 API 有一堆A B、torch.matmul(A, B)、torch.mm(A, B)。听起来很相似但差异非常重要torch.mm只支持真正的二维矩阵相乘。torch.matmul更通用支持高维张量的批量矩阵相乘还能玩广播。运算符直接调torch.matmul是matmul的语法糖。所以实际写代码时用就够了。训练过程中一批数据是形状(batch_size, input_dim)权重矩阵是形状(input_dim, output_dim)二者的矩阵乘法就是X W生成形状(batch_size, output_dim)的输出。我专门做过一个验证小实验加深对维度匹配的理解X torch.randn(3, 4) # 3个样本每个4个特征 W torch.randn(4, 5) # 输入4维输出5维 Y X W # shape: (3, 5) print(Y.shape)如果不小心把 W 定义成torch.randn(5, 4)那一跑就是维度不匹配的报错。从最早的 MLP 到现在的 Transformer所有线性层的核心都是这个矩阵乘法真的没有第二种形式。把这一行代码理解透就读懂了深度学习模型里最通用的计算骨架。4.3 小规模线性代数验证用代码确认数学性质我学习线性代数的习惯是每学一个数学性质就在 PyTorch 里验证一遍。比如书上提到“矩阵转置”几个基本性质我写成代码去跑一遍比死记硬背有效得多。A torch.tensor([[1.0, 2.0], [3.0, 4.0]]) B torch.tensor([[5.0, 6.0], [7.0, 8.0]]) # 性质1: (A.T).T A print((A.T).T) # 性质2: (A B).T A.T B.T left (A B).T right A.T B.T print(torch.allclose(left, right)) # True # 性质3: (A B).T B.T A.T注意顺序颠倒 left2 (A B).T right2 B.T A.T print(torch.allclose(left2, right2)) # True这里用到的torch.allclose是专门用来比较两个张量是否数值上相等的函数比更健壮因为浮点运算会有微小的精度误差直接用会得到False。这个小知识点在写自定义损失函数、自定义层的时候非常常用。范数也一样。书上给了一个 L2 范数的公式我转头就用代码算了一遍torch.norm再跟公式手算的平方根对比数值完全一致。这种“先公式后代码”的对照学习法对非科班出身的人特别友好能消除数学符号的陌生感。4.4 从第二章到实战几个值得动手练的延伸练习如果你学完这一章想检验自己到底掌握得怎么样我建议做下面几个小练习打开一份真实 CSV比如 Kaggle 上的 Titanic 数据集用 pandas 完成读入、看缺失值、填充或删除、对离散列独热编码、转成 torch tensor 的完整流程。自己手写一个“迷你全连接层”不要调用nn.Linear只用torch.matmul和一个自定义权重矩阵实现X W b的前向传播。做完这一步你对线性层的理解会上升一个维度。对同一个矩阵做reshape(-1, 1)和squeeze(-1)观察两次结果的形状区别搞清什么时候该增维、什么时候该减维。这两个函数的区别我在之后看广播机制和损失计算时被反复考到。这三个练习都不需要 GPUCPU 上几秒钟就能跑完。关键是动手敲一遍、改一遍、报错一遍才能真正把书上的代码内化成自己的能力。5. 常见问题与排查技巧实录5.1 pandas 数据预处理阶段的四大经典报错我这一周在数据预处理上遇到的最典型的报错以及对应的排查思路整理成表格。这些错误几乎是每个人都会遇到的报错/现象原因排查与解决NaN出现在 loss 里缺失值没处理干净数据转换时带入了 NaN用data.isna().sum()逐列检查确认填充方式合理objectdtype 无法转 tensorDataFrame 里有字符串或混合类型列没有统一先data.astype(float)或pd.to_numeric()再做to_numpy(dtypefloat)Length of values does not match length of index对 DataFrame 逐列计算后直接赋值长度不匹配使用data[col] data.groupby(...)[col].transform(lambda x: x.fillna(x.mean()))duplicate axis或列名重复对重复列名做 get_dummies 时产生冲突尽早用data.columns data.columns.str.strip()清理列名其中第二个问题我身边至少有四个朋友问过我。他们的做法通常是把整个 DataFrame 丢给torch.tensor()或者torch.from_numpy(data.values)结果遇到字符串就报类型错误。解决方式就是书里那行data.to_numpy(dtypefloat)它会强制所有列转 float转不过去的会在这一步炸出来反而帮助你更早发现问题。5.2 张量运算阶段最常见的十二个隐蔽坑相比 pandas 阶段的报错张量运算阶段的问题更隐蔽因为它很多时候不报错而是“能跑但结果不对”。我总结了几条深度踩坑经验用torch.reshape和torch.view时view 要求张量在内存中是连续的reshape 会自动处理。你自己写代码建议统一用reshape少用view。矩阵乘法搞混*和。逐元素运算和矩阵乘法的结果形状可能恰好一样但数值完全不同你在损失函数里看不出来只在反传时发现梯度和预期不符。广播机制“太过智能”。torch.randn(3, 1) torch.randn(3)是合法的结果为(3, 3)。你以为你在加偏置其实系统给你扩展了一个维度。遇到莫名其妙的多出维度先看形状再做运算。.mean()默认对所有元素求均值不会自动按 batch 维度归约。如果你想做按行或按列归约必须显式传dim0或dim1。.sum()一个有bool类型的数据时会默认把True当 1 计入总和。如果你不小心把一个 mask 直接 sum结果看着是正常的但方向错了。两个张量的dtype不一致时PyTorch 不会自动把 int64 和 float32 做矩阵乘法会直接报 type mismatch。遇到就让两者都.float()。.item()只能在标量张量上用很多人把它用在向量上直接报错。torch.tensor(2.0)和torch.tensor([2.0])看起来差不多一个是标量、一个是向量后面很多操作对二者的处理逻辑完全不同。把torch.tensor的dtype忘了指定遇到大整数自动用 int64模型权重是 float32一乘就报类型错误。squeeze默认把所有维度为 1 的维度都去掉比如形状(1, 3, 1, 4)会变成(3, 4)。如果只想去掉特定维度必须传dim。permute和transpose不同transpose只能交换两个维度permute可以打乱所有维度。用permute更灵活但要注意结果的元素顺序和你想的是否一致。.T只对二维矩阵有效高维张量没有.T得用.permute或者transpose。我在处理 batch 维度变化时不止一次因为习惯用.T直接报错。排查这些坑我的标准流程是先打印print(x.shape, x.dtype)再打印一小块数据print(x[:2])然后才判断问题在哪。几乎所有维度、类型相关的问题都能在两行打印中暴露出来。5.3 我自己的两条排查“口诀”说到这分享两条在实操中摸索出来的排查口诀。第一条是“先形状、后数值、再类型”。遇到任何关于张量的报错不要只盯着报错信息看直接按这个顺序查shape对不对数值里有没有NaN或infdtype是否是同一个。90% 的张量问题都能在这三步里面解决。第二条是“把中间结果打印出来而不是只打印最终结果”。很多人习惯只在最后一行print(loss)但中间只要有一个张量的形状不对最终的 loss 可能是“合法”的只是含义完全错了。我在调试过程中会把每个关键变换的输出形状和值都打印出来比如原始数据形状、标准化后均值、第一个 batch 的形状、模型输出形状、损失值。这能让我在非常早的阶段就发现问题而不是等训练跑了一个小时之后才猛然发现结果不对。5.4 关于环境与版本的一些经验我跑这一章用的 PyTorch 是 2.xpandas 是 2.x。这里有个版本上的变化要特别提一下pandas 2.x 对缺失值的表示方式有细微调整使用fillna时的行为更严格如果传入的数据类型和列类型不匹配它会报ValueError而不是像 pandas 1.x 那样悄悄把类型强转。另外初学者如果在内存小的机器上跑注意不要用data.values直接转大型数据集。先做data data.astype(float)再to_numpy()最后再torch.tensor()。这样避免一次性把整个 DataFrame 的字符串复制到 numpy 再复制到 torch省内存也能减少类型转换的报错概率。6. 核心速查表与后续学习建议6.1 张量操作速查表这一章学完我把最核心的 PyTorch 操作整理成了一个速查表贴在我的笔记开头。每次写模型卡壳就回来翻一眼需求代码说明创建 0/1 矩阵torch.zeros(2, 3)/torch.ones(2, 3)默认 float32创建等差序列torch.arange(3, 10, 2)生成 [3, 5, 7, 9]查看形状x.shape返回 torch.Size 对象元素总数x.numel()等价于x.shape[0] * x.shape[1]重塑形状x.reshape(2, -1)-1 表示自动推断该维度转置x.T仅二维可用交换维度x.transpose(0, 1)指定两个维度交换打乱维度x.permute(1, 0, 2)适合多维张量重排增加维度x.unsqueeze(0)在指定位置加长度为 1 的维度压缩维度x.squeeze()默认压缩所有长度为 1 的维度逐元素相加x y要求形状相同或可广播矩阵乘法x y等价于torch.matmul(x, y)逐元素乘法x * y注意和矩阵乘法的区别L2 范数torch.norm(x)常用作求向量的模长按行求平均x.mean(dim0)dim0 是列方向归约拼接torch.cat([x, y], dim0)维度索引与最终结果的 dim 对应数值相等判断torch.allclose(x, y)考虑浮点误差比更可靠这个表我一定要建议你存下来。它不是最终的工具箱但足够覆盖第二章以及后续两章的绝大多数操作。等你往后写到更复杂的架构时多学几个函数再往里加就行。6.2 线性代数概念速查表对应地我也整理了线性代数概念的速查表。这张表帮助我在书和代码之间建立映射概念数学定义PyTorch 对应深度学习中的作用标量单独的数值torch.tensor(2.0)学习率、损失值向量一组数torch.arange(4)单个样本的特征向量、偏置矩阵二维数表torch.arange(6).reshape(2, 3)权重矩阵、批量数据张量n 维数组torch.randn(2, 3, 4)批量数据、图像通道、序列转置行列互换x.T维度匹配、求导链式法则逐元素乘法对应位置相乘A * B注意力掩码、门控机制矩阵乘法行与列点积A B全连接层、注意力向量L2 范数模长平方和开根号torch.norm(x)正则化、权重衰减L1 范数所有元素绝对值之和torch.abs(x).sum()L1 正则化、稀疏化对称矩阵A A.T(A A.T).all()协方差矩阵、二次型正交矩阵A.T A I手动验证保持信息、稳定训练特征向量/值A v λ v用torch.linalg.eig验证PCA、马尔可夫链、部分降维算法6.3 从这一章出发建议的学习顺序和拓展方向这一章学完之后我非常建议你按下面的顺序做点扩展不要急着往第三章冲第一把数据预处理章节用到的方法迁移到一份真实数据上。找任何一份有点脏的数据集完成“读入—缺失值统计—填充/删除—离散列编码—标准化—张量化”全流程。做的时候刻意不用书里的代码自己写。写不出来的地方再回去翻书这比照着代码敲十遍都有效。第二把线性代数章节里的概念在纸面上推导一遍然后用 PyTorch 验证。比如你看到一个矩阵的性质就用自己的随机矩阵去验证它。这能让你形成“数学性质代码逻辑”的映射后面的公式基本不会吓到你。第三可以去翻一翻后续章节中融合这两块内容的例子比如线性回归从零实现那一节。你会发现模型训练的全流程就是“数据处理 张量运算 梯度更新”。把第二章的基础打牢那里会顺畅很多。最后说一点个人体会。我学这一章时有个很强烈的感受深度学习新手最害怕的往往不是数学有多难而是没有建立起从“数据”到“矩阵”到“模型”的桥梁。数据预处理是桥的起点线性代数是桥的材料张量操作是建桥的手艺。三样东西缺一样后面看代码就会觉得哪里都隔着一层。第二章的价值恰恰是把这三样东西整合到一本书里讲明白。希望这份笔记能帮你把这座桥建得更稳。