全文共5838字,預計學習時長20分鐘或更長
今天,本文將帶你回顧2018年度神經信息處理系統大會(NIPS)中的最佳論文獎:《神經常微分方程》(Neural ODEs)Neural Ordinary Differential Equations。
這篇文章的重點將介紹神經常微分方程的實際用途、應用這種所需的神經網絡類型的方式、原因以及可行性。
為什麼需要關注常微分方程?
首先,快速回顧一下什麼是常微分方程。它描述了某個變量(這就是為什麼是常微分)在某個過程中的變化,這種隨時間的變化用導數來表示為:
簡單的常微分方程例子
如果存在一些初始條件(變化過程的起始點),並且想要觀察該過程將如何發展到某個最終狀態的話,我們可以探討此微分方程的求解。函數解也稱為積分曲線(因為可以對方程進行積分得到解x(t))。讓我們嘗試使用SymPy包來求解上圖中方程:
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是常數,可以在給定一些初始條件的情況下確定。如果以適當的形式給出,則可以用解析法求解,但通常用數值法求解。最古老、最簡單的算法之一是歐拉法。其核心思想是用切線逐步逼近函數解:
請訪問圖片下面的連結以獲得更詳細的說明。但最後,對於此方程,我們可得出一個非常簡單的公式:
在n個時間步長的離散網格上的解為:
ResNets是常微分方程的解嗎?
當然!y_{n+1} = y_n + f(t_n, y_n) 只是ResNet中的一個殘差連接,其中某個層的輸出是 f()層本身的輸出與該層y_n的輸入的總和。這基本上是神經常微分方程的主要思想:神經網絡中的殘差塊鏈基本上是用歐拉法來求解常微分方程。
在這種情況下,系統的初始條件是「時間」0,它表示神經網絡的第一層,因為x(0)將作用於正常輸入,這可以是時間序列、圖像,以及任何你想要的!「時間」 t的最終條件是神經網絡的期望輸出:標量值、表示類的或其他任何東西的向量。
如果這些殘差連接是歐拉法的離散時間步長,那麼就意味著只要選擇離散方案,可以調節神經網絡的深度。因此,可以使解(又名神經網絡)更精確或更粗略,甚至使它延伸至無限層!
具有固定層數的 ResNet與具有靈活層數的常微分方程網之間的差異
歐拉法是不是過於原始了?確實如此,所以讓我們用一些抽象的概念來代替ResNet 或是 EulerSolverNet,比如ODESolveNet,其中ODESolve將是一個函數,它提供了一個比歐拉法更精確的常微分方程(簡單地說:神經網絡本身)解決方案。網絡體系結構現在可能如下所示:
nn = Network(
Dense(...), # making some primary embedding
ODESolve(...), # "infinite-layer neural network"
Dense(...) # output layer
)
我們忘記了一件事……神經網絡是一個可微函數,所以我們可以用基於梯度的優化過程來完善它。我們應該如何通過ODESolve() 函數進行反向傳播?在例子中,這實際上也像一個黑匣子。特別地,我們需要一個由輸入和動力學參數組成的損失函數斜率。這種數學方法叫做伴隨敏度法。可參考原始文件和教程以獲得更多詳細信息,但其本質展示於下圖中(L代表我們要優化的主要損失函數):
為ODESolve()法設計「反向傳播」梯度
簡而言之,伴隨系統與描述該過程的原始動力系統一起,通過鏈式規則(即眾所周知的反向傳播的根源所在)描述後續過程的每個點的導數狀態。正是由此可以得到導數的初始狀態,並以類似的方式,通過一個函數的參數即動力學建模(一個「殘差塊」,或「舊」歐拉法的離散步驟)。
神經常微分方程的可能應用
首先,與「正常ResNet」相比的優勢和動機:
· 高效率內存:在反向傳播時,不需要存儲所有參數和變化率。
· 自擬合計算:可用離散化方案來平衡速度和精度,而且,在訓練和推理時會有不同的離散化方案。
· 高效率參數:附近「層」的參數自動綁定在一起。
· 對新型可逆密度模型進行流程規格化。
· 連續時間序列模型:連續定義的動力學模型可以自動包含在任意時間到達的數據。
根據這篇文章,除了用ODENet代替ResNet來實現計算機視覺外,還存在一些目前無法付諸現實的應用:
· 將複雜的常微分方程壓縮為單個動力學建模神經網絡。
· 將其應用於缺少時間步長的時間序列。
· 可逆流程規格化(超出此文章的範圍)。
對於不足之處,請參考原論文。有了充足的理論後,現在來看看一些實例。
學習動力學系統
正如之前所展示的,微分方程廣泛應用於描述複雜的連續過程。當然,在現實生活中,我們把它們看成是離散的過程,最重要的是,在時間步長 t_i 中,很多觀察結果可能會被忽略。假設想用一個神經網絡來模擬這樣一個系統。在經典的序列建模範例中,將如何處理這種情況?可能會運用遞歸神經網絡,而遞歸神經網絡甚至不是為它而設計的。在這一部分中,將考察神經常微分方程將如何處理這些情況。
設置如下:
1. 定義常微分方程本身,建模為PyTorch nn.Module()
2. 確定一個簡單的(或不是真正的)神經網絡,該神經網絡將在從h_t到h_{t+1}的兩個後續動力學步驟之間進行動力學建模,或者在動力學系統中,對 x_t和 x_{t+1}進行建模。
3. 運行通過常微分方程求解器反向傳播的優化過程,使實際動力學和動力學建模之間的差異最小化。
在下面的所有實驗中都會伴有神經網絡(這足以用兩個變量來建立簡單的函數模型):
self.net = nn.Sequential(
nn.Linear(2, 50),
nn.Tanh(),
nn.Linear(50, 2),
)
所有更深層次的例子都受到了這個資料庫的啟發,並給出了詳盡的解釋。在接下來的幾小節中將展示所建立的動力學系統模型在代碼中的體現和系統如何隨著時間演化以及ODENet如何擬合相圖。
簡單螺旋形函數
在此處以及所有後續的圖像中,虛線代表擬合模型。
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)
上邊是相空間,下邊是時間-空間。直線代表真實的軌跡,虛線代表神經常微分方程系統學習的變化過程。
隨機矩陣函數
true_A = torch.randn(2, 2)/2.
上邊是相空間,下邊是時間-空間。直線代表真實的軌跡,虛線代表神經常微分方程系統學習的變化過程。
Volterra-Lotka系統
a, b, c, d = 1.5, 1.0, 3.0, 1.0true_A = torch.tensor([[0., -b*c/d], [d*a/b, 0.]])
上邊是相空間,下邊是時間-空間。直線代表真實的軌跡,虛線代表神經常微分方程系統學習的變化過程。
非線性函數
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
上邊是相空間,下邊是時間-空間。直線代表真實的軌跡,虛線代表神經常微分方程系統學習的變化過程。
如上所示,單個「殘差塊」不能很好地學習這個過程,所以可能會使其更加複雜,以應對隨後的函數。
神經網絡函數
使用帶有隨機初始權值的多層感知器充分確定函數的參數:
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
左邊是相空間,右邊是時間-空間。直線代表真實的軌跡,虛線代表神經常微分方程系統學習的變化過程。
此處的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),
)
左邊是相空間,右邊是時間-空間。直線代表真實的軌跡,虛線代表神經常微分方程系統學習的變化過程。
現在基本上可以按照預期工作了,請勿忘記檢查代碼。
作為生成式模型的神經常微分方程
論文作者還聲稱可以通過利用神經節點作為VAE框架的一部分來建立生成時間序列模型。那麼工作原理如何呢?
· 首先,使用一些「標準」時間序列算法對輸入序列進行編碼,例如RNN,以進行過程中的初次嵌入。
· 通過神經常微分方程運行嵌入,實現「連續」嵌入
· 從VAE的「連續」嵌入中恢復初始序列。
為證明此概念,我們可以從存儲庫中重新運行代碼,它似乎在學習螺旋軌跡方面運行良好:
點代表採樣噪聲軌跡,藍線是真實軌跡,橙線代表恢復軌跡和插值軌跡。
隨後,我們可以從心電圖(ECG)轉換為 x(t)以為時間-空間,x`(t)為微分-空間的相圖(如本文所示),並嘗試擬合不同的VAE設置。這種用例對於像MAWI BandMawi Band這樣的可穿戴設備可能非常有用,由於有噪聲或中斷的信號,我們必須恢復它(實際上我們是在深度學習的幫助下完成的(the help of deep learning),但心電圖是一個連續的信號,不是嗎?)不幸的是,它並沒有很好地保持一致,顯示出了所有過度擬合於單一形式的跳動跡象。
相空間。藍線—實際軌跡,橙線—抽樣軌跡以及噪聲軌跡,綠線—自動編碼軌跡。
時空。藍線-實際信號,橙線-抽樣信號和噪聲信號,綠線-自動編碼信號。
我們還可以嘗試另一個實驗:只在每個跳動的部分研究該自動編碼器,並從中恢復整個波形(即外推出一個信號)。不幸的是,無論如何進行超參數和數據預處理,將這段信號向左或向右外推,都無法得出任何有意義的結果。也許讀者們可以幫助解決這個問題。
下一步是什麼?
很明顯,神經常微分方程是為了研究相對簡單的過程而設計的(這就是為什麼標題中有「常」字),所以需要一個能夠對更豐富的函數族建模的模型。已經有兩種有趣的方法:
當然,我們還需要時間來進行探究。畢竟神經常微分方程現階段無法投入實踐。這本身是個偉大的想法,目前只存在兩個實際應用:
· 在經典神經網絡中使用ODESolve()層來平衡速度/精度折衷。
· 將常規常微分方程「壓縮」到神經架構中,以將其嵌入標準數據科學流水線中。
留言 點讚 關注
我們一起分享AI學習與發展的乾貨
歡迎關注全平臺AI垂類自媒體 「讀芯術」