TCN全稱Temporal Convolutional Network,時序卷積網絡,是在2018年提出的一個卷積模型,可是能夠用來處理時間序列。python
時間序列預測,最容易想到的就是那個馬爾可夫模型:網絡
就是計算某一個時刻的輸出值,已知條件就是這個時刻以前的全部特徵值。上面公式中,P表示機率,能夠不用管這個,\(y_k\)表示k時刻的輸出值(標籤),\(x_k\)表示k時刻的特徵值。ide
若是使用LSTM或者是GRU這樣的RNN模型,天然是能夠處理這樣的時間序列模型的,畢竟RNN生來就是爲了這個的。函數
可是這個時間序列模型,宏觀上思考的話,其實就是對這個這個時刻以前的數據作某個操做,而後生成一個標籤,回想一下在卷積在圖像中的操做,其實有殊途同歸。(這裏不理解也無妨,由於我以前搞了一段時間圖像處理,因此對卷積相對熟悉一點)。學習
假設有一個時間序列,總共有五個時間點,比方說股市,有一個股票的價格波動:[10,13,12,14,15]:
TCN中,或者說因果卷積中,使用的卷積核大小都是2,我也不知道爲啥不用更大的卷積核,看論文中好像沒有說明這個,若是有小夥伴知道緣由或者有猜測,能夠下方評論處一塊兒討論討論。spa
卷積核是2,那麼可想而知,對上面5個數據作一個卷積核爲2的卷積是什麼樣子的:
五個數據通過一次卷積,能夠變成四個數據,可是每個卷積後的數據都是基於兩個原始數據獲得的,因此說,目前卷積的視野域是2。.net
能夠看到是輸入是5個數據,可是通過卷積,變成4個數據了,在圖像中有一個概念是經過padding來保證卷積先後特徵圖尺寸不變,因此在時間序列中,依然使用padding來保證尺寸不變:
padding是左右兩頭都增長0,若是padding是1的話,就是上圖的效果,其實會產生6個新數據,可是秉着:「輸入輸出尺寸相同」和「咱們不能知道將來的數據」,因此最後邊那個將來的padding,就省略掉了,以後再代碼中會體現出來。3d
總之,如今咱們大概能理解,對時間序列卷積的大體流程了,也就是對一維數據卷積的過程(圖像卷積算是二維)。code
下面看如何使用Pytorch來實現一維卷積:orm
net = nn.Conv1d(in_channels=1,out_channels=1,kernel_size=2,stride=1,padding=1,dilation=1)
其中的參數跟二維卷積很是相似,也是有通道的概念的。這個好好品一下,一維數據的通道跟圖像的通道同樣,是根據不一樣的卷積核從相同的輸入中抽取出來不一樣的特徵。kernel_size=2以前也說過了,padding=1也沒問題,不過這個公式中假如輸入5個數據+padding=1,會獲得6個數據,最後一個數據被捨棄掉。dilation是膨脹係數,下面的下面會講。
以前已經講了一維卷積的過程了,那麼因果卷積,其實就是一維卷積的一種應用吧算是。
假設想用上面講到的概念,作一個股票的預測決策模型,而後但願決策模型能夠考慮到這個時間點以前的4個時間點的股票價格進行決策,總共有3種決策:
因此其實就是一個分類問題。由於要求視野域是4,因此按照上面的設想,要堆積3個卷積核爲2的1維卷積層:
三次卷積,可讓最後的輸出,擁有4個視野域。就像是上圖中紅色的部分,就是作出一個決策的過程。
股票數據,每每是按照分鐘記錄的,那少說也是十萬、百萬的數據量,咱們決策,想要考慮以前1000個時間點呢?視野域要是1000,那意味着要999層卷積?啥計算機吃得消這樣的計算。因此引入了膨脹因果卷積。
而後咱們依然實現上面那個例子,每次決策想要視野域爲4:
能夠看到,第一次卷積使用dilation=1的卷積,而後第二次使用dilation=2的卷積,這樣經過兩次卷積就能夠實現視野域是4.
那麼假設事業域要是8呢?那就再加一個dilation=4的卷積。dilation的值是2的次方,而後視野域也是2的次方的增加,那麼就算是要1000視野域,那十層大概就好了。
這裏有一個動圖,挺好看的:
TCN基本就是一個膨脹因果卷積的過程,只是上面咱們實現因果卷積就只有一個卷積層。而TCN的稍微複雜一點(可是不難!)
若是不瞭解的話,emm,我要安利個人博文了2333:
從零學習pytorch 第5課 PyTorch模型搭建三要素
# 導入庫 import torch import torch.nn as nn from torch.nn.utils import weight_norm
# 這個函數是用來修剪卷積以後的數據的尺寸,讓其與輸入數據尺寸相同。 class Chomp1d(nn.Module): def __init__(self, chomp_size): super(Chomp1d, self).__init__() self.chomp_size = chomp_size def forward(self, x): return x[:, :, :-self.chomp_size].contiguous()
能夠看出來,這個函數就是第一個數據到倒數第chomp_size的數據,這個chomp_size就是padding的值。比方說輸入數據是5,padding是1,那麼會產生6個數據沒錯吧,那麼就是保留前5個數字。
# 這個就是TCN的基本模塊,包含8個部分,兩個(卷積+修剪+relu+dropout) # 裏面提到的downsample就是下采樣,其實就是實現殘差連接的部分。不理解的能夠無視這個 class TemporalBlock(nn.Module): def __init__(self, n_inputs, n_outputs, kernel_size, stride, dilation, padding, dropout=0.2): super(TemporalBlock, self).__init__() self.conv1 = weight_norm(nn.Conv1d(n_inputs, n_outputs, kernel_size, stride=stride, padding=padding, dilation=dilation)) self.chomp1 = Chomp1d(padding) self.relu1 = nn.ReLU() self.dropout1 = nn.Dropout(dropout) self.conv2 = weight_norm(nn.Conv1d(n_outputs, n_outputs, kernel_size, stride=stride, padding=padding, dilation=dilation)) self.chomp2 = Chomp1d(padding) self.relu2 = nn.ReLU() self.dropout2 = nn.Dropout(dropout) self.net = nn.Sequential(self.conv1, self.chomp1, self.relu1, self.dropout1, self.conv2, self.chomp2, self.relu2, self.dropout2) self.downsample = nn.Conv1d(n_inputs, n_outputs, 1) if n_inputs != n_outputs else None self.relu = nn.ReLU() self.init_weights() def init_weights(self): self.conv1.weight.data.normal_(0, 0.01) self.conv2.weight.data.normal_(0, 0.01) if self.downsample is not None: self.downsample.weight.data.normal_(0, 0.01) def forward(self, x): out = self.net(x) res = x if self.downsample is None else self.downsample(x) return self.relu(out + res)
最後就是TCN的主網絡了:
class TemporalConvNet(nn.Module): def __init__(self, num_inputs, num_channels, kernel_size=2, dropout=0.2): super(TemporalConvNet, self).__init__() layers = [] num_levels = len(num_channels) for i in range(num_levels): dilation_size = 2 ** i in_channels = num_inputs if i == 0 else num_channels[i-1] out_channels = num_channels[i] layers += [TemporalBlock(in_channels, out_channels, kernel_size, stride=1, dilation=dilation_size, padding=(kernel_size-1) * dilation_size, dropout=dropout)] self.network = nn.Sequential(*layers) def forward(self, x): return self.network(x)
咋用的呢?就是num_inputs就是輸入數據的通道數,通常就是1; num_channels應該是個列表,其餘的np.array也行,比方說是[2,1]。那麼整個TCN模型包含兩個TemporalBlock,整個模型共有4個卷積層,第一個TemporalBlock的兩個卷積層的膨脹係數\(dilation=2^0=1\),第二個TemporalBlock的兩個卷積層的膨脹係數是\(dilation=2^1=2\).
沒了,整個TCN挺簡單的,若是以前學過PyTorch和圖像處理的一些內容,而後用TCN來上手時間序列,效果會和LGM差很少。(根據最近作的一個比賽),沒有跟Wavenet比較過,Wavenet的pytorch資源看起來怪複雜的,由於wavenet是用來處理音頻生成的,會更加複雜一點。
總之TCN就這麼多,謝謝你們。