(python源码)小案例:归一化_零均值的作用

归一化_零均值的作用


1.通过一个简单的小案例讲解下,为什么归一化后,训练速度会增加。

2. 案例很简单,将蓝色的小正方行通过旋转、缩放后变换为红色正方形。

变量(Variable):旋转角度angle_、缩放系数scale_。

(python源码)小案例:归一化_零均值的作用_第1张图片


3.直接上图,说出迭代的结论

3.1 下面两幅图为“变量与loss的关系图”,一系列的黑点代表变量的迭代过程,一个红点代表最优loss位置。

3.2 该图表示“没有进行归一化”,

    可以看出,angle_变量的梯度很大,scale_变量的梯度很小,图像很尖锐。

    由于angle_变量的梯度非常大,所以学习率要设置非常小,否则会不收敛。

    然而,scale_变量的梯度又过于小,在很小的学习率上收敛的速度非常慢,经过很多轮迭代才能找到最优点。

迭代次数:1500次,误差率 : 0.058%

(python源码)小案例:归一化_零均值的作用_第2张图片

3.3 该图表示“进行归一化”,

    可以看出,angle_变量、scale_变量的梯度分配比较均匀,图像趋于平滑。

迭代次数:300次,误差率 :0.003%

(python源码)小案例:归一化_零均值的作用_第3张图片


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

你可能感兴趣的:((python源码)小案例:归一化_零均值的作用)