C'est très nouveau, mais je vais vous montrer comment utiliser la bibliothèque d'implémentation Neural ODE. À propos, Neural ODE est le meilleur article de NeuroIPS 2018.
Les auteurs officiels de Neural ODE ont publié une bibliothèque de dépôts officiels appelée torchdiffeq.
Bien que Neural ODE ait de nombreux articles expliquant la théorie et l'interprétation, je pensais qu'il y avait peu d'articles japonais décrivant l'utilisation réelle de cette bibliothèque, j'ai donc résumé l'utilisation de base dans cet article. À propos, torchdiffeq est une bibliothèque pour PyTorch.
En lisant cet article, vous pourrez:
--Torchdiffeq peut résoudre le problème de la valeur initiale de l'équation différentielle ordinaire du premier ordre --Torchdiffeq peut résoudre le problème de la valeur initiale de l'équation différentielle ordinaire du second ordre
Je passerai en revue les connaissances préalables à l'utilisation de torchdiffeq.
Parmi les équations différentielles, celle avec essentiellement une seule variable inconnue est appelée équation différentielle normale. Par exemple, les équations différentielles telles que $ \ frac {dz} {dt} = f (z (t), t) $ et $ m \ ddot {x} = -kx $ ont plusieurs variables, mais $ Puisque z $ et $ x $ sont des fonctions de $ t $, il n'y a essentiellement qu'une seule variable inconnue, $ t $, et on peut dire que c'est une équation différentielle normale.
Il existe de nombreux autres articles faciles à comprendre sur Neural ODE, veuillez donc les consulter.
Pour expliquer brièvement les grandes lignes, on peut dire que Neural ODE est un "réseau de neurones à couches continues".
Il existe une théorie selon laquelle il est difficile de saisir le concept car il existe un mot «équation différentielle normale» qui ne peut pas être entendu dans la zone du réseau neuronal, mais je pense que le point important est que «les couches sont continues». .. Cela permet par exemple de "retirer la sortie de la 0,5 ème couche", ce qui n'était pas possible avec le modèle classique.
Lien de référence ci-dessous:
Voyons maintenant comment utiliser torchdiffeq.
Pour installer, exécutez la commande suivante.
pip install torchdiffeq
Avant d'entrer dans l'implémentation de Neural ODE, prenons une simple équation différentielle ordinaire du premier ordre comme exemple pour voir comment utiliser facilement torchdiffeq.
Considérez l'équation différentielle d'équation suivante.
Cette solution utilise $ C $ comme constante d'intégration
Puisque $ z (0) = 0
La mise en œuvre la plus simple pour résoudre ce problème avec torchdiffeq est ci-dessous.
first_order.py
from torchdiffeq import odeint
def func(t, z):
return t
z0 = torch.Tensor([0])
t = torch.linspace(0,2,100)
out = odeint(func, z0, t)
Ci-dessous, les points sont listés.
func
correspond à $ f $ de l'équation différentielle ci-dessus $ \ frac {dz} {dt} = f (t, z) $. Les arguments sont dans l'ordre «(t, z)». Les dimensions de la sortie doivent correspondre à «z». Vous n'êtes pas obligé d'utiliser "z ou t".t [0]
est le temps correspondant à la valeur initiale.――Il faut noter que l'élément de t doit être une colonne qui augmente (diminue) au sens étroit. Une erreur se produira même si la même valeur est incluse, telle que t = tenseur ([0, 0, 1])
.
t = tenseur ([t0, t1, ..., tn])
, ʻout = tenseur ([z0, z1, ..., zn]) . Puisque
t [0]est l'heure initiale, la sortie ʻout [0]
correspond toujours à z0
.Tracez les résultats ci-dessus.
from matplotlib.pyplot as plt
plt.plot(t, out)
plt.axes().set_aspect('equal', 'datalim') #Rapport hauteur / largeur 1:Définir sur 1
plt.grid()
plt.xlim(0,2)
plt.show()
Vous pouvez voir qu'il correspond à la solution $ z = \ frac {t ^ 2} {2} $ de l'équation différentielle obtenue par calcul manuel.
Si vous utilisez torchdiffeq, vous pouvez également résoudre l'équation différentielle du second ordre. À titre d'exemple, nous résolvons l'équation différentielle de vibration simple (?) Familière à la science avec torchdiffeq. L'équation différentielle de la vibration simple est la suivante.
Ici, $ \ boldsymbol {y} = \ left [
\begin{array}{c}
x \
\dot{x} \
\end{array}
Si vous mettez \ right] $, cette équation différentielle du second ordre se traduira par l'équation différentielle du premier ordre suivante.
La mise en œuvre est la suivante. $ k = 1, m = 1 $.
oscillation.py
class Oscillation:
def __init__(self, km):
self.mat = torch.Tensor([[0, 1],
[-km, 0]])
def solve(self, t, x0, dx0):
y0 = torch.cat([x0, dx0])
out = odeint(self.func, y0, t)
return out
def func(self, t, y):
# print(t)
out = y @ self.mat # @Est-ce que le produit de la matrice
return out
if __name__=="__main__":
x0 = torch.Tensor([1])
dx0 = torch.Tensor([0])
import numpy as np
t = torch.linspace(0, 4 * np.pi, 1000)
solver = Oscillation(1)
out = solver.solve(t, x0, dx0)
Si vous le dessinez, vous pouvez voir que la solution de la vibration simple est correctement obtenue.
Maintenant que vous êtes habitué à utiliser torchdiffeq, voyons comment implémenter réellement ODE Block. Le bloc ODE est un module qui forme la dynamique de $ \ frac {dz} {dt} = f (t, z) $. Le Neural ODE réel est construit en utilisant le bloc ODE avec la couche Full-Connect normale et la couche de convolution.
L'implémentation suivante met l'accent sur la simplicité et n'est qu'un exemple.
from torchdiffeq import odeint_adjoint as odeint
class ODEfunc(nn.Module):
def __init__(self, dim):
super(ODEfunc, self).__init__()
self.seq = nn.Sequential(nn.Linear(dim, 124),
nn.ReLU(),
nn.Linear(124, 124),
nn.ReLU(),
nn.Linear(124, dim),
nn.Tanh())
def forward(self, t, x):
out = self.seq(x)
return out
class ODEBlock(nn.Module):
def __init__(self, odefunc):
super(ODEBlock, self).__init__()
self.odefunc = odefunc
self.integration_time = torch.tensor([0, 1]).float()
def forward(self, x):
self.integration_time = self.integration_time.type_as(x)
out = odeint(self.odefunc, x, self.integration_time)
return out[1] # out[0]Parce que la valeur initiale est incluse dans.
Pour expliquer brièvement,
--ODE Block traite l'entrée reçue «x» comme la valeur initiale de l'équation différentielle. ―― ʻODEfunc` est $ f $ qui décrit la dynamique du système.
En faisant cela, vous pouvez utiliser ODE Block comme un module du réseau neuronal comme indiqué ci-dessous.
class ODEnet(nn.Module):
def __init__(self, in_dim, mid_dim, out_dim):
super(ODEnet, self).__init__()
odefunc = ODEfunc(dim=mid_dim)
self.fc1 = nn.Linear(in_dim, mid_dim)
self.relu1 = nn.ReLU(inplace=True)
self.norm1 = nn.BatchNorm1d(mid_dim)
self.ode_block = ODEBlock(odefunc) #Utiliser le bloc ODE
self.norm2 = nn.BatchNorm1d(mid_dim)
self.fc2 = nn.Linear(mid_dim, out_dim)
def forward(self, x):
batch_size = x.shape[0]
x = x.view(batch_size, -1)
out = self.fc1(x)
out = self.relu1(out)
out = self.norm1(out)
out = self.ode_block(out)
out = self.norm2(out)
out = self.fc2(out)
return out
Ce modèle a été lent à calculer. Cependant, l'utilisation de torchdiffeq ne semble pas le ralentir, et pour autant que j'ai essayé, le modèle Neural ODE dans le référentiel officiel est aussi rapide qu'un réseau neuronal normal. (Celui-ci devrait être un modèle plus petit ...)
Nous avons introduit une utilisation rudimentaire de torchdiffeq qui est utile pour implémenter Neural ODE. Si vous souhaitez voir le programme qui entraîne réellement le modèle, veuillez consulter le Dépôt officiel de torchdiffeq ou [Mon référentiel d'implémentation](https: // github. com / TakadaTakumi / neuralODE_sample).
torchdiffeq - GitHub Mon référentiel d'implémentation
Recommended Posts