2 添加网络层
Layers是神经网络基本构建块。一个Layer包含了tensor-in/tensor-out的计算方法和一些状态,并保存在TensorFlow变量中(即layers的权重weights)。
Layers主要分为6个类别,基础层,核心层,卷基层,池化层,循环层,融合层。
2.1 基础层The Base Layer
tf.keras.layers.Layer(
trainable=True, name=None, dtype=None, dynamic=False, **kwargs
)
Args | 参数 |
---|---|
trainable | 布尔类型,变量是否可以被训练 |
name | layer名字 |
dtype | layer计算和权重的类型 |
dynamic | True为动态图,False为静态图 |
对派生类的实现可以用以下方法:
** init(): 定义layer的属性,创建layer的静态变量。
** build(self, input_shape): 创建依赖于输入的变量,可以调用add_weight()。
** call(self, *args, **kwargs): 在确保已调用build()之后,在call中调用。
** get_config(self): 返回包含用于初始化此层的配置的字典类型。
派生类例子1:
创建SimpleDense派生类,在build()函数里添加trainable weights。实现y=input*w +b
class SimpleDense(tf.keras.layers.Layer):
def __init__(self, units=32):
super(SimpleDense, self).__init__()
self.units = units
def build(self, input_shape): # add weights in build, the weights depends on input
self.w = self.add_weight(shape=(input_shape[-1], self.units),
initializer='random_normal',
trainable=True)
self.b = self.add_weight(shape=(self.units,),
initializer='random_normal',
trainable=True)
print("input_shape[-1]: {},\n self.w:\n {}".format(input_shape[-1],self.w.numpy()))
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
linear_layer = SimpleDense(3)
y = linear_layer(tf.ones((2, 2)))
print("y value:\n ",y.numpy())
assert len(linear_layer.weights) == 2
# These weights are trainable, so they're listed in `trainable_weights`:
assert len(linear_layer.trainable_weights) == 2
结果输出:
input_shape[-1]: 2,
self.w:
[[-0.03338138 -0.03652136 0.0161477 ]
[-0.02402006 -0.12441503 -0.01301991]]
y value:
[[-0.02291155 -0.19580051 0.02063639]
[-0.02291155 -0.19580051 0.02063639]]
派生类例子2:
创建ComputeSum派生类,在init函数里添加 non-trainable weights。实现输入矩阵沿轴0元素相加后,x=x+self.total
class ComputeSum(tf.keras.layers.Layer):
def __init__(self, input_dim):
super(ComputeSum, self).__init__()
# Create a non-trainable weight.
self.total = tf.Variable(initial_value=tf.zeros((input_dim,)),
trainable=False)
def call(self, inputs):
self.total.assign_add(tf.reduce_sum(inputs, axis=0))
return self.total
my_sum = ComputeSum(2)
x = tf.ones((2, 2))
print(x.numpy())
y = my_sum(x)
print(y.numpy()) # [2\. 2.]
y = my_sum(x)
print(y.numpy()) # [4\. 4.]
assert my_sum.weights == [my_sum.total]
assert my_sum.non_trainable_weights == [my_sum.total]
assert my_sum.trainable_weights == []
结果输出:
[[1. 1.]
[1. 1.]]
[2. 2.]
[4. 4.]
2.2 核心网络层
核心层是最常用的层,涉及到数据的转换和处理的时候都会用到这些层。
2.2.1 Dense
Dense层就是所谓的全连接神经网络层,简称全连接层。全连接层中的每个神经元与其前一层的所有神经元进行全连接。
tf.keras.layers.Dense(
units,
activation=None,
use_bias=True,
kernel_initializer="glorot_uniform",
bias_initializer="zeros",
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
**kwargs
)
Dense 实现以下操作: output = activation(dot(input, kernel) + bias) 其中 activation 是按逐个元素计算的激活函数,kernel 是由网络层创建的权值矩阵,以及 bias 是其创建的偏置向量 (只在 use_bias 为 True 时才有用)。
Args | 参数 |
---|---|
units | 正整数,输出空间维度 |
activation | 激活函数 |
use_bias | 布尔值,该层是否使用偏置向量 |
kernel_initializer | kernel 权值矩阵的初始化器 |
bias_initializer | 偏置向量的初始化器 |
kernel_regularizer | 运用到 kernel 权值矩阵的正则化函数 |
bias_regularizer | 运用到偏置向的的正则化函数 |
activity_regularizer | 运用到层的输出的正则化函数 |
kernel_constraint | 运用到 kernel 权值矩阵的约束函数 |
bias_constraint | 运用到偏置向量的约束函数 |
2.2.2 Activation
将激活函数应用于输出。输入信号进入神经元后进行的运算处理。
tf.keras.layers.Activation(activation, **kwargs)
常见内置激活函数: | ||
---|---|---|
elu | tf.keras.activations.elu(x, alpha=1.0) | 指数线性单元 |
exponential | tf.keras.activations.exponential(x) | 指数激活函数 |
gelu | tf.keras.activations.gelu(x, approximate=False) | 高斯误差线性单元 |
linear | tf.keras.activations.linear(x) | 线性激活函数(即不做任何改变) |
relu | tf.keras.activations.relu(x, alpha=0.0, max_value=None, threshold=0) | 整流线性单元 |
selu | tf.keras.activations.selu(x) | 可伸缩的指数线性单元 |
sigmoid | tf.keras.activations.sigmoid(x) | sigmoid(x) = 1 / (1 + exp(-x)) |
softplus | tf.keras.activations.softplus(x) | softplus(x) = log(exp(x) + 1) |
softsign | tf.keras.activations.softsign(x) | softsign(x) = x / (abs(x) + 1) |
swish | tf.keras.activations.swish(x) | swish(x) = x * sigmoid(x) |
tanh | tf.keras.activations.tanh(x) | 双曲正切激活函数 |
sigmoid、tanh、ReLU、softplus的对比曲线如下图所示:
激活函数可以通过设置单独的激活层Activation实现,也可以在构造层对象时通过传递 activation 参数实现:
# 方法一:激活函数可以通过设置单独的激活层Activation实现
import tensorflow as tf
from tensorflow import keras
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(64))
model.add(tf.keras.layers.Activation('tanh'))
# 方法二:构造层对象时通过传递 activation 参数实现
import tensorflow as tf
from tensorflow import keras
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(64, activation='tanh'))
2.2.3 Dropout
Dropout在训练中每次更新时,将输入单元的按比率随机设置为0,这有助于防止过拟合。未设置为0的输入将按1 /(1-rate)放大,以使所有输入的总和不变。
f.keras.layers.Dropout(rate, noise_shape=None, seed=None, **kwargs)
请注意,仅当训练设置为True时才应用Dropout层,以便在推理过程中不会丢弃任何值。 使用model.fit时,训练将自动适当地设置为True。
- rate: 在 0 和 1 之间浮动。需要丢弃的输入比例。
- noise_shape: 1D 整数张量, 表示将与输入相乘的二进制 dropout 掩层的形状。 例如,如果你的输入尺寸为 (batch_size, timesteps, features),然后 你希望 dropout 掩层在所有时间步都是一样的, 你可以使用 noise_shape=(batch_size, 1, features)。
- seed: 一个作为随机种子的 Python 整数。
2.2.4 Flatten
将输入展平。不影响批量大小。注意:如果输入的形状是(batch,)没有特征轴,则展平会增加通道尺寸,而输出的形状是(batch, 1)。
tf.keras.layers.Flatten(data_format=None, **kwargs)
2.2.5 Reshape
将输入重新调整为特定的尺寸
tf.keras.layers.Reshape(target_shape, **kwargs)
2.2.6 Lambda
将任意表达式封装为Layer对象。在Lambda层,以便在构造模型时可以使用任意TensorFlow函数。 Lambda层最适合简单操作或快速实验。 Lambda层是通过序列化Python字节码来保存的。
# Lambda定义
tf.keras.layers.Lambda(
function, output_shape=None, mask=None, arguments=None, **kwargs
)
# 举例说明 add a x -> x^2 layer
model.add(tf.keras.layers.Lambda(lambda x: x ** 2))
2.2.7 Masking
使用覆盖值覆盖序列,以跳过时间步。
对于输入张量的每一个时间步(张量的第一个维度),如果所有时间步中输入张量的值与mask_value相等,则将在所有下游层中屏蔽(跳过)该时间步。如果任何下游层不支持覆盖但仍然收到此类输入覆盖信息,会引发异常。
# Masking定义
tf.keras.layers.Masking(mask_value=0.0, **kwargs)
举例说明:
#考虑将要喂入一个 LSTM 层的 Numpy 矩阵 x, 尺寸为 (samples, timesteps, features)。
#你想要覆盖时间步#3 和 #5,因为你缺乏这几个时间步的数据。
#你可以:设置 x[:, 3, :]=0\. 以及 x[:, 5, :]=0\. 在 LSTM 层之前,插入一个 mask_value=0 的 Masking 层:
import tensorflow as tf
from tensorflow import keras
import numpy as np
samples, timesteps, features = 32, 10, 8
inputs = np.random.random([samples, timesteps, features]).astype(np.float32)
inputs[:, 3, :] = 0.
inputs[:, 5, :] = 0.
model = tf.keras.models.Sequential()
model.add(tf.keras.layers.Masking(mask_value=0.,
input_shape=(timesteps, features)))
model.add(tf.keras.layers.LSTM(32))
output = model(inputs)
# The time step 3 and 5 will be skipped from LSTM calculation.
2.2.8 Embedding
Embedding 是一个将离散变量转为连续向量表示的一个方式。该层只能用作模型中的第一层。
Embedding 有以下3个主要目的: 在 embedding 空间中查找最近邻,这可以很好的用于根据用户的兴趣来进行推荐。 作为监督性学习任务的输入。 用于可视化不同离散变量之间的关系.
# Embedding定义
tf.keras.layers.Embedding(
input_dim, output_dim, embeddings_initializer='uniform',
embeddings_regularizer=None, activity_regularizer=None,
embeddings_constraint=None, mask_zero=False, input_length=None, **kwargs)
- input_dim: int > 0。词汇表大小,即最大整数 index + 1。
- output_dim: int >= 0。词向量的维度。
- embeddings_initializer: embeddings 矩阵的初始化方法。
- embeddings_regularizer: embeddings matrix 的正则化方法。
- embeddings_constraint: embeddings matrix 的约束函数。
- mask_zero: 是否把 0 看作为一个应该被遮蔽的特殊的"padding"值。这对于可变长的循环神经网络层十分有用。如果设定为True,那么接下来的所有层都必须支持masking,否则就会抛出异常。如果mask_zero为True,作为结果,索引 0 就不能被用于词汇表中(input_dim 应该与 vocabulary + 1 大小相同)。
- input_length: 输入序列的长度,当它是固定的时。如果你需要连接Flatten和Dense层,则这个参数是必须的。没有它,dense 层的输出尺寸就无法计算。
举例说明:
#输入尺寸为 (batch_size, sequence_length) 的 2D 张量。
#输出尺寸为 (batch_size, sequence_length, output_dim) 的 3D 张量。
model = tf.keras.Sequential()
model.add(tf.keras.layers.Embedding(1000, 64, input_length=10))
# The model will take as input an integer matrix of size (batch,
# input_length), and the largest integer (i.e. word index) in the input
# should be no larger than 999 (vocabulary size).
# Now model.output_shape is (None, 10, 64), where `None` is the batch
# dimension.
input_array = np.random.randint(1000, size=(32, 10))
model.compile('rmsprop', 'mse')
output_array = model.predict(input_array)
print(output_array.shape)
输出结果:
(32, 10, 64)
2.3 卷积层 Convolution layers
由维基百科的介绍我们可以得知,卷积是一种定义在两个函数(跟)上的数学操作,旨在产生一个新的函数。那么和的卷积就可以写成∗,数学定义如下:
对应到不同方面,卷积可以有不同的解释: 既可以看作我们在深度学习里常说的核(Kernel),也可以对应到信号处理中的滤波器(Filter)。而 可以是我们所说的机器学习中的特征(Feature),也可以是信号处理中的信号(Signal)。f和g的卷积 (∗)就可以看作是对的加权求和。
一维时域卷积操作:
二维图像卷积操作:
卷积运算的目的是提取输入的不同特征,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网路能从低级特征中迭代提取更复杂的特征。
2.3.1 Conv1D
一维卷积层(即时域卷积),用以在一维输入信号上进行邻域滤波。
# Conv1D 定义
tf.keras.layers.Conv1D(
filters, kernel_size, strides=1, padding='valid', data_format='channels_last',
dilation_rate=1, groups=1, activation=None, use_bias=True,
kernel_initializer='glorot_uniform', bias_initializer='zeros',
kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None,
kernel_constraint=None, bias_constraint=None, **kwargs
)
参数 | |
---|---|
filters | 输出空间的维度。即卷积中滤波器的输出数量 |
kernel_size | 指明1D卷积窗口的长度 |
strides | 指明卷积的步长 |
padding | "valid", "causal" 或 "same" 之一 |
data_format | 字符串, "channels_last" (默认) 或 "channels_first" 之一 |
dilation_rate | 指定用于膨胀卷积的膨胀率 |
activation | 要使用的激活函数 |
use_bias | 布尔值,该层是否使用偏置向量 |
kernel_initializer | kernel 权值矩阵的初始化器 |
bias_initializer | 偏置向量的初始化器 |
kernel_regularizer | 运用到 kernel 权值矩阵的正则化函数 |
bias_regularizer | 运用到偏置向量的正则化函数 |
activity_regularizer | 运用到层输出(它的激活值)的正则化函数 |
kernel_constraint | 运用到 kernel 权值矩阵的约束函数 |
bias_constraint | 运用到偏置向量的约束函数 |
举例说明:
import tensorflow as tf
from tensorflow import keras
# The inputs are 128-length vectors with 10 timesteps, and the batch size is 4.
input_shape = (4, 10, 128) # 输入为 (batch_size, steps, input_dim)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv1D(32, 3, activation='relu',input_shape=input_shape[1:])(x) # filters=32, kernel_size=3
print(y.shape) # 输出为 (batch_size, new_steps, filters)
结果输出:
(4, 8, 32)
2.3.2 Conv2D
2D 卷积层 (例如对图像的空间卷积)。
# Conv2D定义
tf.keras.layers.Conv2D(
filters, kernel_size, strides=(1, 1), padding='valid', data_format=None,
dilation_rate=(1, 1), groups=1, activation=None, use_bias=True,
kernel_initializer='glorot_uniform', bias_initializer='zeros',
kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None,
kernel_constraint=None, bias_constraint=None, **kwargs)
参数 | |
---|---|
filters | 输出空间的维度 |
kernel_size | 指明 2D 卷积窗口的宽度和高度 |
strides | 指明卷积沿宽度和高度方向的步长 |
padding | "valid" 或 "same" |
data_format | 字符串, "channels_last" (默认) 或 "channels_first" 之一 |
dilation_rate | 指定膨胀卷积的膨胀率 |
activation | 要使用的激活函数 |
use_bias | 布尔值,该层是否使用偏置向量 |
kernel_initializer | kernel 权值矩阵的初始化器 |
bias_initializer | 偏置向量的初始化器 |
kernel_regularizer | 运用到 kernel 权值矩阵的正则化函数 |
bias_regularizer | 运用到偏置向量的正则化函数 |
activity_regularizer | 运用到层输出(它的激活值)的正则化函数 |
kernel_constraint | 运用到 kernel 权值矩阵的约束函数 |
bias_constraint | 运用到偏置向量的约束函数 |
举例说明:
import tensorflow as tf
from tensorflow import keras
# The inputs are 28x28 RGB images with `channels_last` and the batch
# size is 4.
input_shape = (4, 28, 28, 3) #输入为(samples, rows, cols, channels)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv2D(
2, 3, activation='relu', input_shape=input_shape[1:])(x) # filters=2, kernel_size=3
print(y.shape) #输出为(samples, new_rows, new_cols, filters)
结果输出:
(4, 26, 26, 2)
2.3.3 Conv3D
3D卷积层(例如体积上的空间卷积)
# Conv3D定义
tf.keras.layers.Conv3D(
filters, kernel_size, strides=(1, 1, 1), padding='valid', data_format=None,
dilation_rate=(1, 1, 1), groups=1, activation=None, use_bias=True,
kernel_initializer='glorot_uniform', bias_initializer='zeros',
kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None,
kernel_constraint=None, bias_constraint=None, **kwargs)
参数 | |
---|---|
filters | 输出空间的维度 |
kernel_size | 指明 2D 卷积窗口的宽度和高度以及深度 |
strides | 指定沿每个空间维度的卷积步长 |
padding | "valid" 或 "same" |
data_format | 字符串, "channels_last" (默认) 或 "channels_first" 之一 |
dilation_rate | 指定膨胀卷积的膨胀率 |
activation | 要使用的激活函数 |
use_bias | 布尔值,该层是否使用偏置向量 |
kernel_initializer | kernel 权值矩阵的初始化器 |
bias_initializer | 偏置向量的初始化器 |
kernel_regularizer | 运用到 kernel 权值矩阵的正则化函数 |
bias_regularizer | 运用到偏置向量的正则化函数 |
activity_regularizer | 运用到层输出(它的激活值)的正则化函数 |
kernel_constraint | 运用到 kernel 权值矩阵的约束函数 |
bias_constraint | 运用到偏置向量的约束函数 |
举例说明:
import tensorflow as tf
from tensorflow import keras
# The inputs are 28x28x28 volumes with a single channel, and the
# batch size is 4
input_shape =(4, 28, 28, 28, 1) #输入为 (batch_size, conv_dim1, conv_dim2, conv_dim3, channels)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv3D(
2, 3, activation='relu', input_shape=input_shape[1:])(x) #filters=2, kernel_size=3
print(y.shape) #输出为 (batch_size, new_conv_dim1, new_conv_dim2, new_conv_dim3, filters)
结果输出:
(4, 26, 26, 26, 2)
2.3.4 SeparableConv1D
深度可分离1D卷积。该层执行分别作用在通道上的深度卷积,然后是混合通道的逐点卷积。 如果use_bias为True并提供了一个偏差初始值设定项,则它将偏差向量添加到输出中。 然后,它可选地应用激活函数以产生最终输出。
# SeparableConv1D定义
tf.keras.layers.SeparableConv1D(
filters, kernel_size, strides=1, padding='valid', data_format=None,
dilation_rate=1, depth_multiplier=1, activation=None, use_bias=True,
depthwise_initializer='glorot_uniform', pointwise_initializer='glorot_uniform',
bias_initializer='zeros', depthwise_regularizer=None,
pointwise_regularizer=None, bias_regularizer=None, activity_regularizer=None,
depthwise_constraint=None, pointwise_constraint=None, bias_constraint=None,
**kwargs)
2.3.5 SeparableConv2D
深度可分离的2D卷积。可分离的卷积包括首先执行深度空间卷积(它分别作用于每个输入通道),然后是点向卷积,它将混合所得的输出通道。 depth_multiplier参数控制在深度步骤中每个输入通道生成多少个输出通道。
直观上,可分离的卷积可以理解为将卷积内核分解为两个较小内核的一种方式,或者是Inception块的一种极端版本。
# SeparableConv2D定义
tf.keras.layers.SeparableConv2D(
filters, kernel_size, strides=(1, 1), padding='valid', data_format=None,
dilation_rate=(1, 1), depth_multiplier=1, activation=None, use_bias=True,
depthwise_initializer='glorot_uniform', pointwise_initializer='glorot_uniform',
bias_initializer='zeros', depthwise_regularizer=None,
pointwise_regularizer=None, bias_regularizer=None, activity_regularizer=None,
depthwise_constraint=None, pointwise_constraint=None, bias_constraint=None,
**kwargs)
2.3.6 Conv2DTranspose
转置卷积层 (有时被成为反卷积)。对转置卷积的需求一般来自希望使用 与正常卷积相反方向的变换,将具有卷积输出尺寸的东西 转换为具有卷积输入尺寸的东西, 同时保持与所述卷积相容的连通性模式。
# Conv2DTranspose定义
tf.keras.layers.Conv2DTranspose(
filters, kernel_size, strides=(1, 1), padding='valid', output_padding=None,
data_format=None, dilation_rate=(1, 1), activation=None,use_bias=True,kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None,
kernel_constraint=None, bias_constraint=None, **kwargs)
2.4 池化层 Pooling layers
池化层是模仿人的视觉系统对数据进行降维,用更高层次的特征表示图像。实施池化的目的:降低信息冗余;提升模型的尺度不变性、旋转不变性。 防止过拟合。
通常有最大池化层,平均池化层。
- 最大池化层对每一个小区域选最最大值作为池化结果
- 平均池化层选取平均值作为池化结果。
池化层有三种形态:1D 用于一维数据,2D 一般用于二维图像数据,3D 带时间序列数据的图像数据
池化层函数 | |
---|---|
MaxPooling1D | 对于时序数据的最大池化 |
MaxPooling2D | 对于空间数据的最大池化 |
MaxPooling3D | 对于3D数据的最大池化 |
AveragePooling1D | 对于时序数据的平均池化 |
AveragePooling2D | 对于空间数据的平均池化 |
AveragePooling3D | 对于3D数据的平均池化 |
GlobalMaxPooling1D | 对于时序数据的全局最大池化 |
GlobalMaxPooling2D | 对于空域数据的全局最大池化 |
GlobalAveragePooling1D | 时序数据的全局平均池化 |
GlobalAveragePooling2D | 空间数据的全局平均池化 |
2.5 循环层Recurrent layers
循环神经网络(Recurrent Neural Network, 简称 RNN),循环神经网络的提出便是基于记忆模型的想法,期望网络能够记住前面出现的特征,并依据特征推断后面的结果,而且整体的网络结构不断循环,因此得名为循环神经网络。
2.5.1 LSTM
长短期记忆网络(Long-Short Term Memory,LSTM)论文首次发表于1997年。由于独特的设计结构,LSTM适合于处理和预测时间序列中间隔和延迟非常长的重要事件。
# LSTM定义
tf.keras.layers.LSTM(
units, activation='tanh', recurrent_activation='sigmoid', use_bias=True,
kernel_initializer='glorot_uniform', recurrent_initializer='orthogonal',
bias_initializer='zeros', unit_forget_bias=True, kernel_regularizer=None,
recurrent_regularizer=None, bias_regularizer=None, activity_regularizer=None,
kernel_constraint=None, recurrent_constraint=None, bias_constraint=None,
dropout=0.0, recurrent_dropout=0.0, implementation=2, return_sequences=False,
return_state=False, go_backwards=False, stateful=False, time_major=False,
unroll=False, **kwargs)
参数 | |
---|---|
units | 输出维度 |
activation | 激活函数 |
recurrent_activation | 为循环步施加的激活函数 |
use_bias | 布尔值,是否使用偏置项 |
kernel_initializer | 权值初始化方法,为预定义初始化方法名的字符串,或用于初始化权重的初始化器 |
recurrent_initializer | 循环核的初始化方法,为预定义初始化方法名的字符串,或用于初始化权重的初始化器 |
bias_initializer | 权值初始化方法,为预定义初始化方法名的字符串,或用于初始化权重的初始化器 |
kernel_regularizer | 施加在权重上的正则项 |
bias_regularizer | 施加在偏置向量上的正则项 |
recurrent_regularizer | 施加在循环核上的正则项 |
activity_regularizer | 施加在输出上的正则项 |
kernel_constraints | 施加在权重上的约束项 |
recurrent_constraints | 施加在循环核上的约束项 |
bias_constraints | 施加在偏置上的约束项 |
dropout | 0~1之间的浮点数,控制输入线性变换的神经元断开比例 |
recurrent_dropout | 0~1之间的浮点数,控制循环状态的线性变换的神经元断开比例 |
举例说明:
import tensorflow as tf
from tensorflow import keras
inputs = tf.random.normal([32, 10, 8])
lstm = tf.keras.layers.LSTM(4)
output = lstm(inputs)
print(output.shape)
lstm = tf.keras.layers.LSTM(4, return_sequences=True, return_state=True)
whole_seq_output, final_memory_state, final_carry_state = lstm(inputs)
print(whole_seq_output.shape)
print(final_memory_state.shape)
print(final_carry_state.shape)
结果输出:
(32, 4)
(32, 10, 4)
(32, 4)
(32, 4)
2.5.2 BRU
GRU门控循环单元- Cho et al. 2014.
在LSTM中引入了三个门函数:输入门、遗忘门和输出门来控制输入值、记忆值和输出值。而在GRU模型中只有两个门:分别是更新门和重置门。与LSTM相比,GRU内部少了一个”门控“,参数比LSTM少,但是却也能够达到与LSTM相当的功能。考虑到硬件的计算能力和时间成本,因而很多时候我们也就会选择更加”实用“的GRU。
# GRU定义
tf.keras.layers.GRU(
units, activation='tanh', recurrent_activation='sigmoid', use_bias=True,
kernel_initializer='glorot_uniform', recurrent_initializer='orthogonal',
bias_initializer='zeros', kernel_regularizer=None, recurrent_regularizer=None,
bias_regularizer=None, activity_regularizer=None, kernel_constraint=None,
recurrent_constraint=None, bias_constraint=None, dropout=0.0,
recurrent_dropout=0.0, implementation=2, return_sequences=False,
return_state=False, go_backwards=False, stateful=False, unroll=False,
time_major=False, reset_after=True, **kwargs )
参数 | |
---|---|
units | 输出维度 |
activation | 要使用的激活函数。默认:双曲正切 (tanh)。 如果传入 None,则不使用激活函数 (即 线性激活:a(x) = x)。 |
recurrent_activation | 用于循环时间步的激活函数。默认:分段线性近似 sigmoid (hard_sigmoid)。 如果传入 None,则不使用激活函数 (即 线性激活:a(x) = x)。 |
use_bias | 布尔值,该层是否使用偏置向量。 |
kernel_initializer | kernel 权值矩阵的初始化器, 用于输入的线性转换 |
recurrent_initializer | recurrent_kernel 权值矩阵 的初始化器,用于循环层状态的线性转换 |
bias_initializer | 偏置向量的初始化器 |
kernel_regularizer | 运用到 kernel 权值矩阵的正则化函数 |
recurrent_regularizer | 运用到 recurrent_kernel 权值矩阵的正则化函数 |
bias_regularizer | 运用到偏置向量的正则化函数 |
activity_regularizer | 运用到层输出(它的激活值)的正则化函数 |
kernel_constraint | 运用到 kernel 权值矩阵的约束函数 |
recurrent_constraint | 运用到 recurrent_kernel 权值矩阵的约束函数 |
bias_constraint | 运用到偏置向量的约束函数 |
dropout | 在 0 和 1 之间的浮点数。 单元的丢弃比例,用于输入的线性转换 |
recurrent_dropout | 在 0 和 1 之间的浮点数 |
implementation | 实现模式,1 或 2。 模式 1 将把它的操作结构化为更多的小的点积和加法操作,而模式 2 将把它们分批到更少,更大的操作中 |
return_sequences | 布尔值。是返回输出序列中的最后一个输出,还是全部序列 |
return_state | 布尔值。除了输出之外是否返回最后一个状态 |
go_backwards | 布尔值 (默认 False)。 如果为 True,则向后处理输入序列并返回相反的序列 |
stateful | 布尔值 (默认 False)。 如果为 True,则批次中索引 i 处的每个样品的最后状态 将用作下一批次中索引 i 样品的初始状态 |
unroll | 布尔值 (默认 False)。 如果为 True,则网络将展开,否则将使用符号循环。 展开可以加速 RNN,但它往往会占用更多的内存。 展开只适用于短序列 |
reset_after | GRU公约 (是否在矩阵乘法之前或者之后使用重置门)。 False =「之前」(默认),Ture =「之后」( CuDNN 兼容) |
举例说明:
improt tensorflow as tf
from tensorflow import keras
inputs = tf.random.normal([32, 10, 8])
gru = tf.keras.layers.GRU(4)
output = gru(inputs)
print(output.shape)
gru = tf.keras.layers.GRU(4, return_sequences=True, return_state=True)
whole_sequence_output, final_state = gru(inputs)
print(whole_sequence_output.shape)
print(final_state.shape)
结果输出:
(32, 4)
(32, 10, 4)
(32, 4)
2.5.3 RNN
循环神经网络层基类。
# RNN定义
tf.keras.layers.RNN(
cell, return_sequences=False, return_state=False, go_backwards=False,
stateful=False, unroll=False, time_major=False, **kwargs)
关于指定 RNN 初始状态的说明
您可以通过使用关键字参数 initial_state 调用它们来符号化地指定 RNN 层的初始状态。 initial_state 的值应该是表示 RNN 层初始状态的张量或张量列表。
可以通过调用带有关键字参数 states 的 reset_states 方法来数字化地指定 RNN 层的初始状态。 states 的值应该是一个代表 RNN 层初始状态的 Numpy 数组或者 Numpy 数组列表。
关于给 RNN 传递外部常量的说明
可以使用 RNN.call(以及 RNN.call)的 constants 关键字参数将「外部」常量传递给单元。 这要求 cell.call 方法接受相同的关键字参数 constants。 这些常数可用于调节附加静态输入(不随时间变化)上的单元转换,也可用于注意力机制。
参数 | |
---|---|
cell | 一个 RNN 单元实例 |
return_sequences | 布尔值。是返回输出序列中的最后一个输出,还是全部序列 |
return_state | 布尔值。除了输出之外是否返回最后一个状态 |
go_backwards | 布尔值 (默认 False)。 如果为 True,则向后处理输入序列并返回相反的序列 |
stateful | 布尔值 (默认 False)。 如果为 True,则批次中索引 i 处的每个样品的最后状态将用作下一批次中索引 i 样品的初始状态 |
unroll | 布尔值 (默认 False)。 如果为 True,则网络将展开,否则将使用符号循环 |
input_dim | 输入的维度 |
input_length | 输入序列的长度 |
举例说明:
# First, let's define a RNN Cell, as a layer subclass.
# 首先,让我们定义一个 RNN 单元,作为网络层子类。
import tensorflow as tf
from keras import backend as K
class MinimalRNNCell(keras.layers.Layer):
def __init__(self, units, **kwargs):
self.units = units
self.state_size = units
super(MinimalRNNCell, self).__init__(**kwargs)
def build(self, input_shape):
self.kernel = self.add_weight(shape=(input_shape[-1], self.units),
initializer='uniform',
name='kernel')
self.recurrent_kernel = self.add_weight(
shape=(self.units, self.units),
initializer='uniform',
name='recurrent_kernel')
self.built = True
def call(self, inputs, states):
prev_output = states[0]
h = K.dot(inputs, self.kernel)
output = h + K.dot(prev_output, self.recurrent_kernel)
return output, [output]
# 让我们在 RNN 层使用这个单元:
cell = MinimalRNNCell(32)
x = keras.Input((None, 5))
layer = keras.layers.RNN(cell)
y = layer(x)
# 以下是如何使用单元格构建堆叠的 RNN的方法:
cells = [MinimalRNNCell(32), MinimalRNNCell(64)]
x = keras.Input((None, 5))
layer = keras.layers.RNN(cells)
y = layer(x)