Pytorch-数据集划分&正则化方法
1.训练集&验证集&测试集
训练集:训练数据
验证集:验证不同算法(比如利用网格搜索对超参数进行调整等),检验哪种更有效
测试集:正确评估分类器的性能
正常流程:验证集会记录每个时间戳的参数,在加载test数据前会加载那个最好的参数,再来评估。比方说训练完6000个epoch后,发现在第3520个epoch的validation表现最好,测试时会加载第3520个epoch的参数。
1 import torch 2 import torch.nn as nn 3 import torch.nn.functional as F 4 import torch.optim as optim 5 from torchvision import datasets, transforms 6 7 #超参数 8 batch_size=200 9 learning_rate=0.01 10 epochs=10 11 12 #获取训练数据 13 train_db = datasets.MNIST('../data', train=True, download=True, #train=True则得到的是训练集 14 transform=transforms.Compose([ #transform进行数据预处理 15 transforms.ToTensor(), #转成Tensor类型的数据 16 transforms.Normalize((0.1307,), (0.3081,)) #进行数据标准化(减去均值除以方差) 17 ])) 18 19 #DataLoader把训练数据分成多个小组,此函数每次抛出一组数据。直至把所有的数据都抛出。就是做一个数据的初始化 20 train_loader = torch.utils.data.DataLoader(train_db, batch_size=batch_size, shuffle=True) 21 22 23 #获取测试数据 24 test_db = datasets.MNIST('../data', train=False, 25 transform=transforms.Compose([ 26 transforms.ToTensor(), 27 transforms.Normalize((0.1307,), (0.3081,)) 28 ])) 29 30 test_loader = torch.utils.data.DataLoader(test_db, batch_size=batch_size, shuffle=True) 31 32 33 #将训练集拆分成训练集和验证集 34 print('train:', len(train_db), 'test:', len(test_db)) #train: 60000 test: 10000 35 train_db, val_db = torch.utils.data.random_split(train_db, [50000, 10000]) 36 print('db1:', len(train_db), 'db2:', len(val_db)) #db1: 50000 db2: 10000 37 38 train_loader = torch.utils.data.DataLoader(train_db, batch_size=batch_size, shuffle=True) 39 val_loader = torch.utils.data.DataLoader(val_db, batch_size=batch_size, shuffle=True) 40 41 42 43 44 class MLP(nn.Module): 45 46 def __init__(self): 47 super(MLP, self).__init__() 48 49 self.model = nn.Sequential( #定义网络的每一层, 50 nn.Linear(784, 200), 51 nn.ReLU(inplace=True), 52 nn.Linear(200, 200), 53 nn.ReLU(inplace=True), 54 nn.Linear(200, 10), 55 nn.ReLU(inplace=True), 56 ) 57 58 def forward(self, x): 59 x = self.model(x) 60 return x 61 62 63 net = MLP() 64 #定义sgd优化器,指明优化参数、学习率,net.parameters()得到这个类所定义的网络的参数[[w1,b1,w2,b2,...] 65 optimizer = optim.SGD(net.parameters(), lr=learning_rate) 66 criteon = nn.CrossEntropyLoss() 67 68 69 for epoch in range(epochs): 70 71 for batch_idx, (data, target) in enumerate(train_loader): 72 data = data.view(-1, 28*28) #将二维的图片数据摊平[样本数,784] 73 74 logits = net(data) #前向传播 75 loss = criteon(logits, target) #nn.CrossEntropyLoss()自带Softmax 76 77 optimizer.zero_grad() #梯度信息清空 78 loss.backward() #反向传播获取梯度 79 optimizer.step() #优化器更新 80 81 if batch_idx % 100 == 0: #每100个batch输出一次信息 82 print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format( 83 epoch, batch_idx * len(data), len(train_loader.dataset), 84 100. * batch_idx / len(train_loader), loss.item())) 85 86 #验证集用来检测训练是否过拟合 87 val_loss = 0 88 correct = 0 89 for data, target in val_loader: 90 data = data.view(-1, 28 * 28) 91 logits = net(data) 92 val_loss += criteon(logits, target).item() 93 94 pred = logits.data.max(dim=1)[1] 95 correct += pred.eq(target.data).sum() 96 97 val_loss /= len(val_loader.dataset) 98 print('\nVAL set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( 99 val_loss, correct, len(val_loader.dataset), 100 100. * correct / len(val_loader.dataset))) 101 102 103 104 #测试集用来评估 105 test_loss = 0 106 correct = 0 #correct记录正确分类的样本数 107 for data, target in test_loader: 108 data = data.view(-1, 28 * 28) 109 logits = net(data) 110 test_loss += criteon(logits, target).item() #其实就是criteon(logits, target)的值,标量 111 112 pred = logits.data.max(dim=1)[1] #也可以写成pred=logits.argmax(dim=1) 113 correct += pred.eq(target.data).sum() 114 115 test_loss /= len(test_loader.dataset) 116 print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( 117 test_loss, correct, len(test_loader.dataset), 118 100. * correct / len(test_loader.dataset)))
2.正则化
正则化可以解决过拟合问题。
2.1L2范数(更常用)
在定义优化器的时候设定weigth_decay,即L2范数前面的$\lambda$参数。
1 optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate, weight_decay=0.01)
2.2L1范数
Pytorch没有直接可以调用的方法,实现如下:
3.动量(Momentum)
Adam优化器内置了momentum,SGD需要手动设置。
1 optimizer = torch.optim.SGD(model.parameters(), args=lr, momentum=args.momentum, weight_decay=args.weight_decay)
4.学习率衰减
torch.optim.lr_scheduler 中提供了基于多种epoch数目调整学习率的方法。
4.1torch.optim.lr_scheduler.ReduceLROnPlateau:基于测量指标对学习率进行动态的下降
1 torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10, verbose=False, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08)
训练过程中,optimizer会把learning rate 交给scheduler管理,当指标(比如loss)连续patience次数还没有改进时,需要降低学习率,factor为每次下降的比例。
scheduler.step(loss_val)每调用一次就会监听一次loss_val。
4.2torch.optim.lr_scheduler.StepLR:基于epoch
1 torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)
当epoch每过stop_size时,学习率都变为初始学习率的gamma倍。
5.提前停止(防止overfitting)
基于经验值。
6.Dropout随机失活
遍历每一层,设置消除神经网络中的节点概率,得到精简后的一个样本。
torch.nn.Dropout(p=dropout_prob)
p表示的示的是删除节点数的比例(Tip:tensorflow中keep_prob表示保留节点数的比例,不要混淆)
测试阶段无需使用dropout,所以在train之前执行net_dropped.train()相当于启用dropout,测试之前执行net_dropped.eval()相当于不启用dropout。