• 问答
  • 技术
  • 实践
  • 资源
深度学习的模型调试小技巧,没别的,就是实用精选
技术讨论

作者:Jonathan Balaban
编译:ronghuaiyang
来源:AI公园
原文:https://towardsdatascience.com/deep-learning-tips-and-tricks-1ef708ec5f53

前言
很多人说深度学习是玄学,有很多说不清道不明的东西在里面,实际上,还是有一些规律可言的,虽然不是什么放之四海而皆准的真理,但也是长期总结的一些经验教训,可以试一试,看是不是有用。

首先,为什么要调试模型?

卷积神经网络(CNN)等深度学习模型具有大量的参数,我们把这些叫做超参数,因为它们并没有在模型中进行优化。你可以为这些超参数搜索最优值,但是你需要大量的硬件和时间。那么,一个真正的数据科学家会满足于瞎猜这些基本参数吗?

改进模型的最佳方法之一是基于在那些对你的领域进行了深入研究的专家做的设计和结构的基础上构建你的模型。 这些专家通常能调用非常多的硬件资源。含蓄一点说,他们经常对生成的建模体系结构和基本原理进行开源。

深度学习技巧

这里有一些方法,可以使用预训练模型来减少你的拟合时间和提高你的准确性:

  • 1.研究理想的预训练结构:了解迁移学习的好处,或浏览一些强大的CNN架构。考虑那些看起来不太合适,但是共享特征的领域。
  • 2.使用较小的学习率:因为预训练的权重通常比随机初始化的权重要好!你在这里的选择取决于学习环境和预训练的进展情况,在不同的epochs上检测误差,了解你离收敛有多近。

  • 3.使用dropout:与Ridge和LASSO正则化回归模型一样,没有一个最优的α适合所有的模型,它是一个超级参数,取决于你的具体问题,必须进行测试。从更大的变化开始,就和上面的学习率一样。
  • 4.限制权值大小:我们可以限制某些层的权值的最大范数(绝对值),以泛化我们的模型。
  • 5.不要动第一层:神经网络的第一个隐藏层倾向于捕捉通用的和可解释的特征,如形状、曲线或交互,这些特征通常与领域相关。我们通常最好是别动这些,重点优化其他的层。这可能意味着添加隐藏层,所以先着急。
  • 6.修改输出层:用一个新的激活函数和适合你的领域的输出大小替换模型默认值。然而,不要把自己局限于最明显的解决方案上。虽然MNIST可能看起来想要10个输出类,但是一些数字有共同的变化,12-16个类可能会更好地解决这些变化,并提高模型性能!正如上面的提示一样,越接近输出,深度学习模型应该越来越多地进行修改和定制。

Keras技巧

下面是如何在Minist数据集上用Keras来调整dropout并限制权重的大小:

# dropout in input and hidden layers

# weight constraint imposed on hidden layers

# ensures the max norm of the weights does not exceed 5

model = Sequential()
model.add(Dropout(0.2, input_shape=(784,))) # dropout on the inputs

# this helps mimic noise or missing data

model.add(Dense(128, input_dim=784, kernel_initializer='normal', activation='relu', kernel_constraint=maxnorm(5)))

model.add(Dropout(0.5))

model.add(Dense(128, kernel_initializer='normal', activation='tanh', kernel_constraint=maxnorm(5)))

model.add(Dropout(0.5))

model.add(Dense(1, kernel_initializer='normal', activation='sigmoid'))


Dropout的最佳实践:

  • 使用20-50%的小的dropout比例,建议输入为20%。过低,效果不明显,过高,导致欠拟合。
  • 在输入层和隐藏层上使用drop,这已经被证明可以提高深度学习的表现。
  • 使用带衰减的大的学习率,大的动量。
  • 限制你的权重!一个大的学习率会导致梯度爆炸。对网络权值施加约束—例如最大范数正则化(size为5)—已被证明可以改善结果。
  • 使用更大的网络。当在更大的网络上使用dropout时,你可能会获得更好的性能,从而给模型提供更多学习独立表示的机会。


    下面是使用MNIST在Keras中修改最后一层的例子,有14个分类:
