如何训练神经网络

如何训练神经网络,第1张

1、先别着急写代码

训练神经网络前,别管代码,先从预处理数据集开始。我们先花几个小时的时间,了解数据的分布并找出其中的规律。

Andrej有一次在整理数据时发现了重复的样本,还有一次发现了图像和标签中的错误。所以先看一眼数据能避免我们走很多弯路。

由于神经网络实际上是数据集的压缩版本,因此您将能够查看网络(错误)预测并了解它们的来源。如果你的网络给你的预测看起来与你在数据中看到的内容不一致,那么就会有所收获。

一旦从数据中发现规律,可以编写一些代码对他们进行搜索、过滤、排序。把数据可视化能帮助我们发现异常值,而异常值总能揭示数据的质量或预处理中的一些错误。

2、设置端到端的训练评估框架

处理完数据集,接下来就能开始训练模型了吗?并不能!下一步是建立一个完整的训练+评估框架。

在这个阶段,我们选择一个简单又不至于搞砸的模型,比如线性分类器、CNN,可视化损失。获得准确度等衡量模型的标准,用模型进行预测。

这个阶段的技巧有:

· 固定随机种子

使用固定的随机种子,来保证运行代码两次都获得相同的结果,消除差异因素。

· 简单化

在此阶段不要有任何幻想,不要扩增数据。扩增数据后面会用到,但是在这里不要使用,现在引入只会导致错误。

· 在评估中添加有效数字

在绘制测试集损失时,对整个测试集进行评估,不要只绘制批次测试损失图像,然后用Tensorboard对它们进行平滑处理。

· 在初始阶段验证损失函数

验证函数是否从正确的损失值开始。例如,如果正确初始化最后一层,则应在softmax初始化时测量-log(1/n_classes)。

· 初始化

正确初始化最后一层的权重。如果回归一些平均值为50的值,则将最终偏差初始化为50。如果有一个比例为1:10的不平衡数据集,请设置对数的偏差,使网络预测概率在初始化时为0.1。正确设置这些可以加速模型的收敛。

· 人类基线

监控除人为可解释和可检查的损失之外的指标。尽可能评估人的准确性并与之进行比较。或者对测试数据进行两次注释,并且对于每个示例,将一个注释视为预测,将第二个注释视为事实。

· 设置一个独立于输入的基线

最简单的方法是将所有输入设置为零,看看模型是否学会从输入中提取任何信息。

· 过拟合一个batch

增加了模型的容量并验证我们可以达到的最低损失。

· 验证减少训练损失

尝试稍微增加数据容量。

近年来,随着量子化学计算和分子动力学模拟等实验的展开产生了巨大的数据量,大多数经典的机器学习技术都无法有效利用目前的数据。而原子系统的对称性表明,能够应用于网络图中的神经网络也能够应用于分子模型。所以,找到一个更加强大的模型来解决目前的化学任务可以等价于找到一个适用于网络图的模型。

本文的目标是证明:能够应用于化学预测任务的模型可以直接从分子图中学习到分子的特征,并且不受到图同构的影响。本文提出的MPNN是一种用于图上监督学习的框架,能够概括之前一些文献提出的一些方法,并且能够按照这个框架提出一些新的架构。本文提出的新的MPNN变种基于实际的应用场景:预测有机小分子的量子力学性质。并且,作者希望以后提出的新的MPNN变种能够从实际的应用出发,从实际应用中获得启发。

本文以QM9作为benchmark数据集,这个数据集由130k个分子组成,每个分子有13个性质,这些性质是通过一种计算昂贵的量子力学模拟方法(DFT)近似生成的,相当于13个回归任务。这些任务似乎代表了许多重要的化学预测问题,并且目前对许多现有方法来说是困难的。

本文提出的模型的性能度量采用两种形式:

①DFT近似的平均估计误差;

②化学界已经确立的目标误差,称为“化学精度”。

本文介绍了能够应用MPNN框架的8篇文献,为了简便起见,以处理无向图 为例,无向图 包含节点特征 和边的特征 ,将这种形式推广到有向重图是不重要的。MPNN前向传播的过程包含两个阶段,即消息传递阶段(message passing phase)和读出阶段(readout phase)。消息传递阶段运行 个时间步并且依赖消息函数 以及节点更新函数 。在消息传递阶段,每个节点的隐状态 都会根据消息 进行更新,具体过程是:

代表节点 的邻居节点集合。读出阶段使用某种读出函数 来为整个图计算一个特征向量:

都是用来学习的可微函数。 作用于节点状态集合,并且必须对节点状态的排列保持不变,以使MPNN对图同构保持不变。注意MPNN也可以学习边的特征,这可以通过为每条边引入隐状态 并应用前面的两个过程来实现。接下来,我们通过指定所使用的消息函数 、顶点更新函数 和读出函数 来定义以前文献中的模型。

本文提出的模型采用的消息函数是:

代表拼接。节点更新函数是:

是节点 的度, 对应于时间步 以及节点度 的学习矩阵。读出函数将之前所有隐状态 进行连接:

