目录
- 原理
- 代码
- 关于归一化的思考
原理
观察数据可知属性之间差距很大,为了平衡所有的属性对模型参数的影响,首先进行归一化处理。
每一行是一个记录,每一列是个属性,所以对每一列进行归一化。
二维数组归一化:1、循环方式2、广播运算,这里使用广播运算
代码
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
boston_housing =tf.keras.datasets.boston_housing
(train_x,train_y),(test_x,test_y)=boston_housing.load_data()
print(train_x.shape,train_y.shape,test_x.shape,test_y.shape)
num_train =len(train_x)
num_test =len(test_x)
#数据处理
x_train=(train_x-train_x.min(axis=0))/(train_x.max(axis=0)-train_x.min(axis=0))
y_train=train_yx_test=(test_x-test_x.min(axis=0))/(test_x.max(axis=0)-test_x.min(axis=0))
y_test=test_yx0_train=np.ones(num_train).reshape(-1,1)
x0_test=np.ones(num_test).reshape(-1,1)
X_train=tf.cast(tf.concat([x0_train,x_train],axis=1),tf.float32)
X_test=tf.cast(tf.concat([x0_test,x_test],axis=1),tf.float32)
print(X_train.shape,X_test.shape)
#把房价转换成列向量
Y_train =tf.constant(y_train.reshape(-1,1),tf.float32)
Y_test =tf.constant(y_test.reshape(-1,1),tf.float32)
print(Y_train.shape,Y_test.shape)#设置超参数
learn_rate=0.01
#迭代次数
iter=2000
#每10次迭代显示一下效果
display_step=200
#设置模型参数初始值
np.random.seed(612)
W=tf.Variable(np.random.randn(14,1),dtype=tf.float32)
#训练模型
#存放训练误差和泛化误差
mse_train=[]
mse_test=[]
for i in range(0,iter+1):with tf.GradientTape() as tape:PRED_train=tf.matmul(X_train,W)Loss_train=0.5*tf.reduce_mean(tf.square(Y_train-PRED_train))PRED_test=tf.matmul(X_test,W)Loss_test=0.5*tf.reduce_mean(tf.square(Y_test-PRED_test))mse_train.append(Loss_train)mse_test.append(Loss_test)#更新参数dL_dW = tape.gradient(Loss_train,W)W.assign_sub(learn_rate*dL_dW)#plt.plot(x,pred)if i % display_step==0:print("i:%i, Train Loss:%f,Test Loss:%f"%(i,mse_train[i],mse_test[i]))
#模型和数据可视化
plt.figure(figsize=(20,4))
#训练误差与泛化误差的对比
plt.subplot(1,3,1)
plt.ylabel("MSE")
plt.plot(mse_train,color="blue",linewidth=3)
plt.plot(mse_test,color="red",linewidth=3)
#训练集:实际房价与预测房价
plt.subplot(1,3,2)
plt.ylabel("Price")
plt.plot(y_train,color="blue",marker="o",label="true_price")
plt.plot(PRED_train,color="red",marker=".",label="predict")
plt.legend()
#测试集:实际房价与预测房价
plt.subplot(1,3,3)
plt.ylabel("Price")
plt.plot(y_test,color="blue",marker="o",label="true_price")
plt.plot(PRED_test,color="red",marker=".",label="predict")
plt.legend()
plt.show()
效果:
接下来增加迭代次数、加大显示间隔(iter=8000,display_step=500),观察一下数据。
i:0, Train Loss:263.193481,Test Loss:276.994110
i:500, Train Loss:26.911524,Test Loss:26.827421
i:1000, Train Loss:21.887274,Test Loss:22.039745
i:1500, Train Loss:19.030270,Test Loss:20.212139
i:2000, Train Loss:17.118929,Test Loss:19.456861
i:2500, Train Loss:15.796998,Test Loss:19.260981
i:3000, Train Loss:14.858858,Test Loss:19.365534
i:3500, Train Loss:14.177205,Test Loss:19.623528
i:4000, Train Loss:13.671043,Test Loss:19.949770
i:4500, Train Loss:13.287543,Test Loss:20.295109
i:5000, Train Loss:12.991438,Test Loss:20.631872
i:5500, Train Loss:12.758676,Test Loss:20.945164
i:6000, Train Loss:12.572536,Test Loss:21.227776
i:6500, Train Loss:12.421189,Test Loss:21.477076
i:7000, Train Loss:12.296155,Test Loss:21.693033
i:7500, Train Loss:12.191257,Test Loss:21.877157
i:8000, Train Loss:12.101960,Test Loss:22.031694
可以发现在迭代次数为2500——3000之间,测试误差上升了,而训练误差一如既往地减少,说明产生过拟合了。从图表也能看出来。
接下来把关注点聚焦于迭代次数为2500——3000之间,增加显示间隔,找到测试集损失上升的点,得到最佳的迭代次数。
确定迭代次数为2520后,再看看效果如何:
这样就是大概的流程了,要注意参数的得到与两个参数有关,一个是迭代次数,一个是学习率,这里我们选择控制变量法,控制学习率为一个较合适的参数之后固定不动,然后调节迭代次数。
关于归一化的思考
对训练集和测试集的归一化可以采用以下3种方式:
1、先把测试集和训练集放在一起,进行属性归一化,然后再分开。
2、先划分训练集和测试集,然后分别归一化。
3、先划分训练集和测试集,归一化训练集,记录训练集的归一化参数(最大值,最小值),然后再使用训练集的参数去归一化测试集。
第一种情况下,相当于强制把训练集和测试集的数据分布统一化,造成训练集和测试集的数据分布类似,测试误差和训练误差关联度高,测试误差并不能很好地反映实际泛化误差,不建议采用;
第二种情况下,训练样本和测试样本独立归一化,保证了两种数据分布的独立性,测试误差与训练误差独立,测试误差能够较好反映泛化误差,实际操作中多采用这种方法;
第三种情况下,由于训练集和测试集都使用训练集的参数进行归一化,使得测试集的数据并不能真正被归一化,只能近似归一化,这种方式在batch_normal中有采用到,也能保证数据的独立性,达到标准化的目的,而且能够简化计算,提高计算效率。