快速上手大模型:机器学习6(模型选择、过/欠拟合、正则化)
目录
1 模型选择
1.1 基本概念
训练误差:模型在训练数据上的误差;
泛化误差:模型在新数据上的误差;
验证数据集:用来评估模型好坏的数据集;
测试数据集:只用一次的数据集,其实就是应用于实际的数据。
1.2 K-则交叉验证
应用于没有足够多数据的情况。
原理是将数据分成K份,其中第i份是验证数据集、其他为训练数据集,如此就有了K份验证集,取K个验证集平均误差做为训练误差。K一般取5或10。
2 过拟合与欠拟合
当模型容量低、数据复杂的时候会出现欠拟合,当模型容量高、数据简单的时候会出现过拟合。随着模型容量的提高,训练误差会逐渐降低直至为0,泛化误差会先降低在变大,所以仅当泛化误差取得极小值的时候最优。
2.1 过拟合
以房屋价格预测为例,线性回归中,图1对训练数据为欠拟合(underfit),即预测曲线与数据样本偏差较大,这种情况也称高度偏差(high bias);图2模型拟合情况良好,具有良好泛化性(generalization);图3模型虽然能够准确拟合真实样本数据、做到误差为0,但出现波动,与实际场景不符,称为过拟合(overfit),也称高方差(high variance)。
逻辑回归中同理,图1欠拟合,图2泛化性良好,图3过拟合。
2.2 解决过拟合
2.2.1 获取更多训练数据集
通过训练更多的数据集,将过拟合曲线变为泛化性良好的状态。
2.2.3 使用较少特征
使用关键特征进行模型建立,进而进行预测。
2.2.3 正则化(Regularization)
正则化通过鼓励学习算法缩小参数值,而不要求参数直接为0。正则化只改变w大小,修改b对曲线无太大影响。
3 正则化
正则化包括 L1、L2、Dropout、早停(early stopping)等方法。
3.1 定义
正则化后代价函数转变为:
,
影响较小可忽略。
选择:
为0,正则化失效,过拟合;过大,欠拟合。
正则化的思想是平衡拟合,使其适中,满足实际场景;正则化的作用是在每次迭代中使wi变小一点。
3.2 正则化线性回归
梯度下降:
此处回归模型为
3.3 正则化逻辑回归
梯度下降:
梯度下降公式与正则化的一致,唯一区别在于f函数,
3.4 核心代码
计算带正则化项的线性回归总损失函数
:
def compute_cost_linear_reg(X, y, w, b, lambda_ = 1): """ Computes the cost over all examples Args: X (ndarray (m,n): Data, m examples with n features y (ndarray (m,)): target values w (ndarray (n,)): model parameters b (scalar) : model parameter lambda_ (scalar): Controls amount of regularization Returns: total_cost (scalar): cost """ m = X.shape[0] n = len(w) cost = 0. for i in range(m): f_wb_i = np.dot(X[i], w) + b #(n,)(n,)=scalar, see np.dot cost = cost + (f_wb_i - y[i])**2 #scalar cost = cost / (2 * m) #scalar reg_cost = 0 for j in range(n): reg_cost += (w[j]**2) #scalar reg_cost = (lambda_/(2*m)) * reg_cost #scalar total_cost = cost + reg_cost #scalar return total_cost计算逻辑回归模型的损失函数
:
def compute_cost_logistic_reg(X, y, w, b, lambda_ = 1): """ Computes the cost over all examples Args: Args: X (ndarray (m,n): Data, m examples with n features y (ndarray (m,)): target values w (ndarray (n,)): model parameters b (scalar) : model parameter lambda_ (scalar): Controls amount of regularization Returns: total_cost (scalar): cost """ m,n = X.shape cost = 0. for i in range(m): z_i = np.dot(X[i], w) + b #(n,)(n,)=scalar, see np.dot f_wb_i = sigmoid(z_i) #scalar cost += -y[i]*np.log(f_wb_i) - (1-y[i])*np.log(1-f_wb_i) #scalar cost = cost/m #scalar reg_cost = 0 for j in range(n): reg_cost += (w[j]**2) #scalar reg_cost = (lambda_/(2*m)) * reg_cost #scalar total_cost = cost + reg_cost #scalar return total_cost #scalar计算线性回归代价函数(含正则化)的梯度
,
:
def compute_gradient_linear_reg(X, y, w, b, lambda_): """ Computes the gradient for linear regression Args: X (ndarray (m,n): Data, m examples with n features y (ndarray (m,)): target values w (ndarray (n,)): model parameters b (scalar) : model parameter lambda_ (scalar): Controls amount of regularization Returns: dj_dw (ndarray (n,)): The gradient of the cost w.r.t. the parameters w. dj_db (scalar): The gradient of the cost w.r.t. the parameter b. """ m,n = X.shape #(number of examples, number of features) dj_dw = np.zeros((n,)) dj_db = 0. for i in range(m): err = (np.dot(X[i], w) + b) - y[i] for j in range(n): dj_dw[j] = dj_dw[j] + err * X[i, j] dj_db = dj_db + err dj_dw = dj_dw / m dj_db = dj_db / m for j in range(n): dj_dw[j] = dj_dw[j] + (lambda_/m) * w[j] return dj_db, dj_dw计算逻辑回归代价函数(含正则化)的梯度
,
:
def compute_gradient_logistic_reg(X, y, w, b, lambda_): """ Computes the gradient for linear regression Args: X (ndarray (m,n): Data, m examples with n features y (ndarray (m,)): target values w (ndarray (n,)): model parameters b (scalar) : model parameter lambda_ (scalar): Controls amount of regularization Returns dj_dw (ndarray Shape (n,)): The gradient of the cost w.r.t. the parameters w. dj_db (scalar) : The gradient of the cost w.r.t. the parameter b. """ m,n = X.shape dj_dw = np.zeros((n,)) #(n,) dj_db = 0.0 #scalar for i in range(m): f_wb_i = sigmoid(np.dot(X[i],w) + b) #(n,)(n,)=scalar err_i = f_wb_i - y[i] #scalar for j in range(n): dj_dw[j] = dj_dw[j] + err_i * X[i,j] #scalar dj_db = dj_db + err_i dj_dw = dj_dw/m #(n,) dj_db = dj_db/m #scalar for j in range(n): dj_dw[j] = dj_dw[j] + (lambda_/m) * w[j] return dj_db, dj_dw
3.5 L2正则化
L2正则化可以通过在损失函数里面加
、权重衰退实现,使得模型参数不会过大从而控制模型复杂度。权重衰减更为常见,介绍如下。
3.5.1 权重衰退(Weight Decay)
计算梯度:
时间t更新参数:
,带入梯度
,通常
(深度学习中叫权重衰退)
代码简洁实现:
def train_concise(wd): net = nn.Sequential(nn.Linear(num_inputs, 1)) for param in net.parameters(): param.data.normal_() loss = nn.MSELoss(reduction='none') num_epochs, lr = 100, 0.003 # 偏置参数没有衰减 trainer = torch.optim.SGD([ {"params":net[0].weight,'weight_decay': wd}, {"params":net[0].bias}], lr=lr) animator = d2l.Animator(xlabel='epochs', ylabel='loss', yscale='log', xlim=[5, num_epochs], legend=['train', 'test']) for epoch in range(num_epochs): for X, y in train_iter: trainer.zero_grad() l = loss(net(X), y) l.mean().backward() trainer.step() if (epoch + 1) % 5 == 0: animator.add(epoch + 1, (d2l.evaluate_loss(net, train_iter, loss), d2l.evaluate_loss(net, test_iter, loss))) print('w的L2范数:', net[0].weight.norm().item())train_concise(0)
train_concise(3)
3.6 丢弃法(Dropout)
3.6.1 原理
Dropout是在层之间加入噪音。
对于x加入噪音得到
,希望期望E不变,即
,即定义
如下
3.6.2 使用
使用dropout后隐藏层有些数会置0,用于模型训练。
3.6.3 代码
import torch from torch import nn from d2l import torch as d2l def dropout_layer(X, dropout): assert 0 <= dropout <= 1 # 在本情况中,所有元素都被丢弃 if dropout == 1: return torch.zeros_like(X) # 在本情况中,所有元素都被保留 if dropout == 0: return X mask = (torch.rand(X.shape) > dropout).float() return mask * X / (1.0 - dropout) net = nn.Sequential(nn.Flatten(), nn.Linear(784, 256), nn.ReLU(), # 在第一个全连接层之后添加一个dropout层 nn.Dropout(dropout1), nn.Linear(256, 256), nn.ReLU(), # 在第二个全连接层之后添加一个dropout层 nn.Dropout(dropout2), nn.Linear(256, 10)) def init_weights(m): if type(m) == nn.Linear: nn.init.normal_(m.weight, std=0.01) net.apply(init_weights); trainer = torch.optim.SGD(net.parameters(), lr=lr) d2l.train_ch3(net, train_iter, test_iter, loss, num_epochs, trainer)
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
















所有评论(0)