面向 AI 的矩阵:读取行、列与神经网络形状
学习读取矩阵的维度和元素,将行与列映射到全连接层的作用,并在 NumPy 中发现形状或索引错误。
一个全连接层接收三个特征并产生两个输出值。这六个权重可以存储在一个长列表中,但那样会隐藏最有用的调试事实:每条输出规则各有三个权重。把相同的数字排列成两行三列,结构就显现出来了:
矩阵的形状 是一个紧凑的契约。第一个数字表示输出规则的数量;第二个数字表示每条规则使用的输入特征数量。在进行任何乘法之前,这个网格已经告诉我们每条轴必须表示什么,以及每个权重应当放在哪里。
学完本课后,你将能够读取矩阵维度,根据两个索引定位一个元素,解释全连接层权重矩阵中的行和列,在 NumPy 中复现这些检查,并诊断那些数值看似合理、却让各条轴承担了错误职责的数组。
**学习成果:**读取矩阵维度并解释行与列。
第 14 课:向量作为 AI 数据说明了有序坐标列表如何表示一个 AI 输入。矩阵增加了第二条轴,因此多个相关列表可以保留它们的共同组织方式。官方的 Mathematics for Machine Learning 配套网站定义了矩阵记号、行、列和元素,详见书中第 2.2 节。下面的全连接层场景、数字、图示、代码、解释和评估题均为原创。
一个矩形携带两个独立的计数
两个索引承担不同的职责。第一个索引在各行之间垂直移动;第二个索引在各列之间水平移动。对于
、,且 。矩阵有 个元素。这里把维度相加得到 ,恰好也产生了相同的数字,但这只是巧合: 矩阵有 个元素,而不是 个。
矩阵不必是方阵。 矩阵和 矩阵一样合法。记号也不会决定一条轴表示什么。行可能是数据集中的样本、层中的输出规则,或序列中的时间步。数据契约才提供这种含义。
两条输出规则变成一个 2 × 3 矩阵
假设一个小型排序层读取三个输入特征:
- :主题匹配度;
- :新近程度;以及
- :来源质量。
它为两个输出规则中的每条规则、每个特征存储一个系数:
第一条规则将产生相关性值;第二条将产生审核优先级值。本课暂不计算这些值,而是要组织这些系数,同时不丢失每个系数连接的输入和输出。
这种构造之所以成立,是因为行标签和列标签保持稳定。如果特征顺序变为 [source quality, topic match, recency],但数字原封不动,矩阵仍会保留同样的形状和值,却描述不同的规则。
| 输出规则(行) | 主题匹配度(第 1 列) | 新近程度(第 2 列) | 来源质量(第 3 列) | 行的解释 |
|---|---|---|---|---|
| 第 1 行 · 相关性 | 0.8 (w₁₁) | −0.4 (w₁₂) | 0.2 (w₁₃) | 与相关性输出关联的三个权重。 |
| 第 2 行 · 审核优先级 | 0.1 (w₂₁) | 0.6 (w₂₂) | ★ −0.5 (w₂₃) | 与审核优先级输出关联的三个权重;w₂₃ 为 −0.5。 |
图示中的框出元素以两种相互独立的方式标识:星号和虚线轮廓在视觉上标记它,而标签和表格直接写出 。第 2 行选择审核优先级规则。第 3 列选择来源质量。它们的交点标识层中的一条关系。
一个单元格记录行与列的关系
一个元素不只是一个孤立的数字。在上述约定下, 回答了一个精确的问题:
哪个权重把输入特征 连接到输出规则 ?
答案来自索引,而不是单纯来自颜色或位置。例如, 属于输出规则 2 和输入特征 1。整个第二行
存储一个输出的系数。整个第二列
收集两个输出中的新近程度系数。
这种行解释属于本课使用的权重约定;并不是每个矩阵的行都普遍表示“输出”。例如,数据集矩阵可能让每一行放置一个观测。根据形状推理之前,务必先说清楚各条轴的契约。
NumPy 让两条轴都可检查
NumPy 用二维 ndarray 表示这个网格。它的 shape 属性返回轴长度组成的元组。基本的 ndarray 索引从零开始,因此 Python 位置 0 对应数学索引 。
import numpy as np
weights = np.array([
[0.8, -0.4, 0.2],
[0.1, 0.6, -0.5],
], dtype=float)
print("shape:", weights.shape)
print("number of axes:", weights.ndim)
print("number of entries:", weights.size)
print("row 2:", weights[1, :])
print("column 3:", weights[:, 2])
print("w_23:", weights[1, 2])
验证输出:
shape: (2, 3)
number of axes: 2
number of entries: 6
row 2: [ 0.1 0.6 -0.5]
column 3: [ 0.2 -0.5]
w_23: -0.5
索引中的标点很重要:
| 目标选择 | 数学描述 | NumPy 表达式 | 结果 |
|---|---|---|---|
| 一个元素 | 第 2 行、第 3 列 | weights[1, 2] | -0.5 |
| 一行 | 第 2 行的每一列 | weights[1, :] | [0.1, 0.6, -0.5] |
| 一列 | 第 3 列的每一行 | weights[:, 2] | [0.2, -0.5] |
冒号表示“沿这条轴取每个位置”。单个整数固定一条轴。这形成了一个有用的调试顺序:先检查整个形状,然后检查一行,再检查一列,最后检查那个含义受到质疑的确切元素。
形状检查应当编码模型契约,而不只是把它打印出来:
expected_shape = (2, 3) # two outputs, three input features
if weights.shape != expected_shape:
raise ValueError(
f"expected {expected_shape}, got {weights.shape}; "
"check the output and input axes"
)
这个检查可以发现转置的数组。它无法发现无声的特征顺序变化,因为 [topic match, recency, source quality] 和 [recency, source quality, topic match] 的长度都为三。名称和来源信息必须保护语义契约。
全连接层暴露其输入与输出契约
当输入写成列向量 时,可以将该层概括为
相邻的大小预示了下一步运算:
三个输入坐标与 的三列相配;两行产生两个输出坐标。第 19 课将把这个矩阵-向量乘积计算为加权和。现在,仅凭维度就能揭示提出的对象是否符合这一约定。
当前的 torch.nn.Linear 文档使用相同的存储权重布局:in_features=3、out_features=2 的层有一个形状为 (out_features, in_features),即 (2, 3) 的权重张量。PyTorch 通常把批量输入写成特征位于最后一条轴,并将运算表示为 。这种面向行的批量记号解释了显式转置;它不会改变存储权重的两行三列契约。
在这个定义下,偏置不是第三个矩阵列,而是一个独立的两坐标向量,每个输出一个偏移。因此,本例中的带偏置层有六个权重标量和两个偏置标量。
三个形状捷径会产生错误的心智模型
还有一个普通课堂记号常常隐含不说的软件边界。本课定义 ,所以每个矩阵至少有一行和一列。然而 NumPy 仍然可以构造形状为 (0, 3) 或 (2, 0) 的数组。这样的数组有两条轴和零个元素,但不能作为上面那个双输出、三输入的权重网格。框架的形状规则和数学模型的含义必须同时通过检查。
行已经为下一步运算做好准备
矩阵之所以紧凑,是因为它同时履行两个承诺。第一条轴保留输出规则的集合;第二条轴让每条规则都对齐到同一个有序输入特征集合。这样的组织使 在算术开始前就可读,也让错误的转置在进入训练运行前就显现出来。
下一节符合先修顺序的课程会把一个输入向量放到这个网格旁边。届时每一行会形成一个加权和,把 的组织变成一个两坐标结果。Math for AI 课程页面将有序课程及其先修关系放在一起。
检查你的理解
Question 1
设 B = [[3, −1, 4], [0, 5, 2]]。写出它的维度、元素总数、b₁₃ 和 b₂₁。
Show the step-by-step solution
先数行: 有两个水平行,因此 。每一行有三个元素,因此 。所以
对于 ,选择第 1 行,再选择第 3 列;那里的值是 。对于 ,选择第 2 行,再选择第 1 列;那里的值是 。因此 且 。索引顺序是先行后列。
Question 2
两条输出规则使用输入 x₁、x₂ 和 x₃:s₁ = 2x₁ + 0x₂ − x₃,s₂ = 0.5x₁ + 3x₂ + 4x₃。每条规则放一行,构造矩阵并验证两个元素。
Show the step-by-step solution
有两条输出规则,因此矩阵需要两行。每条规则使用三个有序输入,因此需要三列。按 的顺序保留每条规则的系数:
规则 1 中 的系数位于第 1 行、第 3 列,所以 。规则 2 中 的系数位于第 2 行、第 2 列,所以 。这些检查与两条原始规则一致。
Question 3
对于本课的权重矩阵 W,哪些 NumPy 表达式可以选择数学元素 w₂₃、第 2 行的全部元素和第 3 列的全部元素?解释从 1 开始到从 0 开始的偏移。
Show the step-by-step solution
本课的数学索引从 开始,而 NumPy 位置从 0 开始。用直接的 NumPy 选择时,把每个数学索引减一:
- 变为
weights[1, 2],返回-0.5; - 第 2 行变为
weights[1, :],返回[0.1, 0.6, -0.5];以及 - 第 3 列变为
weights[:, 2],返回[0.2, -0.5]。
冒号让该轴不受限制;整数把另一条轴固定在一个从零开始的位置。
Question 4
一个全连接层有五个输入特征、四个输出单元,并且每个输出有一个偏置。权重矩阵的形状是什么?该层包含多少个可训练标量?
Show the step-by-step solution
使用 (out_features, in_features) 约定,四个输出单元提供行,五个输入特征提供列:
权重矩阵包含 个标量。偏置向量对四个输出中的每一个都有一个元素,因此还贡献 个。总数为
个可训练标量。偏置数量应当单独相加;它不会把矩阵从 改成 。
Question 5
开发者想要一个三输入、双输出层,却发现 weights.shape == (3, 2)。诊断轴错误,并说明一个安全的下一步。
Show the step-by-step solution
预期的存储布局是 (out_features, in_features)。两个输出、三个输入的预期形状是 (2, 3),而不是 (3, 2)。
观察到的形状把三个输入特征组放在了行轴,把两个输出组放在了列轴。如果这些值本来就是按每列一条输出规则构造的,weights.T 会产生形状 (2, 3)。但盲目转置并不安全:先验证特征和输出标签,只有标签确认轴确实有意颠倒时才转置。修复形状必须保留语义。
Question 6
矩阵 C = [[1, 2, 3, 4]] 和 D = [[1], [2], [3], [4]] 包含相同的四个值。为什么它们不能互换?
Show the step-by-step solution
有一行四列,因此 。它可以存储一个使用四个有序输入的规则。 有四行一列,因此 。它可以存储四个单元素行,或表示一个列向量。
它们的元素数量都等于 ,但轴长度不同,并且可以承载不同的含义。转置把它们联系起来,,但该操作会交换行和列。值相同且元素数量相同,不代表矩阵形状或契约相同。
Question 7
NumPy 可以创建 np.empty((0, 3))。它的形状和大小是什么?为什么它不能替代本课的双输出、三输入权重矩阵?
Show the step-by-step solution
传给 np.empty 的元组就是数组的形状,因此结果的形状为 (0, 3):零行、三列。元素数量是轴长度的乘积:
本课的层需要两条输出规则,因此需要两行。这个空数组不存储任何元素。它的三列轴恰好与输入特征数量匹配,但缺失的输出轴违反了模型契约。形状有效的 NumPy 数组并不自动成为某个特定层有用的矩阵。
Question 8
在矩阵图中,w₂₃ = −0.5。说明它代表的关系。这个负权重是否证明最终的审核优先级输出会是负数?
Show the step-by-step solution
按顺序读取索引。第一个索引 选择第 2 行,即审核优先级输出规则。第二个索引 选择第 3 列,即来源质量输入特征。因此 是把来源质量连接到审核优先级规则的系数。
这一个系数不能决定最终输出的符号。输出还取决于 的实际值、另外两个加权输入贡献以及任何偏置。矩阵元素命名了一条关系;下一课的加权和计算会组合所有贡献。