前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >神经ODEs:另一个深度学习突破的细分领域

神经ODEs:另一个深度学习突破的细分领域

作者头像
代码医生工作室
发布2019-06-21 16:51:50
3K0
发布2019-06-21 16:51:50
举报
文章被收录于专栏:相约机器人

作者 | Alexandr Honchar

来源 | Medium

编辑 | 代码医生团队

今天介绍的主题来自NIPS 2018最佳论文:神经常微分方程(神经ODE)。

在本文中,将简要介绍一下这篇论文的重要性、实际应用以及如何应用这种神经网络。

相关代码可以查看此GitHub存储库,建议您在Google Colab中启动它。

https://arxiv.org/abs/1806.07366

https://github.com/Rachnog/Neural-ODE-Experiments

什么是ODE?

首先,快速回顾一下常微分方程:它描述了某个过程的时间演变,这个过程取决于一个变量,并且这个时间的变化是通过一个衍生物来描述的。

简单的ODE示例

解微分方程,可以理解为有一些初始条件(此时过程开始),想看看过程将如何演变到某个最终状态。求解函数称为积分曲线(因为可以将方程积分得到解x(t))。相关代码如下:

代码语言:javascript
复制
from sympy import dsolve, Eq, symbols, Function
t = symbols('t')
x = symbols('x', cls=Function)
deqn1 = Eq(x(t).diff(t), 1 - x(t))
sol1 = dsolve(deqn1, x(t))

最终将返回解决方案

代码语言:javascript
复制
Eq(x(t), C1*exp(-t) + 1)

其中C1是常数,可以在给定一些初始条件时确定。如果以适当的形式给出,则可以分析地解析ODE,但通常它们以数字方式求解。最古老和最简单的算法之一是欧拉方法:核心思想是使用切线来逐步逼近求解函数:

http://tutorial.math.lamar.edu/Classes/DE/EulersMethod.aspx

请访问图片下方的链接以获取更详细的说明,最终会得出一个非常简单的公式

http://tutorial.math.lamar.edu/Classes/DE/EulersMethod.aspx

n个时间步的离散网格的解是

http://tutorial.math.lamar.edu/Classes/DE/EulersMethod.aspx

ResNets是ODE解决方案吗?

残差连接的公式: Y_ {N + 1} = y_n + F(t_n,y_n)。其中一些层的输出为所述层的输出的总和f()的本身和输入y_n此层。这基本上是神经ODE的主要思想:神经网络中的残差连接块链基本上是ODE与Euler方法的解决方案!在这种情况下,系统的初始条件是“时间” 0,它表示神经网络的第一层,并且x(0)将提供正常输入,可以是时间序列,图像,无论你想要什么!“时间” t的最终条件 将是神经网络的期望输出:标量值,表示类或其他任何东西的向量。

如果这些残差连接是欧拉方法的离散时间步长,这意味着可以调节神经网络的深度,只需选择离散方案,因此,使解决方案(又称神经网络)更多或不太准确,甚至使它无限层!

具有固定层数的ResNet与具有灵活层数的ODENet之间的差异

如果用一些抽象概念取代ResNet / EulerSolverNet 作为ODESolveNet,其中ODESolve将是一个函数,它提供ODE(低键:我们的神经网络本身)的解决方案,其精度比欧拉方法好得多。网络架构如下所示:

代码语言:javascript
复制
nn = Network(
  Dense(...), # making some primary embedding
  ODESolve(...), # "infinite-layer neural network"
  Dense(...) # output layer
)

因为神经网络是一个可微分的函数,所以我们可以用基于梯度的优化程序来训练它。在实现过程中,可以通过ODESolve() 函数反向传播。

为ODESolve()方法制作“反向传播”

在反向传播过程中,系统通过反向链式传导的规则向后描述过程的每个点处的导数状态。这一个过程可以通过初始状态获得导数,并以类似的方式,通过建模动力学的函数的参数(一个“残差块”,或“旧的”欧拉方法中的离散化步骤) 。

神经ODE的应用

