本文参考《TensorFlow2深度学习》
1、深度学习的深度是指网络的层数较深,一般有5层以上。1~4层神经网络称为浅层神经网络。浅层神经网络不能很好的提取数据的高层特征,表达能力一般,很快被1990年代新提出的支持向量机(SVM)所超越。2006年,Hinton大佬提出了一种逐层预训练的算法,可以有效的初始化DBN网络,从而使得训练大规模、深层数(上百万的参数量)的神经网络成为可能。深度学习的概念被首次提出。深度学习和神经网络本质上指代基本一致,深度学习更侧重于深层次的神经网络的相关研究。
2、全连接网络搭建
from tensorflow import keras
from tensorflow.keras import layers,Sequential,losses,optimizers,datasets
#创建4层全连接网络
model=keras.Sequential([
layers.Dense(256,activation='relu'),
layers.Dense(256,activation='relu'),
layers.Dense(256,activation='relu'),
layers.Dense(10)
])
#build模型,并打印模型信息
model.build(input_shape=(4,784))
model.summary()
这是一个简单的4层全连接神经网络,模型各层参数分别为200960,65792,65792,2570,总参数量为335K,约占内存1.34MB。实际上,网络的训练过程还需要缓存计算图模型、梯度信息、输入和中间计算结果等等。由此可见,全连接层较高的内存占有量严重限制了神经网络朝着更深层数的发展。
Dense层的连接方式是全连接层参数量大、计算代价高的根本原因。
3、局部相关性
考虑输入节点对输出节点的重要性分布,输出节点只与最重要的一部分节点相连。在现实生活中存在着大量以位置、距离为重要性分布衡量标准的数据。如2D图片数据,假设与当前像素点欧氏距离<=k/√2的重要性较高。基于距离重要性分布假设称为局部相关性,他只关注和自己距离较近的部分节点,而忽略距离较远的节点。在这种思想下,输出节点j只与以j为中心的局部区域(感受野)相连接(k×k)。
4、权值共享
对于每个输出节点0j,均使用相同的权值矩阵W,无论输出节点的数量是多少,网络层的参数是k×k。在计算某个位置的输出像素时,将W与对应感受野内部的像素相乘累加,作为该位置的像素输出值。这种局部连接、共享权重的网络,就是卷积神经网络。
5、卷积
离散卷积运算:权值相乘累加
卷积的卷是指翻转平移操作,积是积分运算,1D连续卷积定义为:
离散卷积将卷积变成累加运算:
2D卷积定义为:
在深度学习中,权值函数g(m,n)称为卷积核(Kernel)。
2D离散卷积运算流程:每次通过移动卷积核窗口与图片对应位置处的像素相乘累加,得到此位置的输出值。
卷积神经网络通过充分利用局部相关性和权值共享的思想,大大减少了网络的参数量,从而提高训练效率,更容易实现超大规模的深度网络。
1、单通道输入,单卷积核合
2、多通道输入,单卷积核
卷积核的通道数需要与输入X的通道数相匹配,卷积核的第i个通道和X的第i个通道相运算,得到第i个中间矩阵所有通道的中间矩阵对应元素再次相加,作为最终输出。
3、多通道输入,多卷积核
每个卷积核的大小k,步长s,填充设定等都是统一设置,这样才能保证输出的每个通道的大小一致,从而满足拼接条件。
4、步长
感受野密度的控制手段一般是通过移动步长(Strides)实现的。
步长是指感受野窗口每次移动的长度单位。
5、填充
在网络模型设计时,有时希望输出O的高宽能够与输入X的高宽相同,从而方便网络参数的设计,残差连接等。
一般通过在原始输入X的高宽维度上进行填充(Padding)若干无效元素(默认为0)操作。
卷积神经层的输出尺寸[b,h’,w’,c]由卷积核数量c,卷积核大小k,步长s,填充数p以及输入X的高宽h/w共同决定,数学关系为:
h’=(h+2ph-k)/s+1, w’=(w+2pw-k)/s+1,向下取整。
通过设置参数padding=‘SAME’,strides=1可以直接得到输入输出同大小的卷积层。当s>1时,设置padding=‘SAME’将使得输出高宽减少1/s倍地减少
6、卷积层实现
卷积层类layers.Conv2D
import tensorflow as tf
from tensorflow.keras import layers
layer=layers.Conv2D(4,kernel_size=3,strides=1,padding='SAME')
x=tf.random.normal([2,5,5,3])
#layer=layers.Conv2D(4,kernel_size=(3,4),strides=(2,1),padding='SAME')
out=layer(x)
out.shape
layer.trainable_variables#返回Conv2D类维护的W,b张量
基于MNIST手写数字图片数据集训练LeNet-5网络,并测试其最终准确度。
from tensorflow.keras import Sequential,layers,optimizers,losses,datasets
network=Sequnential([
layers.Conv2D(6,kernel_size=3,strides=1),
layers.MaxPooling2D(pool_size=2,strides=2),
layers.ReLU(),
layers.Conv2D(16,kernel_size=3,strides=1),
layers.MaxPooling2D(pool_size=2,strides=2),
layers.ReLU(),
layers.Flatten(),
layers.Dense(120,activation='relu'),
layers.Dense(84,activation='relu'),
layers.Dense(10)
])
network.build(input_shape=(4,28,28,1))
network.summary()
Model: "sequential_5"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_8 (Conv2D) multiple 60
_________________________________________________________________
max_pooling2d_4 (MaxPooling2 multiple 0
_________________________________________________________________
re_lu_4 (ReLU) multiple 0
_________________________________________________________________
conv2d_9 (Conv2D) multiple 880
_________________________________________________________________
max_pooling2d_5 (MaxPooling2 multiple 0
_________________________________________________________________
re_lu_5 (ReLU) multiple 0
_________________________________________________________________
flatten_1 (Flatten) multiple 0
_________________________________________________________________
dense_18 (Dense) multiple 48120
_________________________________________________________________
dense_19 (Dense) multiple 10164
_________________________________________________________________
dense_20 (Dense) multiple 850
=================================================================
Total params: 60,074
Trainable params: 60,074
Non-trainable params: 0
#训练
criteon=losses.CategoricalCrossentropy(from_logits=True)
with tf.GradientTape() as tape:
x=tf.expand_dims(x,axis=3)
out=network(x)
y_onehot=tf.one_hot(y,depth=10)
loss=criteon(y_onehot,out)
grads=tape.gradient(loss,network.trainable_variables)
optimizer.apply_gradients(zip(grads,network.trainable_variables))
correct,total=0,0
for x,y in db_test:
x=tf.expand_dims(x,axis=3)
out=network(x)
pred=tf.argmax(out,axis=-1)
y=tf.cast(y,tf.int64)
correct+=float(tf.reduce_sum(tf.equal(pred,y),tf.float32))
total+=x.shape[0]
print('test acc:',correct/total)
池化层的主要目的是降低总体的特征数量,防止过度拟合和减少计算量。通过降采样的方式,在不影响图像质量的情况下,压缩图片,减少参数。
通常来说,池化方法一般有一下两种:
1.MaxPooling:取滑动窗口里最大的值
2.AveragePooling:取滑动窗口内所有值的平均值