机器学习(一)
最近本来想继续往CNN学,但回头看了一下,发现自己虽然已经用MNIST跑过MLP,也能看懂训练准确率在变化,可是对“模型到底怎么学会的”还没有那么稳。
所以这篇先不急着写神经网络,而是把吴恩达机器学习课程里最前面的概念整理一遍。我的目标不是把机器学习讲成教材,而是把自己现在能理解到的链条写清楚:
数据给进去,模型先做预测;预测和真实答案之间有差距;代价函数把这个差距算出来;梯度下降再一点点调整参数,让差距变小。
为什么先学机器学习
我现在的理解是,深度学习和联邦学习并不是凭空冒出来的。
深度学习里也有模型、参数、损失函数、梯度下降和优化器;联邦学习只是把训练过程放到多个客户端上,还要考虑数据不能直接集中起来的问题。如果这些基础概念不稳,后面看到FedAvg、客户端更新、服务器聚合时,很容易只记住流程,但不知道每一步为什么存在。
所以我先回到机器学习的起点,把几个最基本的问题弄明白:
- 模型到底在学什么?
- 特征和标签分别是什么?
- 训练为什么能让参数变好?
- 为什么从一个特征预测,可以扩展到多个特征一起预测?
监督学习和无监督学习
机器学习(Machine Learning,机器学习)可以先粗略理解成:让模型从数据里学习规律,再用这个规律去处理新的数据。
监督学习(Supervised Learning,监督学习)是我现在最先接触的一类。它的训练数据里既有输入,也有对应答案。这里的输入通常叫特征(Feature,特征),答案通常叫标签(Label,标签)。模型要做的事情,就是从特征到标签之间学出一个映射关系。
比如房价预测里,房屋面积可以是特征,房价可以是标签。训练时模型能同时看到“面积”和“真实价格”,于是它就可以慢慢调整自己,让预测价格更接近真实价格。
监督学习里又有两类常见任务:
- 回归(Regression,回归):预测连续数值,比如房价、温度、销售额。
- 分类(Classification,分类):预测类别,比如邮件是不是垃圾邮件,图片里是数字0还是数字9。
无监督学习(Unsupervised Learning,无监督学习)就不一样了。它的数据里没有明确答案,模型要自己从数据中找结构。比如聚类(Clustering,聚类)就是把相似的数据分到一起;降维(Dimensionality Reduction,降维)是把高维数据压到更容易观察的形式。
这一篇后面主要还是放在监督学习,尤其是线性回归上。
先看训练数据长什么样
课程里经常会先用NumPy数组保存训练数据。我一开始容易忽略这一步,直接往公式和代码看,结果后面反而不知道每个变量对应什么。
1 | # 查看训练数据 |
这段代码不是为了训练模型,而是先确认数据本身:
x_train是输入特征。y_train是真实标签。x_train[:5]和y_train[:5]可以先看前几个样本。shape可以确认一共有多少条数据,以及每条数据有几个特征。
我现在觉得这一步很重要,因为机器学习不是从代码开始的,而是从“我有什么数据、我要预测什么”开始的。
如果是一个输入预测一个输出,还可以先画散点图看一下数据大概是什么趋势:
1 | import matplotlib.pyplot as plt |
这段代码的作用不是训练,而是让我先用图观察数据。比如点大概是不是往一个方向上升,能不能先用一条直线去拟合。对我这种刚开始学的人来说,先看到数据形状,比一上来背公式更容易理解线性回归为什么出现。
模型、参数和线性回归
模型(Model,模型)可以先理解成一个函数:给它输入,它输出预测结果。
参数(Parameter,参数)是模型里面需要通过训练自动调整的量。在线性回归里,最简单的参数就是w和b。
线性回归(Linear Regression,线性回归)想做的事情,是用一条直线去拟合数据趋势。最基础的形式是:
这里每一项的意思是:
x:输入特征,比如房屋面积。f_{w,b}(x):模型根据当前参数算出来的预测值。w:权重,决定这条线的倾斜程度。b:偏置,决定这条线整体往上或往下移动多少。
写成代码就是:
1 | # 线性回归模型 |
这段代码只是在做预测。真正的问题是:现在的w和b好不好?预测值和真实值差多少?这就需要代价函数。
代价函数:先知道错了多少
代价函数(Cost Function,代价函数)是用来衡量模型整体预测效果的。在线性回归里,常见做法是把每个样本的预测误差平方后求平均。
1 | # 代价函数 |
我现在是这样理解这段代码的:
m是训练样本数量。f_wb是模型对第i个样本的预测。y[i]是第i个样本的真实答案。f_wb-y[i]是预测误差。- 平方是为了让正负误差都变成正数,也让大误差更明显。
- 除以
2*m是为了求平均,同时后面求导时形式更方便。
代价函数本身不会让模型变好,它只是告诉我:现在这组参数的效果有多差。接下来要靠梯度下降去调整参数。
课程里也会把不同w、b对应的代价画出来。这个时候我才意识到,训练不是“模型突然变聪明”,而是在很多可能的参数里,尽量找到让代价更小的一组。
梯度下降:一点点把参数调好
梯度下降(Gradient Descent,梯度下降)可以先直觉理解成:沿着让代价函数下降最快的方向,一小步一小步移动参数。

