继续接着上两篇的内容:
深度学习中的损失函数1
深度学习中的损失函数2
还是权当个人学习笔记来记录的。
一.归一化/标准化
从定义上来讲,归一化是指把数据转化为长度为1或者原点附近的小区间,而标准化是指将数据转化为均值为0,标准差为1的数据。。归一化与标准化实质上都是某种数据变化,无论是线性变化还是非线性变化,其都不会改变原始数据中的数值排序,它们都能将特征值转换到同一量纲下。由于归一化是将数据映射到某一特定区间内,因此其缩放范围仅由数据中的极值决定,而标准化是将源数据转化为均值为0,方差为1的分布,其涉及计算数据的均值和标准差,每个样本点都会对标准化过程产生影响。
在深度学习中,使用归一化/标准化后的数据可以加快模型的收敛速度,其有时还能提高模型的精度,这在涉及距离计算的模型中尤为显著,在计算距离时,若数据的量纲不一致,则最终计算结果会更偏向极差大的数据。由于数值层面被减小,在计算机进行计算时,一方面可以防止模型的梯度过大(爆炸),另一方面也能避免一些由于太大的数值引起的数值问题。
二.归一化方法
2.1最小-最大值归一化
2.2均值归一化
2.3对数函数归一化
2.4反正切函数归一化
三.标准化方法
3.1Z-score标准化
常用于数据预处理,需要先计算所有样本数据的均值与标准差然后再对样本进行变化。
3.2Batch Normalization
代码语言:javascript复制def batch_normalization(inp,
name,
weight1=0.99,
weight2=0.99,
is_training=True):
with tf.variable_scope(name):
# 获取输入张量的形状
inp_shape = inp.get_shape().as_list()
# 定义不可训练变量hist_mean记录均值的移动平均值
# 形状与输入张量最后一个维度相同
hist_mean = tf.get_variable('hist_mean',
shape=inp_shape[-1:],
initializer=tf.zeros_initializer(),
trainable=False)
# 定义不可训练变量hist_var记录方差的移动平均值
# 形状与输入张量最后一个维度相同
hist_var = tf.get_variable('hist_var',
shape=inp_shape[-1:],
initializer=tf.ones_initializer(),
trainable=False)
# 定义可训练变量gamma和beta,形状与输入张量最后一个维度相同
gamma = tf.Variable(tf.ones(inp_shape[-1:]), name='gamma')
beta = tf.Variable(tf.zeros(inp_shape[-1:]), name='beta')
# 计算输入张量除了最后一个维度外上面的均值与方差
batch_mean, batch_var = tf.nn.moments(inp,
axes=[i for i in range(len(inp_shape) - 1)],
name='moments')
# 计算均值的移动平均值,并将计算结果赋予hist_mean/running_mean
running_mean = tf.assign(hist_mean,
weight1 * hist_mean (1 - weight1) * batch_mean)
# 计算方差的移动平均值,并将计算结果赋予hist_var/running_var
running_var = tf.assign(hist_var,
weight2 * hist_var (1 - weight2) * batch_var)
# 使用control_dependencies限制先计算移动平均值
with tf.control_dependencies([running_mean, running_var]):
# 根据当前状态是训练或是测试选取不同的值进行标准化
# is_training=True,使用batch_mean & batch_var
# is_training=False,使用running_mean & running_var
output = tf.cond(tf.cast(is_training, tf.bool),
lambda: tf.nn.batch_normalization(inp,
mean=batch_mean,
variance=batch_var,
scale=gamma,
offset=beta,
variance_epsilon=1e-5,
name='bn'),
lambda: tf.nn.batch_normalization(inp,
mean=running_mean,
variance=running_var,
scale=gamma,
offset=beta,
variance_epsilon=1e-5,
name='bn')
)
return output
def _batch_normalization(inp, name, weight1=0.99, weight2=0.99, is_training=True):
with tf.variable_scope(name):
return tf.layers.batch_normalization(
inp,
training=is_training
)
3.3Layer Normalization
代码语言:javascript复制import tensorflow.compat.v1 as tf
def layer_normalization(inp, name):
with tf.variable_scope(name):
# 获取输入张量的形状
inp_shape = inp.get_shape().as_list()
# 定义可训练变量gamma和beta,batch维度与输入张量第一个维度相同
para_shape = [inp_shape[0]] [1] * (len(inp_shape) - 1)
gamma = tf.Variable(tf.ones(para_shape, name='gamma'))
beta = tf.Variable(tf.zeros(para_shape, name='beta'))
# 计算输入张量除了第一个维度外上面的均值与方差
layer_mean, layer_var = tf.nn.moments(inp,
axes=[i for i in range(1, len(inp_shape))],
name='moments', keep_dims=True)
output = gamma * (inp - layer_mean) / tf.sqrt(layer_var 1e-5) beta
return output
if __name__ == "__main__":
a = tf.ones([128, 10, 10, 3])
b = layer_normalization(a, name='ln')
print(b.shape)
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(b))
3.4Instance Normalization
代码语言:javascript复制import tensorflow.compat.v1 as tf
def instance_normalization(inp, name):
with tf.variable_scope(name):
# 获取输入张量的形状
inp_shape = inp.get_shape().as_list()
# 定义可训练变量gamma和beta,形状为[n,1,1,c]方便直接线性变换
para_shape = [inp_shape[0], 1, 1, inp_shape[-1]]
gamma = tf.Variable(tf.ones(para_shape, name='gamma'))
beta = tf.Variable(tf.zeros(para_shape, name='beta'))
# 计算输入张量第一(H)和第二(W)维度外上面的均值与方差
insta_mean, insta_var = tf.nn.moments(inp,
axes=[1,2],
name='moments', keep_dims=True)
output = gamma * (inp - insta_mean) / tf.sqrt(insta_var 1e-5) beta
return output
if __name__ == "__main__":
a = tf.ones([128, 10, 10, 3])
b = instance_normalization(a, name='in')
print(b.shape)
with tf.Session() as sess:
tf.global_variables_initializer().run()
print(sess.run(b))
3.5Group Normalization
代码语言:javascript复制import tensorflow.compat.v1 as tf
def group_normalization(inp, name, G=32):
with tf.variable_scope(name):
# 获取输入张量的形状
insp = inp.get_shape().as_list()
# 将输入的NHWC格式转换为NCHW方便进行分组
inp = tf.transpose(inp, [0, 3, 1, 2])
# 将输入张量进行分组,得到新张量形状为[n,G,c//G,h,w]
inp = tf.reshape(inp,
[insp[0], G, insp[-1] // G, insp[1], insp[2]])
# 定义可训练变量gamma和beta,形状为[1,1,1,c]方便直接线性变换
para_shape = [1, 1, 1, insp[-1]]
gamma = tf.Variable(tf.ones(para_shape, name='gamma'))
beta = tf.Variable(tf.zeros(para_shape, name='beta'))
# 计算输入张量第二、三和四(c//G,h,w)维度外上面的均值与方差
group_mean, group_var = tf.nn.moments(inp,
axes=[2, 3, 4],
name='moments', keep_dims=True)
inp = (inp - group_mean) / tf.sqrt(group_var 1e-5)
# 将张量形状还原为原始形状[n,h,w,c]
# 先将标准化之后的分组结果重新组合为[n,c,w,h]
inp = tf.reshape(inp,
[insp[0], insp[-1], insp[1], insp[2]])
# 通过转置操作将NCHW格式转换为NHWC
inp = tf.transpose(inp, [0, 2, 3, 1])
output = gamma * inp beta
return output
if __name__ == "__main__":
import numpy as np
a = tf.constant(np.random.randn(1,2,2,64), dtype=tf.float32)
b = group_normalization(a, name='gn1')
with tf.Session() as sess:
tf.global_variables_initializer().run()
rb = sess.run(b)
print(rb)
3.6 Switchable Normalization
switchable Normalization的目的则是使模型自动学会最适合的一种标准化策略。