使用ODE代替“ResNets”的优点和动机:

  • 内存效率:不需要在反向传播时存储所有参数和渐变
  • 自适应计算:可以通过离散化方案平衡速度和准确性,而且在训练和推理时使其不同
  • 参数效率:附近“层”的参数自动捆绑在一起(参见论文)
  • 归一化流动新型可逆密度模型
  • 连续时间序列模型:连续定义的动态可以自然地合并在任意时间到达的数据。

当然它也有一定的缺点,具体如下:

  • 将复杂的ODE压缩成单个动态建模神经网络
  • 将其应用于缺少时间步的时间序列
  • 可逆的规范化流程(这里暂不讨论)

对于缺点的描述,以及相关理论,请参考原始论文。同时,这里还有一些实际的例子,所有的实验代码如下:

https://github.com/Rachnog/Neural-ODE-Experiments

学习动力系统

微分方程可以被广泛用于描述复杂的连续过程。在现实生活中,可以将它们视为离散过程,因为在时间步骤t_i中的许多观察可能会有缺失。下面将介绍如何使用神经ODE处理它们。

具体步骤如下:

  • 定义一个简单的(或不是真正的)神经网络,它将模拟从h_t到h_ {t + 1}的两个后续动态步骤之间的动态,或者在动态系统的情况下,x_t和x_ {t + 1}。
  • 运行通过ODE求解器反向传播的优化过程,并最小化实际和建模动态之间的差异。

在实验中,使用一个简单的序列神经网络模型,具体代码如下:

代码语言:javascript
复制
self.net = nn.Sequential(
            nn.Linear(2, 50),
            nn.Tanh(),
            nn.Linear(50, 2),
        )

具体代码可以参考如下链接

https://nbviewer.jupyter.org/github/urtrial/neural_ode/

在可视化代码中,虚线代表拟合模型

代码语言:javascript
复制
true_A = torch.tensor([[-0.1, 2.0], [-2.0, -0.1]])
class Lambda(nn.Module):
    def forward(self, t, y):
        return torch.mm(y, true_A)

上边的相空间,下边的时空。直线代表真实的轨迹并且点缀一个 - 用于神经ODE系统学习的进化

随机矩阵函数

代码语言:javascript
复制
true_A = torch.randn(2, 2)/2.

上边的相空间,下边的时空。直线代表真实的轨迹并且点缀一个 - 用于神经ODE系统学习的进化

Volterra-Lotka系统

代码语言:javascript
复制
a, b, c, d = 1.5, 1.0, 3.0, 1.0
true_A = torch.tensor([[0., -b*c/d], [d*a/b, 0.]])

上边的相空间,下边的时空。直线代表真实的轨迹并且点缀一个 - 用于神经ODE系统学习的进化

非线性函数

代码语言:javascript
复制
true_A2 = torch.tensor([[-0.1, -0.5], [0.5, -0.1]])
true_B2 = torch.tensor([[0.2, 1.], [-1, 0.2]])
class Lambda2(nn.Module):
    
    def __init__(self, A, B):
        super(Lambda2, self).__init__()
        self.A = nn.Linear(2, 2, bias=False)
        self.A.weight = nn.Parameter(A)
        self.B = nn.Linear(2, 2, bias=False)
        self.B.weight = nn.Parameter(B)
    
    def forward(self, t, y):
        xTx0 = torch.sum(y * true_y0, dim=1)
        dxdt = torch.sigmoid(xTx0) * self.A(y - true_y0) + torch.sigmoid(-xTx0) * self.B(y + true_y0)
        return dxdt

上边的相空间,下边的时空。直线代表真实的轨迹并且点缀一个 - 用于神经ODE系统学习的训练。

可以看到,单个“残差块”无法很好地学习这个过程,因此要使用更加复杂的函数进行拟合。

神经网络功能

通过具有随机初始化权重的多层感知器对函数进行完全参数化:

