当前位置:   article > 正文

Python深度学习-Keras》精华笔记4:解决深度学习回归问题_keras的学习笔记

keras的学习笔记

公众号:尤而小屋
作者:Peter
编辑:Peter

持续更新《Python深度学习》一书的精华内容,仅作为学习笔记分享。

本文是第4篇:基于Keras解决深度学习中的回归问题

Keras内置数据集

回归问题中使用的是内置的波士顿房价数据集。在keras中有多个内置的数据集:

  • 波士顿房价数据集
  • CIFAR10数据集(包含10种类别的图片集)
  • CIFAR100数据集(包含100种类别的图片集)
  • MNIST数据集(手写数字图片集)
  • Fashion-MNIST数据集(10种时尚类别的图片集)
  • IMDB电影点评数据集
  • 路透社新闻数据集

其中IMDB数据集在二分类问题中被使用过,路透社新闻数据集在多分类问题中被使用。

In [1]:

import numpy as np
np.random.seed(1234)  # 设置随机种子

import matplotlib.pyplot as plt
%matplotlib inline

import warnings 
warnings.filterwarnings("ignore")  # 忽略notebook中的警告
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

导入数据

In [2]:

from  keras.datasets import boston_housing

(train_data,train_targets), (test_data, test_targets) = boston_housing.load_data()  
  • 1
  • 2
  • 3

查看数据的基本信息:

In [3]:

train_data[:3]
  • 1

Out[3]:

array([[1.23247e+00, 0.00000e+00, 8.14000e+00, 0.00000e+00, 5.38000e-01,
        6.14200e+00, 9.17000e+01, 3.97690e+00, 4.00000e+00, 3.07000e+02,
        2.10000e+01, 3.96900e+02, 1.87200e+01],
       [2.17700e-02, 8.25000e+01, 2.03000e+00, 0.00000e+00, 4.15000e-01,
        7.61000e+00, 1.57000e+01, 6.27000e+00, 2.00000e+00, 3.48000e+02,
        1.47000e+01, 3.95380e+02, 3.11000e+00],
       [4.89822e+00, 0.00000e+00, 1.81000e+01, 0.00000e+00, 6.31000e-01,
        4.97000e+00, 1.00000e+02, 1.33250e+00, 2.40000e+01, 6.66000e+02,
        2.02000e+01, 3.75520e+02, 3.26000e+00]])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

In [4]:

train_data.shape, test_data.shape
  • 1

Out[4]:

((404, 13), (102, 13))
  • 1

数据标准化

在机器学习中,对数据进行标准化是非常重要的,主要有以下原因:

  • 消除量纲影响:不同特征的数值大小可能相差很大,例如重量和价格。如果这些特征之间具有很大的差异,那么某些特征的值可能会主导模型的训练过程,从而削弱其他特征的重要性。通过标准化,可以将所有特征的值缩放到相同的尺度上,消除量纲的影响。
  • 加速收敛:在机器学习算法中,梯度下降是一种常用的优化算法。当数据存在较大的尺度差异时,梯度更新可能会变得非常慢,导致算法收敛速度变慢。通过标准化,可以减少尺度差异,从而加速梯度下降算法的收敛速度。
  • 提高模型性能:标准化可以使数据分布更加均匀,避免出现极端值或离群点。这有助于提高模型的泛化能力和性能。 因此,对数据进行标准化是机器学习中一个重要的预处理步骤,可以提升模型的训练效果和预测性能。

首先求出训练集的均值和标准差,进行标准化;再使用训练集的均值和标准差对测试集进行标准化。

In [5]:

# 手动标准化

mean = train_data.mean(axis=0) # 均值
train_data -= mean

std = train_data.std(axis=0)
train_data /= std 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

对测试集的标准化:

In [6]:

# 仍然使用训练集的mean std

test_data -= mean
test_data /= std
  • 1
  • 2
  • 3
  • 4

搭建网络

In [7]:

from keras import models, layers
  • 1

In [8]:

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))
    model.compile(optimizer="rmsprop",  # 优化器
                  loss="mse",   # 损失
                  metrics=["mae"])  # 评价指标
    return model
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

k折交叉验证

本小节的部分代码和原文有不同:

In [9]:

k = 5  # k折

num_val_samples = (len(train_data)) // k

num_epochs = 500

all_mae = []
all_val_mae = []
all_loss = []
all_val_loss = []

for i in range(k):
    
    print(f"第 {i+1} fold正在running")
    
    # 准备验证集数据
    valid_data = train_data[i*num_val_samples:(i+1)*num_val_samples]
    valid_targets = train_targets[i*num_val_samples:(i+1)*num_val_samples]
    
    # 准备训练集(除去验证集部分)
    part_train_data = np.concatenate([
        train_data[:i*num_val_samples],  # 索引i之前和i+1之后,两部分合并起来成为训练集
        train_data[(i+1)*num_val_samples:]
    ],axis=0)
    
    part_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(part_train_data,
             part_train_targets,
             epochs=num_epochs,
             batch_size=1,
             verbose=0,   # 静默模式,不显示每个epochs的具体打印信息
             validation_data=[valid_data,valid_targets])
    history_dict = history.history
    
    mae = history_dict["mae"]  # 训练集的mae
    val_mae = history_dict["val_mae"]  # 训练集的mae
    loss = history_dict["loss"]
    val_loss = history_dict["val_loss"]
    
    all_mae.append(mae)
    all_val_mae.append(val_mae)
    all_loss.append(loss)
    all_val_loss.append(val_loss)
