线性层(全连接层)
阅读时长:约 10 分钟 难度等级:入门 读完你将学会:理解线性层的数学本质、掌握参数量计算、理解权重和偏置的作用
要点速览
- 线性层执行仿射变换:
- 权重矩阵的每一行是一个特征检测器
- 参数量 = 输入维度 × 输出维度 + 输出维度
前置知识
阅读本文前,你需要了解:
- 张量与维度 - 理解矩阵乘法
本文不假设你了解:
- 任何深度学习框架
- 复杂的线性代数
什么是线性层?
线性层(Linear Layer)也称为全连接层(Fully Connected Layer)或密集层(Dense Layer),是神经网络最基本的构建块。
它执行仿射变换(Affine Transformation):
其中:
:输入向量( 维) :权重矩阵( 行 列) :偏置向量( 维) :输出向量( 维)
线性变换的几何意义
线性变换可以理解为对输入空间的旋转、缩放和剪切。
输入空间 (n维) → 线性变换 W → 输出空间 (m维)
↑ ↑
x y = Wx + b权重矩阵 W 的作用
- 每一行
代表一个"探测器",检测输入的某种特征 计算输入与该探测器的相似度 - 输出维度
就是特征的数量
偏置 b 的作用
- 控制激活的阈值
- 提供平移能力,使决策边界不必过原点
python
# 片段:线性层的实现
import numpy as np
class Linear:
"""
线性层(全连接层)
参数:
in_features: 输入特征数
out_features: 输出特征数
"""
def __init__(self, in_features, out_features):
# Xavier 初始化
scale = np.sqrt(2.0 / (in_features + out_features))
self.W = np.random.randn(out_features, in_features) * scale
self.b = np.zeros(out_features)
# 缓存用于反向传播
self.input = None
def forward(self, x):
"""
前向传播
参数:
x: 输入 (batch_size, in_features) 或 (in_features,)
返回:
y: 输出 (batch_size, out_features) 或 (out_features,)
"""
self.input = x
return x @ self.W.T + self.b
def backward(self, grad_output):
"""
反向传播
参数:
grad_output: 来自上一层的梯度
返回:
grad_input: 传给下一层的梯度
grad_W: 权重梯度
grad_b: 偏置梯度
"""
if self.input.ndim == 1:
grad_W = np.outer(grad_output, self.input)
grad_b = grad_output
else:
grad_W = grad_output.T @ self.input
grad_b = np.sum(grad_output, axis=0)
grad_input = grad_output @ self.W
return grad_input, grad_W, grad_b上述代码实现了线性层:
参数说明:
| 参数 | 形状 | 说明 |
|---|---|---|
W | (out_features, in_features) | 权重矩阵 |
b | (out_features,) | 偏置向量 |
x | (batch_size, in_features) | 输入数据 |
逐行解释:
scale = np.sqrt(2.0 / (in_features + out_features)) - Xavier 初始化的缩放因子,保持前向和反向传播时方差一致。
x @ self.W.T + self.b - 执行线性变换,注意转置操作使维度匹配。
grad_output.T @ self.input - 权重梯度,使用矩阵乘法批量计算。
参数量计算
线性层的参数量计算:
示例:
| 层配置 | 权重参数 | 偏置参数 | 总参数 |
|---|---|---|---|
| Linear(784, 128) | 784 × 128 = 100,352 | 128 | 100,480 |
| Linear(128, 64) | 128 × 64 = 8,192 | 64 | 8,256 |
| Linear(64, 10) | 64 × 10 = 640 | 10 | 650 |
python
# 片段:计算参数量
def count_parameters(in_features, out_features):
"""计算线性层的参数量"""
weight_params = in_features * out_features
bias_params = out_features
return weight_params + bias_params
# 示例
print(f"Linear(784, 128): {count_parameters(784, 128):,} 参数")
print(f"Linear(128, 64): {count_parameters(128, 64):,} 参数")
print(f"Linear(64, 10): {count_parameters(64, 10):,} 参数")为什么需要非线性?
如果只有线性层,无论叠加多少层,最终仍然是线性变换:
这就是为什么需要激活函数引入非线性。
本节要点
记住这三点:
- 线性层执行仿射变换
- 权重矩阵的每一行是一个特征检测器
- 参数量 = 输入维度 × 输出维度 + 输出维度
更新日志
| 日期 | 内容 |
|---|---|
| 2026-03-28 | 初稿发布 |