首先我們先來學習什麼是迴歸?

一樣請移步 迴歸與分類的區別

看完之後,我首先來說說本章具體是做什麼?

首先來說說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介紹

為什麼要做標準化