加載數據
dataset_path = keras.utils.get_file("auto-mpg.data",
"http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")
命名數據表名稱
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)
加載的數據集格式如下所示:raw_dataset.head(15)
原始表格中的數據可能含有空字段(缺失值)的數據項,需要清除這些記錄項:
1.統計空白數據
dataset.isna().sum() # 統計空白數據
2.刪除空白數據
dataset = dataset.dropna() # 刪除空白數據項
3.再次統計空白數據。
由於 Origin 字段爲類別類型數據,我們將其移除,並轉換爲新的 3 個字段:USA、
Europe 和 Japan,分別代表是否來自此產地:
# 處理類別型數據,其中 origin 列代表了類別 1,2,3,分佈代表產地:美國、歐洲、日本
# 先彈出(刪除並返回)origin 這一列
origin = dataset.pop('Origin')
# 根據 origin 列來寫入新的 3 個列
dataset['USA'] = (origin == 1)*1.0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0
dataset.tail(10)是來查看數據集的最後幾項
因爲需要進行訓練和測試,所以我們首先需要劃分數據集和測試集
# 切分爲訓練集和測試集
train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)
# 移動 MPG 油耗效能這一列爲真實標籤 Y
train_labels = train_dataset.pop('MPG')
test_labels = test_dataset.pop('MPG')
統計訓練集的各個字段數值的均值和標準差,並完成數據的標準化,通過 norm()函數 實現,代碼如下:
# 查看訓練集的輸入 X 的統計數據
train_stats = train_dataset.describe()
#train_stats.pop("MPG") # 僅保留輸入 X
train_stats = train_stats.transpose() # 轉置
# 標準化數據
def norm(x): # 減去每個字段的均值,併除以標準差
return (x - train_stats['mean']) / train_stats['std']
normed_train_data = norm(train_dataset) # 標準化訓練集
normed_test_data = norm(test_dataset) # 標準化測試集
print(normed_train_data.shape,train_labels.shape)
print(normed_test_data.shape, test_labels.shape)
(314, 9) (314,)
(78, 9) (78,)
利用切分的訓練集數據構建數據集對象:
我們可以通過簡單地統計數據集中各字段之間的兩兩分佈來觀察各個字段對 MPG 的 影響。
創建網絡:
考慮到 Auto MPG 數據集規模較小,我們只創建一個 3 層的全連接網絡來完成 MPG 值的預測任務。輸入𝑿的特徵共有 9 種,因此第一層的輸入節點數爲 9。第一層、第二層的 輸出節點數設計爲64和64,由於只有一種預測值,輸出層輸出節點設計爲 1。考慮MPG ∈ 𝑅+,因此輸出層的激活函數可以不加,也可以添加 ReLU 激活函數。
我們將網絡實現爲一個自定義網絡類,只需要在初始化函數中創建各個子網絡層,並 在前向計算函數 call 中實現自定義網絡類的計算邏輯即可。自定義網絡類繼承自 keras.Model 基類,這也是自定義網絡類的標準寫法,以方便地利用 keras.Model 基類提供 的 trainable_variables、save_weights 等各種便捷功能。網絡模型類實現如下:
class Network(keras.Model): # 迴歸網絡模型
def __init__(self):
super(Network, self).__init__()
# 創建3個全連接層
self.fc1 = layers.Dense(64, activation='relu')
self.fc2 = layers.Dense(64, activation='relu')
self.fc3 = layers.Dense(1)
def call(self, inputs, training=None, mask=None): # 依次通過 3 個全連接層
x = self.fc1(inputs)
x = self.fc2(x)
x = self.fc3(x)
return x
model = Network() # 創建網絡類實例
# 通過 build 函數完成內部張量的創建,
#其中 4 爲任意設置的 batch 數量,9 爲輸入特徵長度
model.build(input_shape=(None, 9))
model.summary() # 打印網絡信息
設置優化器:
optimizer = tf.keras.optimizers.RMSprop(0.001) # 創建優化器,指定學習率
for epoch in range(20): # 200個Epoch
for step, (x,y) in enumerate(train_db): # 遍歷一次訓練集
# 梯度記錄器,訓練時需要使用它
with tf.GradientTape() as tape:
out = model(x) # 通過網絡獲得輸出
loss = tf.reduce_mean(tf.losses.MSE(y, out)) # 計算 MSE
mae_loss = tf.reduce_mean(tf.losses.MAE(y, out)) # 計算 MAE
# 計算梯度,並更新
grads = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
if epoch: # 間隔性地打印訓練誤差
print(epoch,float(loss))