1.欠拟合、过拟合、正则化、学习曲线
1.1 欠拟合、过拟合
欠拟合:模型相对于要解决的问题来说太简单了,模型并没有拟合训练数据的状态
过拟合:模型相对于要解决的问题来说太复杂了,模型只能拟合训练数据的状态
下图来自:数据分析中的插值与拟合(2) —— 拟合
如何避免过拟合呢?
- 增加全部训练数据的数量
- 使用简单模型
- 正则化
1.2 正则化
正则化有L1正则化、L2正则化等
L1正则化、L2正则化区别
L1 正则化的特征是被判定为不需要的参数会变为 0,从而减少变量个数。而 L2 正则化不会把参数变为 0
L2 正则化会抑制参数,使变量的影响不会过大,而 L1 会直接去除不要的变量。
使用哪个正则化取决于要解决什么问题,不能一概而论
1.2.1 回归的L2正则化
新目标函数 = 目标函数 + 正则项
m
m
m为参数个数、
λ
\lambda
λ 是决定正则化项影响程度的正的常数
注意:
θ
0
\theta_0
θ0这种只有参数的项称为偏置项,一般不对它进行正则化
通过目标函数、正则项、新目标函数的图像来看看正则化到底怎么起作用的
这就是正则化的效果。它可以防止参数变得过大,有助于参数接近较小的值。虽然我们只考虑了
θ
1
\theta_1
θ1,但其他
θ
j
\theta_j
θj 参数的情况也是类似的。
参数的值变小,意味着该参数的影响也会相应地变小,通过减小不需要的参数的影响,将复杂模型替换为简单模型来防止过拟合的方式
为了防止参数的影响过大,在训练时要对参数施加一些惩罚,而
λ
\lambda
λ 可以控制正则化惩罚的强度,
λ
\lambda
λ越大,惩罚越严厉
1.2.2 包含正则项的表达式的微分
1.2.3 回归的正则化的实现
import numpy as np
import matplotlib.pyplot as plt
# 真正的函数
def g(x):
return 0.1 * (x ** 3 + x ** 2 + x)
x = np.linspace(-2, 2, 100)
plt.plot(train_x, train_y, 'o')
plt.plot(x, g(x), linestyle = 'dashed', color= 'm')
plt.ylim(-1, 2)
plt.show()
向函数
g
(
x
)
g(x)
g(x)中加入一些自己造的训练数据
# 随意准备一些向真正的函数加入了一点噪声的训练数据
train_x = np.linspace(-2, 2, 8)
train_y = g(train_x) + np.random.randn(train_x.size) * 0.05
标准化变量x
# 标准化
mu = train_x.mean()
sigma = train_x.std()
def standardize(x):
return (x - mu) / sigma
train_z = standardize(train_x)
假设我们用 10 次多项式来学习这个训练数据
# 创建训练数据的矩阵
def to_matrix(x):
return np.vstack([
np.ones(x.size),
x,
x ** 2,
x ** 3,
x ** 4,
x ** 5,
x ** 6,
x ** 7,
x ** 8,
x ** 9,
x ** 10
]).T
X = to_matrix(train_z)
# 参数初始化
theta = np.random.randn(X.shape[1])
# 预测函数
def f(x):
return np.dot(x, theta)
# 目标函数
def E(x, y):
return 0.5 * np.sum((y - f(x)) ** 2)
# 正则化常量
LAMBDA = 0.5
# 学习率
ETA = 1e-4
# 误差
diff = 1
未应用正则化与应用正则化
# 重复学习(不应用正则化)
error = E(X, train_y)
while diff > 1e-6:
theta = theta - ETA * (np.dot(f(X) - train_y, X))
current_error = E(X, train_y)
diff = error - current_error
error = current_error
theta1 = theta
# 重复学习(应用正则化)
theta = np.random.randn(X.shape[1])
diff = 1
error = E(X, train_y)
while diff > 1e-6:
reg_term = LAMBDA * np.hstack([0, theta[1:]])
theta = theta - ETA * (np.dot(f(X) - train_y, X) + reg_term)
current_error = E(X, train_y)
diff = error - current_error
error = current_error
theta2 = theta
# 绘图确认
plt.plot(train_z, train_y, 'o')
z = standardize(np.linspace(-2, 2, 100))
theta = theta1 # 未应用正则化
plt.plot(z, f(to_matrix(z)), linestyle='dashed')
theta = theta2 # 应用正则化
plt.plot(z, f(to_matrix(z)))
plt.show()
下图中绿色线为添加了正则项的,橙色线为未添加正则项的
1.2.4 逻辑回归的L2正则化
为什么突然添加负号?
反转符号是为了将最大化问题替换为最小化问题
对数似然函数本来以最大化为目标。但是,这次我想让它变成和回归的目标函数一样的最小化问题,所以加了负号。这样就可以像处理回归一样处理它,所以只要加上正则化项就可以了
1.2.5 包含正则项的表达式的微分
1.3 学习曲线(区分欠拟合和过拟合)
先来看一个例子,有10个训练数据
若我们随机挑选2个训练数据,选择一次函数模型对其进行拟合,可以看到一次函数完美拟合,误差为0
我们用这10个训练数据,选择一次函数模型对其进行拟合,可以看到一次函数并不能很好的拟合这些数据,误差已经无法为0了
模型选的太简单了,随着数据量的增加,误差逐渐变大,精度逐渐下降
用测试数据对上面这个简单模型进行评估
使用少量训练数据来训练模型,然后用测试数据评估该模型精度
然后增加训练数据来训练模型,随后用测试数据对模型进行评估,重复这样的步骤,最终能绘制出数据数量和精度的关系曲线图,展示了数据数量和精度的图称为学习曲线
欠拟合状态
图中上方曲线为使用训练数据时,数据数量与其精度的关系曲线
数据量少时,由于只有几个数据,模型可以很好的拟合这些少量数据,误差会很小,精度会很大,但由于模型过于简单,那么随着数据量的增加,误差也会一点点变大。换句话说就是精度会一点点下降
图中下方曲线为使用测试数据时,数据数量与其精度的关系曲线
训练数据较少时训练好的模型难以预测未知的数据,所以精度很低;反过来说,训练数据变多时,预测精度就会一点点地变高。
过拟合状态
随着数据量的增加,使用训练数据时的精度一直很高,而使用测试数据时的精度一直没有上升到它的水准。只对训练数据拟合得较好,这就是过拟合的特征
高偏差为欠拟合
下图来自:2022吴恩达机器学习Deeplearning.ai课程:学习曲线
高方差为过拟合
下图来自:2022吴恩达机器学习Deeplearning.ai课程:学习曲线
通过学习曲线判断出是过拟合还是欠拟合之后,就可以采取相应的对策以便改进模型了。