keras读取模型继续训练,keras 训练
前几天帮一个朋友处理了一个深度学习网络问题。具体场景如下。一共12张照片,分为三类。它们被用作训练集和验证集。训练集与验证集的预处理相同。使用的型号是ResNet50,最终激活函数是softmax。使用keras框架,总共有10个历元,每个历元只有一个批次(因为数据集中只有12个图像,所以一个批次只有12个图像)。
在前几个历元训练时,训练准确率达到100%。因为模型比较复杂,有12个数据集,拟合的很好,但是验证准确率只有33%,也就是训练准确率远高于验证准确率。
在核实了https://blog.csdn.net/qq_16564093/article/details/103563517,提到的可能情况后,问题仍然无法解决。于是我花了三天时间寻找答案。
接下来是我的解题思路:
(1).模型是否出现过拟合现象
猜测,模型可能过于复杂和过拟合,导致模型过拟合训练数据,不适合验证数据集。
于是,为了验证这个猜想,我使用了相同的训练数据集和验证数据集,即数据迭代器都是相同的数据,但结果是,训练准确率仍然远高于验证准确率。可以推测,模型没有过度拟合训练数据集。于是,我用同样的数据对模型进行测试,结果是准确率只有33%,这可以说明一个问题,模型完全不拟合。那么,问题来了,为什么模型的训练准确率能达到100%?即使存在过拟合,且训练集与验证集相同,如果模型过拟合训练集,那么模型也要过拟合验证集,验证准确率要达到100%。
(2).训练集与验证集是否存在随机处理。
猜测训练集和验证集之间是否有一些随机的处理方法,比如某个角度的随机旋转,某个范围内亮度和色度的变化。然后,在数据集迭代器的每次迭代之后,处理数据。当模型过拟合时,数据集迭代器在过拟合训练集后处理数据,因此数据处理后不能应用模型生成新的数据集。但是,我对所有的数据处理方法都设置了Flase,也就是保证数据不变。在这种情况下,验证准确率仍然只有33%,而训练准确率达到100%。
(3).设置计算训练准确率跟验证准确率的计算方式不同。
因为使用的keras,我猜测计算训练精度和验证精度的方式是否有区别,是否有额外的计算训练精度的方式。但是我查了keras官方文档,没有发现额外的设置方式,也就是说计算训练精度和验证精度的标准是一样的。
(4).keras底层是否对训练集跟验证集的准确率,损失的计算方式不同。
于是,排除各种外界因素,我开始探究keras的底层。我猜测除了keras的底层,训练集和验证集的精度是用不同的方法计算的,虽然计算标准都是精度。还有一种可能,就是在训练模式下,keras底层对一批的数据进行了分段。所以接下来就是我对底层代码的探索,谜底慢慢揭晓。
keras底层代码解剖# # #模型的生成代码为:model=keras . models . model(inputs=base _ model . input,outputs=x) # #模型的训练代码为:model . fit _ generator(train _ data _ generator,validation _ data=train _ data _ generator)。
(1).首先model.fit_generator函数进行解剖。
通过逐层解剖发现,模型对训练集和验证集的准确率计算方法是一样的,但是模型对训练集和验证集的正向传递导致输出结果不一致,即在训练模式和验证模式下,模型输入相同的图片,输出结果不一致。
(2).对训练模型下跟验证模式下,模型的输出结果出现差异进行解剖。
因此,我继续跟踪模型的输出,比较模型在训练期间调用的推理函数和模型在验证期间调用的推理函数。最后,我发现了这个脚本的不同之处:
# # # site-packages \ tensor flow _ core \ python \ keras \ engine \ training _ eager . pydef _ model _ loss(model,inputs,targets,output_loss_metrics=None,Sample _ weights=none,training=false) # # #在这个函数中,有这样一段代码,这里输出的结果是不同的。输出=型号(输入,* *千瓦)(3).对model(inputs, **kwargs)函数进行深入解剖。
我们在keras中建立模型后,一般用fit函数进行拟合,mode mode,predict进行估计,很少用model()进行调用。例如:
# # #通常model=keras . models . model(inputs=base _ model . input,outputs=x)model . fit _ generator(train _ data _ generator,Validation _ data=train _ data _ generator,epochs=10)RES=model . predict(input)# #但实际上你可以调用res=model (pic,training=true) res=model (pic,training=false) # # #这两个区别在于模型是否处于训练模式。实际上它调用的是class的__call__函数。(4).对model的__call__函数进行解剖。
逐层解剖函数,逐一比较训练模式和未训练模式的区别。最后在批量归一化层的处理函数中发现差异,这也是批量归一化后数据的差异。
# # # Site-packages \ tensor flow _ core \ python \ keras \ layers \ normalization . pydef _ fused _ batch _ norm(self,inputs,training): # # #在上面的内部函数中,有这个代码def _ fused _ batch _ norm _ training():returnnn . fused _ batch _ norm(inputs,gamma,beta,epsilon=,data_format=self。_ data _ format)def _ fused _ batch _ norm _ inference():return nn . fused _ batch _ norm(inputs,gamma,beta,mean=self.moving_mean,variance=self.moving_variance,=self,is_training=False,data_format=self。_data_format) output,mean,Variance=TF _ utils . smart _ cond(training,_ fused _ batch _ norm _ training,_ fused _ batch _ norm _ infection) # #从上面的代码可以看出# # #在训练模式下,模型调用的批量归一化函数是_fused_batch_norm_training###在非训练模式下, 模型调用的批量归一化函数是_ fused _ batch _ norm _ influence # # # # #虽然两者都调用nn.fused_batch_norm函数# # #,但是在训练模式下,均值和方差都是在传输过程中临时计算的。 # # #而不是训练模式,均值和方差都是自己传入的。然后,我发现在训练模式下,返回的方差值都在(-1,1)之间,而在非训练模式下,传入批量归一化函数的方差数据达到了上千,所以这就是问题所在。在训练模式下,由于均值和方差都在合理的值,所以批量归一化数据属于正态分布,而在非训练模式下,方差过大,导致数据输出。
但还有一个问题,因为在训练模式下,批量归一化后返回的均值和方差会被再次保存并赋给self.moving_mean和self.moving_variance,所以在非训练模式下,要使用正确的均值和方差,所以我继续跟踪self.moving_mean和self.moving _ variance的更新过程。
然后,我追踪了这段代码:
decay=ops . convert _ to _ tensor(1.0-momentum,name=decay)if decay.dtype!=变量。数据类型。base _ dtype:decay=math _ ops . cast(decay,variable。数据类型。base _ dtype)update _ delta=(variable-math _ ops . cast(值,变量。dtype)) * decay这意味着均值随着方差的更新具有动量。因此,当均值和方差达到正常范围时,需要更多的历元进行迭代更新。
所以,结果是模型并非过拟合,而是还未拟合,因为批归一化中的mean跟variance仍需要迭代很多次,才能达到合理值,而在前几个epoch中,训练模型下,mean跟variance都是通过数据集进行计算的,所以模型的输出是合理的,训练准确率也较高,但在验证集上,模型处于非训练模式,mean跟variance都是使用保存下来的,都仍然偏大,还未迭代到合理数值,所以模型的输出都异常,验证准确率也偏低。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。