avatar

目录
cnn

https://www.cnblogs.com/pinard/p/6489633.html

https://www.cnblogs.com/pinard/p/6494810.html

特征图

  1. 数据输入层:Input Layer
  2. 卷积计算层:CONV Layer
    ReLU激励层:ReLU Incentive Layer
    池化层:Pooling Layer 下采样
  3. 全连接层:FC Layer -分类,回归
    备注:Batch Normalization Layer(必备)
    结构:输入层–{[卷积层+批归一化+激活函数+dropout(可选)]*N-池化层}*M–拉平层–[FC+批归一化+激活]*K–输出层–激活函数(分类用:softmax或sigmoid)

卷积神经网络-Input Layer:

分类:one-hot 哑编码

回归:z-score

和神经网络/机器学习一样,需要对输入的数据需要进行预处理操作,需要进行预处理的主要原因是:
输入数据单位不一样,可能会导致神经网络收敛速度慢,训练时间长
数据范围大(方差大)的输入在模式分类中的作用可能偏大,而数据范围小的作用就有可能偏小
由于神经网络中存在的激活函数是有值域限制的,因此需要将网络训练的目标数据映射到激活函数的值域
S形激活函数在(-4, 4)区间以外区域很平缓,区分度太小。例如S形函数f(X),f(100)与f(5)只相差0.0067

常见3种数据预处理方式
去均值
将输入数据的各个维度中心化到0
归一化 (0,255) (0,1)
将输入数据的各个维度的幅度归一化到同样的范围
PCA/白化
用PCA降维(去掉特征与特征之间的相关性)
白化是在PCA的基础上,对转换后的数据每个特征轴上的幅度进行归一化
http://ufldl.stanford.edu/wiki/index.php/白化

卷积计算层:CONV Layer
局部关联:每个神经元看做一个filter/kernel
窗口(receptive field–感受野)滑动,filter对局部数据进行计算
相关概念
输入特征图的深度: depth == channel
卷积核大小(滤波器): kernel size 11 3/3
输出深度==卷积核个数
步幅:stride(取值:1 2 4 ) 影响输出图片的高和宽
填充值:zero-padding
填充方式:same 或者 valid
CONV过程参考:http://cs231n.github.io/assets/conv-demo/index.html

Code
"""
tf.nn.conv2d(input, # 卷积的输入,必须是一个4-D tensor对象
filter, # 滤波器
strides, # 步幅
padding, # 填充方式 string: 'SAME' or 'VALID'
data_format="NHWC", # 对输入数据格式的要求,[N, height, width, channels]; 也可以是另一种格式:"NCHW"
dilations=[1, 1, 1, 1], #扩大感受野
name=None)
"""
或者
conv_output1 = tf.layers.conv2d(
inputs=input_x, kernel_size=7, filters=20, strides=2, padding='valid',
use_bias=True
)

池化层:

Code
"""
max_pool(value, # 也是4-D tensors [N, height, width, channels]
ksize, # 池化核大小
strides, # 池化步幅大小
padding, # 填充方式
data_format="NHWC", # 对输入数据格式的约定,也可以是另一种格式:"NCHW"
name=None)
"""

卷积神经网络-参数初始化:

在卷积神经网络中,可以看到神经元之间的连接是通过权重w以及偏置b实现的。在具体的神经网络之前,我们还有一个任务需要做,那就是初始化参数
权重的初始化(截尾正态分布 标准差为(经验分布)1n\frac{1}{\sqrt{n}}或者0.1)2

