我的TensorFlow代码写得并不好,在自定义一些网络训练场景的时候乱写会导致学习效率很低,因为tf本身的优化太棒了,恰当地使用tensor进行运算会让程序的算力消耗显著降低。所以可以记录一下,方便自己随时回顾。
因此,难免出现一些神奇难解的词语/形容/符号,可能只有我自己(甚至我自己也不能)看得懂。
内容的组织结构将按照以下方式进行(当你有了数据集和明确的任务目标,从算法上你需要做什么呢?):
- 预处理数据集
- 搭建网络结构
- 确定损失函数
- 确定优化器
- 分析训练结果
数据集我感觉是挺麻烦的事儿,因此把它放在最后,其他按照上述逻辑顺序依次展开。
示例主要是使用fashion mnist数据集,不刻意区分全连接的神经网络/CNN/RNN。
1 搭建网络结构
1.1 Sequential的方式搭建层以及可用的层类型
keras.Sequential函数允许很方便地直接将你需要的层结构堆砌在列表中,直接生成网络。
列表中只需要放置很多的keras.layers中的你所需要的层。
import tensorflow.keras as keras
import tensorflow as tf
# 如果用from tensorflow import keras,会无法自动补全
model = keras.Sequential([
keras.layers.Conv2D(1, 1),
keras.layers.Conv2D(64, 3),
keras.layers.MaxPooling2D(),
keras.layers.BatchNormalization(),
keras.layers.ReLU(),
keras.layers.Conv2D(128, 3),
keras.layers.Conv2D(128, 3),
keras.layers.MaxPooling2D(),
keras.layers.BatchNormalization(),
keras.layers.ReLU(),
keras.layers.GlobalAvgPool2D(),
keras.layers.Dense(8192 ,activation='relu'),
keras.layers.Dense(2048 ,activation='relu'),
keras.layers.Dropout(0.5),
keras.layers.Dense(10),
])
model(tf.zeros((1,28,28,1)))
基本常用的层结构都可以在keras.layers中找到,可以随意挑选设计网络结构,有些复杂一点的例如Resnet中残差块这种的就要自己定义,在下一部分会介绍。
有哪些常用的层
keras.layers.Dense | 全连接层 最基本的 |
keras.layers.Conv2D | 二维卷积层 包括kernel_size/strides等基本参数的设置 |
keras.layers.MaxPooling2D | 二维池化层 有最大池化/均值池化/全局最大/全局均值池化 |
keras.layers.Flatten | 我曾经将卷积层结果通过池化强行降维 直到发现有flatten |
keras.layers.BatchNormalization | 批归一化 将层输出的每个维度变为均值为0 方差为1(它应该用在非线性层之前)很多时候会简称为BN |
keras.layers.Dropout | 我也曾不知道竟然dropout也有可以调用的层 太方便了 |
keras.layers.SimpleRNN/LSTM/GRU | 常用的RNN基本单元 |
keras.layers.SimpleRNNCell/LSTMCell/GRUCell | 值得一提的是为了方便细节设计 还有单个cell的版本 |
keras.layers.LeakyReLU | 以此为代表的一系列激活函数层 |
有的地方会在Sequential的第一层指明网络输入向量的形状,如果网络对输入向量的形状未知,是无法计算每一层的形状的,模型无法被建立。
但也可以像我一样,在网络搭建完成后,给网络输入随便一个和输入向量同形状的向量(严格地说,应该叫张量了),网络也会自动初始化。
建立好的模型可以使用模型的summary()方法,查看网络结构。
下面展示了部分输出,非常了然。
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (1, 28, 28, 1) 2
conv2d_1 (Conv2D) (1, 26, 26, 64) 640
max_pooling2d (MaxPooling2D (1, 13, 13, 64) 0
)
batch_normalization (BatchN (1, 13, 13, 64) 256
ormalization)
re_lu (ReLU) (1, 13, 13, 64) 0
conv2d_2 (Conv2D) (1, 11, 11, 128) 73856
conv2d_3 (Conv2D) (1, 9, 9, 128) 147584
max_pooling2d_1 (MaxPooling (1, 4, 4, 128) 0
2D)
batch_normalization_1 (Batc (1, 4, 4, 128) 512
hNormalization)
.............................................
=================================================================
Total params: 18,079,372
Trainable params: 18,078,988
Non-trainable params: 384
_________________________________________________________________
1.2 选择合适的激活函数
如果对于每个层的作用都明确的话,它们的参数也是相当明确易懂的,这里谈论比较公共的参数,比如激活函数。
添加激活函数有两种方式,可以直接在层的activation参数中给出,例如:
# 设定一个激活函数是relu
keras.layers.Dense(8192 ,activation='relu')
# relu比较好记,但是leakyrelu我就不确定大小写或者下划线了,所以有的时候可以选择从keras.activations中选择,比如tanh
keras.layers.Dense(8192 ,activation=keras.activations.tanh)
除此之外也可以单独添加一个非线性激活层,比如有时候你希望在卷积层后先使用BN层,在添加激活层,就可以
# 卷积层后先池化,再归一化,最后过激活层
keras.layers.Conv2D(64, 3),
keras.layers.MaxPooling2D(),
keras.layers.BatchNormalization(),
keras.layers.ReLU(),
怎么选用合适的激活函数。
softmax ( x ( 1 × n ) ) = [ p 1 , . . . , p n ] , p i ∈ [ 0 , 1 ] , Σ i = 1 n p i = 1 \text{softmax}(\bold{x}_{(1\times n)})=[p_1,...,p_n], p_i\in[0,1],\Sigma_{i=1}^np_i=1 softmax(