是一个神经网络, 是时间步 的一个学习矩阵。

这样的消息传递的方法可能有问题,因为最终得到的消息向量为 ,这是边和节点状态向量的加和,缺乏边和节点状态向量的交互。

消息函数为:

是特定于边的标签的学习矩阵(这个模型假设边有离散的标签)。更新函数如下:

GRU就是门控循环单元,一种循环神经网络,对于每个时间步进行权重共享,也就是说每个时间步共用同一个更新函数。最后,读出函数:

代表神经网络, 代表哈达玛积。

这个模型考虑了两种情况,一种是每个节点都有自己的目标,另一种是有一个graph level的目标。它还考虑了在每个时间步骤中存在node level影响的情况,在这种情况下,更新函数将 连接作为输入,其中 是一个外部向量,表示顶点 受到的外部影响。消息函数 是一个神经网络,使用拼接向量 作为输入,节点更新函数 也是一个神经网络,使用 作为输入。最终读出函数得到一个graph level的输出: ,这里 是一个神经网络。注意,这个模型只定义了 的情况。

这个模型与之前的MPNNs稍微有一些不同,是因为它引入了边的表示 ,并且会在消息传递阶段进行更新。消息函数为:

节点更新函数为:

同样的 代表拼接, 代表ReLU激活函数, 是学习权重矩阵。边状态更新的方式是:

都是学习矩阵。

消息函数为:

是矩阵, 是偏置向量。更新函数为:

读出函数使用单个隐层神经网络独立地通过每个节点,并对输出进行求和:

8篇文献中有3篇属于这一类。其中两篇采用消息函数:

矩阵 通过拉普拉斯矩阵的特征向量和模型的学习参数来参数化。更新函数为:

代表非线性函数,比如ReLU激活函数。

另一篇文献采用消息函数:

这里 。节点更新函数为:

本文以前述GG-NN作为baseline进行改进,提出一种新的MPNN变种。下文中以 代表节点特征的维度,以 代表图的节点的数量。这一变种适用于有向图,这意味着入边和出边有分别的信息通道,那么信息 由 和 拼接而成,当我们将模型应用无向图时,就把无向图的边看做两条边,包含一条入边,一条出边,有相同的标签,这样处理的方式意味着信息通道的大小是 而不是 。

模型的输入是每个节点的特征向量 以及邻接矩阵 ,邻接矩阵 具有向量分量,表示分子中的不同化学键以及两个原子之间的成对空间距离。初始状态 是原子输入特征集合 ,并且需要padding到维度 。在实验中的每个时间步 都要进行权重共享,并且更新函数采用GRU。

GG-NN原本采用的消息函数,采用矩阵相乘的方式(注意原来的GG-NN的边有离散的标签,而现在我们假设的边有一个特征向量 ):

是特定于边的标签的学习矩阵。为了兼容边特征,本文提出了新的消息函数:

是一个神经网络,将边的特征向量 映射到一个 的矩阵。上述两种消息函数的特点是消息只依赖于 和 而不依赖于 ,如果消息同时依赖目标节点与源节点,那么应该是更加高效的,可以尝试以下这种消息函数:

这里 是一个神经网络。

对于有向图,一共有两个消息函数 和 ,对于边 应用哪个消息函数取决于边的方向。

本文探索了两种方式来改变模型中信息的传递。第一种是为未连接的节点对添加一个单独的“虚拟”边类型。这一处理可以在预处理时实现,效果是可以使得在传播过程中让信息传播更远的距离。

另一种方式是添加一个“master”节点,让它通过一种特殊类型的边与所有节点连接。“master”节点充当全局暂存空间,每个节点在消息传递的每个步骤中都对其进行读写 *** 作。另外“master”节点拥有单独的节点维度 ,以及内部更新函数(实验中是GRU)的单独权重。这同样可以使得在传播过程中让信息传播更远的距离。这样可以允许模型有更大的容量,同时也不会过多的损失效率,其复杂度为 。

读出函数采用set2set模型,这个模型使用 作为输入,然后再经过 步计算后生成一个graph level的embedding ,其中过程与 内节点顺序无关,最终将 输入到一个神经网络中来获得最终输出。具体参考文献: Sequence to sequence for sets。

由于消息传递阶段的复杂度为 ,当 和 增大时,计算上就会是昂贵的。处理的方法是将 拆分成 个不同的 维的embedding ,并且在每个 上独立运行传播过程得到 ,然后进行混合:

代表神经网络, 代表拼接, 在所有节点上共享。这样的混合过程保持了节点排列的不变性,同时允许图的不同副本在传播阶段相互通信。这样的设计提升了计算效率,比如在使用矩阵相乘的消息函数时一个副本的复杂度为 ,当有 个副本时一共为 。

一个分子有很多特征,如下图所示:

边的特征包括化学键与距离,因此有以下三种表示方式:

①化学图(Chemical Graph):在不考虑距离的情况下,邻接矩阵的值是离散的键类型:单键,双键,三键或芳香键;