代码语言:javascript
复制
true_y0 = torch.tensor([[1., 1.]])
t = torch.linspace(-15., 15., data_size)
class Lambda3(nn.Module):
  
    def __init__(self):
        super(Lambda3, self).__init__()
        self.fc1 = nn.Linear(2, 25, bias = False)
        self.fc2 = nn.Linear(25, 50, bias = False)
        self.fc3 = nn.Linear(50, 10, bias = False)
        self.fc4 = nn.Linear(10, 2, bias = False)
        self.relu = nn.ELU(inplace=True)
        
    def forward(self, t, y):
        x = self.relu(self.fc1(y * t))
        x = self.relu(self.fc2(x))
        x = self.relu(self.fc3(x))
        x = self.relu(self.fc4(x))
        return x

上边的相空间,下边的时空。直线代表真实的轨迹并且点缀一个 - 用于神经ODE系统学习的进化

这里2-50-2网络失败可怕,因为它太简单了,增加它的深度:

代码语言:javascript
复制
self.net = nn.Sequential(
            nn.Linear(2, 150),
            nn.Tanh(),
            nn.Linear(150, 50),
            nn.Tanh(),
            nn.Linear(50, 50),
            nn.Tanh(),
            nn.Linear(50, 2),
        )

上边的相空间,下边的时空。直线代表真实的轨迹并且点缀一个 - 用于神经ODE系统学习的更新

神经ODEs作为生成模型

作者还声称可以通过VAE框架构建生成时间序列模型,使用神经ODE作为其中的一部分。它是如何工作的?

原始纸上的插图

  • 首先,使用一些“标准”时间序列算法对输入序列进行编码,假设RNN用于获取进程的主要嵌入
  • 通过神经ODE运行嵌入以获得“连续”嵌入
  • 以VAE方式从“连续”嵌入中恢复初始序列

作为一个概念证明,只是重新运行了这个存储库中的代码,它似乎在学习螺旋轨迹方面做得非常好:

https://nbviewer.jupyter.org/github/urtrial/neural_ode/blob/master/Neural%20ODEs%20%28Russian%29.ipynb

点是采样噪声轨迹,蓝线是真实轨迹,橙色线代表恢复和插值轨迹

其中x(t)为时空,x`(t)为衍生空间,并适应不同的VAE设置。这个用例可能对Mawi Band这样的可穿戴设备非常有用,因为必须恢复信号(必须在深度学习的帮助下进行,但实际上是通过深度学习来实现的,但是ECG是一个连续的信号,不是吗?)。不幸的是,它并没有很好地收敛,显示出过度拟合到单一形式节拍的所有迹象:

相空间。蓝线 - 真实轨迹,橙色线 - 采样和噪声轨迹,绿线 - 自动编码轨迹

时空。蓝线 - 实信号,橙线 - 采样和噪声信号,绿线 - 自动编码信号

还尝试了另一个实验:只在每个节拍的部分上学习这个自动编码器并从中恢复整个波形。不幸的是,没有提出任何有意义的信息,无论是向左还是向右外推这个信号 -  只要折叠到无穷大,无论对超参数和数据预处理做了什么。也许读者中的某些人可能会帮助理解出了什么问题

扩展

很明显神经ODE旨在学习相对简单的过程,因此需要一个能够为更丰富的函数族建模的模型。目前已经有两种增强的方法:

1.增强神经ODE:

https://github.com/EmilienDupont/augmented-neuralodes

2.神经跳随机DEs:

https://www.groundai.com/project/neural-jump-stochastic-differential-equations/1

结论

神经异构在技术还没有完善时,就尝试应用到实践中。这是个很好的想法。但是它不仅让人们想起Geoffrey Hinton的胶囊网络,现在它们在哪里......?它们可以在一些玩具任务上显示出良好的结果,但在接近实际应用或大规模数据集的任务上都失败了。

关于ODE现在能看到的,只有两个实际应用:

  • 使用ODESolve()层来平衡经典神经网络中的速度/准确度权衡
  • 将常规ODE“挤压”到神经架构中,将它们嵌入到标准数据科学管道中

希望这个方向能有进一步的发展,产出更多的模型结构。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 相约机器人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档