机器学习基础 本笔记是对 CMU Pratical Data Science Course 的机器学习相关部分的整理。
1. 一般化的机器学习 一般地,一个机器学习算法包含如下的核心要素:
输入(Inputs / Features) x ( i ) ∈ R n , i = 1 , 2 , … , m x(i) \in \mathbb{R}^n, i=1, 2, \dots,m x ( i ) ∈ R n , i = 1 , 2 , … , m 。这是我们传入算法的信息。x ( i ) x(i) x ( i ) 代表第 i i i 个数据样本。它是一个 n n n 维的实数向量。 输出 (Outputs) y ( i ) ∈ Y y(i) \in Y y ( i ) ∈ Y :这是我们希望算法预测的目标。Y Y Y 代表所有可能输出的集合(输出空间)。输出可以是多种多样的,例如:回归 (Regression):输出是连续的实数值(如用电量、房价)。 分类 (Classification):输出是离散的类别(如“是/否”、“猫/狗/鸟”)。 参数 (Parameters) θ ∈ R d \theta \in \mathbb{R}^d θ ∈ R d :θ θ θ 是一个 d d d 维向量,包含了模型中所有需要通过学习来确定的数值 。我们的最终目的就是找到一组最优的 θ θ θ ,使得模型的预测尽可能准确。 假设函数 (Hypothesis Function) h θ : R n → Y ^ h_θ: R^n \rightarrow \hat{Y} h θ : R n → Y ^ :这是一个从输入空间 R n R^n R n 到预测空间 Y ^ \hat{Y} Y ^ 的映射,就是我们的预测模型。给定一个输入 x x x ,它会输出一个预测值 h θ ( x ) hθ(x) h θ ( x ) 。模型的输出也由参数 θ θ θ 决定,所以严格来说应该写作 h ( θ , x ) h(θ, x) h ( θ , x ) ,但通常写作 h θ ( x ) h_θ(x) h θ ( x ) 来强调它是一个从 x x x 到 y y y 的映射。 预测空间 Y ^ \hat{Y} Y ^ 不一定和真实输出空间 Y Y Y 完全一样,但可以很容易地转换过去。例如在分类问题中,h θ ( x ) h_θ(x) h θ ( x ) 可能输出一个0到1之间的概率,而真实的 y y y 是0或1,这时两者就不同了。 损失函数 (Loss Function) ℓ : Y ^ × Y → R + \ell: \hat{Y} × Y \rightarrow R_+ ℓ : Y ^ × Y → R + :这是一个衡量单次预测好坏的函数。它接收一个预测值 h θ ( x ) h_θ(x) h θ ( x ) 和一个真实值 y y y ,然后输出一个非负实数。 有了这些核心概念后,几乎所有的监督式机器学习算法都可以被归纳为以下的标准形式:
minimize 1 m ∑ i = 1 m ℓ ( h θ ( x ( i ) , y ( i ) ) ) ⇒ minimize E ( θ ) \text{minimize}\frac{1}{m}\sum _{i=1}^m \ell(h_{\theta}(x^{(i)}, y^{(i)})) \Rightarrow \text{minimize} E(\theta) minimize m 1 i = 1 ∑ m ℓ ( h θ ( x ( i ) , y ( i ) )) ⇒ minimize E ( θ ) 因此,要定义任何一个具体的机器学习算法,我们只需要回答以下三个问题:
假设函数 h θ h_θ h θ 的形式是什么? (是线性模型、神经网络还是决策树?) 损失函数 ℓ \ell ℓ 是什么? (是用平方误差、绝对值误差还是其他的?) 我们如何解决这个最小化优化问题? (是用梯度下降、解析解还是其他优化方法?) 下面我们从这些概念入手,讲解一些具体的方法。
2. 前置方法介绍 a . a. a . 梯度下降求解最小化优化问题的一个常用方法就是梯度下降。
i . i. i . 简单例子以下面这个假设函数为例:
h θ ( x ( i ) ) = θ 1 x ( i ) + θ 2 h_{\theta}(x^{(i)})=\theta_1 x^{(i)} + \theta_2 h θ ( x ( i ) ) = θ 1 x ( i ) + θ 2 我们计算待优化函数 E ( θ ) E(\theta) E ( θ ) 相对 θ 1 \theta_1 θ 1 和 θ 2 \theta_2 θ 2 的梯度:
∂ E ( θ ) ∂ θ 1 = ∂ ∂ θ 1 1 m ∑ i = 1 m ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 2 = 1 m ∑ i = 1 m ∂ ∂ θ 1 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 2 = 1 m ∑ i = 1 m 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) ∂ ∂ θ 1 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) = 1 m ∑ i = 1 m 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) x ( i ) \begin{aligned} \frac{\partial E(\theta)}{\partial \theta_1} &= \frac{\partial}{\partial \theta_1} \frac{1}{m} \sum_{i=1}^{m} (\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)})^2 \\ &= \frac{1}{m} \sum_{i=1}^{m} \frac{\partial}{\partial \theta_1} (\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)})^2 \\ &= \frac{1}{m} \sum_{i=1}^{m} 2(\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)}) \frac{\partial}{\partial \theta_1} (\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)}) \\ &= \frac{1}{m} \sum_{i=1}^{m} 2(\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)}) x^{(i)} \end{aligned} ∂ θ 1 ∂ E ( θ ) = ∂ θ 1 ∂ m 1 i = 1 ∑ m ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 2 = m 1 i = 1 ∑ m ∂ θ 1 ∂ ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 2 = m 1 i = 1 ∑ m 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) ∂ θ 1 ∂ ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) = m 1 i = 1 ∑ m 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) x ( i ) ∂ E ( θ ) ∂ θ 2 = ∂ ∂ θ 2 1 m ∑ i = 1 m ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 2 = 1 m ∑ i = 1 m ∂ ∂ θ 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 2 = 1 m ∑ i = 1 m 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) ∂ ∂ θ 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) = 1 m ∑ i = 1 m 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) \begin{aligned} \frac{\partial E(\theta)}{\partial \theta_2} &= \frac{\partial}{\partial \theta_2} \frac{1}{m} \sum_{i=1}^{m} (\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)})^2 \\ &= \frac{1}{m} \sum_{i=1}^{m} \frac{\partial}{\partial \theta_2} (\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)})^2 \\ &= \frac{1}{m} \sum_{i=1}^{m} 2(\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)}) \frac{\partial}{\partial \theta_2} (\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)}) \\ &= \frac{1}{m} \sum_{i=1}^{m} 2(\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)}) \end{aligned} ∂ θ 2 ∂ E ( θ ) = ∂ θ 2 ∂ m 1 i = 1 ∑ m ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 2 = m 1 i = 1 ∑ m ∂ θ 2 ∂ ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 2 = m 1 i = 1 ∑ m 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) ∂ θ 2 ∂ ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) = m 1 i = 1 ∑ m 2 ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 然后,我们就可以沿着梯度下降方向、以 α \alpha α 步长更新这些参数、让 E ( θ ) E(\theta) E ( θ ) 变小:
θ 1 : = θ 1 − α 2 m ∑ i = 1 m ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) x ( i ) θ 2 : = θ 2 − α 2 m ∑ i = 1 m ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) \begin{aligned} \theta_1 &:= \theta_1 - \alpha \frac{2}{m} \sum_{i=1}^{m} (\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)}) x^{(i)} \\ \theta_2 &:= \theta_2 - \alpha \frac{2}{m} \sum_{i=1}^{m} (\theta_1 \cdot x^{(i)} + \theta_2 - y^{(i)}) \end{aligned} θ 1 θ 2 := θ 1 − α m 2 i = 1 ∑ m ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) x ( i ) := θ 2 − α m 2 i = 1 ∑ m ( θ 1 ⋅ x ( i ) + θ 2 − y ( i ) ) 这里的 E ( θ ) = ∑ i = 1 m ( h θ ( x ( i ) − y ( i ) ) ) 2 E(\theta)=\sum_{i=1}^m(h_{\theta}(x^{(i)}-y^{(i)}))^2 E ( θ ) = ∑ i = 1 m ( h θ ( x ( i ) − y ( i ) ) ) 2 叫作最小二乘估计 。
更新 θ 1 \theta_1 θ 1 ,θ 2 \theta_2 θ 2 简单代码如下:
theta = np.array([0. , 0. ])
alpha = 1.0
for t in range (100 ):
theta[0 ] -= alpha/len (x) * 2 * sum ((theta[0 ] * x_norm + theta[1 ] - y_norm)*x_norm)
theta[1 ] -= alpha/len (x) * 2 * sum ((theta[0 ] * x_norm + theta[1 ] - y_norm))
i i . ii. ii . 最小二乘梯度下降方法整理我们考虑 E ( θ ) E(\theta) E ( θ ) 对 θ j \theta_j θ j 的梯度:
∂ E ( θ ) ∂ θ j = ∂ ∂ θ j 1 m ∑ i = 1 m ( ∑ k = 1 n θ k x k ( i ) − y ( i ) ) 2 = 1 m ∑ i = 1 m ∂ ∂ θ j ( ∑ k = 1 n θ k x k ( i ) − y ( i ) ) 2 = 1 m ∑ i = 1 m 2 ( ∑ k = 1 n θ k x k ( i ) − y ( i ) ) ∂ ∂ θ j ( ∑ k = 1 n θ k x k ( i ) − y ( i ) ) = 2 m ∑ i = 1 m ( ∑ k = 1 n θ k x k ( i ) − y ( i ) ) x j ( i ) \begin{aligned} \frac{\partial E(\theta)}{\partial \theta_j} &= \frac{\partial}{\partial \theta_j} \frac{1}{m} \sum_{i=1}^{m} \left( \sum_{k=1}^{n} \theta_k x^{(i)}_k - y^{(i)} \right)^2 \\ &= \frac{1}{m} \sum_{i=1}^{m} \frac{\partial}{\partial \theta_j} \left( \sum_{k=1}^{n} \theta_k x^{(i)}_k - y^{(i)} \right)^2 \\ &= \frac{1}{m} \sum_{i=1}^{m} 2 \left( \sum_{k=1}^{n} \theta_k x^{(i)}_k - y^{(i)} \right) \frac{\partial}{\partial \theta_j} \left( \sum_{k=1}^{n} \theta_k x^{(i)}_k - y^{(i)} \right) \\ &= \frac{2}{m} \sum_{i=1}^{m} \left( \sum_{k=1}^{n} \theta_k x^{(i)}_k - y^{(i)} \right) x^{(i)}_j \end{aligned} ∂ θ j ∂ E ( θ ) = ∂ θ j ∂ m 1 i = 1 ∑ m ( k = 1 ∑ n θ k x k ( i ) − y ( i ) ) 2 = m 1 i = 1 ∑ m ∂ θ j ∂ ( k = 1 ∑ n θ k x k ( i ) − y ( i ) ) 2 = m 1 i = 1 ∑ m 2 ( k = 1 ∑ n θ k x k ( i ) − y ( i ) ) ∂ θ j ∂ ( k = 1 ∑ n θ k x k ( i ) − y ( i ) ) = m 2 i = 1 ∑ m ( k = 1 ∑ n θ k x k ( i ) − y ( i ) ) x j ( i ) 这样,针对最小二乘法的梯度下降算法可以整理如下:
初始化 :θ : = 0 \theta := 0 θ := 0 迭代(直至收敛) :F o r j = 1 , … , n For\;j\;=1,\dots,n F or j = 1 , … , n :θ j : = θ j + α 2 m ∑ i = 1 m ( ∑ k = 1 n θ k x k ( i ) − y ( i ) ) x j ( i ) \theta_j := \theta_j + \alpha \frac{2}{m} \sum_{i=1}^{m} \left( \sum_{k=1}^{n} \theta_k x^{(i)}_k - y^{(i)} \right) x^{(i)}_j θ j := θ j + α m 2 i = 1 ∑ m ( k = 1 ∑ n θ k x k ( i ) − y ( i ) ) x j ( i ) b . b. b . 归一化i . i. i . 具体步骤我们一般使用下面这个简单的操作,将 x ~ \tilde{x} x ~ 映射到 [ 0 , 1 ] [0, 1] [ 0 , 1 ] 区间中:
x ~ = x ( i ) − min i x ( i ) max i x ( i ) − min i x ( i ) \tilde{x} = \frac{x^{(i)}-\min_ix^{(i)}}{\max_ix^{(i)}-\min_ix^{(i)}} x ~ = max i x ( i ) − min i x ( i ) x ( i ) − min i x ( i ) ( ~ y ) \tilde(y) ( ~ y ) 同理。
i i . ii. ii . 数据转换我们在将数据归一化、进行梯度下降或者其他算法计算后,需要将它转换回原始数据。原始数据与归一化后数据的关系如下:
y ~ ≈ x ~ ⋅ θ 1 + θ 2 ⇒ y − a b ≈ x − c d ⋅ θ 1 + θ 2 ⇒ y − a ≈ b ( x − c d ⋅ θ 1 + θ 2 ) ⇒ y ≈ ( x − c ) ⋅ b d θ 1 + b θ 2 + a ⇒ y ≈ x ⋅ b d θ 1 − c b d θ 1 + b θ 2 + a ⇒ y ≈ x ⋅ ( b d θ 1 ) + ( a + b θ 2 − c b d θ 1 ) ⇒ y ≈ x ⋅ θ ^ 1 + θ ^ 2 \begin{aligned} & & \tilde{y} &\approx \tilde{x} \cdot \theta_1 + \theta_2 \\ \Rightarrow & & \frac{y-a}{b} &\approx \frac{x-c}{d} \cdot \theta_1 + \theta_2 \\ \Rightarrow & & y-a &\approx b \left( \frac{x-c}{d} \cdot \theta_1 + \theta_2 \right) \\ \Rightarrow & & y &\approx (x-c) \cdot \frac{b}{d}\theta_1 + b\theta_2 + a \\ \Rightarrow & & y &\approx x \cdot \frac{b}{d} \theta_1- \frac{cb}{d} \theta_1 + b\theta_2 + a \\ \Rightarrow & & y &\approx x \cdot \left( \frac{b}{d} \theta_1 \right) + \left( a + b\theta_2 - \frac{cb}{d} \theta_1 \right) \\ \Rightarrow & & y &\approx x \cdot \hat{\theta}_1 + \hat{\theta}_2 \end{aligned} ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ y ~ b y − a y − a y y y y ≈ x ~ ⋅ θ 1 + θ 2 ≈ d x − c ⋅ θ 1 + θ 2 ≈ b ( d x − c ⋅ θ 1 + θ 2 ) ≈ ( x − c ) ⋅ d b θ 1 + b θ 2 + a ≈ x ⋅ d b θ 1 − d c b θ 1 + b θ 2 + a ≈ x ⋅ ( d b θ 1 ) + ( a + b θ 2 − d c b θ 1 ) ≈ x ⋅ θ ^ 1 + θ ^ 2 其中:
a = min i y ( i ) , b = max i y ( i ) − min i y ( i ) , c = min i x ( i ) , d = max i x ( i ) − min i x ( i ) a = \min_i y^{(i)},\quad b = \max_i y^{(i)} - \min_i y^{(i)}, \quad c = \min_i x^{(i)}, \quad d = \max_i x^{(i)} - \min_i x^{(i)} a = i min y ( i ) , b = i max y ( i ) − i min y ( i ) , c = i min x ( i ) , d = i max x ( i ) − i min x ( i ) 并且:
θ ^ 1 = b d θ 1 θ ^ 2 = b θ 2 + a − c ⋅ b d θ 1 \begin{aligned} \hat{\theta}_1 &= \frac{b}{d}\theta_1 \\ \hat{\theta}_2 &= b\theta_2 + a - c \cdot \frac{b}{d}\theta_1 \end{aligned} θ ^ 1 θ ^ 2 = d b θ 1 = b θ 2 + a − c ⋅ d b θ 1 对于原始数据矩阵 X X X 与结果向量 y y y ,有:
y − min ( y ) r a n g e ( y ) = ∑ j = 1 n − 1 θ j x j − min ( x j ) r a n g e ( x j ) + θ n ⇒ y − min ( y ) = r a n g e ( y ) ( ∑ j = 1 n − 1 θ j x j − min ( x j ) r a n g e ( x j ) + θ n ) ⇒ y = ∑ j = 1 n − 1 θ j r a n g e ( y ) r a n g e ( x j ) ( x j − min ( x j ) ) + θ n r a n g e ( y ) + min ( y ) ⇒ y = ∑ j = 1 n − 1 ( θ j r a n g e ( y ) r a n g e ( x j ) ) x j + ( θ n r a n g e ( y ) + min ( y ) − ∑ j = 1 n − 1 θ j r a n g e ( y ) r a n g e ( x j ) min ( x j ) ) ⇒ y = ∑ j = 1 n − 1 θ ^ j x j + θ ^ n \begin{aligned} & & \frac{y - \min(y)}{\mathrm{range}(y)} &= \sum_{j=1}^{n-1} \theta_j \frac{x_j - \min(x_j)}{\mathrm{range}(x_j)} + \theta_n \\ \Rightarrow & & y - \min(y) &= \mathrm{range}(y) \left( \sum_{j=1}^{n-1} \theta_j \frac{x_j - \min(x_j)}{\mathrm{range}(x_j)} + \theta_n \right) \\ \Rightarrow & & y &= \sum_{j=1}^{n-1} \theta_j \frac{\mathrm{range}(y)}{\mathrm{range}(x_j)} (x_j - \min(x_j)) + \theta_n \mathrm{range}(y) + \min(y) \\ \Rightarrow & & y &= \sum_{j=1}^{n-1} \left( \theta_j \frac{\mathrm{range}(y)}{\mathrm{range}(x_j)} \right) x_j + \left( \theta_n \mathrm{range}(y) + \min(y) - \sum_{j=1}^{n-1} \theta_j \frac{\mathrm{range}(y)}{\mathrm{range}(x_j)} \min(x_j) \right) \\ \Rightarrow & & y &= \sum_{j=1}^{n-1} \hat{\theta}_j x_j + \hat{\theta}_n \\ \end{aligned} ⇒ ⇒ ⇒ ⇒ range ( y ) y − min ( y ) y − min ( y ) y y y = j = 1 ∑ n − 1 θ j range ( x j ) x j − min ( x j ) + θ n = range ( y ) ( j = 1 ∑ n − 1 θ j range ( x j ) x j − min ( x j ) + θ n ) = j = 1 ∑ n − 1 θ j range ( x j ) range ( y ) ( x j − min ( x j )) + θ n range ( y ) + min ( y ) = j = 1 ∑ n − 1 ( θ j range ( x j ) range ( y ) ) x j + ( θ n range ( y ) + min ( y ) − j = 1 ∑ n − 1 θ j range ( x j ) range ( y ) min ( x j ) ) = j = 1 ∑ n − 1 θ ^ j x j + θ ^ n 其中新的系数为:
θ ^ j = θ j r a n g e ( y ) r a n g e ( x j ) θ ^ n = θ n r a n g e ( y ) + min ( y ) − ∑ j = 1 n − 1 θ ^ j min ( x j ) \begin{aligned} \hat{\theta}_j &= \theta_j \frac{\mathrm{range}(y)}{\mathrm{range}(x_j)} \\ \hat{\theta}_n &= \theta_n \mathrm{range}(y) + \min(y) - \sum_{j=1}^{n-1} \hat{\theta}_j \min(x_j) \end{aligned} θ ^ j θ ^ n = θ j range ( x j ) range ( y ) = θ n range ( y ) + min ( y ) − j = 1 ∑ n − 1 θ ^ j min ( x j ) 这一过程的简单代码实现如下:
def normalize_data (X, y, normalize_cols ):
""" Normalize y and specified columns of X in place. """
min_X = X[:,normalize_cols].min (axis=0 )
max_X = X[:, normalize_cols].max (axis=0 )
min_y = y.min ()
max_y = y.max ()
X[:, normalize_cols] = (X[:,normalize_cols] - min_X) / (max_X - min_X)
y[:] = (y - min_y) / (max_y - min_y)
return (min_X, max_X, min_y, max_y)
def unnormalize_theta (theta, normalize_cols, ranges ):
theta[normalize_cols] /= (ranges[1 ] - ranges[0 ])
theta *= ranges[3 ] - ranges[2 ]
theta[-1 ] += ranges[2 ] - theta[normalize_cols] @ ranges[0 ]
c . c. c . 解析解对于最小二乘法这个特殊形式,处理梯度下降方法,我们还可以采用解析解的方法求解最优状态。
解析解方法基于下面的基本原理:E ( θ ) E(\theta) E ( θ ) 的最小值在梯度为0的地方取得 。
先回到我们在最小二乘法的梯度下降公式:
∂ E ( θ ) ∂ θ j = 2 m ∑ i = 1 m ( ∑ k = 1 n θ k x k ( i ) − y ( i ) ) x j ( i ) \frac{\partial E(\theta)}{\partial \theta_j} = \frac{2}{m} \sum_{i=1}^{m} \left( \sum_{k=1}^{n} \theta_k x^{(i)}_k - y^{(i)} \right) x^{(i)}_j ∂ θ j ∂ E ( θ ) = m 2 i = 1 ∑ m ( k = 1 ∑ n θ k x k ( i ) − y ( i ) ) x j ( i ) 这里和 j j j 有关的项只有 x j ( i ) x_j^{(i)} x j ( i ) ,于是我们整理一下这个式子的形式:
∇ E ( θ ) = 2 m ∑ i = 1 m x ( i ) ( ∑ k = 1 n θ k x k ( i ) − y ( i ) ) \nabla E(\theta) = \frac{2}{m} \sum_{i=1}^{m} x^{(i)} \left( \sum_{k=1}^{n} \theta_k x^{(i)}_k - y^{(i)} \right) ∇ E ( θ ) = m 2 i = 1 ∑ m x ( i ) ( k = 1 ∑ n θ k x k ( i ) − y ( i ) ) 而根据线性代数中点积的定义:∑ k = 1 n θ k x k = θ T x = x T θ \sum _{k=1} ^n \theta_kx_k=\theta^Tx=x^T\theta ∑ k = 1 n θ k x k = θ T x = x T θ ,于是:
∇ E ( θ ) = 2 m ∑ i = 1 m x ( i ) ( x ( i ) T θ − y ( i ) ) = 2 m ∑ i = 1 m x ( i ) x ( i ) T θ − 2 m ∑ i = 1 m x ( i ) y ( i ) = 2 m ( ∑ i = 1 m x ( i ) x ( i ) T ) θ − 2 m ∑ i = 1 m x ( i ) y ( i ) \begin{aligned} \nabla E(\theta) &= \frac{2}{m} \sum_{i=1}^{m} x^{(i)} (x^{(i)T} \theta - y^{(i)}) \\ &= \frac{2}{m} \sum_{i=1}^{m} x^{(i)} x^{(i)T} \theta - \frac{2}{m} \sum_{i=1}^{m} x^{(i)} y^{(i)} \\ &= \frac{2}{m} \left( \sum_{i=1}^{m} x^{(i)} x^{(i)T} \right) \theta - \frac{2}{m} \sum_{i=1}^{m} x^{(i)} y^{(i)} \end{aligned} ∇ E ( θ ) = m 2 i = 1 ∑ m x ( i ) ( x ( i ) T θ − y ( i ) ) = m 2 i = 1 ∑ m x ( i ) x ( i ) T θ − m 2 i = 1 ∑ m x ( i ) y ( i ) = m 2 ( i = 1 ∑ m x ( i ) x ( i ) T ) θ − m 2 i = 1 ∑ m x ( i ) y ( i ) 我们令 ∇ E ( θ ) = 0 \nabla E(\theta)=0 ∇ E ( θ ) = 0 :
∇ E ( θ ⋆ ) = 0 ⟺ 2 m ( ∑ i = 1 m x ( i ) x ( i ) T ) θ ⋆ − 2 m ∑ i = 1 m x ( i ) y ( i ) = 0 ⟺ ( ∑ i = 1 m x ( i ) x ( i ) T ) θ ⋆ = ∑ i = 1 m x ( i ) y ( i ) ⟺ θ ⋆ = ( ∑ i = 1 m x ( i ) x ( i ) T ) − 1 ( ∑ i = 1 m x ( i ) y ( i ) ) \begin{aligned} \nabla E(\theta^\star) = 0 & \iff \frac{2}{m} \left( \sum_{i=1}^{m} x^{(i)} x^{(i)T} \right) \theta^\star - \frac{2}{m} \sum_{i=1}^{m} x^{(i)} y^{(i)} = 0 \\ & \iff \left( \sum_{i=1}^{m} x^{(i)} x^{(i)T} \right) \theta^\star = \sum_{i=1}^{m} x^{(i)} y^{(i)} \\ & \iff \theta^\star = \left( \sum_{i=1}^{m} x^{(i)} x^{(i)T} \right)^{-1} \left( \sum_{i=1}^{m} x^{(i)} y^{(i)} \right) \end{aligned} ∇ E ( θ ⋆ ) = 0 ⟺ m 2 ( i = 1 ∑ m x ( i ) x ( i ) T ) θ ⋆ − m 2 i = 1 ∑ m x ( i ) y ( i ) = 0 ⟺ ( i = 1 ∑ m x ( i ) x ( i ) T ) θ ⋆ = i = 1 ∑ m x ( i ) y ( i ) ⟺ θ ⋆ = ( i = 1 ∑ m x ( i ) x ( i ) T ) − 1 ( i = 1 ∑ m x ( i ) y ( i ) ) 这个式子可以通过下面的代码计算:
def analytic_ls (X, y ):
m, n = X.shape
A = np.zeros((n, n))
b = np.zeros(n)
for i in range (m):
A += X[i].T @ X[i]
b += X[i].dot(y)
return np.linalg.solve(A, b)
d . d. d . 矩阵记号下的梯度下降与解析解我们将输入数据和期望结果用如下记号表示:
X ∈ R m × n = [ x ( 1 ) T x ( 2 ) T ⋮ x ( m ) T ] , y ∈ R m = [ y ( 1 ) y ( 2 ) ⋮ y ( m ) ] X \in \mathbb{R}^{m \times n} = \begin{bmatrix} x^{(1)T} \\ x^{(2)T} \\ \vdots \\ x^{(m)T} \end{bmatrix}, \quad y \in \mathbb{R}^{m} = \begin{bmatrix} y^{(1)} \\ y^{(2)} \\ \vdots \\ y^{(m)} \end{bmatrix} X ∈ R m × n = x ( 1 ) T x ( 2 ) T ⋮ x ( m ) T , y ∈ R m = y ( 1 ) y ( 2 ) ⋮ y ( m ) 在这样的记号下,先前的最小二乘梯度计算:
∇ E ( θ ) = 2 m ∑ i = 1 m x ( i ) ( x ( i ) T θ − y ( i ) ) \nabla E(\theta) = \frac{2}{m} \sum_{i=1}^{m} x^{(i)} (x^{(i)T} \theta - y^{(i)}) ∇ E ( θ ) = m 2 i = 1 ∑ m x ( i ) ( x ( i ) T θ − y ( i ) ) 可以重新写作:
∇ E ( θ ) = 2 m X T ( X θ − y ) \nabla E(\theta) = \frac{2}{m}X^T(X\theta-y) ∇ E ( θ ) = m 2 X T ( Xθ − y ) 这个公式十分简洁,同时解析解的形式也非常简洁:
∇ E ( θ ⋆ ) = 0 ⟺ ∇ E ( θ ) = 2 m X T ( X θ − y ) = 0 ⟺ θ ⋆ = ( X T X ) − 1 X T Y \nabla E(\theta^\star) = 0 \iff \nabla E(\theta) = \frac{2}{m}X^T(X\theta-y)=0 \iff \theta^\star = (X^TX)^{-1}X^TY ∇ E ( θ ⋆ ) = 0 ⟺ ∇ E ( θ ) = m 2 X T ( Xθ − y ) = 0 ⟺ θ ⋆ = ( X T X ) − 1 X T Y 两者的计算都只需要一行代码即可:
errors = X.T @ theta - y
grad = (2 /m) * (X.T @ errors)
theta = np.linalg.solve(X.T @ X, X.T * y)
梯度计算式 ∇ E ( θ ) = 2 m X T ( X θ − y ) \nabla E(\theta) = \frac{2}{m}X^T(X\theta-y) ∇ E ( θ ) = m 2 X T ( Xθ − y ) 可以拆分成三个模块来理解:grad = (尺度调节器) * (责任分配器) @ (误差方向盘)
。 X θ − y X\theta-y Xθ − y 计算了我们当前模型 θ θ θ 对每一个数据点的预测值 X θ Xθ Xθ 与真实值 y y y 之间的差距,这个值告诉我们误差的幅度和方向。
X T X^T X T 则实现了将 e r r o r s errors errors 误差进行分配的功能。由最初的梯度计算式,θ j θ_j θ j 的总梯度,等于每一个样本的误差 e r r o r s i errors_i error s i ,乘以该样本上 θ j θ_j θ j 所对应的特征值 X i , j X_{i,j} X i , j ,然后把这些乘积全部加起来。这就像一个加权投票的过程:X X X 中的每个样本 i i i 都在对 θ j θ_j θ j 应该增加还是减少?”进行投票。投票的“票面价值”就是 X i , j X_{i, j} X i , j ,投票的“权重”就是 e r r o r s i errors_i error s i
2 m \frac{2}{m} m 2 是一个简单的“尺度调节器”,其中 m m m 负责取平均值、让梯度更加稳定;而 2 只是一个求导过程产生的参数,可以被学习率 α \alpha α 吸收。
e . e. e . 线性回归简单实现根据上面的内容,我们仿照 scikit-learn
的设计,实现一个简单的线性回归类:
class MyLinearRegression :
def __init__ (self, method='gd' , learning_rate=0.1 , n_iters=1000 ):
self .method = method
self .learning_rate = learning_rate
self .n_iters = n_iters
self ._theta = None
def fit (self, X, y ):
m, n = X.shape
X_b = np.c_[np.ones((m, 1 )), X]
if self .method == 'gd' :
theta = np.zeros(0 )
for i in range (self .n_iters):
errors = X_b @ theta - y
grad = (2 /m) * (X_b.T @ errors)
theta = theta - self .learning_rate * grad
self ._theta = theta
elif self .method == 'normal' :
A = X_b.T @ X_b
b = X_b.T @ y
self .theta_ = np.linalg.solve(A, b)
else :
raise ValueError("method must be gd or normal" )
return self
def predict (self, X ):
if self .theta_ is None :
raise RuntimeError("Please train the model before prediction" )
X_b = np.c_[np.ones((X.shape[0 ], 1 )), X]
return X_b @ self .theta_
@property
def intercept_ (self ):
return self .theta_[0 ] if self .theta_ is not None else None
@property
def coef_ (self ):
return self .theta_[1 :] if self .theta_ is not None else None
3. 线性分类问题 a . a. a . 相关概念与前面讨论的回归问题相比,分类问题有如下特点:
输出空间 Y Y Y 是有限的、离散的集合,而不是连续的区间。 预测空间 Y ^ \hat{Y} Y ^ 仍然是连续的实数 R \mathbb{R} R 。在中间过程中,我们的假设模型 h θ h_{\theta} h θ 会输出一个实数(如5.2,-1.7),其中:值的符号 (sign) 决定了最终的预测类别 :如果 hθ(x) 是正数,就预测为 +1;如果是负数,就预测为 -1。 值的绝对值大小 (magnitude) 代表了预测的把握有多大 。 通过让我们的假设模型返回一个连续的实数结果,我们可以得到更为平滑的结果、更好地进行梯度下降等算法。因为 { + 1 , − 1 } \lbrace +1, -1\rbrace { + 1 , − 1 } 这样的输出是非连续、不平滑的。
b . b. b . 损失函数设计分类问题常用的损失函数如下:
逻辑损失 (Logistic Loss) log ( 1 + exp ( − h θ ( x ) ⋅ y ) ) \log(1 + \exp(-h_θ(x) \cdot y)) log ( 1 + exp ( − h θ ( x ) ⋅ y ))
当预测非常正确时,h θ ( x ) ⋅ y h_θ(x)\cdot y h θ ( x ) ⋅ y 是很大的正数),exp \exp exp 趋近于0,总损失趋近于 log ( 1 ) = 0 \log(1)=0 log ( 1 ) = 0 。 当预测非常错误时,h θ ( x ) ⋅ y h_θ(x)\cdot y h θ ( x ) ⋅ y 是很大的负数),损失近似线性增长。 合页损失 (Hinge Loss) max { 1 − h θ ( x ) ⋅ y , 0 } \max \lbrace 1 - h_θ(x) \cdot y, 0 \rbrace max { 1 − h θ ( x ) ⋅ y , 0 }
只要 h θ ( x ) ⋅ y ≥ 1 h_θ(x) \cdot y \geq 1 h θ ( x ) ⋅ y ≥ 1 (即不仅分类正确,而且置信度超过一个“边界”1 ),损失就精确地为 0。 如果 h θ ( x ) ⋅ y < 1 h_θ(x) \cdot y \lt 1 h θ ( x ) ⋅ y < 1 ,损失会线性增加。 指数损失 (Exponential Loss) exp ( − h θ ( x ) ⋅ y ) \exp(-h_θ(x) \cdot y) exp ( − h θ ( x ) ⋅ y )
当预测正确时,损失趋近于 0。 当预测错误时,损失会指数级地爆炸式增长。 有了这些损失函数,我们的分类问题处理框架就和回归问题的类似了:
min θ 1 m ∑ i = 1 m ℓ ( h θ ( x ( i ) ) , y ( i ) ) \min_{\theta} \frac{1}{m} \sum_{i=1}^{m} \ell(h_{\theta}(x^{(i)}), y^{(i)}) θ min m 1 i = 1 ∑ m ℓ ( h θ ( x ( i ) ) , y ( i ) ) c . c. c . 支持向量机支持向量机 (Support vector machines, SVMs) 算法使用合页损失。SVM的假设函数有线性和核性两种。线性 SVM 使用如下的假设函数:
h θ ( x ) = ∑ j = 1 n θ j x j = θ T x h_{\theta}(x)=\sum_{j=1}^n\theta_jx_j=\theta^Tx h θ ( x ) = j = 1 ∑ n θ j x j = θ T x 核性 SVM 使用如下的假设函数:
h θ ( x ) = ∑ j = 1 n θ j K ( x , x ( i ) ) h_{\theta}(x)=\sum_{j=1}^n\theta_jK(x, x^{(i)}) h θ ( x ) = j = 1 ∑ n θ j K ( x , x ( i ) ) 添加了正则化参数的完整表达式如下:
min θ 1 m ∑ i = 1 m max { 1 − θ T x ( i ) ⋅ y ( i ) , 0 } + λ ∑ j = 1 n θ j 2 \min_{\theta}\frac{1}{m}\sum_{i=1}^m\max\lbrace 1-\theta^Tx^{(i)}\cdot y^{(i)}, 0 \rbrace + \lambda\sum_{j=1}^n\theta_j^2 θ min m 1 i = 1 ∑ m max { 1 − θ T x ( i ) ⋅ y ( i ) , 0 } + λ j = 1 ∑ n θ j 2 我们推导 SVM 梯度的计算。假设函数部分:
∂ ∂ θ j max { 1 − y ( θ T x ) , 0 } = − x j y ⋅ 1 { ( θ T x ) ⋅ y ≤ 1 } \frac{\partial}{\partial \theta_j} \max\{1 - y(\theta^T x), 0\} = -x_j y \cdot 1 \lbrace (\theta^T x) \cdot y \le 1 \rbrace ∂ θ j ∂ max { 1 − y ( θ T x ) , 0 } = − x j y ⋅ 1 {( θ T x ) ⋅ y ≤ 1 } 正则化部分:
∂ ∂ θ j ( λ ∑ k = 1 n θ k 2 ) = 2 λ θ j \frac{\partial}{\partial \theta_j} \left( \lambda \sum_{k=1}^{n} \theta_k^2 \right) = 2\lambda\theta_j ∂ θ j ∂ ( λ k = 1 ∑ n θ k 2 ) = 2 λ θ j 于是:
∇ θ E ( θ ) = ∇ θ ( 1 m ∑ i = 1 m max { 1 − y ( i ) ( θ T x ( i ) ) , 0 } + λ ∑ k = 1 n θ k 2 ) = − 1 m ∑ i = 1 m x ( i ) y ( i ) 1 { θ T x ( i ) ⋅ y ( i ) ≤ 1 } + 2 λ θ \begin{aligned} \nabla_{\theta} E(\theta) &= \nabla_{\theta} \left( \frac{1}{m} \sum_{i=1}^{m} \max\{1 - y^{(i)}(\theta^T x^{(i)}), 0\} + \lambda \sum_{k=1}^{n} \theta_k^2 \right) \\ &= - \frac{1}{m} \sum_{i=1}^{m} x^{(i)} y^{(i)} 1\lbrace\theta^T x^{(i)} \cdot y^{(i)} \le 1 \rbrace + 2\lambda\theta \end{aligned} ∇ θ E ( θ ) = ∇ θ ( m 1 i = 1 ∑ m max { 1 − y ( i ) ( θ T x ( i ) ) , 0 } + λ k = 1 ∑ n θ k 2 ) = − m 1 i = 1 ∑ m x ( i ) y ( i ) 1 { θ T x ( i ) ⋅ y ( i ) ≤ 1 } + 2 λ θ 矩阵形式的梯度表达式如下:
∇ θ E ( θ ) = − 1 m X T Y ⋅ 1 { Y X θ ≤ 1 } + 2 λ θ \nabla_{\theta} E(\theta) = -\frac{1}{m} X^T Y \cdot 1 \lbrace Y X\theta \le 1\rbrace + 2\lambda\theta ∇ θ E ( θ ) = − m 1 X T Y ⋅ 1 { Y Xθ ≤ 1 } + 2 λ θ 其中 Y = d i a g ( y ) Y=diag(y) Y = d ia g ( y ) 。
这里的 Y X θ ≤ 1 Y X\theta \le 1 Y Xθ ≤ 1 可以理解为“只对支持向量进行计算,其他样本的梯度贡献为0”,这也是“支持向量机”算法名称的来源。
根据这个矩阵形式梯度计算公式,我们可以写出如下代码:
def svm_dg (X, y, alpha, iters, lam ):
m, n = X.shape
theta = np.zeros(n)
YX = X * y[:, None ]
loss, err = np.zeros(iters), np.zeros(iters)
for i in range (iters):
hy = YX @ theta
loss[i] = np.maximum(1 -hy, 0 ).mean()
err[i] = (hy <= 0 ).mean()
theta = theta - alpha * (-YX.T @ (YX * theta <= 1 ) / m + 2 * lam * theta)
return theta, loss, err
这里的 YX.T
可以通过维度匹配判断需要转置。
d . d. d . 逻辑回归逻辑回归 (Logistic Regression) 算法使用逻辑损失函数:
ℓ logistic ( h θ ( x ) , y ) = log ( 1 + exp ( − y ⋅ h θ ( x ) ) ) \ell_{\text{logistic}}(h_{\theta}(x), y) = \log(1 + \exp(-y \cdot h_{\theta}(x))) ℓ logistic ( h θ ( x ) , y ) = log ( 1 + exp ( − y ⋅ h θ ( x ))) 我们推导逻辑回归梯度的计算:
∂ ∂ θ j log ( 1 + exp ( − y ( θ T x ) ) ) = 1 1 + exp ( − y ( θ T x ) ) ⋅ ∂ ∂ θ j ( 1 + exp ( − y ( θ T x ) ) ) = exp ( − y ( θ T x ) ) 1 + exp ( − y ( θ T x ) ) ⋅ ( − y x j ) = − exp ( − y ( θ T x ) ) 1 + exp ( − y ( θ T x ) ) y x j = − 1 1 + exp ( y ( θ T x ) ) y x j \begin{aligned} \frac{\partial}{\partial \theta_j} \log(1 + \exp(-y(\theta^T x))) &= \frac{1}{1 + \exp(-y(\theta^T x))} \cdot \frac{\partial}{\partial \theta_j}(1 + \exp(-y(\theta^T x))) \\ &= \frac{\exp(-y(\theta^T x))}{1 + \exp(-y(\theta^T x))} \cdot (-y x_j) \\ &= - \frac{\exp(-y(\theta^T x))}{1 + \exp(-y(\theta^T x))} y x_j \\ &= - \frac{1}{1 + \exp(y(\theta^T x))} y x_j \end{aligned} ∂ θ j ∂ log ( 1 + exp ( − y ( θ T x ))) = 1 + exp ( − y ( θ T x )) 1 ⋅ ∂ θ j ∂ ( 1 + exp ( − y ( θ T x ))) = 1 + exp ( − y ( θ T x )) exp ( − y ( θ T x )) ⋅ ( − y x j ) = − 1 + exp ( − y ( θ T x )) exp ( − y ( θ T x )) y x j = − 1 + exp ( y ( θ T x )) 1 y x j 因此:
∇ θ E ( θ ) = ∇ θ ( 1 m ∑ i = 1 m log ( 1 + exp ( − y ( i ) ( θ T x ( i ) ) ) ) ) = 1 m ∑ i = 1 m − y ( i ) x ( i ) 1 + exp ( y ( i ) ( θ T x ( i ) ) ) \begin{aligned} \nabla_{\theta} E(\theta) &= \nabla_{\theta} \left( \frac{1}{m} \sum_{i=1}^{m} \log(1 + \exp(-y^{(i)}(\theta^T x^{(i)}))) \right) \\ &= \frac{1}{m} \sum_{i=1}^{m} \frac{-y^{(i)} x^{(i)}}{1 + \exp(y^{(i)}(\theta^T x^{(i)}))} \end{aligned} ∇ θ E ( θ ) = ∇ θ ( m 1 i = 1 ∑ m log ( 1 + exp ( − y ( i ) ( θ T x ( i ) ))) ) = m 1 i = 1 ∑ m 1 + exp ( y ( i ) ( θ T x ( i ) )) − y ( i ) x ( i ) 矩阵形式的梯度表达如下:
∇ θ E ( θ ) = 1 m X Y 1 + exp Y X θ \nabla_{\theta} E(\theta) = \frac{1}{m}\frac{XY}{1+\exp{YX\theta}} ∇ θ E ( θ ) = m 1 1 + exp Y Xθ X Y 根据这个矩阵形式梯度计算公式,我们可以写出如下代码:
def logistic_reg_gd (X, y, alpha, iters ):
m, n = X.shape
theta = np.zeros(n)
YX = X * y[:, None ]
loss, err = np.zeros(iters), np.zeros(iters)
for i in range (iters):
hy = YX @ theta
loss[t] = np.log(1 +np.exp(-hy)).mean()
err[t] = (hy <= 0 ).mean()
theta -= alpha * -YX.T @ (1 /(1 +np.exp(YX @ theta)))/m
return theta, loss, err
4. 多种类分类问题 前面我们讨论的都是二元分类问题,但是现实生活中有很多问题是需要多重分类的。多重分类的输出空间是一个包含 k k k 个离散值的集合:Y = { 1 , 2 , … , k } Y=\lbrace 1, 2, \dots,k \rbrace Y = { 1 , 2 , … , k } 。处理多分类问题一般有下面两种方法:
“一对多” (One-versus-All, OvA):把一个 k k k 分类问题,拆解成 k k k 个独立的二元分类问题。具体做法如下:为每一个类别 i i i ,我们都训练一个专属的二元分类器 h θ i h_θi h θ i 。这个分类器 h θ i h_θi h θ i 的任务是回答一个“是/否”问题:“这个样本是第 i i i 类,还是不是第 i i i 类?” 在为分类器 h θ i h_θi h θ i 准备训练数据时,我们将所有原始标签为 i i i 的样本,其新标签设为 +1,其他样本的新标签设为 -1。 重复这个过程 k k k 次,我们就得到了 k k k 个训练好的二元分类器。 当来一个新的样本 x x x 时,我们让它分别通过所有 k k k 个分类器,得到 k k k 个代表“置信度”的实数值输出:h θ 1 ( x ) , h θ 2 ( x ) , . . . , h θ k ( x ) h_{θ1}(x), h_{θ2}(x), ..., h_{θk}(x) h θ 1 ( x ) , h θ 2 ( x ) , ... , h θ k ( x ) 。由于可能有多个分类器返回整数,因此我们比较它们的绝对大小,选择给出了最高置信度分数的分类器所对应的类别 :
y p r e d = arg max i h θ i ( x ) y_{pred} = \arg\max_i h_{θi}(x) y p re d = arg i max h θ i ( x ) 原生多分类 (Native Multiclass):我们可以不把 k k k 个分类器看作是独立的,而是把它们看作一个统一的、更复杂的分类器 。这个统一的分类器的假设函数 h θ h_θ h θ ,其输出不再是一个单独的实数,而是一个 k k k 维的向量 R k R^k R k 。k k k 维向量的第 i i i 个元素 h θ ( x ) i h_θ(x)^i h θ ( x ) i ,就代表了模型认为样本属于第 i i i 类的“相对置信度”。 有了 k k k 维的输出,我们就可以定义一个“原生”的损失函数 ℓ \ell ℓ 。这个函数接收一个 k k k 维的预测向量 h θ ( x ) h_θ(x) h θ ( x ) 和一个真实的类别标签 y y y ,然后计算出一个损失值。常见的损失函数有 softmax 函数
5. 泛化与过拟合 a . a. a . 相关概念在前面内容中,我们提到在训练机器学习模型的一个任务:
minimize 1 m ∑ i = 1 m ℓ ( h θ ( x ( i ) , y ( i ) ) ) \text{minimize}\frac{1}{m}\sum _{i=1}^m \ell(h_{\theta}(x^{(i)}, y^{(i)})) minimize m 1 i = 1 ∑ m ℓ ( h θ ( x ( i ) , y ( i ) )) 然而,这只是手段,不是最终目的。因为训练集里的数据是已知的,我们已经知道正确答案 y ( i ) y(i) y ( i ) 了。我们真正关心的是泛化能力 (Generalization) :当一个全新的、模型从未见过的数据出现时,我们的模型能否依然做出准确的预测。
由此,我们引入泛化误差 (Generalization Error) 。它指的是模型在新数据上的预测误差 。我们真正需要的是最小化泛化误差,而不是训练误差。
而一个模型如果在训练集上表现极好(训练误差很低),但在新数据上表现很差(泛化误差很高),它就是过拟合 (Overfitting) 的。
b . b. b . 交叉验证交叉验证是找到那个泛化误差最低的最佳点的常用手段。
最简单的交叉验证方法如下:
将原始数据集分成两部分,例如:70% 作为训练集 (Training Set),30% 作为验证集 (Validation Set / Hold-out Set)。 我们只用训练集来训练模型(即调整参数 θ θ θ )。 训练完成后,用验证集来测试模型,计算其误差(称为验证误差)。 验证集和测试集在概念上是不同的。验证集用于选择模型和调整超参数,而测试集是在所有选择和调整都完成后,对最终模型的一次性最终评估,评估后就不能再返回去修改模型了。
简单的70/30划分有一个缺点:结果可能受到单次随机划分的影响。如果某次划分碰巧把一些很“奇怪”的数据点(离群点)都分到了验证集,那么评估结果可能就不太准。为了解决这个问题,我们可以使用K-折交叉验证,它的步骤如下:
将整个数据集平均分成 k k k 份(称为 k fold)。 进行 k k k 次训练和验证,每次:选其中 1 份作为验证集。 剩下的 k − 1 k-1 k − 1 份作为训练集。 将 k k k 次验证得到的误差取平均值,作为最终的评估结果。 6. 正则化 a . a. a . 相关概念机器学习模型有一个重要的参数:模型参数(系数)的大小 (magnitude of the model parameters)。一个模型如果依赖巨大的、精巧抵消的系数 ,说明它非常不稳定和复杂。它对输入数据的微小变化会非常敏感 。一个更简单、更鲁棒的模型,其系数通常会比较小,曲线也更平滑。
正则化正是一种在机器学习模型的优化过程中,通过在损失函数中加入一个惩罚项 (penalty term) 来限制模型参数大小 的技术。
b . b. b . 最小二乘中的正则化我们将 ℓ 2 \ell_2 ℓ 2 正则化应用到最小二乘模型中:
min θ 1 m ∑ i = 1 m ( θ T x ( i ) − y ( i ) ) + λ ∑ j = 1 n θ j 2 \min_\theta\frac{1}{m}\sum_{i=1}^m(\theta^Tx^{(i)}-y^{(i)}) + \lambda\sum_{j=1}^n\theta_j^2 θ min m 1 i = 1 ∑ m ( θ T x ( i ) − y ( i ) ) + λ j = 1 ∑ n θ j 2 在前面的内容中,我们已经知道平均损失部分的梯度:
∇ E ( θ ) = 2 m X T ( X θ − y ) \nabla E(\theta) = \frac{2}{m}X^T(X\theta-y) ∇ E ( θ ) = m 2 X T ( Xθ − y ) 而正则化部分的梯度:
∇ λ ∑ j = 1 n θ j 2 = 2 λ θ \nabla \lambda\sum_{j=1}^n\theta_j^2=2\lambda\theta ∇ λ j = 1 ∑ n θ j 2 = 2 λ θ 于是:
∇ θ E ( θ ⋆ ) = 0 ⇒ 2 m X T ( X θ ⋆ − y ) + 2 λ θ ⋆ = 0 ⇒ X T ( X θ ⋆ − y ) + m λ θ ⋆ = 0 ⇒ ( X T X + m λ I ) θ ⋆ = X T y ⇒ θ ⋆ = ( X T X + m λ I ) − 1 X T y \begin{aligned} & \nabla_{\theta} E(\theta^\star) = 0 \\ \Rightarrow \quad & \frac{2}{m} X^T(X\theta^\star - y) + 2\lambda\theta^\star = 0 \\ \Rightarrow \quad & X^T(X\theta^\star - y) + m\lambda\theta^\star = 0 \\ \Rightarrow \quad & (X^T X + m\lambda I)\theta^\star = X^T y \\ \Rightarrow \quad & \theta^\star = (X^T X + m\lambda I)^{-1} X^T y \end{aligned} ⇒ ⇒ ⇒ ⇒ ∇ θ E ( θ ⋆ ) = 0 m 2 X T ( X θ ⋆ − y ) + 2 λ θ ⋆ = 0 X T ( X θ ⋆ − y ) + mλ θ ⋆ = 0 ( X T X + mλ I ) θ ⋆ = X T y θ ⋆ = ( X T X + mλ I ) − 1 X T y 我们可以把 m m m 并入正则化参数 λ \lambda λ 中:
θ ⋆ = ( X T X + λ I ) − 1 X T y \theta^\star = (X^T X + \lambda I)^{-1} X^T y θ ⋆ = ( X T X + λ I ) − 1 X T y 这个结果体现了正则化的另一个好处:在标准的最小二乘法中,如果 X T X X^TX X T X 不可逆(比如特征之间高度相关),就无法求解。但加入正则化项后,由于我们加上了一个 λ I λI λ I 项(即在 X T X X^TX X T X 的对角线上都加上一个小的正数 λ \lambda λ ),这使得矩阵几乎总是可逆的 ,从而求解过程更加稳定。
这个正则化项可以简单地迁移到梯度下降中,我们只需要将参数更新规则改为下面的形式:
θ : = θ − α ( ∇ θ ( loss ) + 2 λ θ ) \theta := \theta - \alpha(\nabla_\theta(\text{loss})+2\lambda \theta) θ := θ − α ( ∇ θ ( loss ) + 2 λ θ ) 6. 非线性特征 a . a. a . 特征映射特征映射是将非线性问题转化成线性问题的一个常用方法。特征映射将 n n n 维原始输入映射为例 k k k 维的特征向量:
ϕ : R n → R k \phi:\mathbb{R}^n \rightarrow \mathbb{R}^k ϕ : R n → R k 这样,我们就可以转而考虑一个线性的多项式函数(对 k k k 阶向量而言)作为假设函数,它的参数 θ ∈ R k \theta\in\mathbb{R}^k θ ∈ R k :
h θ ( x ) = θ T ϕ ( x ) h_{\theta}(x)=\theta^T\phi(x) h θ ( x ) = θ T ϕ ( x ) 特征映射的神奇之处在于:我们不需要发明新的、复杂的非线性算法,我们只需要在应用简单线性算法之前,对数据进行一次“升维和变换” 。
b . b. b . 径向基函数i . i. i . 定义与特征径向基函数的形式如下:
ϕ : R → R k = [ exp ( − ( x − μ ( 1 ) ) 2 2 σ 2 ) exp ( − ( x − μ ( 2 ) ) 2 2 σ 2 ) ⋮ exp ( − ( x − μ ( k − 1 ) ) 2 2 σ 2 ) 1 ] \phi: \mathbb{R} \to \mathbb{R}^k = \begin{bmatrix} \exp\!\left(-\dfrac{(x-\mu^{(1)})^2}{2\sigma^2}\right) \\ \exp\!\left(-\dfrac{(x-\mu^{(2)})^2}{2\sigma^2}\right) \\ \vdots \\ \exp\!\left(-\dfrac{(x-\mu^{(k-1)})^2}{2\sigma^2}\right) \\ 1 \end{bmatrix} ϕ : R → R k = exp ( − 2 σ 2 ( x − μ ( 1 ) ) 2 ) exp ( − 2 σ 2 ( x − μ ( 2 ) ) 2 ) ⋮ exp ( − 2 σ 2 ( x − μ ( k − 1 ) ) 2 ) 1 其中 μ ( 1 ) , … , μ k − 1 \mu^{(1)},\dots,\mu^{k-1} μ ( 1 ) , … , μ k − 1 称作均值 ,σ \sigma σ 称作带宽 。
与多项式这样的全局特征 (global features) 不同,RBF 是局部特征 (local features)。RBF 的每个特征只在输入空间的一小块区域内有显著的非零值 ,在其他地方都接近于零。
这些参数对特征的影响如下:
μ ( j ) μ(j) μ ( j ) :是第 j j j 个基函数的中心 (center)。它决定了这个“钟形”的峰值在哪里。σ σ σ : 它决定了这个“钟形”的胖瘦。σ σ σ 越大,钟形越胖,特征影响的范围越广;σ σ σ 越小,钟形越瘦,特征影响的范围越窄。exp ( − . . . ) \exp(-...) exp ( − ... ) : 确保当 x x x 离中心 μ ( j ) μ(j) μ ( j ) 越远,φ j ( x ) φ_j(x) φ j ( x ) 的值就越快地衰减到 0。当 x = μ ( j ) x = μ(j) x = μ ( j ) 时,φ j ( x ) φ_j(x) φ j ( x ) 取最大值 1。和多项式一样,RBF 也会过拟合。如果我们使用的 RBF 特征数量过多(即中心 μ μ μ 的数量太多),模型就会变得过于灵活,试图去拟合训练数据中的每一个点,导致函数曲线变得非常“扭曲”和“振荡”。
最终 RBF 会得到一个如下的特征矩阵:
Φ ( X ) = [ exp ( − ( x 1 − μ ( 1 ) ) 2 2 σ 2 ) exp ( − ( x 1 − μ ( 2 ) ) 2 2 σ 2 ) ⋯ exp ( − ( x 1 − μ ( k − 1 ) ) 2 2 σ 2 ) 1 exp ( − ( x 2 − μ ( 1 ) ) 2 2 σ 2 ) exp ( − ( x 2 − μ ( 2 ) ) 2 2 σ 2 ) ⋯ exp ( − ( x 2 − μ ( k − 1 ) ) 2 2 σ 2 ) 1 ⋮ ⋮ ⋱ ⋮ ⋮ exp ( − ( x m − μ ( 1 ) ) 2 2 σ 2 ) exp ( − ( x m − μ ( 2 ) ) 2 2 σ 2 ) ⋯ exp ( − ( x m − μ ( k − 1 ) ) 2 2 σ 2 ) 1 ] \Phi(X)= \begin{bmatrix} \exp\!\left(-\dfrac{(x_1-\mu^{(1)})^2}{2\sigma^2}\right) & \exp\!\left(-\dfrac{(x_1-\mu^{(2)})^2}{2\sigma^2}\right) & \cdots & \exp\!\left(-\dfrac{(x_1-\mu^{(k-1)})^2}{2\sigma^2}\right) & 1 \\ \exp\!\left(-\dfrac{(x_2-\mu^{(1)})^2}{2\sigma^2}\right) & \exp\!\left(-\dfrac{(x_2-\mu^{(2)})^2}{2\sigma^2}\right) & \cdots & \exp\!\left(-\dfrac{(x_2-\mu^{(k-1)})^2}{2\sigma^2}\right) & 1 \\ \vdots & \vdots & \ddots & \vdots & \vdots \\ \exp\!\left(-\dfrac{(x_m-\mu^{(1)})^2}{2\sigma^2}\right) & \exp\!\left(-\dfrac{(x_m-\mu^{(2)})^2}{2\sigma^2}\right) & \cdots & \exp\!\left(-\dfrac{(x_m-\mu^{(k-1)})^2}{2\sigma^2}\right) & 1 \end{bmatrix} Φ ( X ) = exp ( − 2 σ 2 ( x 1 − μ ( 1 ) ) 2 ) exp ( − 2 σ 2 ( x 2 − μ ( 1 ) ) 2 ) ⋮ exp ( − 2 σ 2 ( x m − μ ( 1 ) ) 2 ) exp ( − 2 σ 2 ( x 1 − μ ( 2 ) ) 2 ) exp ( − 2 σ 2 ( x 2 − μ ( 2 ) ) 2 ) ⋮ exp ( − 2 σ 2 ( x m − μ ( 2 ) ) 2 ) ⋯ ⋯ ⋱ ⋯ exp ( − 2 σ 2 ( x 1 − μ ( k − 1 ) ) 2 ) exp ( − 2 σ 2 ( x 2 − μ ( k − 1 ) ) 2 ) ⋮ exp ( − 2 σ 2 ( x m − μ ( k − 1 ) ) 2 ) 1 1 ⋮ 1 然后我们就可以使用这个矩阵作为特征输入,进行梯度计算等操作了。
使用 RBF 作为特征工程的简单实现如下:
def rbf_feat (x, mu, sig ):
return np.hstack([np.exp(-(x[:, None ] - mu)**2 / (2 * sig ** 2 )), np.ones(len (x), 1 )])
def train_rbf (x, y, n_rbf ):
min_x, max_x = x.min (), x.max ()
sig = (max_x - min_x)/(n_rbf-1 )
mu = np.linspace(min_x, max_x, n_rbf-1 )
Phi = rbf_feat(x, mu, sig)
theta = np.linalg.solve(Phi.T @ Phi, Phi.T @ y)
return theta, mu, sig
i i . ii. ii . 超参数RBF 的主要超参数如下:
中心点的数量和位置 μ μ μ :这是最直接控制模型复杂度的参数。中心点越多,模型越复杂。在一维数据中,可以简单地将它们均匀分布。但在高维数据中,如何选择中心点本身就是一个问题(例如,可以随机选一些数据点作为中心,或使用聚类算法来确定中心)。 正则化参数 λ λ λ 带宽参数 σ σ σ :带宽也控制着模型的复杂度。当 σ \sigma σ 较大时,钟形曲线很胖,各个基函数之间重叠很多。最终的函数会更平滑,模型更简单。增大带宽 σ σ σ 和增大正则化参数 λ λ λ 有类似的效果,都是在简化模型,使其更平滑。 7. 多维度中的非线性特征 a . a. a . 多维多项式当原始输入 x x x 是一个 n n n 维向量时,如果需要构建它的多项式特征,除了每个维度自身的高次项 x 1 2 x_1^2 x 1 2 , x 2 2 x_2^2 x 2 2 , x 3 3 x_3^3 x 3 3 外,我们还必须包含不同维度之间的交叉项 x 1 x 2 x_1x_2 x 1 x 2 , x 1 2 x 2 x_1^2x_2 x 1 2 x 2 , x 1 x 2 2 x_1x_2^2 x 1 x 2 2 等。
Python 的 itertools
模块的 combinations_with_replacement
方法可以从一个列表中有放回地选出指定数量的元素。利用这个方法可以轻松生成 x 1 , … , x n x_1,\dots,x_n x 1 , … , x n 的各种组合:
x = np.array(["x1" ,"x2" ,"x3" ])
list (combinations_with_replacement(x,3 ))
如果我们需要生成最高阶为 n n n 的项 ,我们可以在数组中添加一个常数项 1: x = np.array(["x1" ,"x2" ,"x3" ,"1" ])
list (combinations_with_replacement(x,3 ))
在输入矩阵 X X X 中,我们可以通过下面这个简单函数计算矩阵元素所有多项式乘积:
def poly_feat (X,d ):
m = X.shape[0 ]
X_ = np.hstack([X, np.ones(m, 1 )]).T
return np.array([np.array(a).prod(axis=0 ) for a in combinations_with_replacement(X_,d)]).T
在数学计算中,一个维度为 n n n 的 d d d 阶多项式具有的特征数量为 C ( n + d ) , d C(n+d), d C ( n + d ) , d 。
b . b. b . 多维 RBF为了将 RBF 推广到多维,只需要将一维的距离 ( x − μ ) 2 (x - μ)^2 ( x − μ ) 2 替换为多维空间中的平方欧氏距离 ∣ ∣ x − μ ∣ ∣ 2 ||x - μ||^2 ∣∣ x − μ ∣ ∣ 2 :
ϕ j ( x ) = exp ( − ∣ ∣ x − μ j ∣ ∣ 2 2 σ 2 ) \phi_j(x)=\exp(\frac{-\mid\mid x-\mu_j \mid\mid ^2}{2\sigma ^ 2}) ϕ j ( x ) = exp ( 2 σ 2 − ∣∣ x − μ j ∣ ∣ 2 ) 直接计算平方欧式距离的效率较低,我们可以通过矩阵向量运算进行优化,对单个向量我们有:
∥ x ( i ) − μ ( j ) ∥ 2 2 = ( x ( i ) − μ ( j ) ) T ( x ( i ) − μ ( j ) ) = ∥ x ( i ) ∥ 2 2 + ∥ μ ( j ) ∥ 2 2 − 2 x ( i ) T μ ( j ) \begin{aligned} \|x^{(i)} - \mu^{(j)}\|_2^2 &= (x^{(i)} - \mu^{(j)})^T (x^{(i)} - \mu^{(j)}) \\ &= \|x^{(i)}\|_2^2 + \|\mu^{(j)}\|_2^2 - 2\, x^{(i)T} \mu^{(j)} \end{aligned} ∥ x ( i ) − μ ( j ) ∥ 2 2 = ( x ( i ) − μ ( j ) ) T ( x ( i ) − μ ( j ) ) = ∥ x ( i ) ∥ 2 2 + ∥ μ ( j ) ∥ 2 2 − 2 x ( i ) T μ ( j ) 由于我们最终需要得到维度为 m × k m \times k m × k 的矩阵,因此 x ( i ) T μ ( j ) x^{(i)T} \mu^{(j)} x ( i ) T μ ( j ) 转换成矩阵形式为 X M T XM^T X M T 。利用 numpy 的广播机制,我们可以写出如下的函数:
def sqdist (X, M ):
return (X**2 ).sum (axis=1 )[:,None ] + (M**2 ).sum (axis=1 ) - 2 *X @ M.T
同样地,多维 RBF 特征计算如下:
def rbf_feat (X, mu, sig ):
return np.exp(-sqdist(X,mu) / (2 *sig**2 ))
在数学计算中,n n n 维 d d d 中心的 RBFs 具有的特征数量为 d n d^n d n 。
c . c. c . 多项式与 RBF 多维特征的实用准则多维多项式特征的一些基本准则如下:
C ( n + d , d ) C(n+d, d) C ( n + d , d ) 这个公式告诉我们,只有当维度 n n n 和阶数 d d d 同时很大时,特征数量才会爆炸。因此:如果原始维度 n n n 很高,那么只使用很低的阶数 d d d (通常 d = 2 d=2 d = 2 ,即只生成二次项,这已经很常见且有效了)。 如果确实需要使用很高的阶数 d d d ,那么必须保证原始维度 n n n 非常低。 处理二元特征 (Binary Features):如果一个特征 x j x_j x j 是二元的(即取值只有 0 或 1),那么 x j 2 = x j x_j^2 = x_j x j 2 = x j , x j 3 = x j x_j^3 = x_j x j 3 = x j ,这意味着对这个特征自身取更高次幂是毫无意义的,因为它们是完全冗余的 。但是,它与其他特征的交叉项x j ⋅ x o t h e r x_j \cdot x_{other} x j ⋅ x o t h er 仍然是有意义的。 选择性地创建交叉项:不需要创建所有可能的交叉项,而是可以根据对问题的理解,只创建那些有意义的 。 RBFs 的一些基本准则如下:
μ \mu μ 应该从数据本身中选取。真实世界的高维数据几乎从不均匀地分布在整个空间里,而是倾向于聚集在某个低维的流形 (manifold)上 。我们应该让中心点 μ \mu μ 分布在这些有实际数据的地方。一个简单的方法是从已有 m m m 个数据点中,随机抽取 k k k 个点作为 RBF 的中心 μ \mu μ 。更优的方法是使用 k-means 聚类算法:对数据集运行 k-means,找到 k 个簇的质心 (centroids),然后用这 k 个质心作为 RBF 的中心点 。这是一个非常常用且有效的策略,因为它找到的点既能代表数据的高密度区域,又相对分散,能很好地覆盖住数据所在的流形。 σ \sigma σ 可以选取为数据的中位数 :σ = median ( ∣ ∣ x ( i ) − μ ( j ) ∣ ∣ i , j = 1 , 2 , … , k − 1 ) σ = \text{median}(||x^{(i)} - μ^{(j)}|| i, j = 1, 2, \dots,k-1) σ = median ( ∣∣ x ( i ) − μ ( j ) ∣∣ i , j = 1 , 2 , … , k − 1 ) 。中位数是数据的“典型值”的一个非常稳健的估计量,它不受少数极大或极小距离值的影响。8. 核方法 核方法的巧妙之处在于:它允许我们在一个极高维度(甚至是无限维度)的特征空间中进行计算,而完全不需要显式地创建或存储这些高维特征向量 。
a . a. a . θ \theta θ 的新表达形式首先,我们提出表示定理 :对于一个线性模型 h ( x ) = θ T φ ( x ) h(x) = θ^Tφ(x) h ( x ) = θ T φ ( x ) ,其最优解 θ ⋆ \theta^\star θ ⋆ 总可以表示为所有训练数据点特征向量的线性组合 :
θ ⋆ = ∑ i = 1 m α i ϕ ( x ( i ) ) , i = 1 , 2 , … , m \theta^\star = \sum_{i=1}^m\alpha_i\phi(x^{(i)}), i=1, 2, \dots, m θ ⋆ = i = 1 ∑ m α i ϕ ( x ( i ) ) , i = 1 , 2 , … , m 对这个定理的直观理解如下:最优的权重向量 θ θ θ 一定存在于由训练数据的特征向量 φ ( x ( i ) ) φ(x^{(i)}) φ ( x ( i ) ) 所张成的空间中 。任何超出这个空间的分量都是无用的,因为它与所有训练数据都正交,对损失函数没有贡献。
这个结论意味着,我们不再需要直接求解 k k k 维的 θ θ θ ,而是可以转而求解 m m m 个权重 α α α (m m m 是训练样本的数量) 。
既然 θ θ θ 可以用 α α α 来表示,我们也可以把预测函数 h ( x ) h(x) h ( x ) 也重写成只与 α α α 相关的形式:
h ( x ) = θ T ϕ ( x ) = ( ∑ i = 1 m α i ϕ ( x ( i ) ) ) T ϕ ( x ) = ∑ i = 1 m α i ( ϕ ( x ( i ) ) T ϕ ( x ) ) \begin{aligned} h(x) &= \theta^T \phi(x) \\ &= \left(\sum_{i=1}^m \alpha_i \, \phi\big(x^{(i)}\big)\right)^T \phi(x) \\ &= \sum_{i=1}^m \alpha_i \big(\phi\big(x^{(i)}\big)^T \phi(x)\big) \end{aligned} h ( x ) = θ T ϕ ( x ) = ( i = 1 ∑ m α i ϕ ( x ( i ) ) ) T ϕ ( x ) = i = 1 ∑ m α i ( ϕ ( x ( i ) ) T ϕ ( x ) ) 这个式子展示了一个重要的事实:对一个新点 x ‘ x` x ‘ 的预测只依赖于它的特征向量 φ ( x ) φ(x) φ ( x ) 与所有训练点的特征向量 φ ( x ( i ) ) φ(x(i)) φ ( x ( i )) 之间的点积 。我们根本不需要知道 φ ( x ) φ(x) φ ( x ) 的具体长什么样,我们只需要知道如何计算它与其他向量的内积。而这里就是核计算发挥作用的地方。
b . b. b . 点积的高效计算在核方法中,我们尝试找到一个函数 K ( x , z ) K(x, z) K ( x , z ) ,它能直接在原始的、低维的输入空间中计算出高维特征向量的内积 φ ( x ) T φ ( z ) φ(x)^Tφ(z) φ ( x ) T φ ( z ) ,从而完全绕过高维特征向量的显式计算。函数 K ( x , z ) K(x,z) K ( x , z ) 就是核函数。
i . i. i . 多项式核对于一个 d d d 阶多项式,我们有:
ϕ ( x ) T ϕ ( z ) = ( x T z + 1 ) d ϕ(x)^Tϕ(z)=(x^Tz+1)^d ϕ ( x ) T ϕ ( z ) = ( x T z + 1 ) d 对应的核函数 K : R n × R n → R K: \mathbb{R}^n \times \mathbb{R}^n \rightarrow \mathbb{R} K : R n × R n → R :
K ( x , z ) = ( x T z + 1 ) d . K(x,z)=(x^Tz+1)^d. K ( x , z ) = ( x T z + 1 ) d . i i . ii. ii . RBF 核RBF 特征的核函数如下:
K ( x , z ) = exp ( − ∣ ∣ x − z ∣ ∣ 2 2 σ 2 ) K(x, z) = \exp( \frac{-||x - z||^2}{2\sigma^2} ) K ( x , z ) = exp ( 2 σ 2 − ∣∣ x − z ∣ ∣ 2 ) RBF 核的简单实现如下:
def gaussian_kernel (X1, X2, sig ):
sqd = sqdist(X1, X2)
return np.exp(-sqd/(2 * sig ** 2 ))
我们进一步讨论这个式子展现出的 RBF 的无限维度的表达能力 。我们考虑下面的指数核:
K ( x , z ) = exp ( x z ) K(x, z) = \exp(xz) K ( x , z ) = exp ( x z ) 这个指数核对应的特征向量 φ ( x ) \varphi(x) φ ( x ) 、φ ( z ) \varphi(z) φ ( z ) 可以通过泰勒展开得到:
exp ( x z ) = 1 + ( x z ) + ( x z ) 2 2 ! + ( x z ) 3 3 ! + ⋯ = 1 + ( x z ) + ( x 2 ! ) ( z 2 ! ) + ⋯ \begin{aligned} \exp(xz) &= 1 + (xz) + \frac{(xz)^2}{2!} + \frac{(xz)^3}{3!} + \cdots \\ &=1 + (xz) + \big(\frac{x}{\sqrt2!}\big)\big(\frac{z}{\sqrt2!}\big) + \cdots \end{aligned} exp ( x z ) = 1 + ( x z ) + 2 ! ( x z ) 2 + 3 ! ( x z ) 3 + ⋯ = 1 + ( x z ) + ( 2 ! x ) ( 2 ! z ) + ⋯ 这正是向量点积的形式,于是我们的特征向量可以写为:
φ ( x ) = [ 1 , x , x 2 2 ! , … ] φ ( z ) = [ 1 , z , z 2 2 ! , … ] \begin{aligned} φ(x) &= [ 1, x, \frac{x^2}{\sqrt2!}, \dots ]\\ φ(z) &= [ 1, z, \frac{z^2}{\sqrt2!}, \dots ] \end{aligned} φ ( x ) φ ( z ) = [ 1 , x , 2 ! x 2 , … ] = [ 1 , z , 2 ! z 2 , … ] 这个特征向量 φ ( x ) φ(x) φ ( x ) 包含 x 的所有次幂(从0次、1次、2次...一直到无穷),所以它是一个无限维的向量 。
通过这个无限维的向量,我们获得了无限维度的强大能力,却付出了极低的计算代价 。我们完全避免了“维度灾难”,因为我们从始至终都没有真正创建那个无限维的向量。这正是核方法最精妙、最强大的地方。
c . c. c . 核学习算法构建在算法层面,我们只需要做两处修改:
将模型中的参数从 θ θ θ 换成 α α α 。 将所有涉及特征向量内积 φ ( x ) T φ ( z ) φ(x)^Tφ(z) φ ( x ) T φ ( z ) 的地方,全部替换成核函数 K ( x , z ) K(x, z) K ( x , z ) 。 下面我们以最小二乘方法为例,这个算法被称为核岭回归 (Kernel Ridge Regression)。对正则化项有:
∥ θ ∥ 2 2 = θ T θ = ( ∑ i = 1 m α i ϕ ( x ( i ) ) ) T ( ∑ j = 1 m α j ϕ ( x ( j ) ) ) = ∑ i = 1 m ∑ j = 1 m α i α j K ( x ( i ) , x ( j ) ) = α T K α \begin{aligned} \|\theta\|_2^2 &= \theta^T \theta \\ &= \left(\sum_{i=1}^m \alpha_i\,\phi\big(x^{(i)}\big)\right)^T \left(\sum_{j=1}^m \alpha_j\,\phi\big(x^{(j)}\big)\right) \\ &= \sum_{i=1}^m \sum_{j=1}^m \alpha_i \alpha_j\, K\big(x^{(i)},x^{(j)}\big) \\ &= \alpha^T K \alpha \end{aligned} ∥ θ ∥ 2 2 = θ T θ = ( i = 1 ∑ m α i ϕ ( x ( i ) ) ) T ( j = 1 ∑ m α j ϕ ( x ( j ) ) ) = i = 1 ∑ m j = 1 ∑ m α i α j K ( x ( i ) , x ( j ) ) = α T K α 其中 K ∈ R m × m K\in\mathbb{R}^{m\times m} K ∈ R m × m 是包含所有核函数的矩阵,K i , j = K ( x ( i ) , x ( j ) ) K_{i,j}=K(x^{(i)}, x^{(j)}) K i , j = K ( x ( i ) , x ( j ) ) 。
这样,我们的最小二乘损失由下面的式子给出:
min α 1 m ∑ i = 1 m ( ∑ j = 1 m α j K ( x ( j ) , x ( i ) ) − y ( i ) ) 2 + λ α T K α ⇒ min α 1 m ∥ K α − y ∥ 2 2 + λ α ⊤ K α \begin{aligned} \min_{\alpha} \quad & \frac{1}{m}\sum_{i=1}^m\left( \sum_{j=1}^m \alpha_j K\big(x^{(j)},x^{(i)}\big) - y^{(i)} \right)^2 + \lambda \alpha^T K \alpha \\ \Rightarrow \min_{\alpha} \quad & \frac{1}{m}\|K\alpha - y\|_2^2 + \lambda \alpha^\top K \alpha \end{aligned} α min ⇒ α min m 1 i = 1 ∑ m ( j = 1 ∑ m α j K ( x ( j ) , x ( i ) ) − y ( i ) ) 2 + λ α T K α m 1 ∥ K α − y ∥ 2 2 + λ α ⊤ K α 对这个式子求梯度:
∇ α ( 1 m ∥ K α − y ∥ 2 2 + λ α ⊤ K α ) = 2 m K ( K α − y ) + 2 λ K α \nabla_{\alpha}\left( \frac{1}{m}\|K\alpha - y\|_2^2 + \lambda \alpha^\top K \alpha \right) = \frac{2}{m} K (K\alpha - y) + 2\lambda K \alpha ∇ α ( m 1 ∥ K α − y ∥ 2 2 + λ α ⊤ K α ) = m 2 K ( K α − y ) + 2 λ K α 令梯度为0:
∇ α ( 1 m ∥ K α − y ∥ 2 2 + λ α ⊤ K α ) = 0 ⇒ 2 m K ( K α − y ) + 2 λ K α = 0 ⇒ 2 m K K α − 2 m K y + 2 λ K α = 0 ⇒ K K α − K y + m λ K α = 0 ⇒ K ( K + m λ I ) α = K y ⇒ ( K + m λ I ) α = y ⇒ α = ( K + m λ I ) − 1 y \begin{aligned} & \nabla_{\alpha}\!\left(\frac{1}{m}\|K\alpha - y\|_2^2 + \lambda \alpha^\top K \alpha\right) = 0 \\ \Rightarrow\quad & \frac{2}{m}K(K\alpha - y) + 2\lambda K\alpha = 0 \\ \Rightarrow\quad & \frac{2}{m}K K\alpha - \frac{2}{m}K y + 2\lambda K\alpha = 0 \\ \Rightarrow\quad & K K\alpha - K y + m\lambda K\alpha = 0 \\ \Rightarrow\quad & K (K + m\lambda I)\alpha = K y \\ \Rightarrow\quad & (K + m\lambda I)\alpha = y \quad\\ \Rightarrow\quad & \alpha = (K + m\lambda I)^{-1} y \end{aligned} ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ∇ α ( m 1 ∥ K α − y ∥ 2 2 + λ α ⊤ K α ) = 0 m 2 K ( K α − y ) + 2 λ K α = 0 m 2 KK α − m 2 Ky + 2 λ K α = 0 KK α − Ky + mλ K α = 0 K ( K + mλ I ) α = Ky ( K + mλ I ) α = y α = ( K + mλ I ) − 1 y 为了简化最终结果,我们令 λ ~ = m λ \tilde{\lambda}=m\lambda λ ~ = mλ :
α = ( K + λ ~ I ) − 1 y \alpha = (K + \tilde{\lambda} I)^{-1} y α = ( K + λ ~ I ) − 1 y 梯度下降与解析解方法的相关代码实现如下:
def train_krr_gd (X_train, y_train, lam, sig, learning_rate, iters ):
m = X_train.shape[0 ]
alpha = np.zeros(m)
K = gaussian_kernel(X_train, X_train, sig)
loss_history = []
for i in range (iters):
K_alpha = K @ alpha
loss_gradient = (2 / m) * K @ (K_alpha - y_train)
reg_gradient = 2 * lam * K_alpha
gradient = loss_gradient + reg_gradient
alpha = alpha - learning_rate * gradient
loss = (1 /m) * np.sum ((K_alpha - y_train)**2 ) + lam * alpha.T @ K @ alpha
loss_history.append(loss)
return alpha, X_train, loss_history
def train_krr (X, y, lam, sig ):
m = X_train.shape[0 ]
K = gaussian_kernel(X_train, X_train, sig)
A = K + m * lam * np.identity(m)
alpha = np.linalg.solve(A, y)
return alpha, X
d . d. d . 核方法的弊端核方法有下面几个显著的缺点:
参数的数量随着训练样本数量 m m m 的增长而增长,当 m m m 非常大时,模型的复杂度会变得非常高。 计算成本高:求解 α α α 通常需要计算并存储一个 m x m m x m m x m 的核矩阵 K K K ,并对其求逆。求逆的计算复杂度是 O ( m 3 ) O(m^3) O ( m 3 ) 。并且为了预测一个新点 x,你需要计算它与所有 m 个训练点 x(i) 之间的核函数值 K(x(i), x),计算成本是 O(m*n)。这使得在线预测非常慢。 必须保留所有训练数据:根据计算过程,我们不能在训练完后把训练数据丢掉,因为预测时随时需要它们来计算核函数。 由于这些可扩展性 问题,核方法非常适合中小型数据集 。但对于拥有数十万、数百万样本的大数据集,O ( m 3 ) O(m^3) O ( m 3 ) 或 O ( m 2 ) O(m^2) O ( m 2 ) 的计算成本是不可接受的,这也是为什么深度学习在这类问题上成为主流的原因。
Comments