首先我們先來學習什麼是迴歸?
一樣請移步 迴歸與分類的區別
看完之後,我首先來說說本章具體是做什麼?
首先來說說tensorflow官方的栗子做一個預測燃料效率的事情。
然後我們去Kaggle上面做一個比賽House Prices: Advanced Regression Techniques
上程式碼
# Use seaborn for pairplot
!pip install seaborn
!pip install tensorflow==2。0。0-alpha0
import seaborn as sns
import pandas as pd
import tensorflow as t
from tensorflow import keras as k
from tensorflow。keras import layers
import matplotlib。pyplot as plt
print(t。__version__)
dataset_path = k。utils。get_file(“auto-mpg。data”, “https://archive。ics。uci。edu/ml/machine-learning-databases/auto-mpg/auto-mpg。data”)
dataset_path
column_names = [‘MPG’,‘Cylinders’,‘Displacement’,‘Horsepower’,‘Weight’,
• ‘Acceleration’, ‘Model Year’, ‘Origin’]
raw_dataset = pd。read_csv(dataset_path, names=column_names,
• na_values = “?”, comment=‘\t’,
• sep=“ ”, skipinitialspace=True)
dataset = raw_dataset。copy()
dataset[:20]
上面的資料,我們看完了之後,需要去處理資料:
將不完整的資料挑選出來(名詞預設值)
將Origin地址,改成ONE-HOT
ONE-HOT相關資料
# 統計預設值
dataset。isna()。sum()
# 處理這些預設值,處理預設值的方式有很多種,比如去掉,取中位數,平均值等等,我們選取的是去掉這些
dataset = dataset。dropna()
dataset。isna()。sum()
# 將ORIGHT轉換成ONE-HOT
# 這裡是官方文件中處理的方式,其實已經有很多封裝好了的方法,建議大家在這裡可以採取自己的一些方式
origin = dataset。pop(‘Origin’)
dataset[‘USA’] = (origin == 1)*1。0
dataset[‘Europe’] = (origin == 2)*1。0
dataset[‘Japan’] = (origin == 3)*1。0
dataset。tail()
# Pandas分割資料集 如果不是Pandas的資料我們可以參考(三)中使用sklearn進行分割資料集
train_dataset = dataset。sample(frac=0。8,random_state=0)
test_dataset = dataset。drop(train_dataset。index)
sns。pairplot(train_dataset[[“MPG”, “Cylinders”, “Displacement”, “Weight”]])
# describe 統計數值型資料的特性(數量、平均數、標準差、最小值,最大值)
train_stats = train_dataset。describe()
train_stats。pop(“MPG”)
# 這裡之所以要轉置是因為方便之後的矩陣相乘
train_stats = train_stats。transpose()
train_stats
train_labels = train_dataset。pop(‘MPG’)
test_labels = test_dataset。pop(‘MPG’)
train_stats
train_stats = train_stats。transpose()
def norm(x):
‘’‘
標準化,參考3中有為什麼要做標準化的解釋
’‘’
return (x - train_stats[‘mean’]) / train_stats[‘std’]
normed_train_data = norm(train_dataset)
normed_test_data = norm(test_dataset)
normed_train_data。head()
以上就是資料處理的部分了,下面我們要開始老套路 構建模型、配置模型、訓練模型、驗證模型。
# 構建模型
model = k。Sequential([
• layers。Dense(64, activation=‘relu’,input_shape=[len(normed_train_data。keys())]),
• layers。Dense(64, activation=‘relu’),
• layers。Dense(1)
])
model。summary()
# 配置模型
model。compile(optimizer=‘adam’,loss=‘mean_squared_error’,metrics=[‘mean_absolute_error’, ‘mean_squared_error’])
# 訓練模型
history = model。fit(normed_train_data, train_labels,epochs=1000, validation_split = 0。2, verbose=0)
hist = pd。DataFrame(history。history)
def plot_history(history):
hist = pd。DataFrame(history)
hist[‘epoch’] = list(hist。index+1)
plt。figure()
plt。xlabel(‘Epoch’)
plt。ylabel(‘Mean Abs Error [MPG]’)
plt。plot(hist[‘epoch’], hist[‘mean_absolute_error’],
• label=‘Train Error’)
plt。plot(hist[‘epoch’], hist[‘val_mean_absolute_error’],
• label=‘Val Error’)
plt。ylim([0,5])
plt。legend()
plt。show()
plt。figure()
plt。xlabel(‘Epoch’)
plt。ylabel(‘Mean Square Error [MPG^2]’)
plt。plot(hist[‘epoch’],hist[‘mean_squared_error’],
• label=‘Train Error’)
plt。plot(hist[‘epoch’],hist[‘val_mean_squared_error’],
• label=‘Train Error’)
plt。ylim([0,20])
plt。legend()
plt。show()
plot_history(history。history)
在圖中我們發現其實在100輪以後val(驗證集)上面基本上沒有明細的改進了,而訓練集還在繼續訓練,這個時候我們為了確保它擁有很好的泛化性,我們應該在驗證集不在變化的時候就停止訓練。
這個工作在我們fit函式中就可以直接設定。
# 重新該塊的工作,這裡我們和上面的程式碼就重複了,今後我們會使用函式去build這個模型,以防遇到這種問題我們還需要重寫這一塊的程式碼
# 構建模型
model = k。Sequential([
• layers。Dense(64, activation=‘relu’,input_shape=[len(normed_train_data。keys())]),
• layers。Dense(64, activation=‘relu’),
• layers。Dense(1)
])
model。summary()
# 配置模型
model。compile(optimizer=‘adam’,loss=‘mean_squared_error’,metrics=[‘mean_absolute_error’, ‘mean_squared_error’])
# keras 函式回撥的APIhttps://keras。io/zh/callbacks/
early_stop = k。callbacks。EarlyStopping(monitor=‘val_loss’, patience=10)
history = model。fit(normed_train_data, train_labels, epochs=1000, validation_split = 0。2, verbose=1, callbacks=[early_stop])
上面的因為verbose為1,所以輸出了很多繁雜的資料。
我們想個辦法讓它30輪輸出一次,我們可以建立一個回撥函式 API
class PrintLog(k。callbacks。Callback):
• def on_train_begin(self, logs):
• pass
def on_epoch_end(self, epoch, logs):
if epoch % 30 == 0:
print(‘epoch:’,epoch, ‘\tlogs:’,logs)
•
model = k。Sequential([
• layers。Dense(64, activation=‘relu’,input_shape=[len(normed_train_data。keys())]),
• layers。Dense(64, activation=‘relu’),
• layers。Dense(1)
])
model。summary()
# 配置模型
model。compile(optimizer=‘adam’,loss=‘mean_squared_error’,metrics=[‘mean_absolute_error’, ‘mean_squared_error’])
# keras 函式回撥的APIhttps://keras。io/zh/callbacks/
early_stop = k。callbacks。EarlyStopping(monitor=‘val_loss’, patience=10)
history = model。fit(normed_train_data, train_labels, epochs=1000, validation_split = 0。2, verbose=0, callbacks=[PrintLog(),early_stop])
plot_history(history。history)
loss, mae, mse = model。evaluate(normed_test_data, test_labels, verbose=0)
print(“Testing set Mean Abs Error: {:5。2f} MPG”。format(mae))
test_predictions = model。predict(normed_test_data)
normed_test_data。head()
plt。scatter(test_labels, test_predictions)
plt。xlabel(‘True Values’)
plt。ylabel(‘Predictions’)
plt。ylim([0,50])
plt。xlim([0,50])
_ = plt。plot([-100, 100], [-100, 100])
看來真實值與預測值很接近
# 不加下面這句話會導致兩者維度不一致
# https://docs。scipy。org/doc/numpy-1。15。0/reference/generated/numpy。ndarray。flatten。html
test_predictions = test_predictions。flatten()
error = test_predictions - test_labels
plt。hist(error, bins = 25)
plt。xlabel(‘Prediction Error’)
_ = plt。ylabel(‘Count’)
這個圖形不是那麼的高斯,當然因為資料的問題導致的。
總結一下:
迴歸問題可以使用均方差做loss。
平均絕對誤差是迴歸的平均標準。
在上面我們將數字差別太大的值做了一遍縮放。
資料不大的情況我們使用的隱藏層的層數儘量設定小一點,防止過擬合。
早期終止可以避免過擬合。
練習:House Prices: Advanced Regression Techniques
這是一個房價預測的比賽,來源於Kaggle。
下次更新
Reference
Tensorflow官方教程
train_dataset。describe介紹
為什麼要做標準化