以epoch为单位,计算整个epoch的loss函数和时间。batch size=32或者64,现在程序中设置的batch size=8,每进行一个step需要0.30s,如果训练数据集中包含9600张图片,batch size=32,一个epoch中包含300个step,1秒进行一次step,则300秒一个epoch,5min一个epoch,一小时12个epoch,一般训练过程会跑200-300个epoch,则24小时之后会跑到288个epoch。
训练网络模型常用两种optimizer/学习方法:
(1)Adam:学习率 1e-3
(2)带有momentum项的SGD:通常要对超参数进行调节,如learning_rate,经验值如下:①epoch=0~120/150,learning_rate=0.1,②epoch=120~160,learning_rate=0.01, ③epoch=160~200,learning_rate=0.001
在最开始训练的时候,需要采用大的学习率,只要更新后的权值参数不是NaN(not a number)就可以无限增大学习率,就是说,较大的学习率会使得模型参数更新后的数值超出了float类型数据的表示范围,就会报 not a number。对于softmax输出的类别置信度,很有可能输出的数值会特别小,这时候求classification_loss时,很可能会出现超出float浮点数表示的范围,如-numpy.log(0.0000000001),则会导致无法继续训练,这时候通常会加入一个smooth项,如-numpy.log(0.0000000001+0.00001)。出现这种问题(not a number)解决办法通常是:①将学习率调小②看classification loss中是否有平滑项。
loss函数在接近局部最优值附近再迭代训练,可能会发生震荡(比如在epoch=150到epoch=200之间loss函数都在某个值附近震荡)。这个时候应减小学习率(乘以0.1),可以使在接近最优值附近的loss迅速下降。
loss=classification_loss+localization_loss
要对loss函数进行大致计算,知道最开始的loss值是多大,达到一定的训练准确率之后的loss值又是多大。比如,最开始进行训练时,分类网络可能是对21个类别进行随机猜测,将当前样本分类成每个类别(包括是正确的类别)的概率是1/21=0.05,则平均的分类损失是 -numpy.log(0.05)=2.99,而如果是希望达到90.0%的准确率,则loss=-numpy.log(0.90)=0.105,
localization_loss=
在default boxes(没有调整之前的)中根据IOU值找到的一些正样本肯定都是与ground truth很近的样本,则四个坐标的loss都接近于0。
计算出编码之后的ground truth值后,再与FPNSSD模型的输出值相比较计算出差值,再对差值取smooth L1,其实对于localization loss,误差差值是0.1就已经是很大的误差了,因为正样本的default boxes就在ground truth boxes附近,因为差值的分母处除以了宽度(对于坐标x),则说明default boxes的x坐标(经过网络预测后的输出)距离ground truth 的x坐标很远。可以假设初始的坐标损失较大,但是可能也就在0.1量级,再进行smoothL1计算,得到0.01,则loss函数值并不会太大。
实际上并不是loss函数越小,模型的测试准确率/评估准确率越高,而且在实验过程中,很多情况下,找到的使得测试准确率较小的模型参数并不是使loss函数最小的模型,这可能是由于训练数据集中的图片数量过少,发生了过拟合overfit。
要会直接根据loss函数的数值判断当前训练模型性能的好坏。loss函数的数值则需要根据loss的公式定义来看,loss的定义决定了最优的loss值大概在什么数值范围。
如果的值设定的很大,比如100,则loss函数的最优值可能不需要达到0.001/0.01的数量级就已经是最优的了。
对于当前的loss值所得到的网络模型参数进行评估,计算测试的mAP,
pytorch中的可视化工具:tensorboard,或打印print loss函数值进行调试,
用pretrained model在FPNSSD512上训练时,开始的时候loss=12,cls_loss=3(accuracy=1/21=0.05),loc_loss=12-3=9。模型的分类输出是经过softmax函数作用后,故分类输出的值域在(0,1),但是localization却只是经过卷积之后的输出,输出至于范围未知,所以可能会产生较大的loss值。
test/evaluate评估时间会比训练时间短很多,这是因为train阶段有前向传播(一次卷积计算)和反向传播(两次卷积计算),而评估阶段只有前向传播,没有反向传播和梯度计算,训练时间0.3s,评估时间0.1s,则可能是差2倍的卷积时间。
batch size的大小和学习率的调整都会对于网络模型的loss函数是否收敛有影响:
(1)batch size:并不是越大越好,如果每个step中是使用的整个训练数据集中的所有训练样本,即full batch SGD,则训练效果并不一定会比mini-batch SGD好,因为在训练过程中需要对训练数据引入一定的随机性。batch size=1则也会使学习的信息过少,并不准确。比如训练数据集合中共有9,000张图片,batch size=30,在每一次epoch时,先将这9000张图片进行随机打乱,然后每个step中按顺序取出30张图片进行训练,下一次的epoch时,还要对这9000张训练图片再随机打乱一次,每个step中取出batch size张图片进行训练, 故而每进行一次epoch前,都要对训练数据集进行随机重排。对于物体检测的应用,batch size 一般不会取值太小,batch size=32/64,但是对于全卷积网络的应用如语义分割,batch size的取值可能只能取1,这是因为,全卷积网络通常是网络层次很深且输出图像分辨率与输入图像相等,无法降低图像的分辨率,故而训练这样的网络非常消耗显存,如果取batch size=2,很有可能就run out of memory,batch size的取值很大程度上取决于显卡的显存,这个时候为了增大batch size,最好的方法就是使用多个GPU并行,如果一张显卡只能容纳batch size=2,则如果有8张显卡,就可以将batch size设置成16。
对于物体检测问题,如果一个GPU能容纳16张图片,有4块GPU,则可以将batch size设置成64。
当batch size 设置成8后,如果采用多个GPU并行,则会将8张图片分成两块4张图片(即使4张图片远远没能占满一个GPU的显存)。每块GPU前向传播、训练,计算出4张图片的loss 关于当前模型参数的loss之后,再计算梯度,第二块GPU将所计算的梯度传回第一块GPU,这将会导致第一块GPU的显存占用率比第二块GPU更高(约400M),因为第一块GPU需要对第二块GPU传回的梯度进行平均,平均完之后,更新模型参数,再将更新后的模型参数分发给第二块GPU(数据分发),两个GPU之间使用了高速连接设备,所以数据传输速度很快。要注意的是,多个GPU并行的情况下,多个GPU实现的是同一个batch size中的图像数据的训练,因为多个GPU在同一时间的模型参数是相同的(共享模型参数),如果认为是每个GPU上运行一个batch size的数据,训练过程中,是需要当前batch size训练完成更新模型参数后,才能进行下一个batch size的训练,则这样另一块GPU需要空闲等待当前GPU训练完成并将模型参数传到这个GPU,才能开始这个batch size的训练,这样相当于没有并行,所以多个GPU之间并行一定是对于同一个batch size的数据进行平均分配。
保存模型或者大型数据集到 data ssddata文件夹下,不要再保存到home目录下。
task:
1. 打印损失函数信息的时候最好分别打印出classification_loss和localization_loss.观察训练到了什么程度。如果对于测试数据集,classification_loss=0.1,则说明mean accuracy=90%,这对于模型而言是远远不够的,因为它是密集估计且使用了hard example mining策略,故而需要mean accuracy=95%,即loss=0.04左右才行
2.learning rate调节的经验值
看优秀的代码怎么修改学习率 模仿优秀风格的代码 多看代码
①epoch=0~120/150,learning_rate=0.1,②epoch=120~160,learning_rate=0.01, ③epoch=160~200,learning_rate=0.001
在第120个epoch后开始评估模型性能,打印出loss函数,选择几个较小的loss函数所对应的模型,对测试数据集进行评估,可视化一些包围框
模型训练的最好效果必然是在②③阶段出来,不会再①中出来
把网络和测试数据集作为输入,对模型进行评估,torchcv/evaluations/voc_eval.py
loss小于某个阈值(如0.2)之后,调用voc_eval.py对模型进行评估
如果评估的速度很快,就可以把评估模块集成到train.py
需要保留接近10种模型参数,不能只保存一个loss最小的模型参数
经常出现这种情况,不是最小的loss使得测试准确率最高
3.把batch size的数值调大,重新训练 batch size=20
4.把网络模型的结构打印出来
5.跑通ship detection,读取数据代码
6.重现torchcv 中的fpn性能 80.%精确重现准确率 (精确性能)
pytorch中集成了tensorflow中的tensorboard,在代码中加入一些变量,可以实现可视化(用图形展示);
杀死程序
ps -ef|grep python 打印当前所有的正在运行的python程序的进程号
找到想要杀死的python程序进程号,手动删除
在后台运行程序,(关上电脑或者断开网络连接,程序可能中断)
python 1.py &
FPNSSD512-resnet50实践经验总结;
1.使用SGD学习方法,初始学习率不能设置成太大,我开始设置成0.1,经过7.8个batch的参数更新之后,计算得到的loc_loss和cls_loss都特别大(nan,inf),导致训练崩溃,这时候要调小出事的学习率,之前跑过将初始学习率设置成0.001的训练,发现训练过程十分缓慢,每个batch的损失函数变化很小,因此将初始学习率设置成0.01,注意模型的参数是每个batch size更新一次,不是每个epoch更新一次
2.关于初始的损失函数数值的解释:loc_loss:0.08,cls_loss=12,因为正样本都是与ground truthIOU值很大的anchor boxes,故而经过编码之后计算出的回归损失会很小,(localization loss只对正样本进行计算)接近于0,而分类损失是对于正样本以及hard negative mining策略得到的负样本进行计算的,程序中采用的是将困难样本挖掘的数量是正样本数量的3倍,开始可以认为分类器是对于voc数据集的21个类别进行随机猜测,正确类别的概率也是1/21=0.05,-numpy.log(0.05)=2.99,用N表示正样本数量,负样本数量为3N,classification_loss=(N*2.99+3N*2.99)/N=4*2.99=12
3.batch size的值可以尽量设置大,只要程序不崩溃,而num_worker表示的是(在使用一块或者多块GPU的情况下)多块GPU加载数据使用的总进程数,num_worker的经验值一般设置8-12,如果设置的太大会引起进程堵塞。batch size的数值并不一定要设置成2的整数次幂。
训练网络模型的目的在于使得模型的测试准确率提高,而不是使loss函数很小,而且loss函数换一个公式定义后,它的数值又会不一样,所以可以在训练的epoch过程中,训练到达一定的程度后,每隔固定的epoch数量,就计算模型参数在测试数据集上的准确率,打印出来,从而判断模型的测试准确率,因为并不一定是loss值越小准确率越高的。