我们对Keras应该已经有了一个直观、宏观的认识了。现在,我们来系统的学习一下Keras的一些关于网络层的API,本文的主要内容是围绕卷积展开的,包含以下的内容:
- 不同类型的卷积层;
- 不同的参数初始化方式;
- 不同的激活函数;
- 增加L1/L2正则;
- 不同的池化层;
- 多个Normalization层;
- 其他的常用层。
本文内容较多,对于API的学习了解即可。
1 Keras卷积层
Keras的卷积层和PyTorch的卷积层,都包括1D、2D和3D的版本,1D就是一维的,2D是图像,3D是立体图像。这里就用最常见的2D图像来做讲解,1D和3D和2D基本相同,不多赘述。
1.1 Conv2D
先看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
)
先看一个简单的例子:
import tensorflow as tf
input_shape = (4, 28, 28, 3)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv2D(
filters=2,kernel_size=3,
activation='relu',padding='same'
)
print(y(x).shape)
>>> (4, 28, 28, 2)
现在来看参数含义:
- filter: 一个int整数,输出特征图的通道数;
- kernel_size:一个int整数,卷积核大小;
- strides:一个整数或者是(a,b)这样的list,表示卷积核是否跳步;
- padding:
'valid'表示没有padding,'same'表示输出和输入特征图的尺寸相同;只有这两种选择 - data_format:
'channels_last'或者是'channels_first'。默认是'channels_last',表示特征图的最后一个维度是通道,(batch_size, height, width, channels) ;如果选择了'channels_first'表示每一个样本的第一个维度是通道,所以特征图的格式和PyTorch的格式相同,(batch_size, channels, height, width)。 - dilation_rate:碰撞卷积的设置,默认是1,1就是一般的卷积。需要注意的是dilation_rate和stride目前不支持同时不为1,换句话说,如果要膨胀卷积的话,那么stride必须是1;
- groups;分组卷积;
- activation:这个表示,可以直接在卷积层后面设置一个激活层,比方说
'relu',这个在后面的章节会详细讲解目前Keras支持的所有激活层,如果什么都不填入,则不使用激活层 - use_bias:一个bool参数,True表示使用bias,默认是True;
- kernel_initializer:卷积核的初始化的方法,这个会在后面的章节详细讲解;
- bias_initializer:偏置的初始化的方法,这个会在后面的章节详细讲解;
- kernel_regularizer:卷积核的正则化的方法,在后面的章节会详细讲解;
- bias_regularizer:偏置的正则化的方法,在后面的章节会详细讲解;
2 Keras参数初始化
把之前提到的简单的例子,增加卷积核和偏置的初始化:
import tensorflow as tf
input_shape = (4, 28, 28, 3)
initializer = tf.keras.initializers.RandomNormal(mean=0., stddev=1.)
x = tf.random.normal(input_shape)
y = tf.keras.layers.Conv2D(
filters=2,kernel_size=3,
activation='relu',padding='same',
kernel_initializer=initializer,
bias_initializer=initializer
)
print(y(x).shape)
>>> (4, 28, 28, 2)
简单的说,就是先定义一个初始化器initializer,然后把这个初始化器作为参数传给Keras.Layers就行了。
2.1 正态分布
tf.keras.initializers.RandomNormal(mean=0.0, stddev=0.05, seed=None)
2.2 均匀分布
tf.keras.initializers.RandomUniform(minval=-0.05, maxval=0.05, seed=None)
2.3 截尾正态分布
tf.keras.initializers.TruncatedNormal(mean=0.0, stddev=0.05, seed=None)
基本和正态分布一样,但是如果随机的取值是在距离均值两个标准差的这个范围之外的,那么会重新取值。
换句话说,初始化的数值会被限制在均值正负两个标准差的范围内
2.4 常数
tf.keras.initializers.Zeros()
tf.keras.initializers.Ones()
2.5 Xavier/Glorot
tf.keras.initializers.GlorotNormal(seed=None)
这个本质是一个截尾正态分布,但是GlorotNormal(又称Xavier),是一个以0为均值,标准差计算公式是:
是in和out表示输入和输出神经元数目的数目。如果是之前已经学习过或者看过我写的关于Xavier初始化的论文笔记的朋友,可能会发现论文中使用的是一个均匀分布而不是正态分布。
均匀分布的初始化如下:
tf.keras.initializers.GlorotUniform(seed=None)
这个均匀分布是我们讲的: 这个Xavier方法,也是Keras默认的初始化的方法
2.6 自定义初始化
当然,Keras也是支持自定义初始化的方法的。
import tensorflow as tf
class ExampleRandomNormal(tf.keras.initializers.Initializer):
def __init__(self, mean, stddev):
self.mean = mean
self.stddev = stddev
def __call__(self, shape, dtype=None)`:
return tf.random.normal(
shape, mean=self.mean, stddev=self.stddev, dtype=dtype)
def get_config(self): # To support serialization
return {'mean': self.mean, 'stddev': self.stddev}
关键就是在__call__中返回一个和输入参数shape大小相同的一个tf张量就行了。
3 Keras激活函数
基本支持了所有的常见激活函数。在卷积层的参数activation中,可以输入relu,sigmoid,softmax等下面的字符串的形式,全部小写。
3.1 relu
tf.keras.activations.relu(x, alpha=0.0, max_value=None, threshold=0)
- alpha就是斜率,如果是0.1,则变成leakyReLU;
- max_value是ReLU的上界,如果是None则没有上界;
- threshold是ReLU的下界,小于下界的都会被置0,一般默认是0.
3.2 sigmoid
tf.keras.activations.sigmoid(x)
函数方程:
3.3 softmax
tf.keras.activations.softmax(x, axis=-1)
3.4 softplus
tf.keras.activations.softplus(x)
计算公式:
3.5 softsign
tf.keras.activations.softsign(x)
计算公式:
3.6 tanh
tf.keras.activations.tanh(x)
计算公式:
3.6 selu
tf.keras.activations.selu(x)
- 如果,返回;
- 如果,返回;
- scale和是事先设置的数值,alpha=1.67216214,scale=1.05070098
- 与elu激活函数类似,但是多了有个scale系数,
- 2017年的一篇论文提出selu,elu是2016年提出的
4 Keras的L1/L2正则
正则化就比较简单,不是L1就是L2,再或者两者都有。
4.1 L1/L2正则
from tensorflow.keras import layers
from tensorflow.keras import regularizers
layer = layers.Dense(
units=64,
kernel_regularizer=regularizers.l1_l2(l1=1e-5, l2=1e-4),
)
这里的正则化,可以使用:
tf.keras.regularizers.l1_l2(l1=1e-5, l2=1e-4)tf.keras.regularizers.l2(1e-4)tf.keras.regularizers.l1(1e-5)
关于L1和L2的计算细节:
- L1:L1正则就是
- L2:L1正则就是
4.2 自定义正则化
class MyRegularizer(tf.keras.regularizers.Regularizer):
def __init__(self, strength):
self.strength = strength
def __call__(self, x):
return self.strength * tf.reduce_sum(tf.square(x))
def get_config(self):
return {'strength': self.strength}
这个实现的是L2正则的。其中的get_config是用来保存模型数据的,不要的话也没事,只是不能序列化的保存模型(不用使用config或者json来存储模型)。