关于波士顿房价预测实验心得
标准化与归一化
归一化:
对数据的数值范围进行特定缩放,但不改变其数据分布的一种线性特征变换。
标准化:
对数据的分布的进行转换,使其符合某种分布(比如正态分布)的一种非线性特征变换。
mean = train_x.mean(axis=0)std = train_x.std(axis=0)train_x = (train_x - mean) / stdtest_x = (test_x - mean) / std
对比
在涉及到计算点与点之间的距离时,使用归一化或标准化都会对最后的结果有所提升,甚至会有质的区别。那在归一化与标准化之间应该如何选择呢?根据上一节我们看到,如果把所有维度的变量一视同仁,在最后计算距离中发挥相同的作用应该选择标准化,如果想保留原始数据中由标准差所反映的潜在权重关系应该选择归一化。另外,标准化更适合现代嘈杂大数据场景。
总结
在本人实验中,使用标准化后精度有明显的提高!
激活函数的选择
“激活函数”能分成两类——“饱和激活函数” 和 “非饱和激活函数”
- sigmoid和tanh是“饱和激活函数”
- ReLU及其变体则是“非饱和激活函数”。
使用“非饱和激活函数”的优势
- 首先,“非饱和激活函数”能解决所谓的“梯度消失”问题。
- 其次,它能加快收敛速度。
Sigmoid函数需要一个实值输入压缩至[0,1]的范围
σ(x) = 1 / (1 + exp(−x))
tanh函数需要讲一个实值输入压缩至 [-1, 1]的范围
tanh(x) = 2σ(2x) − 1
ReLU
函数的计算是在卷积之后进行的,因此它与tanh函数和sigmoid函数一样,同属于“非线性激活函数”
缺点:训练的时候很“脆弱”,很容易die;如果学习率很大,很有可能导致网络中的40%瘫痪
elus
ELUs是“指数线性单元”,它试图将激活函数的平均值接近零,从而加快学习的速度。
经本人用于波士顿房价预测上的情况是 elus的精度要略大于relu的
leaky_relu
ReLU是将所有的负值都设为零,相反,Leaky ReLU是给所有负值赋予一个非零斜率。