这里最容易混淆的是学习率。
学习率(Learning Rate,学习率)通常写成alpha。它控制每次参数更新走多大一步:
- 如果学习率太小,下降会很慢。
- 如果学习率太大,可能会在最低点附近来回震荡,甚至让代价越来越大。
先计算梯度:
1 | # 梯度计算 |
这段代码在回答一个问题:如果我要让代价函数变小,w和b应该往哪个方向改?
dj_dw表示代价函数对w的变化方向。dj_db表示代价函数对b的变化方向。error越大,说明当前预测偏得越多。- 对所有样本累加后再除以
m,得到的是平均意义上的调整方向。
再把梯度用于参数更新:
1 | # 梯度下降 |
这里的重点不是for循环本身,而是每一次循环都做同一件事:
- 用当前
w和b算梯度。 - 按照梯度方向更新
w和b。 - 期待下一次代价函数比这一次更小。
我之前容易把“训练模型”想得有点神秘。现在看线性回归,训练其实就是不断重复这个过程:预测、算差距、算方向、改参数。
如果想确认梯度下降是不是真的在起作用,可以在训练过程中隔一段时间记录一次成本:
1 | cost_history = [] |
这段代码对我来说比较重要,因为它把“训练有效”变得可观察。不是只看最后的w和b,而是看中间的成本有没有逐步下降。如果成本一直不降,或者忽高忽低,就要回头检查学习率、梯度计算或者数据本身。
训练结束后,就可以用得到的w、b做一个简单预测:
1 | w, b = gradient_descent(x_train, y_train, w=0, b=0, alpha=0.01, num_iters=1000) |
这段代码把前面的东西串起来了:gradient_descent先从训练集里学到参数,后面再用w*x_new+b 对新的输入做预测。这里的预测不是凭空来的,而是前面很多次参数更新的结果。
多特征只是下一步入口
这一篇主要先停在单变量线性回归。也就是一个样本只有一个输入特征,比如只用房屋面积预测房价。
但真实任务里通常不止一个特征。
比如预测房价时,可能同时考虑:
- 面积
- 房间数量
- 楼层
- 房龄
- 距离地铁的距离
多特征(Multiple Features,多特征)就是一个样本有多个输入信息。这个时候,一个样本不再只是一个数字,而是一组数字。
向量(Vector,向量)可以先理解成一组数,比如:
这里的 x_1、x_2、x_3、x_4 分别可以代表不同特征。对应地,参数也会从一个 w 变成一组 w:
这条式子看起来比单变量复杂,但直觉是一样的:
- 每个特征都有一个对应的权重。
- 权重表示这个特征对预测结果的影响方向和大小。
- 最后再加上偏置
b。
向量化(Vectorization,向量化)就是用向量或矩阵运算替代重复循环。这里我只先把它当成下一步入口,不在这一篇展开完整训练。因为我现在更需要先把“模型、成本函数、梯度下降”这条主线弄稳。
我现在容易混淆的点
第一,特征和标签不能混在一起。特征是输入,标签是想预测的目标。训练时两者都能看到,真正使用模型时通常只有特征。
第二,代价函数不是模型本身。模型负责预测,代价函数负责评价预测错多少。
第三,梯度下降也不是“保证一次就找到最好答案”。它是一步一步调整参数,学习率、初始值、数据情况都会影响训练过程。
第四,向量化不是更高级的魔法。它主要是让多特征计算更统一、更快,背后的预测逻辑仍然是“特征乘权重再加偏置”。
这一篇和后面学习的关系
这篇学到这里,我最大的收获是:模型不是凭空会预测的。它一开始只是带着一组参数做猜测,然后通过代价函数知道自己错了多少,再靠梯度下降一点点调整参数。
这条线后面会一直出现。到了MLP和CNN,模型会更复杂,参数会更多,但训练过程里仍然会有预测、损失、反向传播和参数更新。到了联邦学习,变化的是数据分散在不同客户端上,训练和聚合方式更复杂,但每个客户端本地仍然是在做类似的优化过程。
下一篇机器学习基础我准备继续补特征缩放、特征工程和多项式回归。这些先不塞进这一篇,不然现在的主线会太散。




