街景字符识别5-提高模型精度

前面做了模型训练与验证,我们会发现,模型在训练集、测试集的准确性并不一致,主要是因为存在泛化误差。
深度学习中常用于应对过拟合问题的方法:权重衰减和丢弃法(dropout)
Ten Techniques Learned From fast.ai中提到一些深度学习模型训练过程常用于应对过拟合问题的方法:合适的学习率、测试时增强(TTA)

1 权重衰减

1.1 基本内容

权重衰减即L2范数正则化,是在损失函数基础上加入权重参数平方和,以惩罚绝对值较大的权重参数项。那么在小批量随机梯度下降中,线性回归损失函数的权重更新变成了权重参数乘惩罚因子 λ \lambda λ的式子:L2范数正则化令权重w1和w2先自乘小于1的数,再减去不含惩罚项的梯度。随着训练进行,权重衰减,从而可能抑制过拟合。
在这里插入图片描述下图是原始权重更新步骤
在这里插入图片描述
添加L2正则化项后,如图所示
在这里插入图片描述

1.2 Pytorch实现

直接在构造优化器实例时通过weight_decay 指定权重衰减超参数wd,默认情况下Pytorch对权重w和偏差b同时衰减,因此可以分别对权重和偏差构造优化器实例,从而只对权重衰减。

def fit_and_plot_pytorch(wd):
# 对权重参数衰减。
	net = nn.Linear(num_inputs, 1)
	nn.init.normal_(net.weight, mean=0, std=1)
	nn.init.normal_(net.bias, mean=0, std=1)
	optimizer_w = torch.optim.SGD(params=[net.weight], lr=lr,
	weight_decay=wd) # 对权重参数衰减
	optimizer_b = torch.optim.SGD(params=[net.bias], lr=lr) # 对偏差参数衰减

	train_ls, test_ls = [], []
	for _ in range(num_epochs):
		for X, y in train_iter:
			l = loss(net(X), y).mean()
			optimizer_w.zero_grad()
			optimizer_b.zero_grad()
			l.backward()
# 对两个optimizer实例分别调用step函数,从而分别更新权重和偏差
			optimizer_w.step()
			optimizer_b.step()
		train_ls.append(loss(net(train_features),
		train_labels).mean().item())
		test_ls.append(loss(net(test_features),
		test_labels).mean().item())
	semilogy(range(1, num_epochs + 1), train_ls, 'epochs','loss',range(1, num_epochs + 1), test_ls, ['train','test'])
print('L2 norm of w:', net.weight.data.norm().item())

2 倒置丢弃法(Dropout)

2.1 基本内容

随机丢弃隐藏层中的某些神经元,避免了输出层过度依赖某个神经元,从而在训练过程中起到正则化作用,从而减少过拟合的发生。涉及到的超参数是丢弃概率。

图1 丢弃前模型
图2 丢弃h2和h5后模型

2.2 Pytorch实现

def train_ch3(net, train_iter, test_iter, loss, num_epochs,batch_size,params=None, lr=None, optimizer=None):
	for epoch in range(num_epochs):
		train_l_sum, train_acc_sum, n = 0.0, 0.0, 0
		for X, y in train_iter:
			y_hat = net(X)
			l = loss(y_hat, y).sum()
			# 梯度清零
			if optimizer is not None:
				optimizer.zero_grad()
			elif params is not None and params[0].grad is not None:
				for param in params:
					param.grad.data.zero_()
			l.backward()
			if optimizer is None:
				d2l.sgd(params, lr, batch_size)
			else:
				optimizer.step() # 
			train_l_sum += l.item()
			train_acc_sum += (y_hat.argmax(dim=1) ==
			y).sum().item()
			n += y.shape[0]
		test_acc = evaluate_accuracy(test_iter, net)
		print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f'
	% (epoch + 1, train_l_sum / n, train_acc_sum / n,
	test_acc))

# 模型
net = nn.Sequential(
d2l.FlattenLayer(),
nn.Linear(num_inputs, num_hiddens1),
nn.ReLU(),
nn.Dropout(drop_prob1),#以指定的丢弃概率随机丢弃上一层输出元素
nn.Linear(num_hiddens1, num_hiddens2),
nn.ReLU(),
nn.Dropout(drop_prob2),#以指定的丢弃概率随机丢弃上一层输出元素
nn.Linear(num_hiddens2, 10)
)
#参数初始化
for param in net.parameters():
	nn.init.normal_(param, mean=0, std=0.01)
#定义优化器
optimizer = torch.optim.SGD(net.parameters(), lr=0.5)
#训练
train_ch3(net, train_iter, test_iter, loss, num_epochs,batch_size, None, None, optimizer)

3 合适的学习率

在Cyclical Learning Rates方法中,首先使用较低学习率来训练神经网络,并在每个批次中以指数形式增加学习率,然后找出学习率最高且Loss值仍在下降的拐点确定最佳学习率。在下面的情况中,最佳学习率将为0.01。

图1 随训练进行,学习率指数上升
图2 学习率-Loss
具体学习率的设定还不明白怎么分层设置,但是可以知道有Adam,AdaGrad自适应控制学习率。

4 测试集数据扩增

4.1 基本内容

测试时增强(test time augmentation, TTA):测试样本原始图像造出多个不同版本(包括不同区域裁剪和更改缩放程度等,比如tta=3),并将它们输入到模型中;然后对多个版本进行多次预测,并平均作为图像的最终输出分数。
这种技术很有效,因为测试样本原始图像显示的区域可能会缺少一些重要特征,在模型中输入图像的多个版本并取平均值,能解决上述问题。

4.2 Pytorch实现

 def predict(test_loader, model, tta=3):
    model.eval()
    test_pred_tta = 0
    # TTA 次数
    for _ in range(tta):
        test_pred = []
    
        with torch.no_grad():
            for i, (input, target) in enumerate(test_loader):
                c0, c1, c2, c3, c4, c5 = model(data[0])
                output = np.concatenate([c0.data.numpy(), c1.data.numpy(),
                   c2.data.numpy(), c3.data.numpy(),
                   c4.data.numpy(), c5.data.numpy()], axis=1)
                test_pred.append(output)
        
        test_pred = np.vstack(test_pred)
        test_pred_tta += test_pred
	test_pred_tta /= tta   
    return test_pred_tta

# 测试集
test_path = glob.glob('../input/test_a/*.png')
test_path.sort()
test_label = [[1]] * len(test_path)
print(len(val_path), len(val_label))

# 测试集Loader TTA
test_loader = torch.utils.data.DataLoader(
    SVHNDataset(test_path, test_label,
                transforms.Compose([
                    transforms.Resize((64, 128)),
                    transforms.RandomCrop((60, 120)),
                    transforms.ToTensor(),
                    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
    ])), 
    batch_size=40, 
    shuffle=False, 
    num_workers=0,
)

test_predict_label = predict(test_loader, model, tta=3)

参考

《动手学深度学习》
称霸Kaggle的十大深度学习技巧
Ten Techniques Learned From fast.ai
Datawhale 零基础入门CV - Basline

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值