加载数据
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))