卷积神经网络基础
一、卷积神经网络
1. 为什么不将图像搞成向量用DNN来处理?
因为全连接层参数量大、损失相邻像素点的关系、不能学习图像里一些公共的模式。
2. 卷积神经网络采用了什么思想?
- 局部连接(Local Connection):每个神经元只与上一层的一个局部区域连接。
- 权值共享(Weight Sharing):当前层在深度方向上每个channel的神经元都使用同样的权重和偏差,这里考虑的是如果一个特征在计算某个空间位置(x,y)的时候有用,那么它在计算另一个不同位置(x2,y2)的时候也有用。
3. 好处
- 降低了参数量,使训练复杂度大大下降,并减轻了过拟合。
- 权值共享还赋予了卷积网络对平移的容忍性。
4. 主要构成
卷积层、池化层、全连接层、padding操作、stride操作
5. 主要模型
LeNet、AlexNet、GoogleNet、VGG、ResNet
二、卷积层
各种卷积层可以参考 Kunlun Bai 发布在TowardsDataScience上的A Comprehensive Introduction to Different Types of Convolutions in Deep Learning,有人将文章中部分翻译成中文版。
1. 卷积 vs 互相关
卷积,在信号/图像处理领域是两个函数中一个函数经过反转和位移后再相乘得到的积的积分,定义式为:
互相关,是不经过反转,直接位移对应点相乘相加,二者的区别如下图(取自https://zhuanlan.zhihu.com/p/57575810)
关系:深度学习里的卷积并没有经过反转,因此其实是互相关。
2. 1D卷积、2D 卷积 、3D 卷积
1D卷积,过滤器深度和宽度与输入层深度和宽度一样、过滤器高度小于输入层高度,过滤器仅沿图像的高这一个方向移动,输出时一个仅有一个通道且宽为1的1D向量,通常用于NLP中对n-gram词向量的处理,过滤器的高度即n-gram中的n。
2D 卷积,过滤器深度与输入层深度一样(可以是多通道),过滤器仅沿图像的高和宽两个方向移动,输出是一张仅有一个通道的 2D 图像,通常用于对二维图像或彩色图像的处理。
3D卷积,过滤器深度小于输入层深度,在图像的高度、宽度、通道三个方向上移动,输出是一个 3D 数据,通常用于对视频的处理,引入时间维。3D卷积如下图所示(取自https://zhuanlan.zhihu.com/p/57575810)
关系:3D卷积是 2D 卷积的泛化,区分二者的关键是过滤器深度是否小于输入层深度,而非由输入图像(或者卷积核)是2D还是3D来决定。
3. 转置卷积(fractionally strided convolution),又称去卷积(deconvolution),但建议用转置卷积命名
转置卷积,上采样,如生成高分辨率图像以及将低维特征图映射到高维空间。将 2×2 的输入(填充后)上采样成 4×4和5×5的输出的示意图如下图所示(取自https://zhuanlan.zhihu.com/p/57575810)
转置卷积的名字来源:由卷积的C*Large=Small操作变为C^T*Small=Large(取自https://zhuanlan.zhihu.com/p/57575810)
去卷积,在信号处理中是卷积运算的逆运算,但在深度学习里并不是这样,所以最好不要用这个名字。
4. 其他卷积
扩张卷积(Atrous卷积)、可分卷积(空间可分卷积,深度可分卷积)、平展卷积、分组卷积、混洗分组卷积、逐点分组卷积等见https://zhuanlan.zhihu.com/p/57575810
三、池化层
池化层是为了下采样、减少参数、具有一定的防止过拟合的作用,通常有最大池化和平均池化两种。
四、CNN-Text采用1D卷积的TensorFlow模型
模型就是很简单的embedding -> lookup tabel -> conv1d -> 1D maxpooling -> FC1 -> FC2
来自https://github.com/gaussic/text-classification-cnn-rnn/blob/master/run_cnn.py
# coding: utf-8
import tensorflow as tf
class TCNNConfig(object):
"""CNN配置参数"""
embedding_dim = 64 # 词向量维度
seq_length = 600 # 序列长度
num_classes = 10 # 类别数
num_filters = 256 # 卷积核数目
kernel_size = 5 # 卷积核尺寸
vocab_size = 5000 # 词汇表达小
hidden_dim = 128 # 全连接层神经元
dropout_keep_prob = 0.5 # dropout保留比例
learning_rate = 1e-3 # 学习率
batch_size = 64 # 每批训练大小
num_epochs = 10 # 总迭代轮次
print_per_batch = 100 # 每多少轮输出一次结果
save_per_batch = 10 # 每多少轮存入tensorboard
class TextCNN(object):
"""文本分类,CNN模型"""
def __init__(self, config):
self.config = config
# 三个待输入的数据
self.input_x = tf.placeholder(tf.int32, [None, self.config.seq_length], name='input_x')
self.input_y = tf.placeholder(tf.float32, [None, self.config.num_classes], name='input_y')
self.keep_prob = tf.placeholder(tf.float32, name='keep_prob')
self.cnn()
def cnn(self):
"""CNN模型"""
# 词向量映射
with tf.device('/cpu:0'):
embedding = tf.get_variable('embedding', [self.config.vocab_size, self.config.embedding_dim])
embedding_inputs = tf.nn.embedding_lookup(embedding, self.input_x)
with tf.name_scope("cnn"):
# CNN layer
conv = tf.layers.conv1d(embedding_inputs, self.config.num_filters, self.config.kernel_size, name='conv')
# global max pooling layer
gmp = tf.reduce_max(conv, reduction_indices=[1], name='gmp')
with tf.name_scope("score"):
# 全连接层,后面接dropout以及relu**
fc = tf.layers.dense(gmp, self.config.hidden_dim, name='fc1')
fc = tf.contrib.layers.dropout(fc, self.keep_prob)
fc = tf.nn.relu(fc)
# 分类器
self.logits = tf.layers.dense(fc, self.config.num_classes, name='fc2')
self.y_pred_cls = tf.argmax(tf.nn.softmax(self.logits), 1) # 预测类别
with tf.name_scope("optimize"):
# 损失函数,交叉熵
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits=self.logits, labels=self.input_y)
self.loss = tf.reduce_mean(cross_entropy)
# 优化器
self.optim = tf.train.AdamOptimizer(learning_rate=self.config.learning_rate).minimize(self.loss)
with tf.name_scope("accuracy"):
# 准确率
correct_pred = tf.equal(tf.argmax(self.input_y, 1), self.y_pred_cls)
self.acc = tf.reduce_mean(tf.cast(correct_pred, tf.float32))