深度學習 - boston_housing 波士頓房價數據集練習 - 回歸問題
from keras.datasets import boston_housing
(train_data, train_targets), (test_data, test_targets) = boston_housing.load_data()
將訓練數據&測試數據標準化(規一化)
mean = train_data.mean(axis=0)
train_data -= mean
std = train_data.std(axis=0)
train_data /= std
test_data -= mean
test_data /= std
建立網絡訓練模型,一樣使用Sequential()
from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(64, activation='relu',input_shape=(train_data.shape[1],)))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(1))
選擇優化器"rmsprop",損失函數"mse",指標"mae"
model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
這邊選用"mse",mean_squared_error(y_true, y_pred)見Ling之博客 :
損失函數: mean_squared_error
特點: 1)常用於回歸問題 2)MSE均方誤差損失
指標 mean_absolute_error(y_true, y_pred)
特點: 1)MAE平均絕對值誤差損失
指標選平均絕對值誤差,可以評估訓練出來的模型,在未見過的資料預測出的結果與實際結果的絕對差值,並將所有結果取平均。例如mae=0.5 (千美元) 則表示預測結果與實際金額差了500美元的誤差,所以mae越小表示預測越精準。
監督學習 - validation_data
留出驗證資料 取前100組做驗證資料val_data = train_data[:100] partial_train_data = train_data[100:] val_targets = train_targets[:100] partial_train_targets = train_targets[100:]
丟進fit學習,並將學習過程繪製出來
history = model.fit(partial_train_data,
partial_train_targets,
validation_data=(val_data, val_targets),
epochs=200,
batch_size=1, verbose=0)
import matplotlib.pyplot as plt loss = history.history['loss'] val_loss = history.history['val_loss'] epochs = range(1, len(loss) + 1) plt.plot(epochs, loss, 'bo', label='Training loss') plt.plot(epochs, val_loss, 'b', label='Validation loss') plt.title('Training and validation loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend() plt.show()
發現前10個點誤差太大,將前10個點略過,不要畫出。修改成以下:
loss = history.history['loss'][10:]
val_loss = history.history['val_loss'][10:]
mae_data = history.history['mean_absolute_error'][10:]
val_mae_data = history.history['val_mean_absolute_error'][10:]
plt.plot(epochs, mae_data, 'bo', label='mean_absolute_error')
plt.plot(epochs, val_mae_data, 'b', label='val_mean_absolute_error')
plt.title('Training and validation mean_absolute_error')
plt.xlabel('Epochs')
plt.ylabel('MAE')
plt.legend()
plt.show()
可以從圖看出,因為訓練資料太少,導致模型在新數據上表現不佳>>>test_targets.mean()
23.07843137254902
>>>train_targets.mean()
22.395049504950492
可以從targets資料來看,平均房價價格大概在22~23(千美元),而測試絕對誤差竟然在2~2.5(千美元),誤差高達10%,以A.I.應用來看,這是不及格的...所以要利用以下方法,對於較少的數據,做更多的訓練。
K-Fold訓練驗證
將訓練資料拆成K等分,然後再將訓練資料與監督學習validation_data分成K次驗證,validation_data每次在不同區域,然後將K次驗證得到的MAE再取平均值。見書內文解釋:
為了在調節網絡參數(比如訓練的輪數)的同時對網絡進行評估,你可以將數據劃分為訓練集和驗證集。 但由於數據點很少,驗證集會非常小(比如大約 100 個樣本)。因此,驗證分數可能會有很大波動, 這取決於你所選擇的驗證集和訓練集。也就是說,驗證集的劃分方式可能會造成驗證分數上有很大的方差, 這樣就無法對模型進行可靠的評估。 在這種情況下,最佳做法是使用K折交叉驗證(見圖)。這種方法將可用數據劃分為K 個分區(K 通常取4 或5), 實例化K 個相同的模型,將每個模型在K-1 個分區上訓練,並在剩下的一個分區上進行評估。 模型的驗證分數等於 K 個驗證分數的平均值。這種方法的代碼實現很簡單。
這邊因為會用到K次model,將它寫成函數,之前某個insite文章作者說過,一段程式會用到3次以上,就把它寫成函式。
def build_model(): model = models.Sequential() model.add(layers.Dense(64, activation='relu',input_shape=(train_data.shape[1],))) model.add(layers.Dense(64, activation='relu')) model.add(layers.Dense(1)) model.compile(optimizer='rmsprop', loss='mse', metrics=['mae']) return model
import numpy as np k = 4 num_val_samples = len(train_data) // k num_epochs = 100 all_scores = []將train_data 分成K等份,這邊K取4。
每折迭代100次
將每折訓練驗證的MAE存到all_scores裡
for i in range(k):
print('processing fold #', i)
val_data = train_data[i * num : (i + 1) * num]
val_targets = train_targets[i * num : (i + 1) * num]
partial_train_data = np.concatenate(
[train_data[:i * num],
train_data[(i + 1) * num:]],
axis=0)
partial_train_targets = np.concatenate(
[train_targets[:i * num],
train_targets[(i + 1) * num:]],
axis=0)
最後,每折裡面都丟進fit訓練&驗證(迭代num_epochs次),會得到一個MAE,將其丟進all_scores,迭代K次後,all_scores會有K個data。verbose:日誌顯示模式。 0 = 安靜模式, 1 = 進度條, 2= 每輪一行。
得到以下結果,
[2.0645172407131382, 2.153722616705564, 2.9730089938286506, 2.4351987738420466]
平均為2.40661190627235
修改一下,將驗證結果全部記錄在all_mae_histories = []
num_epochs = 500
將收集K次的數據做平均,用np.mean可以將每折迭代做平均
model = build_model()
model.fit(partial_train_data, partial_train_targets,
epochs=num_epochs, batch_size=1, verbose=0)
val_mse, val_mae = model.evaluate(val_data, val_targets, verbose=0)
all_scores.append(val_mae)
print(all_scores)
得到以下結果,
[2.0645172407131382, 2.153722616705564, 2.9730089938286506, 2.4351987738420466]
平均為2.40661190627235
修改一下,將驗證結果全部記錄在all_mae_histories = []
num_epochs = 500
import numpy as np
k = 4
num_val_samples = len(train_data) // k
num_epochs = 500
all_mae_histories = []
all_scores = []
for i in range(k):
print('processing fold #', i)
val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]
partial_train_data = np.concatenate(
[train_data[:i * num_val_samples],
train_data[(i + 1) * num_val_samples:]],
axis=0)
partial_train_targets = np.concatenate(
[train_targets[:i * num_val_samples],
train_targets[(i + 1) * num_val_samples:]],
axis=0)
model = build_model()
history = model.fit(partial_train_data, partial_train_targets,
epochs=num_epochs, batch_size=1, verbose=2)
mae_history = history.history['mean_absolute_error']
all_mae_histories.append(mae_history)
將收集K次的數據做平均,用np.mean可以將每折迭代做平均
average_mae_history = np.mean(all_mae_histories,axis=0)
#average_mae_history = [np.mean([x[i] for x in all_mae_histories]) for i in range(num_epochs)]
import matplotlib.pyplot as plt
plt.plot(range(1, len(average_mae_history) + 1), average_mae_history)
plt.xlabel('Epochs')
plt.ylabel('Validation MAE')
plt.show()
一樣前10個data差據太大看不出變化,略過前10個data。
smooth_mae_history = smooth_curve(average_mae_history[10:])
plt.plot(range(1, len(smooth_mae_history) + 1), smooth_mae_history)
plt.xlabel('Epochs')
plt.ylabel('Validation MAE')
plt.show()
可以看到在大約Epochs=80時,所得到的MAE最低,故最後調整訓練模型。
完整程式碼:
from keras.datasets import boston_housing (train_data, train_targets), (test_data, test_targets) = boston_housing.load_data() mean = train_data.mean(axis=0) train_data -= mean std = train_data.std(axis=0) train_data /= std test_data -= mean test_data /= std from keras import models from keras import layers def build_model(): model = models.Sequential() model.add(layers.Dense(64, activation='relu',input_shape=(train_data.shape[1],))) model.add(layers.Dense(64, activation='relu')) model.add(layers.Dense(1)) model.compile(optimizer='rmsprop', loss='mse', metrics=['mae']) return model model = build_model() model.fit(train_data, train_targets, epochs=80 , batch_size=1, verbose=2) final_test_data = model.evaluate(test_data, test_targets, verbose=0) print(final_test_data)
[11.513197506175322, 2.2164718123043285]
最後MAE為2.2,在這樣少的data中,這預測平均絕對誤差已經是極限了。
沒有留言:
張貼留言