归一化_零均值的作用
1.通过一个简单的小案例讲解下,为什么归一化后,训练速度会增加。
2. 案例很简单,将蓝色的小正方行通过旋转、缩放后变换为红色正方形。
变量(Variable):旋转角度angle_、缩放系数scale_。
3.直接上图,说出迭代的结论
3.1 下面两幅图为“变量与loss的关系图”,一系列的黑点代表变量的迭代过程,一个红点代表最优loss位置。
3.2 该图表示“没有进行归一化”,
可以看出,angle_变量的梯度很大,scale_变量的梯度很小,图像很尖锐。
由于angle_变量的梯度非常大,所以学习率要设置非常小,否则会不收敛。
然而,scale_变量的梯度又过于小,在很小的学习率上收敛的速度非常慢,经过很多轮迭代才能找到最优点。
迭代次数:1500次,误差率 : 0.058%
3.3 该图表示“进行归一化”,
可以看出,angle_变量、scale_变量的梯度分配比较均匀,图像趋于平滑。
迭代次数:300次,误差率 :0.003%
4. python源码
# encoding:utf-8
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
pi = 3.1415926535898 #定义圆周率
min_angle,max_angle = -3.0,3.0 #定义绘图时,angle坐标的范围
min_scale,max_scale = 0.0,6.0 #定义绘图时,scale坐标的范围
#获取数据
def get_data():
triangle_1 = np.array([[2.0,2.0],[2,1.5],[2,1],[2,0.5],[2,0],[2.5,0],[3,0],[3.5,0],[4,0],[4,0.5],[4,1],[4,1.5],[4,2],[3.5,2],[3,2],[2.5,2]])
angle_ = 0.25
rotate_mat = [[np.cos(angle_*pi),-np.sin(angle_*pi)],
[np.sin(angle_*pi), np.cos(angle_*pi)]]
triangle_2 = np.dot(triangle_1,rotate_mat)
triangle_2 = triangle_2*5
return triangle_1 , triangle_2
#归一化:零均值,乘以标准差
def get_mean_std(in_x,in_y):
return (in_x - np.mean(in_x,axis=0))/np.std(in_x,axis=0),(in_y - np.mean(in_y,axis=0))/np.std(in_y,axis=0)
#前向传播函数
def forward_p(x_):
scale_ = tf.Variable(3.5) #缩放系数
angle_ = tf.Variable(1.5) #绕原点(0,0)旋转的角度
# rotate_mat: 旋转变化矩阵
rotate_mat = [[tf.cos(angle_*pi),-tf.sin(angle_*pi)],
[tf.sin(angle_*pi),tf.cos(angle_*pi)]]
#返回经过旋转和缩放后的x_
return tf.matmul(x_,rotate_mat)*scale_,angle_,scale_
#训练,返回每一轮迭代后的(变量值,对应的loss_值)
def train(x_input,y_input,iter_times,learning_rate):
x_ = tf.constant(x_input,dtype=tf.float32)
y_ = tf.constant(y_input,dtype=tf.float32)
predict_,angle_,scale_ = forward_p(x_) #获取预测值
loss_ = tf.reduce_mean(tf.square(y_-predict_)) #loss计算
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss_)
iter_points = np.zeros((iter_times,3))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
for i in range(iter_times):
iter_points[i,0] = sess.run(angle_)
iter_points[i,1] = sess.run(scale_)
iter_points[i,2] = sess.run(loss_)
sess.run(train_step)
return iter_points
#生成高密度(变量值_loss)数据,用于绘制曲面
def surface_data(x_input,y_input):
angle_arr = np.linspace(min_angle,max_angle,50)
scale_arr = np.linspace(min_scale,max_scale,50)
scale_arr,angle_arr = np.meshgrid(scale_arr,angle_arr)
loss_arr = np.zeros(scale_arr.shape)
for i in range(50):
for j in range(50):
angle_ = angle_arr[i][j]
rotate_mat = [[np.cos(angle_*pi),-np.sin(angle_*pi)],
[np.sin(angle_*pi), np.cos(angle_*pi)]]
predict_ = np.dot(x_input,rotate_mat)*scale_arr[i][j]
loss_arr[i][j] = np.mean(np.square(y_input - predict_))
return angle_arr,scale_arr,loss_arr
#绘制loss曲面、序列迭代点
def plot_(triangle_1,triangle_2,iter_points,norm_ = True):
angle_,scale_,loss_ = iter_points[:,0],iter_points[:,1],iter_points[:,2]
angle_arr,scale_arr,loss_arr = surface_data(triangle_1,triangle_2)
ax = Axes3D(plt.figure())
ax.plot_surface(angle_arr,scale_arr,loss_arr,alpha = 0.4)
ax.scatter(angle_,scale_,loss_,s=10, c='black', marker=".")
if norm_:
ax.scatter(2.25,1.0,0.1,s=100, c='red', marker=".") #有归一化,最优点的位置
else:
ax.scatter(2.25,5.0,0,s=100, c='red', marker=".") #无归一化,最优点的位置
ax.set_xlabel('angle_')
ax.set_ylabel('scale_')
ax.set_zlabel('loss_')
plt.savefig("img1.png")
plt.show()
plt.close()
#norm:bool类型,是否归一化; circle_:迭代轮数;learning_rate:学习率
def solve(norm_,circle_,learning_rate):
triangle_1 , triangle_2 = get_data()
if norm_:
triangle_1 , triangle_2 = get_mean_std(triangle_1 , triangle_2)
iter_points = train(triangle_1,triangle_2,circle_,learning_rate)
if norm_:
print "err_with_normaliztion:" ,iter_points[circle_-1,2]/np.mean(np.square(triangle_2))
else:
print "err_without_normaliztion:" ,iter_points[circle_-1,2]/np.mean(np.square(triangle_2))
plot_(triangle_1,triangle_2,iter_points,norm_)
def main():
solve(True,300,0.01) #归一化后的效果
solve(False,1500,0.00015) #无归一化的效果
if __name__ == "__main__":
main()
转载请注明出处:https://blog.csdn.net/m0_38097087/article/details/80116949