②距离分桶(Distance bins):GG-NN基于矩阵乘法的消息函数的前提假设是“边信息是离散的”,因此作者将键的距离分为 10 个 bin,比如说 中均匀划分 8 个 bin, 为 1 个 bin, 为 1 个 bin;

③原始距离特征(Raw distance feature):也可以同时考虑距离和化学键的特征,这时每条边都有自己的特征向量,此时邻接矩阵的每个实例都是一个 5 维向量,第一维是距离,其余4维是一个独热向量,代表4种不同的化学键。

实验中对比了本文提出的方法与现有的方法:

以下为不考虑空间信息的结果:

以下为一些消融实验:

具体实验设置参照原文。

用Keras搭建神经网络的步骤:

深度学习框架Keras——像搭积木般构建神经网络,主要分为7个部分,每个部分只需要几个keras API函数就能实现,用户即可像搭积木般一层层构建神经网络模型。

1. 创建模型 Create model

2. 添加层级 Add Layer

3. 模型编译 Compile

4. 数据填充 Fit

5. 模型评估 Evaluate

6. 模型预测 Predict

7. 模型保存 Save model

下面章节会对每一部分具体来介绍。。。

Keras 中主要有三类模型:Sequential model, Functional model, Subclass model

在开始创建模型之前,首先需要引入tensorflow和keras模块,然后再创建一个Sequential model

Sequential API定义如下:

layers参数可以为空, 然后通过add method向模型中添加layer,相对应的通过pop method移除模型中layer。

创建Function API模型,可以调用Keras.Model来指定多输入多数出。

Keras.Model定义:

Layers是神经网络基本构建块。一个Layer包含了tensor-in/tensor-out的计算方法和一些状态,并保存在TensorFlow变量中(即layers的权重weights)。

Layers主要分为6个类别,基础层,核心层,卷基层,池化层,循环层,融合层。

对派生类的实现可以用以下方法:

** init (): 定义layer的属性,创建layer的静态变量。

** build(self, input_shape): 创建依赖于输入的变量,可以调用add_weight()。

** call(self, *args, **kwargs): 在确保已调用build()之后,在 call 中调用。

** get_config(self): 返回包含用于初始化此层的配置的字典类型。

创建SimpleDense派生类,在build()函数里添加trainable weights。实现y=input*w +b

结果输出:

创建ComputeSum派生类,在 init 函数里添加 non-trainable weights。实现输入矩阵沿轴0元素相加后,x=x+self.total

结果输出:

核心层是最常用的层,涉及到数据的转换和处理的时候都会用到这些层。

Dense层就是所谓的全连接神经网络层,简称全连接层。全连接层中的每个神经元与其前一层的所有神经元进行全连接。

Dense 实现以下 *** 作: output = activation(dot(input, kernel) + bias) 其中 activation 是按逐个元素计算的激活函数,kernel 是由网络层创建的权值矩阵,以及 bias 是其创建的偏置向量 (只在 use_bias 为 True 时才有用)。

将激活函数应用于输出。输入信号进入神经元后进行的运算处理。

sigmoid、tanh、ReLU、softplus的对比曲线如下图所示:

激活函数可以通过设置单独的激活层Activation实现,也可以在构造层对象时通过传递 activation 参数实现:

Dropout在训练中每次更新时,将输入单元的按比率随机设置为0,这有助于防止过拟合。未设置为0的输入将按1 /(1-rate)放大,以使所有输入的总和不变。

请注意,仅当训练设置为True时才应用Dropout层,以便在推理过程中不会丢弃任何值。 使用model.fit时,训练将自动适当地设置为True。

将输入展平。不影响批量大小。注意:如果输入的形状是(batch,)没有特征轴,则展平会增加通道尺寸,而输出的形状是(batch, 1)。

将输入重新调整为特定的尺寸

将任意表达式封装为Layer对象。在Lambda层,以便在构造模型时可以使用任意TensorFlow函数。 Lambda层最适合简单 *** 作或快速实验。 Lambda层是通过序列化Python字节码来保存的。

使用覆盖值覆盖序列,以跳过时间步。

对于输入张量的每一个时间步(张量的第一个维度),如果所有时间步中输入张量的值与mask_value相等,则将在所有下游层中屏蔽(跳过)该时间步。如果任何下游层不支持覆盖但仍然收到此类输入覆盖信息,会引发异常。

举例说明:

Embedding 是一个将离散变量转为连续向量表示的一个方式。该层只能用作模型中的第一层。

Embedding 有以下3个主要目的: 在 embedding 空间中查找最近邻,这可以很好的用于根据用户的兴趣来进行推荐。 作为监督性学习任务的输入。 用于可视化不同离散变量之间的关系.

举例说明:

输出结果:

由维基百科的介绍我们可以得知,卷积是一种定义在两个函数(

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/bake/11918977.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-19
下一篇 2023-05-19

发表评论

登录后才能评论

评论列表(0条)

保存