from keras.layers.core import Activation, Dense

model.layers.pop() # defaults to last

model.outputs = [model.layers[-1].output]

model.layers[-1].outbound_nodes = []

model.add(Dense(14, activation='softmax')) 



如何冻结前五层的权重:

for layer in model.layers[:5]:
    layer.trainable = False

或者,我们可以将该层的学习率设置为零,或者使用每个参数的自适应学习算法,比如Adadelta或Adam。这有点复杂,这在Caffe等其他平台上可以更好地实现。

在Jupyter里可视化你的TensorBoard图

对你的模型有一个直观的认识是很重要的。如果你使用Keras,会给你提供高级的抽象,但是不允许你深入到模型的各个部分进行更深入的分析。幸运的是,下面的代码让我们可以直接用Python可视化我们的模型:

# From: https://nbviewer.jupyter.org/github/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/deepdream/deepdream.ipynb

# Helper functions for TF Graph visualization

from IPython.display import clear_output, Image, display, HTML

def strip_consts(graph_def, max_const_size=32):

"""Strip large constant values from graph_def."""

    strip_def = tf.GraphDef()

for n0 in graph_def.node:

        n = strip_def.node.add() 

        n.MergeFrom(n0)

        if n.op == 'Const'
:

            tensor = n.attr['value'].tensor

            size = len(tensor.tensor_content)

            if size > max_const_size:

                tensor.tensor_content = bytes("<stripped %d bytes>"%size, 'utf-8')

    return strip_def

def rename_nodes(graph_def, rename_func):

    res_def = tf.GraphDef()

    for n0 in graph_def.node:

        n = res_def.node.add() 

        n.MergeFrom(n0)

        n.name = rename_func(n.name)

        for i, s in enumerate(n.input):

            n.input[i] = rename_func(s) if s[0]!='^' else '^'+rename_func(s[1:])

        return res_def

def show_graph(graph_def, max_const_size=32):

      " " "Visualize TensorFlow graph."""

if hasattr(graph_def, 'as_graph_def'):

        graph_def = graph_def.as_graph_def()

    strip_def = strip_consts(graph_def, max_const_size=max_const_size)

    code = " " "

        <script>

          function load() {{

            document.getElementById("{id}").pbtxt = {data};

          }}

        </script>

        <link rel="import" href="https://tensorboard.appspot.com/tf-graph-basic.build.html" onload=load()>

        <div style="height:600px">

          <tf-graph-basic id="{id}"></tf-graph-basic>

        </div>

    " " ".format(data=repr(str(strip_def)), id='graph'+str(np.random.rand()))

    iframe = " " "

        <iframe seamless style="width:800px;height:620px;border:0" srcdoc="{}"></iframe>

    " " ".format(code.replace('"', '"'))

    display(HTML(iframe))

# Visualizing the network graph. Be sure expand the "mixed" nodes to see their 

# internal structure. We are going to visualize "Conv2D" nodes.

graph_def = tf.get_default_graph().as_graph_def()

tmp_def = rename_nodes(graph_def, lambda s:"/".join(s.split('_',1)))

show_graph(tmp_def)


使用Keras可视化你的模型

绘制模型图保存成png文件:

This will plot a graph of the model and save it as a png file:

from keras.utils import plot_model

plot_model(model, to_file='model.png')


plot可以接收两个可选参数:

  • show_shapes (默认是False) 控制了是否在图中显示输出的形状。
  • show_layer_names (默认是True) 控制了是否在图中显示层的名字。

你也可以直接获取pydot.Graph对象,自己渲染,比如在ipython notebook中显示:

from IPython.display import SVG

from keras.utils.visualize_util import model_to_dot

SVG(model_to_dot(model).create(prog='dot', format='svg'))



希望这些可以对你的深度学习项目有所帮助。如果你有其他关于深度学习的模型调试小技巧,也欢迎留言回复与大家交流~





推荐阅读
样本生而不等——聊聊那些对训练数据加权的方法
微软开源的深度学习模型转换工具 MMdnn
快速上手笔记,PyTorch 模型训练实用教程(附代码)

  • 12
  • 85
  • 4413
收藏
暂无评论