时域卷积网络(Temporal Convolutional Network,TCN)由Shaojie Bai et al.在2018年提出的,可以用于时序数据处理,详细内容请看论文。
因果卷积如上图所示。对于上一层t时刻的值,只依赖于下一层t时刻及其之前的值。与传统的卷积神经网络的不同之处在于,因果卷积不能看到未来的数据,它是单向的结构,不是双向的。也就是说,先有前因,才能有后果,它是一种严格的时间约束模型,因此被称为因果卷积。
膨胀卷积(Dilated Convolution)也被称为空洞卷积
纯净的因果卷积仍然存在传统卷积神经网络的问题,即建模时间的长短受到卷积核大小的限制。 如果想获得更长的依赖关系,需要线性的堆叠许多层。 为了解决这个问题,研究人员提出了膨胀卷积,如下图所示。
与传统卷积不同,膨胀卷积允许在卷积期间对输入进行间隔采样,并且采样率由图中的 d d d控制。 底层的 d = 1 d = 1 d=1表示在输入的过程中对每个点进行采样,中间层的 d = 2 d = 2 d=2表示在输入过程中对每2个点采样一次作为输入。 一般来说,层级越高,d的数值越大。 因此,膨胀卷积使有效窗口的大小随着层数呈指数型增长。 通过这种方法,卷积网络可以使用较少的层,就能获得大的感受野。
残差连接被证明是训练深度网络的有效方法,它允许网络以跨层方式传输信息。
论文中构造了一个残差块来替换卷积层。 如上图所示,一个残差块包含两层卷积和非线性映射,并将WeightNorm和Dropout添加到每一层用来正则化网络。
(1)并行性。当给定一个句子,TCN可以将并行处理句子,而不需要像RNN那样顺序的处理。
(2)灵活的感受野。TCN的感受野的大小由层数、卷积核大小、扩张系数确定。可以根据不同的任务不同的特点点进行灵活定制。
(3)梯度稳定。RNN经常存在梯度消失和梯度爆炸的问题,这主要是由于在不同时间段共享参数导致的。像传统的卷积神经网络一样,TCN也不存在梯度消失和梯度爆炸的问题。
(4)内存更低。RNN在使用时需要保存每一步的信息,这会占用大量的内存,TCN的卷积内核在一个层中共享,内存使用更低。
(1)TCN 在迁移学习方面可能没有那么强的适应性。这是因为在不同的领域,模型预测所需的历史信息量可能会有所不同。因此,在将一个模型从一个需要较少内存信息的问题迁移到一个需要较长内存的问题上时,TCN 的性能可能会很差,因为其感受野不够大。
(2)论文中描述的TCN仍然是单向结构。在诸如语音识别和语音合成等任务上,纯单向结构仍然非常有用。然而,大多数文本使用双向结构。TCN可以很容易扩展为双向结构,只需使用传统的卷积结构代替因果卷积即可。
(3)TCN毕竟是卷积神经网络的一种变体。虽然使用扩展卷积可以扩大感受野,但仍然受到限制。与Transformer相比,任意长度的相关信息都可以获取的特性仍然很差。TCN在文本中的应用还有待检验。
多个特征对应一个标签,即(xi1,xi2,xi3,…xin)-yi
本地环境:
Python 3.6
IDE:Pycharm
库版本:
keras 2.2.0
numpy 1.16.2
tensorflow 1.9.0
1.下载数据集
MINST数据集
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
Keras-based time domain convolutional network (TCN)
Keras-TCN
[Tensorflow] Implementing Temporal Convolutional Networks