请谨慎使用预训练的深度学习模型

2019-11-23 17:16:58 浏览数 (1)

作者:Cecelia Shao 编译:ronghuaiyang

导读

预训练模型用起来非常容易,但是你是否忽略了可能影响模型性能的细节呢?

你运行过多少次下面的代码:

代码语言:javascript复制
import torchvision.models as models
inception = models.inception_v3(pretrained=True)

或者是这个

代码语言:javascript复制
from keras.applications.inception_v3 import InceptionV3
base_model = InceptionV3(weights='imagenet', include_top=False)

看起来使用这些预训练的模型已经成为行业最佳实践的新标准。毕竟,有一个经过大量数据和计算训练的模型,你为什么不利用呢?

预训练模型万岁!

利用预训练的模型有几个重要的好处:

  • 合并超级简单
  • 快速实现稳定(相同或更好)的模型性能
  • 不需要太多的标签数据
  • 迁移学习、预测和特征提取的通用用例

NLP领域的进步也鼓励使用预训练的语言模型,如GPT和GPT-2、AllenNLP的ELMo、谷歌的BERT、Sebastian Ruder和Jeremy Howard的ULMFiT。

利用预训练模型的一种常见技术是特征提取,在此过程中检索由预训练模型生成的中间表示,并将这些表示用作新模型的输入。通常假定这些最终的全连接层得到的是信息与解决新任务相关的。

每个人都参与其中

每一个主流框架,如Tensorflow,Keras,PyTorch,MXNet等,都提供了预先训练好的模型,如Inception V3,ResNet,AlexNet等,带有权重:

  • Keras Applications
  • PyTorch torchvision.models
  • Tensorflow Official Models (and now TensorFlow Hubs)
  • MXNet Model Zoo
  • Fast.ai Applications

很简单,是不是?

但是,这些benchmarks可以复现吗?

这篇文章的灵感来自Curtis Northcutt,他是麻省理工学院计算机科学博士研究生。他的文章‘Towards Reproducibility: Benchmarking Keras and PyTorch’ 提出了几个有趣的观点

  1. resnet结构在PyTorch中执行得更好, inception结构在Keras中执行得更好
  2. 在Keras应用程序上不能复现Keras Applications上的已发布的基准测试,即使完全复制示例代码也是如此。事实上,他们报告的准确率(截至2019年2月)通常高于实际的准确率。
  3. 当部署在服务器上或与其他Keras模型按顺序运行时,一些预先训练好的Keras模型会产生不一致或较低的精度。
  4. 使用batch normalization的Keras模型可能不可靠。对于某些模型,前向传递计算(假定梯度为off)仍然会导致在推理时权重发生变化。

你可能会想:这怎么可能?这些不是相同的模型吗?如果在相同的条件下训练,它们不应该有相同的性能吗?

并不是只有你这么想,Curtis的文章也在Twitter上引发了一些反应:

关于这些差异的原因有一些有趣的见解:

了解(并信任)这些基准测试非常重要,因为它们允许你根据要使用的框架做出明智的决策,并且通常用作研究和实现的基线。

那么,当你利用这些预先训练好的模型时,需要注意什么呢?

使用预训练模型的注意事项

1、你的任务有多相似?你的数据有多相似?

对于你的新x射线数据集,你使用Keras Xception模型,你是不是期望0.945的验证精度?首先,你需要检查你的数据与模型所训练的原始数据集(在本例中为ImageNet)有多相似。你还需要知道特征是从何处(网络的底部、中部或顶部)迁移的,因为任务相似性会影响模型性能。

阅读CS231n — Transfer Learning and ‘How transferable are features in deep neural networks?’

2、你如何预处理数据?

你的模型的预处理应该与原始模型相同。几乎所有的torchvision模型都使用相同的预处理值。对于Keras模型,你应该始终为相应的模型级模块使用 preprocess_input函数。例如:

代码语言:javascript复制
# VGG16
keras.applications.vgg16.preprocess_input
# InceptionV3
keras.applications.inception_v3.preprocess_input
#ResNet50
keras.applications.resnet50.preprocess_input

3、你的backend是什么?

有一些关于HackerNews的传言称,将Keras的后端从Tensorflow更改为CNTK (Microsoft Cognitive toolkit)提高了性能。由于Keras是一个模型级库,它不处理诸如张量积、卷积等较低级别的操作,所以它依赖于其他张量操作框架,比如TensorFlow后端和Theano后端。

Max Woolf提供了一个优秀的基准测试项目,发现CNTK和Tensorflow之间的准确性是相同的,但CNTK在LSTMs和多层感知(MLPs)方面更快,而Tensorflow在CNNs和embeddings方面更快。

Woolf的文章是2017年发表的,所以如果能得到一个更新的比较结果,其中还包括Theano和MXNet作为后端,那将是非常有趣的(尽管Theano现在已经被废弃了)。

还有一些人声称,Theano的某些版本可能会忽略你的种子。

4、你的硬件是什么?

你使用的是Amazon EC2 NVIDIA Tesla K80还是Google的NVIDIA Tesla P100?甚至可能是TPU??看看这些不同的pretrained模型的有用的基准参考资料。

  • Apache MXNet’s GluonNLP 0.6:Closing the Gap in Reproducible Research with BERT
  • Caleb Robinson’s ‘How to reproduce ImageNet validation results’ (and of course, again, Curtis’ benchmarking post)
  • DL Bench
  • Stanford DAWNBench
  • TensorFlow’s performance benchmarks

5、你的学习率是什么?

在实践中,你应该保持预训练的参数不变(即,使用预训练好的模型作为特征提取器),或者用一个相当小的学习率来调整它们,以便不忘记原始模型中的所有内容。

6、在使用batch normalization或dropout等优化时,特别是在训练模式和推理模式之间,有什么不同吗?

正如Curtis的帖子所说:

使用batch normalization的Keras模型可能不可靠。对于某些模型,前向传递计算(假定梯度为off)仍然会导致在推断时权重发生变化。

但是为什么会这样呢?

Expedia的首席数据科学家Vasilis Vryniotis首先发现了Keras中的冻结batch normalization层的问题。

Keras当前实现的问题是,当冻结批处理规范化(BN)层时,它在训练期间还是会继续使用mini-batch的统计信息。我认为当BN被冻结时,更好的方法是使用它在训练中学习到的移动平均值和方差。为什么?由于同样的原因,在冻结层时不应该更新mini-batch的统计数据:它可能导致较差的结果,因为下一层没有得到适当的训练。

Vasilis还引用了这样的例子,当Keras模型从训练模式切换到测试模式时,这种差异导致模型性能显著下降(从100%下降到50%)。

0 人点赞