写在开篇
各位读者大家好,今天我们要一起来学习Keras包装层中的两个工具:TimeDistributed 和Bidirectional。虽然并不算十分常见,但自有其神奇之处。
类型说明
TimeDistributed
TimeDistributed这个层还是比较难理解的。事实上通过这个层,可以实现从二维像三维的过渡,甚至通过这个层的包装,可以实现图像分类视频分类的转化。
1 keras.layers.TimeDistributed(layer)
这个封装器将一个层应用于输入的每个时间片。
输入至少为 3D,且第一个维度应该是时间所表示的维度。
考虑 32 个样本的一个 batch, 其中每个样本是 10 个 16 维向量的序列。那么这个 batch 的输入尺寸为 (32, 10, 16)
, 而 input_shape
不包含样本数量的维度,为 (10, 16)
。使用 TimeDistributed
来将 Dense
层独立地应用到 这 10 个时间步的每一个:
可以这么理解,输入数据是一个特征方程,X1+X2+...+X10=Y,从矩阵的角度看,拿出未知数Y,就是10个向量,每个向量有16个维度,这16个维度是评价Y的16个特征方向。TimeDistributed层的作用就是把Dense层应用到这10个具体的向量上,对每一个向量进行了一个Dense操作,假设是下面这段代码:
1 2 3 4 model = Sequential() model.add(TimeDistributed(Dense(8 ), input_shape=(10 , 16 )))
输出的尺寸为 (32, 10, 8)
。输出还是10个向量,但是输出的维度由16变成了8。
在后续的层中,将不再需要指定 input_shape
:
1 2 model.add(TimeDistributed(Dense(32 )))
输出的尺寸为 (32, 10, 32)
。
TimeDistributed
可以应用于任意层,不仅仅是 Dense
, 例如运用于 Conv2D
层:
1 2 3 model = Sequential() model.add(TimeDistributed(Conv2D(64 , (3 , 3 )), input_shape=(10 , 299 , 299 , 3 )))
Bidirectional
1 keras.layers.Bidirectional(layer, merge_mode='concat', weights=None)
RNN 的双向封装器,对序列进行前向和后向计算。
参数
layer : Recurrent
实例。
merge_mode : 前向和后向 RNN 的输出的结合模式。为 {'sum', 'mul', 'concat', 'ave', None} 其中之一。如果是 None,输出不会被结合,而是作为一个列表被返回。
异常
ValueError : 如果参数 merge_mode
非法。
例
1 2 3 4 5 6 7 model = Sequential() model.add(Bidirectional(LSTM(10 , return_sequences=True ), input_shape=(5 , 10 ))) model.add(Bidirectional(LSTM(10 ))) model.add(Dense(5 )) model.add(Activation('softmax' )) model.compile (loss='categorical_crossentropy' , optimizer='rmsprop' )
Bidirectional 一个常用的例子是双向LSTM,下面的例程展示了如何在IMDB情绪分类任务中,训练一个Bidirectional LSTM模型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 from __future__ import print_functionimport numpy as npfrom keras.preprocessing import sequencefrom keras.models import Sequentialfrom keras.layers import Dense, Dropout, Embedding, LSTM, Bidirectionalfrom keras.datasets import imdbmax_features = 20000 maxlen = 100 batch_size = 32 print ('Loading data...' )(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features) print (len (x_train), 'train sequences' )print (len (x_test), 'test sequences' )print ('Pad sequences (samples x time)' )x_train = sequence.pad_sequences(x_train, maxlen=maxlen) x_test = sequence.pad_sequences(x_test, maxlen=maxlen) print ('x_train shape:' , x_train.shape)print ('x_test shape:' , x_test.shape)y_train = np.array(y_train) y_test = np.array(y_test) model = Sequential() model.add(Embedding(max_features, 128 , input_length=maxlen)) model.add(Bidirectional(LSTM(64 ))) model.add(Dropout(0.5 )) model.add(Dense(1 , activation='sigmoid' )) model.compile ('adam' , 'binary_crossentropy' , metrics=['accuracy' ]) print ('Train...' )model.fit(x_train, y_train, batch_size=batch_size, epochs=4 , validation_data=[x_test, y_test])
写在文末
相信大家经过今天的学习,能够对包装层的两个工具有一定的认识。文末还为有兴趣实践的读者附上了Bidirectional的使用例,感兴趣的读者不妨动手一试。