🧩 第一部分:图像处理与可视化(OpenCV + Matplotlib)
1. 颜色空间的"语言不通"问题
-
是什么 :
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)是颜色编码转换器。 -
有什么用 :OpenCV 内部存储是 BGR (蓝绿红),而 Matplotlib/PIL/网页是 RGB(红绿蓝)。如果不转换,用 plt 显示时颜色会严重失真(蓝色变红色)。
-
为什么这样设计(易错) :OpenCV 诞生于 90 年代的 C 语言底层优化,硬件早期偏爱 BGR 排列,这形成了历史包袱。易错点 :如果你先用
cv2.imread读图,直接丢给plt.imshow,必蓝;务必在显示前cv2.cvtColor(img, cv2.COLOR_BGR2RGB)。
2. Matplotlib 布局与直方图调参
-
plt.subplot(1, 2, 1):画布分割器。作用:1行2列,激活第1个位置(左半边)。 -
plt.xlim([0, 256]):X轴锁定。作用 :强制直方图的 X 轴显示 0~255(像素全范围)。易错:图像直方图不设 xlim 时,若像素集中在暗部,坐标轴会自动缩放到局部,导致视觉对比误导。 -
plt.grid(alpha=0.3):网格辅助线。alpha=0.3控制半透明,防止喧宾夺主。
3. 路径与布局防重叠
-
os.getcwd():获取当前 Python 解释器运行的工作目录(非脚本所在目录)。易错 :在 Jupyter 中它返回启动目录;在 PyCharm 中返回项目根目录。写文件路径时建议用os.path.join(os.getcwd(), 'data')保证跨平台。 -
plt.tight_layout():自动调整子图间距,杜绝标题与坐标轴重叠。必须放在plt.show()之前。
🔢 第二部分:PyTorch 张量核心操作(张量维度与梯度切割)
1. 维度操控(AI模型的"形状规矩")
-
unsqueeze(0):在第 0 维插入一个维度,大小为 1。作用 :将[C, H, W]的单张图变成[1, C, H, W]的 Batch。因为 PyTorch 所有网络(如 ResNet)都强制要求输入为 4 维 (N, C, H, W)。 -
tensor.dim():返回张量维度数量(秩)。易错 :区分size()(形状元组)和dim()(维度个数,如标量是 0,向量是 1)。
2. 梯度切割三兄弟(防爆显存与防误传)
| 操作 | 作用范围 | 核心本质 | 典型场景 |
|---|---|---|---|
.item() |
仅限标量张量 | 提取 Python 数值,切断计算图。 | 打印 Loss 数值。 |
.detach() |
单个张量 | 返回新张量,共享数据内存 ,但 requires_grad=False。 |
提取目标特征图(target)用于 Loss 计算,但防止梯度更新目标。 |
torch.no_grad() |
上下文代码块(缩进内所有代码) | 关闭整个 Autograd 引擎,不追踪任何操作,省显存提速。 | 验证集评估、推理、提取固定特征。 |
.clone() |
单个张量 | 深拷贝数据内存 ,完全独立(配合 .detach() 使用)。 |
将 GPU 上的模型输出转为 CPU 图片,防止后续原地操作污染原梯度。 |
💡 致命易错:
-
detach()只是切断了梯度追踪,依然和原张量共享内存 。如果你修改detach()后的数据,原张量也会变(虽然原地操作会报错)。 -
no_grad()是上下文管理器,必须用with缩进。若忘记加,验证集前向传播会构建计算图,导致显存爆炸(OOM)。
🧠 第三部分:模型构建(torch.nn 宇宙全解)
(对应你超长的 nn 模块笔记)
1. 三大核心容器(骨架)
-
nn.Module:所有模型的祖宗。必须继承它,并在__init__定义层,forward写计算逻辑。 -
nn.Sequential:流水线作业。适合串行结构(如Conv -> BN -> ReLU)。局限:无法处理残差连接(ResNet)或循环拼接(RNN)。 -
nn.ModuleList/ModuleDict:用于存放多个层,方便for循环遍历(如 Transformer 的 12 层解码器)。注意 :它只是个列表,不会自动传递数据 ,你必须手写for layer in self.layers: x = layer(x)。
2. 线性层与循环层(NLP/时序核心)
-
nn.Linear(in, out):全连接层,做y = xA^T + b。 -
nn.RNN/nn.LSTM/nn.GRU:处理序列。输入要求(seq_len, batch, features)。 -
易错点 :
nn.GRU和nn.RNN默认batch_first=False。如果你习惯传(batch, seq, feature),必须设置batch_first=True,否则形状会错乱。
3. 卷积层(DCGAN 上采样秘技)
-
nn.ConvTranspose2d(转置卷积) :用于上采样(放大图像)。黄金参数 :kernel_size=4, stride=2, padding=1实现尺寸完美翻倍(输入 1x1 → 输出 4x4)。 -
nn.PixelShuffle(像素洗牌) :另一种上采样方式,将通道数压缩为空间分辨率。对比:转置卷积易产生"棋盘格伪影",PixelShuffle 更平滑,常被用于超分辨率(ESRGAN)。
4. 激活函数与归一化(稳定训练的根基)
-
激活选型:
-
ReLU :最常用,
max(0,x),但易导致神经元"坏死"(负数永远变 0)。 -
LeakyReLU:给负数微小斜率(如 0.01),防坏死。
-
Tanh:输出 -1~1,DCGAN 生成器最后一层强制用 Tanh。
-
-
归一化选型:
-
BatchNorm :依赖批次(Batch),CV 任务首选。易错 :训练时用
model.train()(统计当前 batch 均方差),验证时必须model.eval()(使用全局滑动均方差),否则结果崩盘。 -
LayerNorm:不依赖批次,Transformer/NLP 用得多。
-
5. 损失函数(判分标尺)
| 损失函数 | 内部是否带 Softmax | 输入要求 | 结论 |
|---|---|---|---|
nn.CrossEntropyLoss |
是(自带 LogSoftmax) | 原始分数(Logits),任意实数 | 工业界标准,一步到位,防数值溢出。 |
nn.NLLLoss |
否 | 必须已是 对数概率 (log_softmax 输出,负数) |
99% 场景不单独使用。若忘了在外面加 log_softmax,Loss 会变成负无穷,训练彻底失败。 |
⚖️ 第四部分:权重初始化哲学(决定能否收敛)
-
nn.init.normal_(weight, 0.0, 0.02):高斯初始化。DCGAN 的标准做法(均值 0,标准差 0.02)。 -
nn.init.constant_(bias, 0):偏置置零。因为 BatchNorm 自带 β 偏置,卷积层的 bias 可以安全设为 0。
核心对比:Kaiming vs 正交初始化
| 对比维度 | Kaiming 初始化 (kaiming_normal_) |
正交初始化 (orthogonal_) |
|---|---|---|
| 保护对象 | 保护信号方差(防止梯度消失/爆炸) | 保护向量长度(范数)(防止方向扭曲) |
| 最佳搭档 | CNN + ReLU(视觉任务绝对王者) | RNN / LSTM(处理极长序列) / StyleGAN 映射网络 |
| 实战铁律 | 视觉任务无脑选 Kaiming。 | 若你的网络深度 > 50 层且全是全连接,正交是救命稻草。 |
易错:初始化并非越随机越好。标准差设为 0.02 是为了配合 ReLU 的稀疏性;若标准差太大(如 0.1),深层输出会迅速发散为 NaN。
🔄 第五部分:训练机制(从手动求导到自动微分)
1. 底层透视(Numpy 手写 vs PyTorch 自动)
-
np.random.randn:生成标准正态分布(均值 0,方差 1)占位数据。 -
x.dot(w1)(矩阵乘法) :线性变换,改变形状(如 64x1000 → 64x100)。 -
np.maximum(h, 0)(ReLU) :非线性激活,不改变形状,只修剪负数。 -
手动反向传播 :必须按前向的严格逆序 手写链式法则(先算
grad_w2,再截断 ReLU 梯度,最后算grad_w1)。极其繁琐且易错。 -
PyTorch Autograd :只需
loss.backward(),框架自动构建计算图并填充.grad。易错 :PyTorch 默认累加梯度 (为了支持大 batch 拆分为小 batch 模拟),每次optimizer.step()后必须optimizer.zero_grad(),否则梯度会叠加爆炸。
2. 数据管道(DataLoader)
-
shuffle=True:训练集开启,打乱顺序防止模型记忆样本;验证集必须 False,保持可复现性。 -
num_workers:多进程读取。Windows 致命坑 :必须把 DataLoader 放在if __name__ == '__main__':下,否则会递归创建进程导致死锁。
3. 优化器选择(LBFGS vs Adam)
-
Adam / SGD:一阶梯度下降,适合大规模非凸问题(深度学习 99% 场景)。
-
LBFGS(拟牛顿法) :二阶方法,收敛极快,但内存占用巨大 ,且必须传入
closure函数(多次重新计算 Loss)。仅限 :小批量、平滑凸问题(如逻辑回归、传统稀疏编码)。深度学习慎用。
🚀 第六部分:模型导出与部署(ONNX + TorchScript)
1. ONNX(AI界的"通用翻译官")
-
是什么 :开放神经网络交换格式,存储为
.onnx二进制文件(Protobuf 序列化)。 -
有什么用:打破 PyTorch 和 TensorFlow 的壁垒。你可以用 PyTorch 训练,导出 ONNX,再用 NVIDIA TensorRT 或 ONNX Runtime 在 C++ 环境下极速推理。
-
易错 :ONNX 不支持动态控制流 (如
if或变化长度的循环)以及自定义算子。如果你的模型里有nn.GRU且batch_first=True,ONNX 导出时可能会产生冗余的Transpose节点,需用opset_version控制。
2. TorchScript(JIT) vs 普通 torch.save
| 对比维度 | torch.save (研究态) |
torch.jit.save / torch.jit.load (生产态) |
|---|---|---|
| 包含内容 | 仅权重(state_dict) |
结构(计算图)+ 权重 融为一体 |
| 运行时依赖 | 必须有 原始 Python 类定义(class Net) |
完全脱离 Python,可在 C++ / Java / iOS 运行 |
| 灵活性 | 极高(支持动态图修改) | 冻结为静态图,无法改动 |
| 获取对象 | nn.Module 子类实例 |
torch.jit.ScriptModule(不再依赖源码) |
易错 :torch.jit.trace 只能跟踪输入路径下的操作,若模型中有 if data.sum() > 0 这种数据依赖分支,trace 会失效,必须改用 torch.jit.script(编译 Python AST)。
🎯 第七部分:DCGAN 专项细节
-
weights_init遍历陷阱 :model.apply(weights_init)会递归寻找子模块。若用find('Conv')字符串判断,漏掉Linear全连接层 。若生成器有全连接映射网络,需手动补全elif isinstance(m, nn.Linear)。 -
转置卷积输出计算公式 :
Output = (Input - 1) * Stride - 2 * Padding + Kernel_Size。套用k=4, s=2, p=1,输出正好翻倍(例如1 -> 4 -> 8 -> 16 -> 32 -> 64)。 -
Tanh 输出层 :生成器末尾必须用
Tanh,且bias=False(因为紧跟着的 BatchNorm 自带 β,再设 bias 会冗余)。易错 :输入噪声通常是 100 维向量,必须unsqueeze(2).unsqueeze(3)变成(batch, 100, 1, 1)才能喂给转置卷积。
⚠️ 最终"易错急救清单"(金句总结)
-
颜色:OpenCV 读图是 BGR,显示用 Matplotlib 记得转 RGB。
-
维度 :任何预训练模型输入都必须是 4 维
(N,C,H,W),单张图必须unsqueeze(0)。 -
梯度 :验证集推理必须 套
with torch.no_grad(),否则显存泄漏。 -
清零 :
optimizer.step()之前 必须optimizer.zero_grad()。 -
模式切换 :含有 BN 或 Dropout 的模型,验证/测试时必须
model.eval(),训练时model.train()。 -
损失 :用了
CrossEntropyLoss就不要再手动加 Softmax,否则双重激活导致梯度消失。 -
导出 :生产部署用
torch.jit.save摆脱 Python 依赖;跨框架用 ONNX。