TCN基本結構
時域卷積網絡(Temporal Convolutional Network,TCN)由Shaojie Bai et al.在2018年提出的,可以用於時序數據處理,詳細內容請看論文。
1.因果卷積(Causal Convolution)

因果卷積如上圖所示。對於上一層t時刻的值,只依賴於下一層t時刻及其之前的值。與傳統的卷積神經網絡的不同之處在於,因果卷積不能看到未來的數據,它是單向的結構,不是雙向的。也就是說,先有前因,才能有后果,它是一種嚴格的時間約束模型,因此被稱為因果卷積。
2.膨脹卷積(Dilated Convolution)
膨脹卷積(Dilated Convolution)也被稱為空洞卷積
純凈的因果卷積仍然存在傳統卷積神經網絡的問題,即建模時間的長短受到卷積核大小的限制。 如果想獲得更長的依賴關系,需要線性的堆疊許多層。 為了解決這個問題,研究人員提出了膨脹卷積,如下圖所示。

與傳統卷積不同,膨脹卷積允許在卷積期間對輸入進行間隔采樣,並且采樣率由圖中的\(d\)控制。 底層的\(d = 1\)表示在輸入的過程中對每個點進行采樣,中間層的\(d = 2\)表示在輸入過程中對每2個點采樣一次作為輸入。 一般來說,層級越高,d的數值越大。 因此,膨脹卷積使有效窗口的大小隨着層數呈指數型增長。 通過這種方法,卷積網絡可以使用較少的層,就能獲得大的感受野。
3.殘差連接(Residual Connections)
殘差連接被證明是訓練深度網絡的有效方法,它允許網絡以跨層方式傳輸信息。