​ 一般方式:很小的随机数(对于多层深度神经网络,太小的值会导致回传的梯度非常小),一般随机数是服从均值为0,方差未知(建议:2/n, n为权重数量,https://arxiv.org/pdf/1502.01852.pdf)的高斯分布随机数列。
错误方式:全部初始化为0,全部设置为0,在反向传播的时候是一样的梯度值,那么这个网络的权重是没有办法差异化的,也就没有办法学习到东西。
偏置项的初始化
​ 一 般直接设置为0,在存在ReLU激活函数的网络中,也可以考虑设置为一个很小的数字

卷积神经网络正则化和Dropout

神经网络的学习能力受神经元数目以及神经网络层次的影响,神经元数目越大,神经网络层次越高,那么神经网络的学习能力越强,那么就有可能出现过拟合的问题;(通俗来讲:神经网络的空间表达能力变得更紧丰富了)
Regularization:正则化,通过降低模型的复杂度,通过在cost函数上添加一个正则项的方式来降低overfitting,主要有L1和L2两种方式

Dropout:通过随机删除神经网络中的神经元来解决overfitting问题,在每次迭代的时候,只使用部分神经元训练模型获取W和d的值,参考:《Dropout: A Simple Way to Prevent Neural Networks from Overfitting》

4

3

模型保存与恢复持久化训练

python
def create_file_path(dir_path):
"""
创建文件夹函数
:param dir_path:
:return:
"""
if not os.path.exists(dir_path):
os.makedirs(dir_path)
print('创建文件夹:{}'.format(dir_path))
Code
# 6、构建持久化对象
CKECKPOINT_DIR = './model/ai13'
create_file_path(CKECKPOINT_DIR)
saver = tf.train.Saver(max_to_keep=1)
Code
#持久化模型
checkpoints_file = 'model_{}'

全部代码:Mnist数据集cnn分类

Code
import os
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets(
'../datas/mnist', one_hot=True, reshape=False)
print(mnist.train.num_examples)

# 超参数设置
lr = 1e-2
epochs = 10
batch_size = 256
test_valid_size = 512 # 验证或者测试样本的数量
num_classes = 10 # 类别数量
keep_prob = 0.7 # dropout保留概率, 丢弃概率=1-0.7 = 0.3

"""
网络结构图
input [N, 28, 28, 1]
Conv1 weights=[5, 5, 1, 32] S=1 ---> [N, 28, 28, 32]
MaxPool1 kernel_size=[1, 2, 2, 1] S=2 ---> [N, 28/2, 28/2, 32]
Conv2 weights=[5, 5, 32, 64] S=1 ---> [N, 28/2, 28/2, 64]
MaxPool2 kernel_size=[1, 2, 2, 1] S=2 ---> [N, 28/4, 28/4, 64]

Flatten [N, 28/4, 28/4, 64] 4-D ---> [N, 7*7*64] 2-D
FC1 Weights=[7*7*64, 1024] ---> [N, 1024]
FC2 Weights=[1024, 10] ---> [N, 10]
"""
# 构建模型图 1、创建变量
graph = tf.Graph()
with graph.as_default():
weights = {
'conv1': tf.get_variable('w1', shape=[5, 5, 1, 32], initializer=tf.truncated_normal_initializer(stddev=0.1)),
'conv2': tf.get_variable('w2', shape=[5, 5, 32, 64], initializer=tf.truncated_normal_initializer(stddev=0.1)),
'fc1': tf.get_variable('w3', shape=[7*7*64, 1024], initializer=tf.truncated_normal_initializer(stddev=0.1)),
'fc2': tf.get_variable('w4', shape=[1024, num_classes], initializer=tf.truncated_normal_initializer(stddev=0.1))
}
biases = {
'conv1': tf.get_variable('b1', shape=[32], initializer=tf.zeros_initializer()),
'conv2': tf.get_variable('b2', shape=[64], initializer=tf.zeros_initializer()),
'fc1': tf.get_variable('b3', shape=[1024], initializer=tf.zeros_initializer()),
'fc2': tf.get_variable('b4', shape=[num_classes], initializer=tf.zeros_initializer())
}


def conv2d(input_tensor, filter_w, filter_b, strides=[1, 1, 1, 1]):
"""
实现 卷积 + 偏置项相加 + 激活函数
:param input_tensor: 输入
:param filter_w: 卷积核变量
:param filter_b: 偏置项
:param strides: 步幅
:return:
"""
# 1、卷积
conv = tf.nn.conv2d(
input=input_tensor, filter=filter_w, strides=strides, padding='SAME'
)
# 2、偏置项相加
conv = tf.nn.bias_add(conv, filter_b)
# 3、激活
conv = tf.nn.relu(conv)
return conv


def maxpool2d(input_tensor, k=2):
kernel_size = [1, k, k, 1]
strides = [1, k, k, 1]
maxpool_out = tf.nn.max_pool(
value=input_tensor, ksize=kernel_size, strides=strides, padding='SAME'
)
return maxpool_out


def fully_connect(input_tensor, weights, biases, activation=tf.nn.relu):
"""
实现全连接 + 偏置项相加 + 激活
:param input_tensor:
:param weights:
:param biases:
:param activation:
:return:
"""
fc = tf.matmul(input_tensor, weights) + biases
if activation:
fc = activation(fc)
return fc
else:
# 这里是为了返回最终输出的logits。
return fc

"""
网络结构图
input [N, 28, 28, 1]
Conv1 weights=[5, 5, 1, 32] S=1 ---> [N, 28, 28, 32]
MaxPool1 kernel_size=[1, 2, 2, 1] S=2 ---> [N, 28/2, 28/2, 32]
Conv2 weights=[5, 5, 32, 64] S=1 ---> [N, 28/2, 28/2, 64]
MaxPool2 kernel_size=[1, 2, 2, 1] S=2 ---> [N, 28/4, 28/4, 64]
Flatten [N, 28/4, 28/4, 64] 4-D ---> [N, 7*7*64] 2-D
FC1 Weights=[7*7*64, 1024] ---> [N, 1024]
FC2 Weights=[1024, 10] ---> [N, 10]
"""

def model(input_x, weights, biases, keep_prob):
"""
搭建CNN网络,返回logits
:param input_x: 模型输入,是占位符
:param weights:
:param biases:
:return:
"""
with tf.variable_scope('Network'):
# 卷积1 [N, 28, 28, 1] --> [N, 28, 28, 32]
conv1 = conv2d(
input_tensor=input_x, filter_w=weights['conv1'], filter_b=biases['conv1'])
# 池化1 [N, 28, 28, 32] -->[N, 28/2, 28/2, 32]
pool1 = maxpool2d(conv1)
# 卷积2 [N, 28/2, 28/2, 32] --> [N, 28/2, 28/2, 64]
conv2 = conv2d(
input_tensor=pool1, filter_w=weights['conv2'], filter_b=biases['conv2'])
# 池化2 [N, 28/2, 28/2, 64] -->[N, 28/4, 28/4, 64]
pool2 = maxpool2d(conv2)

# 拉平层 [N, 28/4, 28/4, 64] ---> [N, 7*7*64]
shape = pool2.get_shape() # [N, 7, 7, 64]
flatten_shape = shape[1] * shape[2] * shape[3]
flatted = tf.reshape(pool2, shape=[-1, flatten_shape])

# 全连接层1 [N, 7*7*64] ---> [N, 1024]
fc1 = fully_connect(
input_tensor=flatted, weights=weights['fc1'], biases=biases['fc1'])
fc1 = tf.nn.dropout(fc1, keep_prob=keep_prob)

# 全连接层2(输出层) [N, 1024] ---> [N, 10]
logits = fully_connect(
input_tensor=fc1, weights=weights['fc2'], biases=biases['fc2'], activation=None
)
return logits


def create_file_path(dir_path):
"""
创建文件夹函数
:param dir_path:
:return:
"""
if not os.path.exists(dir_path):
os.makedirs(dir_path)
print('创建文件夹:{}'.format(dir_path))


def train():
"""
构建模型
:return:
"""
with graph.as_default():
# 1、创建占位符
input_x = tf.placeholder(tf.float32, [None, 28, 28, 1], name='input_x')
input_y = tf.placeholder(tf.float32, [None, num_classes], name='input_y')
learning_rate = tf.placeholder(tf.float32, shape=None, name='learning_rate')
keep_probab = tf.placeholder(tf.float32, shape=None, name='keep_probab')

# 2、构建模型
logits = model(input_x, weights, biases, keep_prob=keep_probab)

# 3、构建模型损失
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(
logits=logits, labels=input_y
))
# 可视化代码
tf.summary.scalar('train_loss', loss, collections=['train'])
tf.summary.scalar('valid_loss', loss, collections=['valid'])

