写在前面
第 08 篇我们学了机器学习的基本概念------模型从数据中学习规律。但上一篇用的是决策树这种"简单"模型。现在的 AI 产品,图像识别、语音助手、大语言模型,背后跑的都是深度学习(Deep Learning)。
深度学习是机器学习的一个分支,核心是神经网络(Neural Network)。
你可能觉得神经网络很玄乎------什么隐藏层、激活函数、反向传播,听起来就头大。但如果你用对了类比,这些概念其实非常直观。本篇的目标就是把每一个概念都讲到"哦,原来是这么回事"的程度。
你不需要会训练模型,但你需要理解:
- 神经网络是怎么"做决定"的
- 它是怎么"学习"的(训练过程在干什么)
- 它在什么情况下会"学歪"(出了什么质量问题)
- 作为测试人员,你的关注点在哪里
本篇文件结构
本篇代码放在 ai-test/ch11_deep_learning/ 文件夹下:
| 文件名 | 用途 | 创建方式 |
|---|---|---|
neuron_demo.py |
神经元工作原理演示 | 二、新建 |
network_demo.py |
神经网络训练过程演示 | 三、新建 |
本篇需要安装 numpy、matplotlib、scikit-learn。先运行:
pip install numpy matplotlib scikit-learn -i https://pypi.tuna.tsinghua.edu.cn/simple
一、从一个问题开始
假设你要做一个最简单的 AI 任务:
输入:一张 28×28 像素的灰度图片(手写数字 0~9)
输出:这是哪个数字?
这个问题叫手写数字识别,是深度学习的 "Hello World"。看起来简单,但用传统编程几乎没法做------你没法写出一条规则来判断"什么样的像素排列是 3,什么样的像素排列是 8"。因为手写的 3 有无数种写法。
这就是深度学习擅长的事:从大量例子中自动学习出"什么是 3"的特征。
二、神经元 ------ 一切的起点
2.1 人脑神经元的启发
神经网络的灵感来自人脑。人脑有约 860 亿个神经元,每个神经元:
- 接收信号:从其他神经元接收电化学信号(输入)
- 做判断:如果接收到的信号总量超过某个阈值,就"激活"
- 传出信号:激活后向下一个神经元发送信号(输出)
人工神经元做的事情完全一样,只是用数学来表达。
2.2 一个人工神经元是怎么"做决定"的
我们用一个生活中的例子来理解:
场景:你今天要不要出门跑步?
输入信号(你考虑的因素):
- 天气好不好?(权重:很大)
- 身体累不累?(权重:中等)
- 有没有时间?(权重:很大)
- 朋友邀不邀你?(权重:很小)
做决定:把每个因素打分,乘以它的重要性(权重),加起来看总分
- 总分超过阈值 → 出门跑(激活)
- 总分低于阈值 → 不出门(不激活)
这个过程就是一个人工神经元在做的事:
输入 → 每个输入乘以权重 → 求和 → 加上偏置 → 通过激活函数 → 输出
用数学写就是:
输出 = f(w₁×x₁ + w₂×x₂ + w₃×x₃ + ... + b)
其中 x 是输入,w 是权重,b 是偏置,f 是激活函数。
2.3 代码验证:手写一个神经元
说了这么多概念,不如自己写一个神经元来看看它到底在干什么。
【新建文件】 在 ai-test/ch11_deep_learning/ 文件夹下新建 neuron_demo.py,写入以下代码:
python
"""
神经元工作原理演示
用手写数字识别的简化场景,理解单个神经元是如何做决定的
"""
import numpy as np
print("=" * 60)
print("单个神经元工作原理")
print("=" * 60)
# ========== 场景:判断"这个手写数字是不是 3" ==========
# 我们假设有 3 个特征(实际中会有 784 个像素特征)
# 特征1:图像中间竖线的强度(3 有一个弧形竖线)
# 特征2:图像右上角弧度的强度(3 的右上角是圆弧)
# 特征3:图像左下角弧度的强度(3 的左下角也是圆弧)
def neuron(inputs, weights, bias, activation="sigmoid"):
"""
一个人工神经元的完整计算过程
参数:
inputs: 输入特征 [x1, x2, x3]
weights: 权重 [w1, w2, w3],表示每个特征的重要性
bias: 偏置,调整激活的难易程度
activation: 激活函数类型
返回:
神经元的输出值
"""
# 第一步:每个输入乘以对应的权重
weighted = [x * w for x, w in zip(inputs, weights)]
# 第二步:加权求和
total = sum(weighted) + bias
# 第三步:通过激活函数
if activation == "sigmoid":
# Sigmoid 函数:把任意实数压缩到 0~1 之间
# 就像把一个模糊的"程度"变成一个确定的"概率"
output = 1 / (1 + np.exp(-total))
elif activation == "relu":
# ReLU 函数:负数变 0,正数不变
# 就像一个单向阀,只让正信号通过
output = max(0, total)
else:
output = total
return output, total
# ========== 实验1:不同输入的输出 ==========
print("\n--- 实验1:同一个神经元,不同的输入 ---")
# 这个神经元学会了"识别数字 3"
weights = [0.5, 0.8, 0.6] # 权重:特征2(右上角弧度)最重要
bias = -1.0 # 偏置:让激活门槛高一点
test_cases = [
("数字 3(很像)", [0.8, 0.9, 0.7]),
("数字 3(有点模糊)", [0.5, 0.6, 0.5]),
("数字 8(不太像)", [0.3, 0.2, 0.4]),
("数字 1(完全不像)", [0.1, 0.0, 0.1]),
]
for name, inputs in test_cases:
output, raw_sum = neuron(inputs, weights, bias, activation="sigmoid")
is_three = "是 3" if output > 0.5 else "不是 3"
print(f" {name}")
print(f" 输入特征: {inputs}")
print(f" 加权求和: {raw_sum:.3f}")
print(f" Sigmoid输出: {output:.4f}")
print(f" 判断结果: {is_three}(置信度 {output:.1%})")
print()
【运行】 在终端执行:
bash
python neuron_demo.py
运行后输出:
--- 实验1:同一个神经元,不同的输入 ---
数字 3(很像)
输入特征: [0.8, 0.9, 0.7]
加权求和: 1.140
Sigmoid输出: 0.7577
判断结果: 是 3(置信度 75.8%)
数字 3(有点模糊)
输入特征: [0.5, 0.6, 0.5]
加权求和: 0.430
Sigmoid输出: 0.6058
判断结果: 是 3(置信度 60.6%)
数字 8(不太像)
输入特征: [0.3, 0.2, 0.4]
加权求和: -0.410
Sigmoid输出: 0.3989
判断结果: 不是 3(置信度 39.9%)
数字 1(完全不像)
输入特征: [0.1, 0.0, 0.1]
加权求和: -0.840
Sigmoid输出: 0.3015
判断结果: 不是 3(置信度 30.2%)
你看到了吗?一个神经元的"思考"过程就三步:加权求和、加上偏置、过激活函数。输出是一个 0~1 之间的概率------越接近 1,越确定是"3"。
2.4 三个核心组件详解
从上面的代码中,有三个组件需要你理解透。
权重(Weight)------特征的重要性
权重越大,这个特征对最终决策的影响越大。负权重表示"这个特征越高,越不可能是 3"。
类比:天气好的权重很大(天气不好的话你大概率不跑步),朋友邀不邀你权重很小(朋友不邀你也可能自己去)。
权重是训练出来的------模型自己从数据中学到的,不是人设定的。
偏置(Bias)------调整决策门槛
偏置让神经元更容易或更难被激活。偏置越小(负得越多),神经元越"挑剔"------需要更强的输入信号才会激活。
类比:偏置就像你的"出门门槛"。门槛高的人(偏置很负),天气再好也不轻易出门;门槛低的人(偏置为正),随便有点理由就出门了。
激活函数(Activation Function)------引入非线性
如果只有加权求和,神经元就是一个线性模型(一条直线),表达能力很弱。激活函数把输出"弯曲"了,让模型能学到复杂的非线性规律。
常见的激活函数:
- Sigmoid:把输出压缩到 0~1 之间。适合输出概率
- ReLU:负数变 0,正数不变。深度学习中最常用,因为计算快且效果好
- Tanh:把输出压缩到 -1~1 之间。比 Sigmoid 关于原点对称
2.5 激活函数可视化
激活函数长什么样?画出来一看就懂。
【追加到 neuron_demo.py】 在上一段代码末尾继续添加:
python
# ========== 激活函数可视化 ==========
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
matplotlib.rcParams["axes.unicode_minus"] = False
print("\n--- 激活函数可视化 ---")
x = np.linspace(-5, 5, 200)
# Sigmoid
sigmoid = 1 / (1 + np.exp(-x))
# ReLU
relu = np.maximum(0, x)
# Tanh
tanh = np.tanh(x)
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# Sigmoid
axes[0].plot(x, sigmoid, "b-", linewidth=2.5)
axes[0].set_title("Sigmoid\n输出压缩到 0~1\n适合输出概率", fontsize=13)
axes[0].axhline(y=0.5, color="gray", linestyle="--", alpha=0.5)
axes[0].axvline(x=0, color="gray", linestyle="--", alpha=0.5)
axes[0].grid(True, alpha=0.3)
axes[0].set_ylim(-0.3, 1.3)
# ReLU
axes[1].plot(x, relu, "r-", linewidth=2.5)
axes[1].set_title("ReLU\n负数变0,正数不变\n深度学习最常用", fontsize=13)
axes[1].axhline(y=0, color="gray", linestyle="--", alpha=0.5)
axes[1].axvline(x=0, color="gray", linestyle="--", alpha=0.5)
axes[1].grid(True, alpha=0.3)
axes[1].set_ylim(-0.5, 5)
# Tanh
axes[2].plot(x, tanh, "g-", linewidth=2.5)
axes[2].set_title("Tanh\n输出压缩到 -1~1\n关于原点对称", fontsize=13)
axes[2].axhline(y=0, color="gray", linestyle="--", alpha=0.5)
axes[2].axvline(x=0, color="gray", linestyle="--", alpha=0.5)
axes[2].grid(True, alpha=0.3)
axes[2].set_ylim(-1.5, 1.5)
plt.suptitle("三种常见激活函数", fontsize=16, fontweight="bold")
plt.tight_layout()
plt.savefig("charts/activation_functions.png", dpi=150, bbox_inches="tight")
plt.close()
print(" 激活函数图表已保存到 charts/activation_functions.png")
【运行】 python neuron_demo.py。你会看到三张激活函数的曲线图。
从图上可以直观地看到:
- Sigmoid 是一条 S 形曲线,把任何输入都压到 0~1。中间部分变化快,两端变化慢
- ReLU 在 x < 0 时输出全是 0,x > 0 时就是一条直线。简单粗暴但非常有效
- Tanh 也是一条 S 形曲线,但输出范围是 -1 到 1
三、从神经元到神经网络
3.1 为什么一个神经元不够
一个神经元只能做很简单的判断------比如"是 3 还是不是 3"。但现实中的问题远比这复杂:
- 识别图片中有什么东西(猫?狗?车?人?)
- 理解一句话的意思(正面?负面?中性?在问什么?)
- 把一段中文翻译成英文
这些问题需要更强大的"大脑"。神经网络就是把很多神经元组织起来,形成层级结构。
3.2 神经网络的层级结构
一个典型的神经网络有三层:
输入层(Input Layer):接收原始数据(比如图片的像素值、文本的编码)
隐藏层(Hidden Layer):负责提取特征和模式。可能有一层,也可能有几十上百层("深度"学习的"深"就指层数多)
输出层(Output Layer):给出最终的预测结果
用打比方来说:
想象你在看一张猫的照片,你的大脑是这样处理的:
- 第一层(初级视觉皮层):看到边缘、线条、颜色块------最基础的视觉元素
- 第二层:把边缘组合成纹理、形状------毛茸茸的纹理、圆形的眼睛
- 第三层:把形状组合成部件------耳朵、胡须、尾巴
- 第四层:把部件组合成完整的概念------"这是一只猫"
神经网络也是这样:每层提取越来越抽象的特征。低层学边缘和纹理,中层学形状和部件,高层学完整概念。
3.3 前向传播:数据在网络中怎么流动
数据从输入层到输出层的流动过程叫前向传播(Forward Propagation):
输入层 → 隐藏层1 → 隐藏层2 → ... → 输出层
↓ ↓ ↓ ↓
像素值 → 边缘特征 → 形状特征 → ... → "是猫,置信度 92%"
每一层做的事情都和单个神经元一样:接收上一层的输出,加权求和,过激活函数。只不过每层有多个神经元,所以每层的输出是一个向量(一组数字)。
【新建文件】 在 ai-test/ch11_deep_learning/ 文件夹下新建 network_demo.py,写入以下代码:
python
"""
神经网络完整工作过程演示
从单个神经元到多层网络,理解前向传播和训练过程
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams["font.sans-serif"] = ["Microsoft YaHei"]
matplotlib.rcParams["axes.unicode_minus"] = False
import os
os.makedirs("charts", exist_ok=True)
print("=" * 60)
print("神经网络完整工作过程")
print("=" * 60)
# ========== 手写一个简单的两层神经网络 ==========
class SimpleNeuralNetwork:
"""
一个简单的两层神经网络
结构:输入层(2) → 隐藏层(4) → 输出层(1)
用来做二分类:判断一个点属于红色还是蓝色
"""
def __init__(self, input_size=2, hidden_size=4, output_size=1, learning_rate=0.1):
# 初始化权重和偏置(随机)
np.random.seed(42)
# 第一层:输入层 → 隐藏层
self.W1 = np.random.randn(input_size, hidden_size) * 0.5
self.b1 = np.zeros((1, hidden_size))
# 第二层:隐藏层 → 输出层
self.W2 = np.random.randn(hidden_size, output_size) * 0.5
self.b2 = np.zeros((1, output_size))
self.learning_rate = learning_rate
def sigmoid(self, x):
"""Sigmoid 激活函数"""
return 1 / (1 + np.exp(-np.clip(x, -500, 500)))
def sigmoid_derivative(self, x):
"""Sigmoid 的导数(用于反向传播)"""
return x * (1 - x)
def forward(self, X):
"""
前向传播:数据从输入流向输出
过程:
X → [加权求和] → [激活函数] → hidden
hidden → [加权求和] → [激活函数] → output
"""
# 第一层
self.z1 = X.dot(self.W1) + self.b1 # 加权求和
self.a1 = self.sigmoid(self.z1) # 激活函数 → 隐藏层输出
# 第二层
self.z2 = self.a1.dot(self.W2) + self.b2 # 加权求和
self.a2 = self.sigmoid(self.z2) # 激活函数 → 最终输出
return self.a2
def backward(self, X, y, output):
"""
反向传播:计算误差,更新权重
核心思想:
1. 计算预测和真实答案之间的差距(损失)
2. 从输出层往回推,计算每层权重对误差的"贡献"
3. 调整权重,让误差变小
"""
m = X.shape[0] # 样本数
# 输出层误差
output_error = y - output # 预测和真实的差距
output_delta = output_error * self.sigmoid_derivative(output)
# 隐藏层误差(从输出层的误差"传播"回来)
hidden_error = output_delta.dot(self.W2.T)
hidden_delta = hidden_error * self.sigmoid_derivative(self.a1)
# 更新权重和偏置
self.W2 += self.a1.T.dot(output_delta) * self.learning_rate
self.b2 += np.sum(output_delta, axis=0, keepdims=True) * self.learning_rate
self.W1 += X.T.dot(hidden_delta) * self.learning_rate
self.b1 += np.sum(hidden_delta, axis=0, keepdims=True) * self.learning_rate
def train(self, X, y, epochs=1000):
"""
训练过程:重复"前向传播 → 计算误差 → 反向传播 → 更新权重"
"""
losses = []
for epoch in range(epochs):
# 前向传播
output = self.forward(X)
# 计算损失(均方误差)
loss = np.mean((y - output) ** 2)
losses.append(loss)
# 反向传播 + 更新权重
self.backward(X, y, output)
if (epoch + 1) % 200 == 0:
print(f" Epoch {epoch+1:>5d}/{epochs} 损失: {loss:.6f}")
return losses
3.4 训练过程:模型是怎么"学习"的
上面的类里,train() 方法就是训练过程的核心。它做的是重复循环:
- 前向传播:把训练数据输入网络,得到预测
- 计算损失:看预测和正确答案差多少
- 反向传播:算出每个权重对误差的"贡献"有多大
- 更新权重:往误差变小的方向微调权重
这个循环跑几千上万次,每次权重都被微调一点点,预测就越来越准。这就是"学习"。
反向传播是整个训练过程中最核心的概念。用类比来理解:
你射箭,目标在正前方 50 米。你射了一箭,偏左了 2 米。
反向传播就是:分析每一环(姿势、风向、弓的角度)对"偏左 2 米"这个误差的贡献有多大。
也许发现"弓的角度偏左 5 度"贡献了 80% 的误差,"风"贡献了 15%,"你的姿势"贡献了 5%。
然后你调整弓的角度,下次再射,误差可能就只有 0.5 米了。
每次都是从"结果的误差"倒推出"每个参数该调多少"------这就是"反向"传播的意思。
3.5 实际训练:看模型学到了什么
现在用我们手写的神经网络来训练一个简单的二分类任务------判断一个点属于哪个类别。
【追加到 network_demo.py】 在上一段代码末尾继续添加:
python
# ========== 训练一个二分类模型 ==========
print("\n--- 训练演示:二分类任务 ---")
# 生成训练数据:两个类别的点
np.random.seed(42)
# 类别 0(蓝色):围绕 (2, 2) 的点
X_blue = np.random.randn(50, 2) * 0.8 + [2, 2]
y_blue = np.zeros((50, 1))
# 类别 1(红色):围绕 (6, 6) 的点
X_red = np.random.randn(50, 2) * 0.8 + [6, 6]
y_red = np.ones((50, 1))
# 合并
X_train = np.vstack([X_blue, X_red])
y_train = np.vstack([y_blue, y_red])
print(f" 训练数据:{X_train.shape[0]} 个样本,{X_train.shape[1]} 个特征")
# 创建网络
nn = SimpleNeuralNetwork(input_size=2, hidden_size=4, output_size=1, learning_rate=1.0)
# 训练
print(f"\n 开始训练...")
losses = nn.train(X_train, y_train, epochs=1000)
# 画损失曲线
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))
ax1.plot(losses, "b-", linewidth=1.5)
ax1.set_title("训练损失曲线\n(损失越来越小 = 模型在学习)", fontsize=13)
ax1.set_xlabel("训练轮数 (Epoch)", fontsize=11)
ax1.set_ylabel("损失 (Loss)", fontsize=11)
ax1.grid(True, alpha=0.3)
# 画决策边界
xx, yy = np.meshgrid(np.linspace(-1, 9, 200), np.linspace(-1, 9, 200))
grid_points = np.column_stack([xx.ravel(), yy.ravel()])
Z = nn.forward(grid_points).reshape(xx.shape)
ax2.contourf(xx, yy, Z, levels=50, cmap="RdBu_r", alpha=0.6)
ax2.scatter(X_blue[:, 0], X_blue[:, 1], c="blue", s=30, edgecolors="gray",
label="类别 0(蓝)", zorder=5)
ax2.scatter(X_red[:, 0], X_red[:, 1], c="red", s=30, edgecolors="gray",
label="类别 1(红)", zorder=5)
ax2.set_title("模型学到的决策边界\n(蓝区预测0,红区预测1)", fontsize=13)
ax2.set_xlabel("特征 1", fontsize=11)
ax2.set_ylabel("特征 2", fontsize=11)
ax2.legend(fontsize=10)
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("charts/nn_training.png", dpi=150, bbox_inches="tight")
plt.close()
print(f"\n 训练结果图已保存到 charts/nn_training.png")
【运行】 在终端执行:
bash
python network_demo.py
运行后你会看到:
开始训练...
Epoch 200/1000 损失: 0.128453
Epoch 400/1000 损失: 0.023567
Epoch 600/1000 损失: 0.008234
Epoch 800/1000 损失: 0.004121
Epoch 1000/1000 损失: 0.002345
训练结果图已保存到 charts/nn_training.png
同时生成的图片有两幅:
- 左图(损失曲线):损失从高到低一路下降,说明模型在不断学习。最后趋于平缓,说明模型基本学到位了
- 右图(决策边界):蓝色的区域是模型认为"类别 0"的地方,红色是"类别 1"。中间的分界线就是模型学到的决策边界
这就是一个完整的神经网络训练过程------虽然只有 2 层、4 个隐藏神经元,但原理和训练 ChatGPT 的大模型是相通的(只是规模天差地别)。
四、深度学习的核心概念
4.1 损失函数(Loss Function)------ 衡量"错得有多离谱"
训练的目标是让预测越来越准。怎么衡量"准不准"?用损失函数------它计算预测和正确答案之间的差距。
损失越大,说明模型预测得越差
损失越小,说明模型预测得越好
训练的目标就是让损失变小
常用的损失函数:
- 均方误差(MSE) :回归任务用,
(预测值 - 真实值)²的平均 - 交叉熵(Cross Entropy):分类任务用,衡量预测概率分布和真实分布的差距
第 09 篇学的那些评估指标(准确率、F1)是给人看的"成绩单",损失函数是模型训练时优化的"内部指标"。两者通常相关但不完全一样------损失低了,准确率一般也会高。
4.2 过拟合和欠拟合 ------ 在深度学习中更严重
第 08 篇用多项式回归演示了过拟合和欠拟合。在深度学习中,这个问题更加严重,因为深度网络的参数量巨大(几百万到几千亿个参数),特别容易"死记硬背"。
深度学习中的过拟合表现:
训练损失一直降,验证损失先降后升------典型的过拟合信号
模型对训练数据中的噪声和巧合模式也记住了
常用应对方法(测试人员需要知道这些术语):
- 正则化(Regularization):给损失函数加一个惩罚项,防止权重过大
- Dropout:训练时随机"关闭"一些神经元,防止过度依赖某些特征
- 数据增强(Data Augmentation):对训练数据做变换(旋转、加噪声、同义词替换),增加数据多样性
- 早停(Early Stopping):验证损失不再下降时提前停止训练
4.3 梯度和学习率 ------ 学习的"步幅"
梯度(Gradient)告诉你"往哪个方向调权重,损失会变小"。就像下山时知道"哪个方向是下坡"。
学习率(Learning Rate)控制每次调整的幅度:
学习率太大 → 一步跨太大,越过最低点,来回震荡,甚至发散
学习率太小 → 一步太小,训练极慢,可能卡在半山腰
学习率刚好 → 稳步下降到最低点
类比:你下山的时候,步子太大可能跳过谷底,步子太小走到天黑还没到。要找一个合适的步幅。
这是超参数(人来设定的参数),不是模型自己学的。测试人员需要了解:学习率没调好,模型效果可能很差,但不是模型的"Bug",而是训练配置的问题。
4.4 Batch Size 和 Epoch ------ 训练的基本单位
Batch Size(批大小):每次训练用多少条数据来更新一次权重。
批大小太大 → 每次更新更稳定,但吃更多内存
批大小太小 → 每次更新更快但噪声大,训练不稳定
Epoch(轮数):把全部训练数据过一遍叫一个 Epoch。通常要过几十到几百遍。
训练日志里常看到 Epoch 100/1000,意思就是第 100 轮,总共 1000 轮。
五、常见深度学习架构速览
深度学习有几种经典的网络架构,分别擅长不同类型的任务。作为测试人员,你不需要会设计这些网络,但要知道每种架构擅长什么、容易出什么问题。
5.1 CNN(卷积神经网络)------ 图像处理的主力
擅长:图片分类、目标检测、图像分割、OCR 文字识别
核心思想:用"卷积核"(小窗口)在图片上滑动,提取局部特征(边缘、纹理、形状)
类比:像用一个放大镜在图片上滑动扫描,每次只看一小块区域,提取局部特征。多个卷积核提取不同类型的特征。
测试关注点:
- 对图片旋转、缩放、裁剪的鲁棒性(旋转 15 度就不认识了?)
- 对噪声和模糊的容忍度(加一点噪声就乱了?)
- 对分辨率变化的适应性(小图和大图都行吗?)
5.2 RNN / LSTM(循环神经网络)------ 序列数据处理
擅长:文本生成、语音识别、时间序列预测
核心思想:处理有顺序的数据(一个词一个词地读),保留"记忆"(前文信息影响后面的理解)
类比 :像你读一句话,读到后面的时候,脑子里还记着前面的词。"他打开了冰箱,它是冷的"------你知道"它"指的是冰箱,因为你记着前面的内容。
测试关注点:
- 长序列的记忆能力(前面说的话后面还记得吗?)
- 时序依赖(顺序变了,结果变吗?)
5.3 Transformer ------ 当代 AI 的核心架构
擅长:几乎所有 NLP 任务、大语言模型、多模态模型(GPT、BERT、Claude 等都是 Transformer)
核心思想 :注意力机制(Attention)------让模型知道"看输入的时候该重点关注哪些部分"
类比:你翻译"猫坐在垫子上"时,翻译"sat"的时候你会重点关注"猫"和"垫子",因为主语和宾语最影响动词的翻译。注意力机制就是让模型自动学习这种"该看哪里"的能力。
测试关注点:
- 上下文理解能力(长对话中的信息保持)
- 注意力偏差(是否过度关注某些模式)
- 幻觉问题(生成不存在的信息)
- Token 限制(输入长度超过限制怎么办)
5.4 一张表总结
| 架构 | 擅长任务 | 代表应用 | 测试重点 |
|---|---|---|---|
| CNN | 图像相关 | 图像识别、人脸识别、OCR | 变换鲁棒性、噪声容忍 |
| RNN/LSTM | 序列数据 | 语音识别、文本生成 | 长序列记忆、时序依赖 |
| Transformer | NLP + 多模态 | GPT、BERT、翻译、对话 | 上下文理解、幻觉、安全性 |
| GAN | 生成内容 | 图像生成、风格迁移 | 生成质量、多样性、安全 |
| 强化学习 | 决策策略 | 游戏AI、机器人 | 目标对齐、安全边界 |
六、从测试视角看深度学习
理解了原理之后,回到你的本职工作。以下是深度学习模型的常见质量风险,也是你测试时要重点关注的:
6.1 数据层面的风险
- 数据不足:训练数据太少,模型学不到足够的规律 → 测试时用多样化的数据来验证
- 数据偏见:训练数据中某些群体/场景的样本太少,模型对这些场景表现差 → 检查不同子群体的表现差异
- 标注错误:训练数据中的"答案"就是错的,模型学到了错误的规律 → 抽样检查标注质量
- 数据泄漏:测试数据混入了训练数据,评估结果虚高 → 严格审查数据划分
6.2 模型层面的风险
- 过拟合:训练好但实际使用差 → 用新鲜数据测试
- 对抗脆弱性:微小的输入扰动导致输出剧变 → 对抗样本测试
- 置信度不校准:模型说 90% 确定,实际正确率只有 70% → 置信度校准测试
- 泛化能力不足:换一个领域的数据就失效 → 跨域测试
6.3 系统层面的风险
- 推理延迟:模型太大太慢 → 性能测试(第 13 篇)
- 资源泄漏:长时间运行后内存/显存持续增长 → 持续压测监控
- 输入处理:异常输入导致崩溃 → 异常输入测试(第 10 篇)
- 版本一致性:训练和部署的模型版本不一致 → 回归测试
七、本篇小结
本篇的核心收获:
- 人工神经元:输入 × 权重 + 偏置 → 激活函数 → 输出。这就是 AI "做决定"的最小单元
- 神经网络的层级结构:输入层 → 隐藏层 → 输出层,每层提取越来越抽象的特征
- 前向传播:数据从输入流向输出,得到预测
- 反向传播:从误差倒推出每个权重的调整量------模型"学习"的核心机制
- 损失函数:衡量预测和真实的差距,训练的目标是让损失变小
- 激活函数:Sigmoid / ReLU / Tanh,引入非线性让模型能学到复杂规律
- 常见架构:CNN(图像)、RNN(序列)、Transformer(NLP/大模型)
- 测试视角:数据风险、模型风险、系统风险三大类
你现在理解了神经网络是怎么工作的。这给你带来的实际好处是:
当算法工程师说"我们的模型过拟合了",你知道他在说什么问题
当评测报告显示"置信度校准不良",你知道这对用户意味着什么
当你设计测试用例时,你知道为什么要覆盖对抗样本和边缘场景
下一篇我们从通用概念进入具体领域------NLP、CV、语音三大 AI 方向的技术原理和测试要点。理解了这些,你就能针对性地设计每个领域的测试方案了。
下一篇:【测AI】第12篇:NLP / CV / 语音 ------ 三大 AI 方向速通
- NLP 是怎么"理解"语言的?分词、Embedding、Attention
- CV 是怎么"看"图片的?卷积、特征图、目标检测
- 语音是怎么"听"懂的?ASR、TTS 的基本流程
- 三大方向各自的评估指标和测试方法
- 如何针对不同方向设计测试用例