第 1 fold正在running
第 2 fold正在running
第 3 fold正在running
第 4 fold正在running
第 5 fold正在running
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55

模型指标可视化

In [10]:

len(all_mae) # 5折
  • 1

Out[10]:

5
  • 1

In [11]:

# all_mae[0]  # 第1折的全部信息
  • 1

第1折有500个元素(epochs=500)

In [12]:

len(all_mae[0])
  • 1

Out[12]:

500
  • 1

计算每个指标的平均值:

In [13]:

mae_average = [np.mean([x[i] for x in all_mae]) for i in range(num_epochs)]
mae_val_average = [np.mean([x[i] for x in all_val_mae]) for i in range(num_epochs)]

loss_average = [np.mean([x[i] for x in all_loss]) for i in range(num_epochs)]
loss_val_average = [np.mean([x[i] for x in all_val_loss]) for i in range(num_epochs)]
  • 1
  • 2
  • 3
  • 4
  • 5

LOSS

In [14]:

num_epochs
  • 1

Out[14]:

500
  • 1

In [15]:

epochs = range(1, num_epochs+ 1)  # 作为横轴

plt.figure(figsize=(12,6))
plt.plot(epochs, loss_val_average, "blue")
plt.xlabel("Epochs")
plt.ylabel("Loss")

plt.legend()
plt.title("Validation Loss")
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

基于plotly绘制图像:

In [16]:

import plotly_express as px

px.scatter(x=epochs,y=loss_val_average)
  • 1
  • 2
  • 3

In [17]:

epochs = range(1, num_epochs+ 1)  # 作为横轴

plt.figure(figsize=(12,6))

plt.plot(epochs, loss_average, "blue", label="Training Loss")
plt.plot(epochs, loss_val_average, "red", label="Validation Loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")

plt.legend()
plt.title("Training and Validation Loss")
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

MAE

In [18]:

epochs = range(1, num_epochs+1)  # 作为横轴

plt.plot(epochs, mae_average, "blue", label="Training MAE")
plt.plot(epochs, mae_val_average, "red", label="Validation MAE")
plt.xlabel("Epochs")
plt.ylabel("MAE")

plt.legend()
plt.title("Training and Validation MAE")
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

模型优化

可以看到,在训练集或者验证集上,不管是损失Loss还是误差MAE,前面的10个数据点和其他点差异很大,属于异常值,考虑直接删除。

数据的平滑处理:将每个数据点替换为前面数据点的平均值,得到较为光滑的曲线。

In [19]:

def smooth(points, factor=0.9):
    smooth_points = []

    for point in points:
        if smooth_points: 
            previous = smooth_points[-1]
            smooth_points.append(previous * factor + point * (1 - factor)) # 前一个点 * 0.9 + 当前点 * 0.1
        else:  # 不存在元素则添加point点
            smooth_points.append(point)
                
    return smooth_points
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

排除前10个点后进行平滑处理:

In [20]:

smooth_mae = smooth(mae_average[10:]) 
smooth_mae_val = smooth(mae_val_average[10:]) 
smooth_loss = smooth(loss_average[10:]) 
smooth_loss_val = smooth(loss_val_average[10:]) 
  • 1
  • 2
  • 3
  • 4

新LOSS

In [21]:

epochs = range(1, len(smooth_mae)+ 1)  # 作为横轴

plt.figure(figsize=(12,6))

plt.plot(epochs, smooth_loss, "blue", label="Training Loss")
plt.plot(epochs, smooth_loss_val, "red", label="Validation Loss")
plt.xlabel("Epochs")
plt.ylabel("Loss")

plt.legend()
plt.title("Smoothed Training and Validation Loss")
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

# fig = px.scatter(x=epochs, y=smooth_mae)
fig = px.scatter(x=epochs, y=smooth_loss_val)

fig.show()
  • 1
  • 2
  • 3
  • 4

新MAE

In [23]:

epochs = range(1, len(smooth_mae)+ 1)  # 作为横轴

plt.figure(figsize=(12,6))

plt.plot(epochs, smooth_mae, "blue", label="Training MAE")
plt.plot(epochs, smooth_mae_val, "red", label="Validation MAE")
plt.xlabel("Epochs")
plt.ylabel("MAE")

plt.legend()
plt.title("Smoothed Training and Validation MAE")
plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

# fig = px.scatter(x=epochs, y=smooth_mae)
fig = px.scatter(x=epochs, y=smooth_mae_val) 

fig.show()
  • 1
  • 2
  • 3
  • 4

可以看到:在训练集上loss和mae随着轮次的进行,都在逐渐变小;但是在验证集上,并非如此,在50轮左右降到最低;

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/801924
推荐阅读
相关标签
  

闽ICP备14008679号