# 4、构建模型优化器
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_opt = optimizer.minimize(loss=loss)

# 5、求模型准确率
correct_pred = tf.equal(tf.argmax(logits, 1), tf.argmax(input_y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
# 可视化代码
tf.summary.scalar('train_accuracy', accuracy, collections=['train'])
tf.summary.scalar('valid_accuracy', accuracy, collections=['valid'])

# 6、构建持久化对象
CKECKPOINT_DIR = './model/ai13'
create_file_path(CKECKPOINT_DIR)
saver = tf.train.Saver(max_to_keep=1)

# 二、执行会话
with tf.Session(graph=graph) as sess:
sess.run(tf.global_variables_initializer())
# todo 模型可视化。
train_sum = tf.summary.merge_all('train')
valid_sum = tf.summary.merge_all('valid')

LOG_DIR = './model/graph'
train_writer = tf.summary.FileWriter(LOG_DIR+ '/train_graph', graph=sess.graph)
valid_writer = tf.summary.FileWriter(LOG_DIR+ '/valid_graph')

step = 1
for e in range(epochs):
# 构建批量数据的循环操作
for batch in range(mnist.train.num_examples // batch_size):
# 获取当前批量的数据(该数据已经归一化,且随机打乱的)
batch_x, batch_y = mnist.train.next_batch(batch_size)

feed = {input_x: batch_x, input_y:batch_y,
learning_rate:lr, keep_probab:keep_prob}
sess.run(train_opt, feed_dict=feed) # 执行模型训练
if step % 2 == 0:
feed = {input_x: batch_x, input_y: batch_y,
learning_rate: lr, keep_probab: 1.0}
train_loss, train_acc, train_sum_ = sess.run(
[loss, accuracy, train_sum], feed)
train_writer.add_summary(train_sum_, global_step=step)

val_feed = {input_x: mnist.validation.images[:test_valid_size],
input_y: mnist.validation.labels[:test_valid_size],
keep_probab: 1.0}
val_loss, val_acc, valid_sum_ = sess.run(
[loss, accuracy, valid_sum], val_feed)
valid_writer.add_summary(valid_sum_, global_step=step)
print('Epochs:{} - Step:{} - Train Loss:{:.5f} - Valid Loss:{:.5f} - Valid Acc:{:.5f}'.format(
e, step, train_loss, val_loss, val_acc
))
step += 1
# todo 模型持久化
if step % 50 == 0:
files = 'model.ckpt'
save_files = os.path.join(CKECKPOINT_DIR, files)
saver.save(sess, save_path=save_files, global_step=step)
print('模型成功持久化到文件夹:{}'.format(save_files))
# todo 测试数据集效果
test_feed = {input_x: mnist.test.images[:test_valid_size],
input_y: mnist.test.labels[:test_valid_size],
keep_probab: 1.0}
test_acc = sess.run(accuracy, test_feed)
print('Test Acc:{:.5f}'.format(test_acc))


def restore_train():
"""
恢复模型继续训练
:return:
"""
with graph.as_default():
# 1、创建占位符
input_x = tf.placeholder(tf.float32, [None, 28, 28, 1], name='input_x')
input_y = tf.placeholder(tf.float32, [None, num_classes], name='input_y')
learning_rate = tf.placeholder(tf.float32, shape=None, name='learning_rate')
keep_probab = tf.placeholder(tf.float32, shape=None, name='keep_probab')

# 2、构建模型
logits = model(input_x, weights, biases, keep_prob=keep_probab)

# 3、构建模型损失
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(
logits=logits, labels=input_y
))

# 4、构建模型优化器
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_opt = optimizer.minimize(loss=loss)

# 5、求模型准确率
correct_pred = tf.equal(tf.argmax(logits, 1), tf.argmax(input_y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

# 6、构建持久化对象
CKECKPOINT_DIR = './model/ai13'
saver = tf.train.Saver(max_to_keep=1)

# 二、执行会话
with tf.Session(graph=graph) as sess:
# fixme 恢复模型继续训练.
# 获取持久化对象的信息。
ckpt = tf.train.get_checkpoint_state(CKECKPOINT_DIR)
if ckpt is not None:
saver.restore(sess, ckpt.model_checkpoint_path)
print('成功恢复模型继续训练!')
else:
sess.run(tf.global_variables_initializer())
print('没有持久化的模型,从头随机初始化开始训练!')

step = 1
for e in range(epochs):
# 构建批量数据的循环操作
for batch in range(mnist.train.num_examples // batch_size):
# 获取当前批量的数据(该数据已经归一化,且随机打乱的)
batch_x, batch_y = mnist.train.next_batch(batch_size)

feed = {input_x: batch_x, input_y:batch_y,
learning_rate:lr, keep_probab:keep_prob}
sess.run(train_opt, feed_dict=feed) # 执行模型训练
if step % 2 == 0:
feed = {input_x: batch_x, input_y: batch_y,
learning_rate: lr, keep_probab: 1.0}
train_loss, train_acc = sess.run(
[loss, accuracy], feed)

val_feed = {input_x: mnist.validation.images[:test_valid_size],
input_y: mnist.validation.labels[:test_valid_size],
keep_probab: 1.0}
val_loss, val_acc = sess.run(
[loss, accuracy], val_feed)
print('Epochs:{} - Step:{} - Train Loss:{:.5f} - Valid Loss:{:.5f} - Valid Acc:{:.5f}'.format(
e, step, train_loss, val_loss, val_acc
))
step += 1
# todo 模型持久化
if step % 50 == 0:
files = 'model.ckpt'
save_files = os.path.join(CKECKPOINT_DIR, files)
saver.save(sess, save_path=save_files, global_step=step)
print('模型成功持久化到文件夹:{}'.format(save_files))
# todo 测试数据集效果
test_feed = {input_x: mnist.test.images[:test_valid_size],
input_y: mnist.test.labels[:test_valid_size],
keep_probab: 1.0}
test_acc = sess.run(accuracy, test_feed)
print('Test Acc:{:.5f}'.format(test_acc))


if __name__ == '__main__':
# train()
restore_train()

批归一化:

批归一化BN原理—平滑了损失函数超平面6.6

https://www.cnblogs.com/skyfsm/p/8453498.html

训练集

6.7

对测试集6.8

批归一化在激活函数前 dropout在激活函数后

cnn-Adam优化器

自适应学习率(本质是调整梯度值)

指数移动平均数

Mean t = beta* Mean t-1 + (1-beta) * 当前均值
beta = 0.9 0.99

https://zhuanlan.zhihu.com/p/32335746

6.9

只需保存v这个变量

动量Momentum

tf.train.MomentumOptimizer()

减小震荡,向最优值前进。

能够跳出局部最优(当W_2为0,还有V_2)6.13

2、均方根RMSProp

6.14

tf.train.RMSPropOptimizer()

3、Adam

6.15

tf.train.AdamOptimizer()

批归一化作用

  1. 网络训练更快 – 神经网络每一次迭代都会做大量的计算(正向和反向,以及调整超参数),导致很慢。如果能够更快的收敛,那么整体训练速度自然要快很多。

  2. 允许更大的学习率 – 梯度下降算法要求使用非常小的学习率,网络才能收敛。网络越深,反向传播的梯度也会越小,就需要更多的迭代来学习。批归一化允许我们使用相对来说大一些的学习率,可以加速网络训练。

  3. 权重初始化更容易 – 权重初始化是很难的,特别是当网络越来越来深。批归一化允许我们不用过分关心权重初始化的值。

  4. 使激活函数有更多选择 – 部分激活函数有使用条件限定。Sigmoid不能用于深度网络中,因其丢失梯度过高。 ReLUs经常会梯度消失而导致网络完全停止学习,所以非常小心值域范围(读入激活函数的)。但批归一化对任何进入激活函数的值都做了规范,所以之前在深度网络中表现不好的非线性函数也可以作为备选项了。

  5. 创建深度网络更简单 – 基于1-4原因,使用批归一化创建并训练深度网络更简单。当然网络越深,一般而言,效果越好。

  6. 提供了一些正则化作用 – 批归一化是在网络中增加了一些噪音。实际起了一定的dropout功能,所以在使用了批归一化网络中,可以考虑减少dropout的使用。

  7. 总之,让网络效果更佳 – 有一些测试表明批归一化能够改进网络效果。BN是优化网络速度的手段,而不是提升网络精度的方法。显然,若你可以训练的更快,意味着你可以尝试更多网络设计方案,迭代更多次,也可以构建更深的网络(效果更佳)。最终你通过批归一化达到提升网络效果。

批归一化在批量batch_size很小的情况下会失效

6.116.10

6.12

做位移和缩放时按通道数(4)去做

数据增强

增加训练数据,则能够提升算法的准确率,因为这样可以避免过拟合,而避免了过拟合你就可以增大你的网络结构了。当训练数据有限的时候,可以通过一些变换来从已有的训练数据集中生成一些新的数据,来扩大训练数据。数据增强的方法有:

1)水平翻转(旋转) CNN不具有旋转不变性

2)随机裁剪(crop采样)
如原始图像大小为256256,随机裁剪出一些图像224224的图像。如下图,红色方框内为随机裁剪出的224*224的图片。 AlexNet 训练时,对左上、右上、左下、右下、中间做了5次裁剪,然后翻转,得到一些剪切图片。防止大网络过拟合(under ubstantial overfitting)。

3)样本不均衡(解决方案:增加小众类别的图像数据)
样本不均衡即有些类别图像特别多,有些特别少。类别不平衡数据的处理:Label shuffle。

4)其他
平移变换;
旋转/仿射变换(线性变换+平移);
高斯噪声、模糊处理
对颜色的数据增强:图像亮度、饱和度、对比度变化。

5)训练和测试要协调
在训练的时候,我们通常都需要做数据增强,在测试的时候,我们通常很少去做数据增强。这其中似乎有些不协调,因为你训练和测试之间有些不一致。实验发现,训练的最后几个迭代,移除数据增强,和传统一样测试,可以提升一点性能。
如果训练的时候一直使用尺度和长宽比增强数据增强,在测试的时候也同样做这个变化,随机取32个裁剪图片来测试,也可以在最后的模型上提升一点性能。
就是多尺度的训练,多尺度的测试。

经典网络7.1

GoogleNet

1*1卷积核融合的是通道之间的信息

7.37.4

7-6

融合了不同尺度的特征信息7.2

骨干网络趋势

1.深。ResNet DenseNet

2.宽。Inception Inception-ResNet(宽+深) ResNet(宽+深)

3.卷积的注意力机制。SeNet CBAM Non-local-Net Global Context net

文章作者: Eckle
文章链接: https://wowli-up.github.io/2020/02/03/cnn/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Eckle的个人网站
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论