論文中構造了一個殘差塊來替換卷積層。 如上圖所示,一個殘差塊包含兩層卷積和非線性映射,並將WeightNorm和Dropout添加到每一層用來正則化網絡。
TCN總結
優點
(1)並行性。當給定一個句子,TCN可以將並行處理句子,而不需要像RNN那樣順序的處理。
(2)靈活的感受野。TCN的感受野的大小由層數、卷積核大小、擴張系數確定。可以根據不同的任務不同的特點點進行靈活定制。
(3)梯度穩定。RNN經常存在梯度消失和梯度爆炸的問題,這主要是由於在不同時間段共享參數導致的。像傳統的卷積神經網絡一樣,TCN也不存在梯度消失和梯度爆炸的問題。
(4)內存更低。RNN在使用時需要保存每一步的信息,這會占用大量的內存,TCN的卷積內核在一個層中共享,內存使用更低。
缺點
(1)TCN 在遷移學習方面可能沒有那么強的適應性。這是因為在不同的領域,模型預測所需的歷史信息量可能會有所不同。因此,在將一個模型從一個需要較少內存信息的問題遷移到一個需要較長內存的問題上時,TCN 的性能可能會很差,因為其感受野不夠大。
(2)論文中描述的TCN仍然是單向結構。在諸如語音識別和語音合成等任務上,純單向結構仍然非常有用。然而,大多數文本使用雙向結構。TCN可以很容易擴展為雙向結構,只需使用傳統的卷積結構代替因果卷積即可。
(3)TCN畢竟是卷積神經網絡的一種變體。雖然使用擴展卷積可以擴大感受野,但仍然受到限制。與Transformer相比,任意長度的相關信息都可以獲取的特性仍然很差。TCN在文本中的應用還有待檢驗。
TCN應用
MINST手寫數字分類
單標簽,即(xi1,xi2,xi3,...xin)-yi
本地環境:
Python 3.6
IDE:Pycharm
庫版本:
keras 2.2.0
numpy 1.16.2
tensorflow 1.9.0
1.下載數據集
2.創建TCN.py,輸入如下代碼
代碼參考:Keras-based TCN
# TCN for minst data
from tensorflow.examples.tutorials.mnist import input_data
from keras.models import Model
from keras.layers import add, Input, Conv1D, Activation, Flatten, Dense
# Load data 載入數據
def read_data(path):
mnist = input_data.read_data_sets(path, one_hot=True)
train_x, train_y = mnist.train.images.reshape(-1, 28, 28), mnist.train.labels,
valid_x, valid_y = mnist.validation.images.reshape(-1, 28, 28), mnist.validation.labels,
test_x, test_y = mnist.test.images.reshape(-1, 28, 28), mnist.test.labels
return train_x, train_y, valid_x, valid_y, test_x, test_y
# Residual block 殘差塊
def ResBlock(x, filters, kernel_size, dilation_rate):
r = Conv1D(filters, kernel_size, padding='same', dilation_rate=dilation_rate, activation='relu')(
x) # first convolution
r = Conv1D(filters, kernel_size, padding='same', dilation_rate=dilation_rate)(r) # Second convolution
if x.shape[-1] == filters:
shortcut = x
else:
shortcut = Conv1D(filters, kernel_size, padding='same')(x) # shortcut (shortcut)
o = add([r, shortcut])
# Activation function
o = Activation('relu')(o)
return o
# Sequence Model 時序模型
def TCN(train_x, train_y, valid_x, valid_y, test_x, test_y, classes, epoch):
inputs = Input(shape=(28, 28))
x = ResBlock(inputs, filters=32, kernel_size=3, dilation_rate=1)
x = ResBlock(x, filters=32, kernel_size=3, dilation_rate=2)
x = ResBlock(x, filters=16, kernel_size=3, dilation_rate=4)
x = Flatten()(x)
x = Dense(classes, activation='softmax')(x)
model = Model(input=inputs, output=x)
# View network structure 查看網絡結構
model.summary()
# Compile model 編譯模型
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# Training model 訓練模型
model.fit(train_x, train_y, batch_size=500, nb_epoch=epoch, verbose=2, validation_data=(valid_x, valid_y))
# Assessment model 評估模型
pre = model.evaluate(test_x, test_y, batch_size=500, verbose=2)
print('test_loss:', pre[0], '- test_acc:', pre[1])
# MINST數字從0-9共10個,即10個類別
classes = 10
epoch = 30
train_x, train_y, valid_x, valid_y, test_x, test_y = read_data('MNIST_data')
#print(train_x, train_y)
TCN(train_x, train_y, valid_x, valid_y, test_x, test_y, classes, epoch)
3.結果
test_loss: 0.05342669463425409 - test_acc: 0.987100002169609
多個標簽
(xi1,xi2,xi3,...xin)- (yi1,yi2)
只需根據上述代碼進行修改,重新構建訓練、測試數據,設置對應的輸入輸出維度、參數等信息即可。
本地環境:
Python 3.6
IDE:Pycharm
庫版本:
keras 2.2.0
numpy 1.16.2
pandas 0.24.1
sklearn 0.20.1
tensorflow 1.9.0
具體代碼:
# TCN for indoor location
import math
from tensorflow.examples.tutorials.mnist import input_data
from keras.models import Model
from keras.layers import add, Input, Conv1D, Activation, Flatten, Dense
import numpy as np
import pandas
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
# 創建時序數據
def create_dataset(dataset, look_back=1):
dataX, dataY = [], []
for i in range(len(dataset)-look_back-1):
a = dataset[i:(i+look_back), :]
dataX.append(a)
dataY.append(dataset[i + look_back, -2:])
return np.array(dataX), np.array(dataY)
# Residual block
def ResBlock(x, filters, kernel_size, dilation_rate):
r = Conv1D(filters, kernel_size, padding='same', dilation_rate=dilation_rate, activation='relu')(
x) # first convolution
r = Conv1D(filters, kernel_size, padding='same', dilation_rate=dilation_rate)(r) # Second convolution
if x.shape[-1] == filters:
shortcut = x
else:
shortcut = Conv1D(filters, kernel_size, padding='same')(x) # shortcut (shortcut)
o = add([r, shortcut])
o = Activation('relu')(o) # Activation function
return o
# Sequence Model
def TCN(train_x, train_y, test_x, test_y, look_back, n_features, n_output, epoch):
inputs = Input(shape=(look_back, n_features))
x = ResBlock(inputs, filters=32, kernel_size=3, dilation_rate=1)
x = ResBlock(x, filters=32, kernel_size=3, dilation_rate=2)
x = ResBlock(x, filters=16, kernel_size=3, dilation_rate=4)
x = Flatten()(x)
x = Dense(n_output, activation='softmax')(x)
model = Model(input=inputs, output=x)
# View network structure
model.summary()
# Compile model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
# Training model
model.fit(train_x, train_y, batch_size=500, nb_epoch=epoch, verbose=2)
# Assessment model
pre = model.evaluate(test_x, test_y, batch_size=500, verbose=2)
# print(pre)
print('test_loss:', pre[0], '- test_acc:', pre[1])
# 公共參數
np.random.seed(7)
features = 24
output = 2
EPOCH = 30
look_back = 5
trainPath = '../data/train.csv'
testPath = '../data/test.csv'
trainData = pandas.read_csv(trainPath, engine='python')
testData = pandas.read_csv(testPath, engine='python')
# features = 1
dataset = trainData.values
dataset = dataset.astype('float32')
datatestset = testData.values
datatestset = datatestset.astype('float32')
# print(dataset)
# normalize the dataset
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)
datatestset = scaler.fit_transform(datatestset)
trainX, trainY = create_dataset(dataset, look_back)
testX, testY = create_dataset(datatestset, look_back)
# print(trainX)
print(len(trainX), len(testX))
print(testX.shape)
# reshape input to be [samples, time steps, features]
trainX = np.reshape(trainX, (trainX.shape[0], trainX.shape[1], features))
testX = np.reshape(testX, (testX.shape[0], testX.shape[1], features))
# train_x, train_y, valid_x, valid_y, test_x, test_y = read_data('MNIST_data')
print(trainX, trainY)
TCN(trainX, trainY, testX, testY, look_back, features, output, EPOCH)
未完待續...
參考資料
An Empirical Evaluation of Generic Convolutional and Recurrent Networks for Sequence Modeling
TCN-Time Convolutional Network
