打造一个从示例中学习、自己改正错误的人工智能
我们来做一个程序:它查看示例数据,每当预测出错,就自己修正计算中使用的数字。只用一个 Python 文件就能完成,不需要额外的库,也不需要付费的 AI 服务。你也可以直接在这个页面上运行它。
要学习的数据
这次模型要学习的数据如下。
| 输入 | 答案 |
|---|---|
| 1 | 2 |
| 2 | 4 |
| 3 | 6 |
| 4 | 8 |
我们一眼就能看出“输入的两倍”这个规律。现在让程序也用这些数据学会这个关系。结束后,再输入训练中没用过的 5 和 7,检查它的预测。
计算的框架 — 模型
首先,给程序定好下面这样的计算框架,也就是。
预测值 = 输入 × w
w 是程序在中不断调整的数字。这样的值叫作,在这里也叫。
一开始从 w = 0 出发。
输入 3 → 预测 0 → 答案是 6 → 差得很远!
随着训练反复进行,w 接近 2 时,就会变成这样:
输入 3 → 预测约为 6 → 和答案几乎一样!
人准备计算框架和示例数据,程序去找出与数据相符的 w。
代码 — mini_ai.py
把下面的代码保存为 mini_ai.py。在这个页面上点击[运行],浏览器里的 Python 就会立即运行它。你也可以修改代码后再次运行。
点击[运行]后会准备浏览器里的 Python。第一次会下载约 12MB。
# 1. 训练数据: (输入, 答案)
data = [(1, 2), (2, 4), (3, 6), (4, 8)]
# 2. 从不知道规律的状态开始。
weight = 0.0
learning_rate = 0.01
# 3. 看遍全部数据,训练 100 次。
for step in range(100):
gradient = 0.0
for x, answer in data:
prediction = weight * x # 用当前权重预测
error = prediction - answer # 和答案差多少
gradient += 2 * error * x # 修正的方向和大小
# 汇总所有数据的结果,把权重稍微修正一点。
weight -= learning_rate * gradient / len(data)
if step + 1 in [1, 10, 50, 100]:
print(f"第 {step + 1} 次训练: w = {weight:.4f}")
# 4. 用训练中没用过的输入进行预测。
print(f"输入 5 的预测: {weight * 5:.4f}")
print(f"输入 7 的预测: {weight * 7:.4f}")
运行结果
按[运行],结果就会显示在这里。
在自己的电脑上运行
在保存文件的文件夹中,用下面的命令运行:
python3 mini_ai.py
运行结果
这是实际运行后确认的结果。数字显示到小数点后第四位。
第 1 次训练: w = 0.3000 第 10 次训练: w = 1.6063 第 50 次训练: w = 1.9994 第 100 次训练: w = 2.0000 输入 5 的预测: 10.0000 输入 7 的预测: 14.0000
一开始为 0 的,经过变成了约 2。用这个权重计算新输入的答案,就叫预测,也叫。
代码中要理解的三个核心
error错了多少- 预测值减去答案得到的值。时会调整,让这些误差平方的平均值变小。
gradient权重该怎么改- 计算减小误差所需的修正方向和大小。这种方法叫梯度下降法。2 * error * x 是对这个的平方误差求导得到的式子。即使还没完全理解求导,也可以先动手实验。
learning_rate一次改多少- 这里是 0.01。太小,会变慢;太大,可能剧烈摆动,甚至训练失败。
亲手做实验
每次只改一处,然后再运行一次。点击[载入并运行],修改后的代码会放进上方的编辑器并立即运行。
-
把数据改成“三倍”关系
data = [(1, 3), (2, 6), (3, 9), (4, 12)]其余代码保持不变,直接运行。这次检查权重是否学成约 3。
查看确认过的结果
第 1 次训练: w = 0.4500 第 10 次训练: w = 2.4094 第 50 次训练: w = 2.9991 第 100 次训练: w = 3.0000 输入 5 的预测: 15.0000 输入 7 的预测: 21.0000
-
减少训练次数
for step in range(10):和训练 100 次时相比,看看预测变得有多不准确。
查看确认过的结果
第 1 次训练: w = 0.3000 第 10 次训练: w = 1.6063 输入 5 的预测: 8.0313 输入 7 的预测: 11.2438
-
去掉示例中完美的规律
data = [(1, 2.1), (2, 3.9), (3, 6.2), (4, 7.8)]看看即使数据有些偏差,它能否找到整体上最合适的权重。
查看确认过的结果
第 1 次训练: w = 0.2985 第 10 次训练: w = 1.5982 第 50 次训练: w = 1.9894 第 100 次训练: w = 1.9900 输入 5 的预测: 9.9500 输入 7 的预测: 13.9300
下一个挑战 — 输入 × w + b
这个只能表示“输入 × w”这种正比关系。比如要学会 输入 × 2 + 3,就要把模型扩展为 输入 × w + b,并学习 w 和 b 两个数字。b 叫作偏置。
如果理解了上面的实验,先试着自己修改代码;卡住了再打开下面的答案。
查看答案代码
训练数据是用 输入 × 2 + 3 生成的 (1, 5), (2, 7), (3, 9), (4, 11)。因为要学习两个数字,所以把学习率提高到 0.05,训练 1000 次。
# 1. 训练数据: 用 输入 × 2 + 3 生成的 (输入, 答案)
data = [(1, 5), (2, 7), (3, 9), (4, 11)]
# 2. 权重 w 和偏置 b 都从 0 开始。
weight = 0.0
bias = 0.0
learning_rate = 0.05
# 3. 看遍全部数据,训练 1000 次。
for step in range(1000):
grad_w = 0.0
grad_b = 0.0
for x, answer in data:
prediction = weight * x + bias # 用当前的 w 和 b 预测
error = prediction - answer # 和答案差多少
grad_w += 2 * error * x # 修改 w 的方向和大小
grad_b += 2 * error # 修改 b 的方向和大小
# 把 w 和 b 一起稍微修正一点。
weight -= learning_rate * grad_w / len(data)
bias -= learning_rate * grad_b / len(data)
if step + 1 in [1, 10, 100, 500, 1000]:
print(f"第 {step + 1} 次训练: w = {weight:.4f}, b = {bias:.4f}")
# 4. 用训练中没用过的输入进行预测。
print(f"输入 5 的预测: {weight * 5 + bias:.4f}")
print(f"输入 7 的预测: {weight * 7 + bias:.4f}")
第 1 次训练: w = 2.2500, b = 0.8000 第 10 次训练: w = 2.6082, b = 1.2119 第 100 次训练: w = 2.1565, b = 2.5399 第 500 次训练: w = 2.0004, b = 2.9989 第 1000 次训练: w = 2.0000, b = 3.0000 输入 5 的预测: 13.0000 输入 7 的预测: 17.0000
w 一开始会超过 2,随着 b 变大又回到 2,最后得到 w = 2、b = 3。