专栏首页相约机器人神经ODEs:另一个深度学习突破的细分领域

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

作者 | 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))。相关代码如下:

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))

最终将返回解决方案

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(低键:我们的神经网络本身)的解决方案,其精度比欧拉方法好得多。网络架构如下所示:

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求解器反向传播的优化过程,并最小化实际和建模动态之间的差异。

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

self.net = nn.Sequential(
            nn.Linear(2, 50),
            nn.Tanh(),
            nn.Linear(50, 2),
        )

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

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

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

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系统学习的进化

随机矩阵函数

true_A = torch.randn(2, 2)/2.

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

Volterra-Lotka系统

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系统学习的进化

非线性函数

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系统学习的训练。

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

神经网络功能

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

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网络失败可怕,因为它太简单了,增加它的深度:

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“挤压”到神经架构中,将它们嵌入到标准数据科学管道中

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

本文分享自微信公众号 - 相约机器人(xiangyuejiqiren),作者:代码医生

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-13

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用CNN和PyTorch进行面部关键点检测

    面部关键点也称为面部地标,通常指定面部的鼻子,眼睛,嘴巴等区域,该面部按68个关键点分类,并带有该坐标的坐标(x,y)。使用面部关键点,可以实现面部识别,情绪识...

    代码医生工作室
  • 使用PyTorch进行表格数据的深度学习

    使用表格数据进行深度学习的最简单方法是通过fast-ai库,它可以提供非常好的结果,但是对于试图了解幕后实际情况的人来说,它可能有点抽象。因此在本文中,介绍了如...

    代码医生工作室
  • 创建自动滑雪模拟器

    关于自治代理,它们的应用和改进,有很多研究。所以在考虑自动驾驶汽车,它可以在没有任何碰撞的情况下在雪地上行驶。不幸的是,没有足够的资源和时间来构建一个真正的机器...

    代码医生工作室
  • 【注意力机制】空间注意力机制之Spatial Transformer Network

    2015 NIPS(NeurIPS,神经信息处理系统大会,人工智能领域的 A 类会议)论文

    机器视觉CV
  • 腾讯云负载均衡HTTPS转发场景应用

    本文提供视频讲解,详细见地址:https://www.bilibili.com/video/BV1ZA411W7fi/

    研究僧
  • 手把手带你配置一个属于自己的微信小商店,含直播带货功能

    然后点击就可以进入“小商店助手”小程序,这次再点击免费开店,就可以开通微信小商店了。

    编程小石头
  • 从零开始PyTorch项目:YOLO v3目标检测实现

    选自Medium 作者:Ayoosh Kathuria 机器之心编译 目标检测是深度学习近期发展过程中受益最多的领域。随着技术的进步,人们已经开发出了很多用于目...

    机器之心
  • Python数据提取Json

    参考链接: Python-Json 2 : 使用json.load/loads读取JSON文件/字符串

    用户7886150
  • 如何严格管理你的混合云方案

    追求混合云的道路是不适合意志薄弱者的。从短期来看,最佳的混合云模式可能是找出那些可以在不同环境中长时间干净运行的应用。简单的转移工作负载只是冰山一角。更重要的是...

    静一
  • 羊皮书APP(Android版)开发系列(十四)Gson解析json很简单,还在手动的写实体类吗?

    热心的程序员

扫码关注云+社区

领取腾讯云代金券