参数化修正线性单元(PReLU)
PReLU可以看作是Leaky ReLU的一个变体。在PReLU中,负值部分的斜率是根据数据来定的,而非预先定义的。
随机纠正线性单元(RReLU)
“随机纠正线性单元”RReLU也是Leaky ReLU的一个变体。在RReLU中,负值的斜率在训练中是随机的,在之后的测试中就变成了固定的了。RReLU的亮点在于,在训练环节中,aji是从一个均匀的分布U(I,u)中随机抽取的数值。
神经网络的结构选择
DNN (全连接的神经网络)
# 模型构建model = keras.Sequential([layers.Dense(32, activation=tf.nn.elu, input_shape=(13,)),layers.Dense(32, activation=tf.nn.elu),layers.Dense(1])
训练100轮
Epoch 100/900390/390 [==============================] - 0s 96us/sample - loss: 4.1212 - mse: 4.0964 - val_loss: 14.1351 - val_mse: 14.1103
训练200轮
Epoch 200/900390/390 [==============================] - 0s 92us/sample - loss: 3.0193 - mse: 2.9927 - val_loss: 12.8362 - val_mse: 12.8096
训练400轮
采用全连接神经网络,标准化后的最优值MSE在10左右
# 一次测试结果MSE:[12.884271948945289, 12.884273]
总结
由于数据集过小,出现过拟合的现象。
使用Dropout
# 模型构建model = keras.Sequential([# layers.Dense(32,kernel_regularizer=keras.regularizers.l2(0.001), activation=tf.nn.relu, input_shape=(13,)),layers.Dense(32, activation=tf.nn.elu, input_shape=(13,)),# 使用dropoutlayers.Dropout(0.5),layers.Dense(32, activation=tf.nn.elu),# 使用dropoutlayers.Dropout(0.5),layers.Dense(1)])
训练200轮
Epoch 200/900390/390 [==============================] - 0s 49us/sample - loss: 21.8577 - mse: 21.8329 - val_loss: 14.9834 - val_mse: 14.9586
结果并不理想,原因数据集太少,训练次数太少,dropout作用并不是很大
训练400轮
Epoch 400/900390/390 [==============================] - 0s 43us/sample - loss: 16.0063 - mse: 15.9799 - val_loss: 14.5802 - val_mse: 14.5540
训练600轮
Epoch 600/900390/390 [==============================] - 0s 46us/sample - loss: 12.7083 - mse: 12.6801 - val_loss: 14.6778 - val_mse: 14.6496
训练800轮
Epoch 900/900390/390 [==============================] - 0s 54us/sample - loss: 9.2937 - mse: 9.2632 - val_loss: 13.2544 - val_mse: 13.2239
总结
使用dropout后结果也不理想,由于数据集太少。
使用卷积神经网络
# 模型构建model = keras.Sequential([layers.BatchNormalization(input_shape=(13,)),layers.Reshape((13,1)),layers.Conv1D(filters=13,strides=1,padding='same',kernel_size=2, activation=tf.nn.elu,),layers.Conv1D(filters=26, strides=1, padding='same', kernel_size=2, activation=tf.nn.elu,),layers.MaxPooling1D(pool_size=2,strides=1,padding='same'),layers.Conv1D(filters=52, strides=1, padding='same', kernel_size=2, activation='sigmoid'),layers.Conv1D(filters=104, strides=1, padding='same', kernel_size=2, activation='sigmoid'),layers.MaxPooling1D(pool_size=2, strides=1, padding='same'),layers.Dense(32, activation=tf.nn.elu,),layers.Dense(32, activation=tf.nn.elu),layers.Flatten(),layers.Dropout(0.5),layers.Dense(1)])
结果
Epoch 900/900390/390 [==============================] - 0s 207us/sample - loss: 8.5953 - mse: 8.5953 - val_loss: 16.2062 - val_mse: 16.2062102/102 [==============================] - 0s 2ms/sample - loss: 16.2062 - mse: 16.2062[16.206212974062154, 16.206213]
总结
使用卷积神经网络时,效果并不理想。主要原因还是应为训练集过小,复杂的神经网络结构反而起到了相反的结果。
最优
我们还是采用DNN神经网络,通过对数据的预处理进一步优化,和最后通过循环的方式得到目前得到的最优解。
import tensorflow as tfimport tensorflow.keras as kerasimport tensorflow.keras.layers as layersimport pandas as pdimport numpy as npimport datetimetrain_data = pd.read_csv("./data/波士顿房价训练集.csv")test_data = pd.read_csv("./data/波士顿房价测试集.csv")# train_data = train_data[~train_data['MEDV'].isin([50])]train_data = np.array(train_data)test_data = np.array(test_data)train_x = train_data[:, :13]# train_y为最后1列标签数据train_y = train_data[:, 13]test_x = test_data[:, :13]ids = test_data[:, 13]test_y = pd.read_csv("./data/result.csv")test_y = np.array(test_y["MEDV"])boston = np.concatenate((train_x, test_x), axis=0)# n减去平均值/标准差mean = boston.mean(axis=0)train_x -= meanstd = boston.std(axis=0)train_x /= stdtest_x -= meantest_x /= stddef build_model():# 模型构建model = keras.Sequential([layers.Dense(16, activation=tf.nn.elu, input_shape=(13,)),layers.Dense(32, activation=tf.nn.elu),layers.Dense(1)])model.compile(optimizer="rmsprop",# optimizer="adam",# optimizer=tf.keras.optimizers.RMSprop(lr=0.001),loss='mse',# 我们希望在训练的时候可以查看方差metrics=['mae'])# 模型结构model.summary()return model# 加载模型# model = tf.keras.models.load_model("./model/my_model.h5")# log_dir = "logs\\fit\\" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")# print(log_dir)# tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)model = build_model()model.fit(train_x, train_y, validation_data=(test_x, test_y), batch_size=10, epochs=1,verbose=1)bestMath = model.evaluate(test_x, test_y)[0]best_model = modelfor j in range(1):model = build_model()# 模型训练for i in range(200):model.fit(train_x, train_y, validation_data=(test_x, test_y), batch_size=10, epochs=1,# callbacks=[tensorboard_callback],verbose=1)result = model.evaluate(test_x, test_y)print("第", j+1, "轮第", i, "次结果:", result)if (bestMath > result[0]):bestMath = result[0]# 保存模型model.save("./model/my_model.h5")best_model = tf.keras.models.load_model("/home/output/model/my_model.h5")predict = model.predict(test_x)ids = ids.astype(int)predict = pd.DataFrame(predict)ids = pd.DataFrame(ids)predict.columns = ["MEDV"]ids.columns = ["id"]predict = pd.concat([predict, ids], axis=1)predict.to_csv("/home/output/submission.csv", index=False)result = best_model.evaluate(test_x, test_y)print(result)print("bestMath:", bestMath)
