发布网友 发布时间:2024-09-30 17:08
共1个回答
热心网友 时间:2024-10-19 00:10
1.过拟合与欠拟合Underfitting欠拟合的特点:模型的复杂度<数据分布的复杂度1)训练集的准确率不好,loss会比较高2)测试集的准确率也不好,loss也会比较高
Overfitting过拟合的特点:模型的复杂度>数据分布的复杂度1)训练集的准确度比较高,但是测试集的准确度比较低2)过分的准确降低loss,导致效果不好
由于现在的网络层数都比较大,所以出现过拟合的情况比较多,欠拟合的情况相对会少一点
1)提供更多的数据
2)降低模型的复杂度降低神经网络结构的层数或者正则化方法
3)Dropout去掉一部分的神经元
4)DataEnhancement数据增强
5)EarlyStopping对训练过程做一个提前的终结
2.交叉验证train-val-test交叉验证结构的思路:由于datasets.MNIST函数可以将数据样本划分成数据集与测试集两类,但是这是不够的,可以引入第三类,也就是train-val-test交叉验证结构。可以将样本数量较多的训练集再度的划分为train样本集与val样本集,这样可以使用train样本集来训练神经网络,然后使用val样本集来测试来选择一个较好的参数值,最后test数据集是作为最后的样本得出最终的结果
参考代码
#导入需要的模块importtorchimporttorch.nnasnnimporttorch.nn.functionalasFimporttorch.optimasoptimimporttorchvisionfromtorchvisionimporttransforms,datasets#参数的初始化batch_size=200learning_rate=0.01epochs=10#训练集下载train_db=datasets.MNIST('datasets/mnist_data',train=True,download=True,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))]))#测试集下载test_db=datasets.MNIST('datasets/mnist_data',train=False,download=True,transform=transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,),(0.3081,))]))#将训练集再度分成两类,train数据集样本数为50k,val数据集的样本数为10ktrain_db,val_db=torch.utils.data.random_split(train_db,[50000,10000])#接下来进行导入数据train_loader=torch.utils.data.DataLoader(train_db,batch_size=batch_size,shuffle=True)test_loader=torch.utils.data.DataLoader(test_db,batch_size=batch_size,shuffle=True)val_loader=torch.utils.data.DataLoader(val_db,batch_size=batch_size,shuffle=True)#打印三种数据集的样本数量print('train:',len(train_db),'val:',len(val_db),'test:',len(test_db))#输出为:train:50000val:10000test:10000#定义神经网络结构classMLP(nn.Mole):def__init__(self):super(MLP,self).__init__()self.model=nn.Sequential(nn.Linear(784,200),nn.LeakyReLU(inplace=True),nn.Linear(200,200),nn.LeakyReLU(inplace=True),nn.Linear(200,10),nn.LeakyReLU(inplace=True),)defforward(self,x):x=self.model(x)returnx#使用GPU来加速计算device=torch.device('cuda:0')net=MLP().to(device)#设置容器optimizer=optim.SGD(net.parameters(),lr=learning_rate)criteon=nn.CrossEntropyLoss().to(device)#一次epoch是直接训练全部的样本forepochinrange(epochs):#对于train数据集,主要的功能是不断的改进神经网络结构forbatch_idx,(data,target)inenumerate(train_loader):data=data.view(-1,28*28)data,target=data.to(device),target.cuda()logits=net(data)loss=criteon(logits,target)optimizer.zero_grad()loss.backward()optimizer.step()ifbatch_idx%100==0:print('TrainEpoch:{}[{}/{}({:.0f}%)]\tLoss:{:.6f}'.format(epoch,batch_idx*len(data),len(train_loader.dataset),100.*batch_idx/len(train_loader),loss.item()))#然后使用val数据集来挑选一个精度最高的参数值来进行下一次的epoch训练,主要主要是监视时候出现过拟合的情况#根据val样本集输出的情况,进行人为的选择最低loss指的参数,来作为做好的参数,来给最后的test样本集来做验证test_loss=0correct=0fordata,targetinval_loader:data=data.view(-1,28*28)data,target=data.to(device),target.cuda()logits=net(data)test_loss+=criteon(logits,target).item()#data.shape,pred.shape输出为:(torch.Size([200,784]),torch.Size([200]))#也就是data为200张28*28的图片pred=logits.data.max(1)[1]#得出每一个数据的预测数字#输出为:#tensor([3,2,7,0,2,9,3,5,0,1,8,8,1,8,5,0,8,0,5,9,1,9,4,8,#1,0,4,3,7,7,2,2,8,7,1,2,9,9,1,0,2,3,5,4,8,8,2,1,#3,8,2,6,3,2,1,1,7,9,2,1,2,9,9,3,0,0,1,9,7,5,6,4,#5,3,8,3,1,6,0,1,6,1,1,2,6,6,5,3,4,9,9,5,8,3,1,5,#7,9,6,1,2,5,3,4,3,1,7,2,0,3,0,3,1,4,1,6,6,5,3,1,#1,6,2,7,2,8,4,4,0,8,2,9,0,1,6,7,3,1,6,1,0,5,4,9,#9,3,3,0,9,8,9,7,8,1,7,6,4,0,1,8,4,2,4,2,1,1,3,4,#4,8,8,7,4,8,2,1,7,6,0,9,9,6,1,7,9,4,7,5,8,7,3,4,#4,0,0,5,8,3,2,1],device='cuda:0')correct+=pred.eq(target.data).sum()test_loss/=len(val_loader.dataset)print('\nVALset:Averageloss:{:.4f},Accuracy:{}/{}({:.0f}%)\n'.format(test_loss,correct,len(val_loader.dataset),100.*correct/len(val_loader.dataset)))#测试集得出最后的结果,根据上述的输出人为的选择一个最好的参数,去避免神经网络训练次数过多而导致过拟合的情况#这部分代码与val数据集的样本是完全一模一样的test_loss=0correct=0fordata,targetintest_loader:data=data.view(-1,28*28)data,target=data.to(device),target.cuda()logits=net(data)test_loss+=criteon(logits,target).item()pred=logits.data.max(1)[1]correct+=pred.eq(target.data).sum()test_loss/=len(test_loader.dataset)#得出最后一个最终结果print('\nTestset:Averageloss:{:.4f},Accuracy:{}/{}({:.0f}%)\n'.format(test_loss,correct,len(test_loader.dataset),100.*correct/len(test_loader.dataset)))结果输出:
TrainEpoch:0[0/50000(0%)]Loss:2.306638TrainEpoch:0[20000/50000(40%)]Loss:2.004949TrainEpoch:0[40000/50000(80%)]Loss:1.304654VALset:Averageloss:0.0048,Accuracy:7999/10000(80%)TrainEpoch:1[0/50000(0%)]Loss:0.950421TrainEpoch:1[20000/50000(40%)]Loss:0.750856TrainEpoch:1[40000/50000(80%)]Loss:0.486089VALset:Averageloss:0.0024,Accuracy:8725/10000(87%)TrainEpoch:2[0/50000(0%)]Loss:0.551328TrainEpoch:2[20000/50000(40%)]Loss:0.393225TrainEpoch:2[40000/50000(80%)]Loss:0.364113VALset:Averageloss:0.0019,Accuracy:8911/10000(89%)TrainEpoch:3[0/50000(0%)]Loss:0.349589TrainEpoch:3[20000/50000(40%)]Loss:0.392292TrainEpoch:3[40000/50000(80%)]Loss:0.436958VALset:Averageloss:0.0017,Accuracy:9017/10000(90%)TrainEpoch:4[0/50000(0%)]Loss:0.258544TrainEpoch:4[20000/50000(40%)]Loss:0.338164TrainEpoch:4[40000/50000(80%)]Loss:0.359373VALset:Averageloss:0.0016,Accuracy:9062/10000(91%)TrainEpoch:5[0/50000(0%)]Loss:0.273114TrainEpoch:5[20000/50000(40%)]Loss:0.253162TrainEpoch:5[40000/50000(80%)]Loss:0.311780VALset:Averageloss:0.0015,Accuracy:9127/10000(91%)TrainEpoch:6[0/50000(0%)]Loss:0.250342TrainEpoch:6[20000/50000(40%)]Loss:0.315225TrainEpoch:6[40000/50000(80%)]Loss:0.349633VALset:Averageloss:0.0014,Accuracy:9168/10000(92%)TrainEpoch:7[0/50000(0%)]Loss:0.279099TrainEpoch:7[20000/50000(40%)]Loss:0.223900TrainEpoch:7[40000/50000(80%)]Loss:0.316459VALset:Averageloss:0.0014,Accuracy:9201/10000(92%)TrainEpoch:8[0/50000(0%)]Loss:0.349246TrainEpoch:8[20000/50000(40%)]Loss:0.241840TrainEpoch:8[40000/50000(80%)]Loss:0.193532VALset:Averageloss:0.0013,Accuracy:9231/10000(92%)TrainEpoch:9[0/50000(0%)]Loss:0.238849TrainEpoch:9[20000/50000(40%)]Loss:0.193404TrainEpoch:9[40000/50000(80%)]Loss:0.204639VALset:Averageloss:0.0013,Accuracy:9251/10000(93%)Testset:Averageloss:0.0012,Accuracy:9305/10000(93%)由于设置的epoch过小,神经网络没有完全训练好,所以目前loss还是不断地在降低,还没有出现过拟合的情况,所以目前还不需要人为的挑选参数,来给最后的test样本集来进行训练。
3.regularization正则化问题:正则化的操作是为了使得参数分布减小,从而避免过拟合的情况,但是为什么参数范数接近于0的时候,其模型的复杂度会减少?
答案:因为将一个高维函数的高维部分的参数下降为接近于0,所以正则化在另一方面也称为WeightDecay
正则化分为两类:划分的依据是范数的不同1)L1-regularizationimage
2)L2-regularization(较常用)
对于L2-regularization来说,PyTorch有直接API接口可以直接使用,比较的方便,而L1-regularization需要人为进行添加。
#L2-regularization的使用参考device=torch.device('cuda:0')net=MLP().to(device)#其实就是添加了一个参数weight_decay=0.01optimizer=optim.SGD(net.parameters(),lr=learning_rate,weight_decay=0.01)criteon=nn.CrossEntropyLoss().to(device)#weight_decay=0.01的含义:相当于设置了L2-regularization公式中的λ为0.01#由于net.parameters()已经得到了神经网络的全部参数,w’=w-▽w,然后使得参数的二范数|w|——>0需要注意的是,正则化的操作是为了避免网络结果过于的复杂所以需要约束其参数不能过大,也就是避免过拟合的情况,如果网络并没有出现过拟合的情况而使用正则化操作会使得训练的效果差很多
#L1-regularization的使用参考regulatization_loss=0#遍历参数计算出参数的1范数,根据公式也就是模的相加forparaminmodel.parameters():regulatization_loss+=torch.sum(torch.abs(param))#对参数取绝对值求和classify_loss=criteon(logits,target)#计算出结果的交叉熵#交叉熵+参数的1范数损失=总的loss,现在降低这个loss就可以改善网络#根据上述的公式,0.01就是L1-regularization公式中的λ#以下这行代码就是模仿公式的结果loss=classify_loss+0.01*regulatization_loss#基本的三部曲,向后传播更新参数optimizer.zero_grad()loss.backward()optimizer.step()4.动量与学习量的衰减1)动量其中的zk可以理解为上一次梯度更新的方向,增加的动量的机制相当于不仅仅考虑了当前梯度的方向,还考虑了之前的梯度的方向,也就是综合的结合了两次梯度的变化信息来权衡。
Nomomentum
Withappr.momentum参考代码:
#方法1#同样的,pytorch中的SGD优化器也提供的一个接口,使用起来还是比较的方便optimizer=torch.optim.SGD(model.parameters().args.lr,momentum=args.momentum,#仅仅是添加了了着一个参数weight_decay=args.weight_decay)方法20.8表示新一轮产生的数据与前一轮产生的数据之间的使用比例,也就是动量操作nn.BatchNorm2d(128,0.8),
所以在构造神经网络的时候可以使用BN层来间接使用动量操作参考解释:https://blog.csdn.net/t20134297/article/details/104960101/#####2)Learingratedecay![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/577deba18a814fa787451689630eea42~tplv-k3u1fbpfcp-zoom-1.image)当梯度的长时间保持不变的时候,也有可以是learningrate的问题,有时我们调整了一下学习率就可能让loss跳转,所以可以动态的设置learningrate,训练过程一直保持同样的learningrate有时进行的会是非常的缓慢的![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/41a2975b110942f8b60a8eb754ff7d8b~tplv-k3u1fbpfcp-zoom-1.image)![在这里插入图片描述](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e4ea417b6f5a4463a4d7027961331849~tplv-k3u1fbpfcp-zoom-1.image)参考代码:```python#方法1#在SGD容器中设置了正则化操作与动量操作optimizer=torch.optim.SGD(model.parameters().args.lr,momentum=args.momentum,weight_decay=args.weight_decay)#ReceLOonPlateau当loss已经平坦了很长时间之后,可以通过减小learningrate来进一步减小loss#接口函数为:classReceLROnPlateau(builtins.object)#|ReceLROnPlateau(optimizer,mode='min',factor=0.1,patience=10,#threshold=0.0001,threshold_mode='rel',cooldown=0,#min_lr=0,eps=1e-08,verbose=False)scheler=ReceLOonPlateau(optimizer,'min')#mode='min':表示模式是减小lr#patience=10:表示如果10个epoch都没有减小,则降低learingrate#factor=0.1:表示降低learingrate的倍数,lr=factor*lr##训练过程forepochinxrange(args.start_epoch,args.epochs):train(train_loader,model,criterion,optimizer,epoch)result_avg,loss_val=validate(val_loader,model,criterion,epoch)#每调用一次就监听一次loss,若平淡10次就会做出改变scheler.step(loss_val)#方法2:#此方法不需要监听,而是没经过一定数量的训练次数就直接降低learningrate#Assumingoptimizeruseslr=0.05forallgroups#lr=0.05ifepoch<30#lr=0.005if30<=epoch<60#lr=0.0005if60<=epoch<90#......scheler=StepLR(optimizer,step_size=30,gamma=0.1)forepochinrange(100):scheler.step()train(...)validate(...)5.EarlyStopping思想很简单,就是使用val数据要进行验证,如果其准确度已经开始下降时,可以提前的终止训练,而使用当前认为最后的一组参数,其实这个思想前面的推文也有涉及,其简单的步骤归结为:
1)Validationsettoselectparameters:val数据集验证来挑选参数
2)Monitorvalidationperforamce:人工监视来查看性能
3)Stopatthehighestvalperf:在最高的准确度时停止实验
6.DropoutDropout的思想是去除掉一部分是神经元,也就是通过简化神经网络结构来避免过拟合的情况
Learninglesstolearnbetter
Eachconnectionhasp=(0,1)tolose
其与正则化的思想是有部分类似的,但是正则化的思想是使用2范数迫使参数的复杂度降低|w|->0,既使得参数的总范数接近于0而Dropout是想不需要使用全部的参数,可以简化一部分也就是断了部分参数之间的输入输出练习∑w->0,既使得有效的参数越小越好Dropout可以是的loss函数变化的比较平和,因为其使得有效的参数量减少了,避免了网络结构学习了噪声对最后的结果造成了干扰
#Dropout的使用方法如下:net_dropped=torch.nn.Sequential(torch.nn.Linear(784,200),#层(784,200)与层(200,200)之间的连线有一定几率断掉torch.nn