实用!深度学习的模型调试小技巧

作者:Jonathan Balaban
编译: AI公园 - ronghuaiyang

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

下面是我与同事和学生关于如何优化深度模型的对话、消息和讨论的摘要。如果你发现你有很有效的技巧,请分享它们!!

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

卷积神经网络(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: http://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'))

希望这些可以对你的深度学习项目有所帮助。

英文原文:https://towardsdatascience.com/deep-learning-tips-and-tricks-1ef708ec5f53

本文转自:微信号 - AI公园,编译:ronghuaiyang,转载此文目的在于传递更多信息,版权归原作者所有。

最新文章