2 min read 563 words Updated May 03, 2026 Created May 03, 2026

本文作为我看过 # 吴恩达机器学习系列课程 的产物,并不适用于一无所知的学习者。

在机器学习中,有三个很重要的函数:

  • $h_\theta(x)$ 表示预测数据
  • $J(\theta)$ 代价函数,表示预测和实际的差距,$J(\theta) \ge 0$,且 $J(\theta)$ 值越小,差距越小。
  • $\frac {\partial}{\partial \theta} J(\theta)$ 也就是其偏导数,用于梯度下降算法的拟合。

由于本人没有系统的学习偏导数,为了方便表示,这里认为 $\theta' = \frac {\partial}{\partial \theta} J(\theta)$ 是一个与 $\theta$ 同样大小的向量,其中 $\theta'_i$ 表示在第 $i$ 个维度平面内的斜率。故 $\frac {\partial}{\partial \theta} J(\theta)$ 实际上就表示的是 $J$ 函数图像在 $\theta$ 处的斜率。

一个优秀的代价函数是梯度下降算法的核心。
一般来说,需要具有如下特性:

  • 不存在局部最小值 %% 也就是 $\not \exists \theta(J'(\theta) = 0 \wedge \exists \alpha(J(\theta) > J(\alpha))$ %%
  • 没有平坦的部分,也就是没有 $J'(\theta) = 0$ 但是 $J(\theta)$ 不是最小值的地方。

梯度下降算法的目标很简单:

$$\min J(\theta) $$

其过程也很简单:

$$\theta = \theta - \alpha \frac {\partial}{\partial \theta} J(\theta) $$

其中 $\alpha$ 是学习速率。如果 $\alpha$ 过小,则时间成本过大;如果 $\alpha$ 过大,则容易跳过最优解。

如何理解 跳过 ?梯度下降算法的过程,实际上就是沿着斜率不断向下跳的过程。而学习速率决定了向下跳的距离,所以说如果 $\alpha$ 过大,则容易跳过最优解。

线性回归

线性回归,即使用一次函数对于数据进行拟合:

$$h_\theta(x_i) = \theta_0 + \theta_1 x_i $$

我们一般使用的是平方损失函数:

$$J(\theta) = \frac 1 {2m} \sum_{i = 1}^m (h_\theta(x_i) - y_i) ^2 $$

其中 $x_i$ 表示输入特征,而 $y_i$ 表示真实值。

我们不妨将 $x_i$ 简单修改,变成 $(1, x_i)$,记为 $X_i$,则 $X$ 是一个 $2 \times m$ 的矩阵:

$$X = \begin{pmatrix} 1 & x_0 \\ 1 & x_1 \\ \vdots & \vdots \\ 1 & x_{m - 1} \\ \end{pmatrix} $$

那么自然,$J(\theta) = \frac 1 {2m} \mathrm{ones} (1, m) {\large (}(X \theta - y) \cdot (X \theta - y){\large )}$

其中 ${\rm ones}(n, m)$ 表示一个 $n \times m$ 的全为 $1$ 的矩阵。

原本计算式:

$$\theta_j = \theta_j - \alpha \frac 1 m\sum_{i = 1}^m X_{i, j} (X_i *\theta - y) $$

变成矩阵的写法:

$$\theta = \theta - \frac \alpha m X^T (X \times \theta - y) $$

非常的优美。

简单代码

利用 Octave 写的。

% X 是输入数据,y 是目标数据数据

% 标准化输入
[X mu sigma] = featureNormalize(X);

% 新增一列常数 1
X = [ones(m, 1) X];

% 设置训练参数
alpha = 0.01;
num_iters = 400;

% 开始训练
theta = zeros(3, 1);
theta = gradientDescentMulti(X, y, theta, alpha, num_iters);

% 预测函数,这里的 x 是没有常数项的
function [predict] = multiPredict(x, theta, mu, sigma)
	normData = ([1 x] - [0 sigma]) ./ [1 mu];
	predict = normData * theta;
end

一些函数

% 标准化每一列
function [X_norm, mu, sigma] = featureNormalize(X)
X_norm = X;
mu = zeros(1, size(X, 2));
sigma = zeros(1, size(X, 2));

for i = 1:length(X(1, :))
	V = X_norm(:, i);
	sigma(i) = mean(V);
	mu(i) = std(V) * std(V);
	V = (V - sigma(i)) / mu(i);
	X_norm(:, i) = V;
end

end

% 开始梯度下降
function theta = gradientDescentMulti(X, y, theta, alpha, num_iters)
m = length(y); % 样本量

for iter = 1:num_iters
	theta = theta - alpha / m * (X' * (X * theta - y));
end

end

% 计算代价函数 J(\theta)
function J = computeCostMulti(X, y, theta)
m = length(y); % 样本量
diffCost = X * theta - y;
J = sum(diffCost .* diffCost) / 2 / m;

end

这么一看核心代码也就一点点……但是不得不说确实高级。


正则化参数

是一种防止“过拟合出现”的重要方式。

一般来说,为了限制参数的大小,我们会小小修改损失函数:

$$J(\theta) = \frac 1 {2m} \sum_{i = 1}^m (h_\theta(x_i) - y_i) ^2 + \lambda \sum_{i = 1}^c \theta_i^2 $$

那么其偏导数:

$$\frac \partial {\partial \theta} J(\theta) = \frac 1 m \left( X^T \times {\Large (}X \theta - y{\Large )} + \lambda \theta\right) $$

自然参数学习部分变成了:

$$\theta = \frac {m - \lambda} m \theta - \frac \alpha m X^T (X \times \theta - y) $$

不过值得注意的是,一般来说,我们的 $\theta$ 是增广的矩阵,所以需要注意常数项不应该被减少!

也就是说设 $\theta'$ 表示 $\theta$ 常数项被设为 $0$,那么:

$$J(\theta) = - \frac 1 m (y' \log \hat y + (1 - y) \log (1 - \hat y)) + \frac \lambda {2m} \theta'^T \theta' $$

$$\frac {\partial J(\theta)} {\partial \theta} = \frac 1 m (X^T(X \theta - y)) + \frac \lambda m \theta' $$