主页

索引

模块索引

搜索页面

回归问题



# 1. 导入数据
from keras.datasets import boston_housing
(train_data, train_targets), (test_data, test_targets) =boston_housing.load_data()

# 2. 准备数据
# 原因: 输入数据的 每个特征(比如犯罪率)都有不同的取值范围。
#     a. 有些特性是比例,取值范围为 0~1
#     b. 有的取值范围为 1~12
#     c. 有的取值范围为 0~100
#     将取值范围差异很大的数据输入到神经网络中,这是有问题的。
# 解决:
#     数据标准化: 特征平均值为 0,标准差为 1
mean = train_data.mean(axis=0)
train_data -= mean

std = train_data.std(axis=0)
train_data /= std

test_data -= mean
test_data /= std

# 3. 构建网络
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))
    # 损失函数: mse
    # 指标: mae
    model.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])
    return model

# 4. 解决jupyter运行keras不可用问题
import os
os.environ["KMP_DUPLICATE_LIB_OK"]="TRUE"

# 5. K 折线交叉验证
import numpy as np
k=4
num_val_samples = len(train_data) // k 
num_epochs = 100   # 训练100次
all_scores = []

for i in range(k):
    print('processing fold #', i)
    # 1/4作为验证集
    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()

    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('End fold #', i)

# 5. 交叉验证结果
print(all_scores)
# [2.096412181854248, 2.505697727203369, 2.7529520988464355, 2.5774314403533936]
print(np.mean(all_scores))
# 2.4831233620643616

# 结论:
# 每次运行模型得到的验证分数有很大差异,从 2.09 到 2.75 不等
# 平均分数(2.48)是比单一 分数更可靠的指标——这就是 K 折交叉验证的关键
# 预测的房价与实际价格平均相差 2480 美元



# 6. 保存每折的验证结果,并让训练时间更长一点,达到 500 个轮次
num_epochs = 500 
all_mae_histories = []
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,
                    validation_data=(val_data, val_targets),
                    epochs=num_epochs, batch_size=1, verbose=0)
    mae_history = history.history['val_mae']
    all_mae_histories.append(mae_history)
    print('End fold #', i)

# 6. 计算所有轮次中的 K 折验证分数平均值
average_mae_history = [
    np.mean([x[i] for x in all_mae_histories]) for i in range(num_epochs)]

# 7. 绘制验证分数
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()


# 8. 绘制验证分数(删除前 10 个数据点&EMA)
def smooth_curve(points, factor=0.9):
  smoothed_points = []
  for point in points:
    if smoothed_points:
      previous = smoothed_points[-1]
      smoothed_points.append(previous * factor + point * (1 - factor))
    else:
      smoothed_points.append(point)
  return smoothed_points

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()

# 结论:
# 验证 MAE 在 80 轮后不再显著降低,之后就开始过拟合


# 9. 从头开始重新训练一个模型(不需要验证集了)
model = build_model()   # 一个全新的编译好的模型
# 在所有训练数据上训练模型
model.fit(train_data, train_targets, epochs=80, batch_size=16, verbose=0)
# 在测试集上测试模型
test_mse_score, test_mae_score = model.evaluate(test_data, test_targets)



# 10. 小结
  # a. 回归问题使用的损失函数与分类问题不同。回归常用的损失函数是均方误差(MSE)
  # b. 与分类问题不同,精度的概念不适用于回归问题。常见的回归指标是平均绝对误差(MAE)。
  # c. 如果输入数据的特征具有不同的取值范围,应先预处理,对每个特征单独进行缩放。
  # d. 如果可用的数据很少,使用 K 折验证可以可靠地评估模型。
  # e. 如果可用的训练数据很少,最好使用隐藏层较少(通常只有一到两个)的小型网络,以避免严重的过拟合。










主页

索引

模块索引

搜索页面