keras_4_关于Keras的Layer
1. 公共函数
-
layer.get_weights()
: 以含有Numpy矩阵的列表形式返回层的权重。 -
layer.set_weights(weights)
: 从含有Numpy矩阵的列表中设置层的权重(与get_weights
的输出形状相同)。 -
layer.get_config()
: 返回包含层配置的字典。此图层可以通过以下方式重置:layer = Dense(32) config = layer.get_config() reconstructed_layer = Dense.from_config(config) # 或者 from keras import layers config = layer.get_config() layer = layers.deserialize({'class_name': layer.__class__.__name__, 'config': config})
-
如果一个层具有单个节点 (i.e. 如果它不是共享层), 你可以得到它的输入张量,输出张量,输入尺寸和输出尺寸:
layer.input
layer.output
layer.input_shape
layer.output_shape
-
如果层有多个节点 (参见: 层节点和共享层的概念), 您可以使用以下函数:
layer.get_input_at(node_index)
layer.get_output_at(node_index)
layer.get_input_shape_at(node_index)
layer.get_output_shape_at(node_index)
2. 核心网络层
-
Dense
-
Activation
-
Dropout
-
Flatten
-
Input
-
Reshape
-
Permute
-
根据给定的模式置换输入的维度。在某些场景下很有用,例如将 RNN 和 CNN 连接在一起。
model = Sequential() model.add(Permute((2, 1), input_shape=(10, 64))) # 现在: model.output_shape == (None, 64, 10) # 等价于执行了矩阵转置 # 注意: None 是批表示的维度
-
-
RepeatVector
-
Lambda
-
ActivityRegularization
-
Masking
-
SpatialDropout1D
- Dropout 的 Spatial 1D 版本
-
SpatialDropout2D
- Dropout 的 Spatial 2D 版本,此版本的功能与 Dropout 相同,但它会丢弃整个 2D 的特征图而不是丢弃单个元素。
- 如果特征图中相邻的像素是强相关的(通常是靠前的卷积层中的情况),那么常规的 dropout 将无法使激活正则化,且导致有效的学习速率降低。在这种情况下,SpatialDropout2D 将有助于提高特征图之间的独立性,应该使用它来代替 dropout。
-
SpatialDropout3D
- Dropout 的 Spatial 3D 版本,此版本的功能与 Dropout 相同,但它会丢弃整个 3D 的特征图而不是丢弃单个元素。使用场景同上述2D
3. 卷积层(Convolution)
-
Conv1D (比如时序卷积)
-
Conv2D (比如图像中的二维卷积)
-
SeparableConv1D (depth方向的可分离1D卷积)
- 首先执行深度方向的空间卷积 (分别作用于每个输入通道),然后再执行一个将所得输出通道 混合在一起的逐点卷积。
depth_multiplier
参数控 制深度步骤中每个输入通道生成多少个输出通道。可分离的卷积可以理解为一种将卷积核分解成 两个较小的卷积核的方法,或者作为 Inception 块的 一个极端版本。
- 首先执行深度方向的空间卷积 (分别作用于每个输入通道),然后再执行一个将所得输出通道 混合在一起的逐点卷积。
-
SeparableConv2D
- 首先执行深度方向的空间卷积 (分别作用于每个输入通道),紧接一个将所得输出通道 混合在一起的逐点卷积。其余描述同上的1D
-
Conv2DTranspose (同理会有3D)
- 转置卷积(或反卷积),或者叫Deconvolution
-
Conv3D
- 立体空间卷积:比如对一个视频(一个视频可以形式化为包含N帧的二维image,比如NxWxHxC。之前Conv2D处理的是二维image,即WxHxC)
-
Cropping1D
- 1D 输入的裁剪层(例如时间序列),它沿着时间维度(第 1 个轴)裁剪。
- 入参,如cropping=(4,5): 整数或整数元组(长度为 2)。 在裁剪维度(第 1 个轴)的开始和结束位置 应该裁剪多少个单位(此处分别是4,5)。 如果只提供了一个整数,那么这两个位置将使用 相同的值。
-
Croppong2D
-
2D 输入的裁剪层(例如图像),它沿着空间维度裁剪,即宽度和高度。
# 裁剪输入的 2D 图像或特征图 model = Sequential() model.add(Cropping2D(cropping=((2, 2), (4, 4)), input_shape=(28, 28, 3))) # 现在 model.output_shape == (None, 24, 20, 3) model.add(Conv2D(64, (3, 3), padding='same')) # padding='same'保持原有的W,H model.add(Cropping2D(cropping=((2, 2), (2, 2)))) # 现在 model.output_shape == (None, 20, 16. 64)
-
-
Cropping3D
- 3D 数据的裁剪层(例如空间或时空)。
-
Upsampling1D
- 1D 输入的上采样层,沿着时间轴重复每个时间步
size
次。
- 1D 输入的上采样层,沿着时间轴重复每个时间步
-
Upsampling2D
- 2D 输入的上采样层,沿着数据的行和列分别重复
size[0]
和size[1]
次。
- 2D 输入的上采样层,沿着数据的行和列分别重复
-
Upsampling3D
-
ZeroPadding1D
- 1D 输入的零填充层(例如,时间序列)。
-
ZeroPadding2D:
- 2D 输入的零填充层(例如图像)。该图层可以在图像张量的顶部、底部、左侧和右侧添加零表示的行和列。
-
ZeroPadding3D
- 3D 数据的零填充层(空间或时空)。
4. 池化层(Pooling)
- MaxPooling1D
- MaxPooling2D
- MaxPooling3D
- AveragePooling1D
- AveragePooling2D
- AveragePooling3D
- GlobalMaxPooling1D
- GlobalMaxPooling2D
- GlobalMaxPooling3D
- GlobalAveragePooling1D
- GlobalAveragePooling2D
- GlobalAveragePooling3D
5. 局部连接层(Locally-connected)
-
LocallyConnected1D (还有2D,但3D还不知道是否有?)
-
LocallyConnected1D
层与Conv1D
层的工作方式相同,除了权值不共享外, 也就是说,在输入的每个不同部分应用不同的一组过滤器。 -
# 将长度为 3 的非共享权重 1D 卷积应用于 # 具有 10 个时间步长的序列,并使用 64个 输出滤波器 model = Sequential() model.add(LocallyConnected1D(64, 3, input_shape=(10, 32))) # 32应该是指channel? # 现在 model.output_shape == (None, 8, 64) # W_2 = (W_1-F)/S + 1, so 10->8 # 在上面再添加一个新的 conv1d model.add(LocallyConnected1D(32, 3)) # (8-3)/1 + 1 = 6 # 现在 model.output_shape == (None, 6, 32) # so 8->6 # 2D的例子 # 在 32x32 图像上应用 3x3 非共享权值和64个输出过滤器的卷积 # 数据格式 `data_format="channels_last"`: model = Sequential() model.add(LocallyConnected2D(64, (3, 3), input_shape=(32, 32, 3))) # 现在 model.output_shape == (None, 30, 30, 64) # (32-3)/1 + 1 = 30 # 注意这一层的参数数量为 (30*30)*(3*3*3*64) + (30*30)*64 # 每次做卷积都是一组新的参数 # 30x30次卷积,才会得到30x30的feature map,每次卷积的参数量为:3x3x3x64,是因为64个3x3x3的filter;第二项(30x30)x64是bias的数量,因为一共64个filter,每个filter做一次卷积配一个bias # 在上面再加一个 3x3 非共享权值和 32 个输出滤波器的卷积: model.add(LocallyConnected2D(32, (3, 3))) # 现在 model.output_shape == (None, 28, 28, 32)
-
6. 循环层 Recurrent
- RNN
- SimpleRNN
- GRU
- LSTM
- ConvLSTM2D
- SimpleRNNCell
- GRUCell
- LSTMCell
- StackedRNNCells
- tensorflow支持的
- CuDNNGRU
- CuDNNLSTM
7. 嵌入层 Embedding
-
Embedding
model = Sequential() model.add(Embedding(1000, 64, input_length=10)) # 1000 -> 64 ? # 模型将输入一个大小为 (batch, input_length) 的整数矩阵。 # 输入中最大的整数(即词索引)不应该大于 999 (词汇表大小) # 现在 model.output_shape == (None, 10, 64),其中 None 是 batch 的维度。 input_array = np.random.randint(1000, size=(32, 10)) # 原本是 model.compile('rmsprop', 'mse') output_array = model.predict(input_array) assert output_array.shape == (32, 10, 64)
8. 融合层 Merge
-
Add
-
计算一个列表的输入张量的和。相加层接受一个列表的张量, 所有的张量必须有相同的输入尺寸, 然后返回一个张量(和输入张量尺寸相同)
import keras input1 = keras.layers.Input(shape=(16,)) x1 = keras.layers.Dense(8, activation='relu')(input1) # 8-dim的tensor input2 = keras.layers.Input(shape=(32,)) x2 = keras.layers.Dense(8, activation='relu')(input2) # 8-dim的tensor added = keras.layers.Add()([x1, x2]) # 相当于 added = keras.layers.add([x1, x2]) # 16-dim的tensor ?? out = keras.layers.Dense(4)(added) model = keras.models.Model(inputs=[input1, input2], outputs=out)
-
-
Subtract:
-
计算两个输入张量的差。相减层接受一个长度为 2 的张量列表, 两个张量必须有相同的尺寸,然后返回一个值为 (inputs[0] - inputs[1]) 的张量, 输出张量和输入张量尺寸相同。
import keras input1 = keras.layers.Input(shape=(16,)) x1 = keras.layers.Dense(8, activation='relu')(input1) # 8-dim input2 = keras.layers.Input(shape=(32,)) x2 = keras.layers.Dense(8, activation='relu')(input2) # 8-dim # 相当于 subtracted = keras.layers.subtract([x1, x2]) subtracted = keras.layers.Subtract()([x1, x2]) # 8-dim out = keras.layers.Dense(4)(subtracted) # out: 4-dim model = keras.models.Model(inputs=[input1, input2], outputs=out)
-
-
Multiply
- 计算一个列表的输入张量的(逐元素间的,elem-wise)乘积。相乘层接受一个列表的张量, 所有的张量必须有相同的输入尺寸, 然后返回一个张量(和输入张量尺寸相同)。
-
Average
- 计算一个列表的输入张量的平均值。平均层接受一个列表的张量, 所有的张量必须有相同的输入尺寸, 然后返回一个张量(和输入张量尺寸相同)。
-
Maximum
- 计算一个列表的输入张量的(逐元素间的)最大值。最大层接受一个列表的张量, 所有的张量必须有相同的输入尺寸, 然后返回一个张量(和输入张量尺寸相同)。
-
Concatenate
- 串联一个列表的输入张量。串联层接受一个列表的张量, 除了串联轴之外,其他的尺寸都必须相同, 然后返回一个由所有输入张量串联起来的输出张量。(比如对于二维image,depth-wise的cancat,结果是depth-add,W,H不变)
-
Dot
- 计算两个张量之间样本的点积。
- 例如,如果作用于输入尺寸为
(batch_size, n)
的两个张量a
和b
, 那么输出结果就会是尺寸为(batch_size, 1)
的一个张量。 在这个张量中,每一个条目i
是a[i]
和b[i]
之间的点积。
-
add
Add
层的函数式接口。keras.layers.add(inputs)
-
subtract
-
Subtract
层的函数式接口。keras.layers.subtract(inputs)
import keras input1 = keras.layers.Input(shape=(16,)) x1 = keras.layers.Dense(8, activation='relu')(input1) # out: 8-dim input2 = keras.layers.Input(shape=(32,)) x2 = keras.layers.Dense(8, activation='relu')(input2) # 8-dim subtracted = keras.layers.subtract([x1, x2]) # out: 8-dim out = keras.layers.Dense(4)(subtracted) # out: 4-dim model = keras.models.Model(inputs=[input1, input2], outputs=out)
-
-
multiply
Multiply
层的函数式接口。keras.layers.multiply(inputs)
-
average
Average
层的函数式接口。keras.layers.average(inputs)
-
maximum
Maximum
层的函数式接口。keras.layers.maximum(inputs)
-
concatenate
Concatenate
层的函数式接口。keras.layers.concatenate(inputs, axis=-1)
-
dot
Dot
层的函数式接口。keras.layers.dot(inputs, axes, normalize=False)
9. 高级激活层 Advanced Activations
- LeakyReLU
- PReLU
- ELU
- ThresholdedReLU
- Softmax
- Softmax 激活函数。
keras.layers.Softmax(axis=-1)
- Softmax 激活函数。
- ReLU
- ReLU 激活函数。
keras.layers.ReLU(max_value=None)
- ReLU 激活函数。
10. 标准化层 Normalization
- BatchNormalization
- 批量标准化层 (Ioffe and Szegedy, 2014)。在每一个批次的数据中标准化前一层的激活项, 即,应用一个维持激活项平均值接近 0,标准差接近 1 的转换。
11. 噪声层 Noise(或者叫,某些正则化层)
- GaussianNoise
- 应用以 0 为中心的加性高斯噪声。这对缓解过拟合很有用 (你可以将其视为随机数据增强的一种形式)。 高斯噪声(GS)是对真实输入的腐蚀过程的自然选择。由于它是一个正则化层,因此它只在训练时才被激活。(也就是说:evaluate & test 不启动正则化项??不是!!!是这个正则化仅在训练时使用)
- GaussianDropout
- 应用以 1 为中心的 乘性高斯噪声。由于它是一个正则化层,因此它只在训练时才被激活。
- AlphaDropout
- Alpha Dropout是一种
Dropout
,它保持输入的平均值和方差与原来的值不变, 即在 dropout 之后仍然保证数据的自规范性。 通过随机将激活设置为负饱和值,Alpha Dropout 非常适合按比例缩放的指数线性单元(SELU)。
- Alpha Dropout是一种
12. 层封装器 wrappers
-
TimeDistributed
-
这个封装器将一个层应用于输入的每个时间片。输入至少为 3D,且第一个维度应该是时间所表示的维度。
-
考虑 32 个样本的一个 batch, 其中每个样本是 10 个 16 维向量的序列。 那么这个 batch 的输入尺寸为
(32, 10, 16)
, 而input_shape
不包含样本数量的维度,为(10, 16)
。你可以使用TimeDistributed
来将Dense
层独立地应用到 这 10 个时间步的每一个:# 作为模型第一层 model = Sequential() model.add(TimeDistributed(Dense(8), input_shape=(10, 16))) # 有点像map函数 # 现在 model.output_shape == (None, 10, 8) # 因为上一层是FC,output为8-dim,而 # 每个时间步都被dense(8)处理了,所以有10个时间步的执行结果 # 输出的尺寸为 (32, 10, 8)。 # 在后续的层中,再使用TimeDistributed,将不再需要 input_shape: model.add(TimeDistributed(Dense(32))) # 现在 model.output_shape == (None, 10, 32) # 10个时间步,32来自FC的output-dim # TimeDistributed 可以应用于任意层,不仅仅是 Dense, 例如运用于 Conv2D 层: model = Sequential() model.add(TimeDistributed(Conv2D(64, (3, 3)), input_shape=(10, 299, 299, 3)))
-
-
Bidirectional
-
RNN 的双向封装器,对序列进行前向和后向计算。
model = Sequential() model.add(Bidirectional(LSTM(10, return_sequences=True), #实现双向LSTM input_shape=(5, 10))) # 第一层要指明input_shape model.add(Bidirectional(LSTM(10))) model.add(Dense(5)) model.add(Activation('softmax')) model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
-
13. 编写你自己的Keras层
-
对于简单、无状态的自定义操作,你也许可以通过
layers.core.Lambda
层来实现。但是对于那些包含了可训练权重的自定义层,你应该自己实现这种层。这是一个Keras2.0中,Keras层的骨架。你只需要实现三个方法即可:-
build(input_shape)
: 这是你定义权重的地方。这个方法必须设self.built = True
,可以通过调用super([Layer], self).build()
完成。 -
call(x)
: 这里是编写层的功能逻辑的地方。你只需要关注传入call
的第一个参数:输入张量,除非你希望你的层支持masking。 -
compute_output_shape(input_shape)
: 如果你的层更改了输入张量的形状,你应该在这里定义形状变化的逻辑,这让Keras能够自动推断各层的形状。from keras import backend as K from keras.engine.topology import Layer import numpy as np
-
下面好像是在定义了一个一层的FC,即Dense
class MyLayer(Layer): def __init__(self, output_dim, **kwargs): self.output_dim = output_dim super(MyLayer, self).__init__(**kwargs) # 这属于模板语句了,可以认为必写 def build(self, input_shape): # Create a trainable weight variable for this layer. self.kernel = self.add_weight(name='kernel', shape=(input_shape[1], self.output_dim), initializer='uniform', trainable=True) super(MyLayer, self).build(input_shape) # Be sure to call this somewhere! def call(self, x): return K.dot(x, self.kernel) def compute_output_shape(self, input_shape): return (input_shape[0], self.output_dim) # 已有的Keras层 就是实现层的最好的例子。不要犹豫**阅读源码**!
-