Python-数据科学-七-

71 阅读1小时+

Python 数据科学(七)

原文:annas-archive.org/md5/b306e51c73948c57f772d5af5f61eb39

译者:飞龙

协议:CC BY-NC-SA 4.0

第十八章:第八章

行业技巧与窍门

学习目标

到本章结束时,你将能够:

  • 通过迁移学习的帮助,更快地创建更好的深度学习模型

  • 通过帮助分离的训练、开发和测试数据集,利用和使用更好的模型

  • 使用真实数据集

  • 利用 AutoML 找到最优的网络,几乎不需要任何工作

  • 可视化神经网络模型

  • 更好地使用训练日志

本章最后将描述迁移学习的概念,并展示如何有效地使用训练日志。

介绍

现在我们已经涵盖了你启动数据科学之旅所需的几乎所有主题,我们将介绍一些数据科学家用来提高效率、创建更好的机器学习系统的工具和技巧。你将首先学习迁移学习,它可以帮助你在数据不足时训练模型。然后,我们将介绍一些重要的工具和技巧,帮助你成为更好的数据科学家。

迁移学习

训练一个复杂的神经网络很困难且耗时,因为需要大量的数据进行训练。迁移学习帮助数据科学家将一个网络获得的部分知识转移到另一个网络上。这类似于人类如何将知识从一个人传递给另一个人,这样每个人就不必从头开始学习每一项新事物。迁移学习帮助数据科学家更快且用更少的数据点训练神经网络。根据情况,有两种方法可以执行迁移学习。具体如下:

  • 使用预训练模型:在这种方法中,我们使用一个预训练的神经网络模型,并用它来解决当前的问题。预训练模型是为与当前任务不同的目的而创建的神经网络,已经在某个其他数据集上进行了训练,并且已被保存以供将来重用。预训练模型必须在类似或相同的数据集上进行训练,以获得合理的准确度。

  • 创建一个模型:在这种方法中,我们在一个类似实际问题的数据集上训练神经网络模型。然后,我们使用这个模型执行与预训练模型方法相同的步骤。当实际数据集较小,且我们无法创建一个可接受的模型时,这种方法非常有用。

第六章《解码图像》中所讨论的那样,神经网络的不同层次学习图像的不同特征。例如,第一层可能学习识别水平线,而几层后,网络可能学会识别眼睛。这也是为什么迁移学习在图像上有效的原因;我们得到的特征提取器可以用来从同一分布的新图像中提取信息。现在,你一定会好奇,为什么我们不在每个问题上都使用迁移学习呢?

让我们通过以下图示来理解这一点。这里,原始数据集指的是用于训练我们将要迁移知识的网络的数据集:

图 8.1: 不同条件下进行迁移学习的步骤

图 8.1: 不同条件下进行迁移学习的步骤

在图示中,有四个区域:

  • 小数据集(类似于原始数据集):这是最常见的情况,也是迁移学习最有效的场景。由于当前数据集与用于训练预训练模型的数据集相似,我们可以使用预训练模型的各层,并根据问题类型只修改最后的全连接层部分。

  • 大数据集(类似于原始数据集):这是最理想的情况。由于数据的可用性,建议从头开始训练模型,并且为了加速学习,我们可以使用预训练模型的权重作为起点。

  • 小数据集(与原始数据集不同):这是迁移学习和深度学习中最糟糕的情况。面对这种情况,唯一的解决方案是找到一个类似当前数据集的数据集,在其上训练一个模型,然后再使用迁移学习。

  • 大数据集(与原始数据集不同):由于数据集非常大,我们可以从头开始训练模型。为了加快训练速度,可以将预训练模型的权重作为起点,但这并不推荐。

迁移学习仅在两种类型的数据集上取得了成功——图像数据集和自然语言(文本数据)数据集。我们在 第七章 中讨论的词嵌入就是一个迁移学习的例子。接下来,我们将看看如何将迁移学习应用于图像数据。

图像数据的迁移学习

在本节中,我们将使用 Keras 加载一个预训练模型并进行迁移学习。你将学到如何处理数据集与预训练模型数据集相似的两种情况。要开始迁移学习,我们首先必须加载一个预训练模型。我们将使用 Keras 加载 Inception 模型:

import keras
base_model = keras.applications.inception_v3.InceptionV3(include_top=False, weights='imagenet')

include_top=False 去除了网络中的第一个全连接层,使我们可以输入任何大小的图像,而不依赖于原始数据集的图像大小。weights='imagenet' 确保加载预训练权重。如果没有传递给 weights,则权重将随机初始化。Inception 模型在现有的 卷积神经网络CNN)分类器上做出了巨大的改进。在 Inception 之前,最好的模型只是堆叠多个卷积层,希望能获得更好的性能。而 Inception 则不同,它采用了许多技巧,在提高准确率的同时,也减少了预测时间。

图 8.2: Inception 网络的单个神经元

图 8.2:Inception 网络的单个细胞

我们将首先查看的案例是一个与原始数据集相似的小型数据集。在这种情况下,我们需要首先冻结预训练模型的层。为此,我们只需使基础模型的所有层不可训练:

for layer in base_model.layers:
    layer.trainable = False

下一个案例是一个与原始数据集相似的大型数据集。在这种情况下,我们需要通过将预训练权重作为起点来训练模型。在这种情况下,我们不做任何修改,只是训练整个模型,该模型是base_model与一些额外的全连接层的组合,具体取决于我们的任务。例如,如果任务是二分类问题,我们需要使最后一层全连接层有 2 个输出。我们在这种情况下还可以做的一件事是冻结前几层的权重,这样训练过程会更快。冻结前几层是有帮助的,因为这些层学习的是简单的形状,可以应用于任何类型的问题。要在 Keras 中冻结前五层,请使用以下代码:

for layer in base_model.layers[:5]:   layer.trainable = False

练习 58:使用 InceptionV3 比较和分类图像

在这个练习中,我们将利用 Keras 提供的 InceptionV3 模型进行猫狗分类。我们将使用与第六章《解码图像》相同的数据集(github.com/TrainingByP… Inception 卷积层,这样就不需要重新训练它们:

  1. 首先,创建函数从文件名读取图像及其标签。这里,PATH 变量包含训练数据集的路径:

    from PIL import Image
    def get_input(file):
        return Image.open(PATH+file)
    def get_output(file):	
        class_label = file.split('.')[0]
        if class_label == 'dog': label_vector = [1,0]
        elif class_label == 'cat': label_vector = [0,1]
        return label_vector
    
  2. 设置图像的大小和通道:

    SIZE = 200
    CHANNELS = 3
    
  3. 然后,创建一个函数来预处理图像:

    def preprocess_input(image):
    
        # Data preprocessing
        image = image.resize((SIZE,SIZE))
        image = np.array(image).reshape(SIZE,SIZE,CHANNELS)
    
        # Normalize image
        image = image/255.0
    
        return image
    
  4. 现在创建一个生成器函数,读取图像和标签并处理图像:

    import numpy as np
    def custom_image_generator(images, batch_size = 128):
    
        while True:
            # Randomly select images for the batch
            batch_images = np.random.choice(images, size = batch_size)
            batch_input = []
            batch_output = [] 
    
            # Read image, perform preprocessing and get labels
            for file in batch_images:
                # Function that reads and returns the image
                input_image = get_input(file)
                # Function that gets the label of the image
                label = get_output(file)
                # Function that pre-processes and augments the image
                image = preprocess_input(input_image)
                batch_input.append(image)
                batch_output.append(label)
            batch_x = np.array(batch_input)
            batch_y = np.array(batch_output)
            # Return a tuple of (images,labels) to feed the network
            yield(batch_x, batch_y)
    
  5. 接下来,我们将读取验证数据。创建一个函数来读取图像及其标签:

    from tqdm import tqdm
    def get_data(files):
        data_image = []
        labels = []
        for image in tqdm(files):
            label_vector = get_output(image)
    
            img = Image.open(PATH + image)
            img = img.resize((SIZE,SIZE))
    
            labels.append(label_vector)
            img = np.asarray(img).reshape(SIZE,SIZE,CHANNELS)
            img = img/255.0
            data_image.append(img)
    
        data_x = np.array(data_image)
        data_y = np.array(labels)
    
        return (data_x, data_y)
    
  6. 读取验证文件:

    from random import shuffle
    files = os.listdir(PATH)
    random.shuffle(files)
    train = files[:7000]
    test = files[7000:]
    validation_data = get_data(test)
    
  7. 从数据集中绘制一些图像,查看是否正确加载了文件:

    import matplotlib.pyplot as plt
    plt.figure(figsize=(20,10))
    columns = 5
    for i in range(columns):
        plt.subplot(5 / columns + 1, columns, i + 1)
        plt.imshow(validation_data[0][i])
    

    样本图像如下:

    图 8.3:从加载的数据集中提取的样本图像
  8. 加载 Inception 模型并传入输入图像的形状:

    from keras.applications.inception_v3 import InceptionV3
    base_model = InceptionV3(weights='imagenet', include_top=False, input_shape=(200,200,3))
    
  9. 冻结 Inception 模型层,使得训练过程中不会对它们进行训练:

    for layer in base_model.layers:
        layer.trainable = False
    
  10. 现在根据我们的问题,添加输出的全连接层。这里,keep_prob是训练过程中保留节点的比例。因此,丢弃率将是1 – keep_prob

    from keras.layers import GlobalAveragePooling2D, Dense, Dropout
    from keras.models import Model
    x = base_model.output
    x = GlobalAveragePooling2D()(x)
    x = Dense(256, activation='relu')(x)
    keep_prob = 0.5
    x = Dropout(rate = 1 - keep_prob)(x)
    predictions = Dense(2, activation='softmax')(x)
    model = Model(inputs=base_model.input, outputs=predictions)
    
  11. 接下来,编译模型,使其准备好进行训练:

    model.compile(loss='categorical_crossentropy', 
                  optimizer='adam',
                  metrics = ['accuracy'])
    

    然后进行模型训练:

    EPOCHS = 5
    BATCH_SIZE = 128
    model_details = model.fit_generator(custom_image_generator(train, batch_size = BATCH_SIZE),
                        steps_per_epoch = len(train) // BATCH_SIZE, 
                        epochs = EPOCHS, 
                        validation_data= validation_data,
                        verbose=1)
    
  12. 评估模型并获取准确性:

    score = model.evaluate(validation_data[0], validation_data[1])
    print("Accuracy: {0:.2f}%".format(score[1]*100))
    

    准确度如下:

图 8.4:模型的准确性

图 8.4:模型的准确性

如前所示,模型的准确率为 97.8%,这比我们在第六章解码图像中获得的 73%的准确率要高得多。你可以尝试修改我们附加到 Inception 模型上的模型,看看是否能提高准确率。你还可以绘制错误预测的图像,来了解模型的表现如何。

y_pred = model.predict(validation_data[0])
incorrect_indices = np.nonzero(np.argmax(y_pred,axis=1) != np.argmax(validation_data[1],axis=1))[0]
labels = ['dog', 'cat']
image = 5
plt.imshow(validation_data[0][incorrect_indices[image]].reshape(SIZE, SIZE, CHANNELS),  cmap=plt.get_cmap('gray'))
plt.show()
print("Prediction: {0}".format(labels[np.argmax(y_pred[incorrect_indices[image]])]))

错误预测的图像如下所示:

图 8.5:错误预测的样本

](tos-cn-i-73owjymdk6/9698e42548164167bc008b69b0f295b6)

图 8.5:错误预测的样本

活动 21:使用 InceptionV3 进行图像分类

在本活动中,我们将使用 Keras 提供的 InceptionV3 模型进行猫狗分类。我们将使用第六章解码图像中使用的相同数据集并比较我们的结果。在这里,我们将训练整个模型,但我们将使用 Inception 预训练模型中的权重作为起点。这类似于我们刚才讨论的练习,但没有冻结层。

  1. 创建一个生成器来获取图像和标签。

  2. 创建一个函数来获取标签和图像。然后,创建一个函数来预处理图像并对其进行增强。

  3. 加载验证数据集,这些数据集不会进行增强处理。

  4. 加载 Inception 模型并添加最终的全连接层。训练整个网络。

你应该看到这个模型的准确率为 95.4%,这比我们在第六章解码图像中获得的 73%的准确率要高得多。

你一定注意到前面的代码与练习 58相似,但这里我们没有冻结层。模型显然从 Inception 模型的权重中受益,将其作为起点。你可以绘制错误预测的图像,来了解模型的表现如何:

y_pred = model.predict(validation_data[0])
incorrect_indices = np.nonzero(np.argmax(y_pred,axis=1) != np.argmax(validation_data[1],axis=1))[0]
labels = ['dog', 'cat']
image = 5
plt.imshow(validation_data[0][incorrect_indices[image]].reshape(SIZE, SIZE, CHANNELS),  cmap=plt.get_cmap('gray'))
plt.show()
print("Prediction: {0}".format(labels[np.argmax(y_pred[incorrect_indices[image]])]))
注意

本活动的解决方案可以在第 387 页找到。

错误预测的图像如下所示:

图 8.6:数据集中错误预测的样本

](tos-cn-i-73owjymdk6/e2b83fe8d0d443e3b5cfdc859c50a2d1)

图 8.6:数据集中错误预测的样本

有用的工具和技巧

在本节中,你将首先了解数据集的不同拆分的重要性。之后,你将学到一些技巧,这些技巧在处理未经过处理的数据集时会派上用场。然后,我们将介绍像 pandas profiling 和 TensorBoard 这样的工具,它们通过提供简便的信息访问,使你的工作更加轻松。我们还将看看 AutoML,以及它如何在无需大量人工操作的情况下获得高性能模型。最后,我们将可视化我们的 Keras 模型并将模型图导出到文件。

训练集、开发集和测试集

我们在前几章中简要讨论了训练集、开发集和测试集。在这里,我们将深入探讨这个话题。

训练集(或训练数据集)是从数据集中获取的一个样本,我们用它来创建我们的机器学习模型。开发集(或验证集,也称为开发数据集)是一个样本,帮助我们调整已创建模型的超参数。测试集(或测试数据集)是我们用来最终评估模型的样本。拥有这三种数据集对模型开发至关重要。

数据集的分布

开发集和测试集应该来自相同的分布,并且应该代表你期望模型在未来接收到的数据。如果分布不同,模型将会调优到一个在未来看不见的分布,这会影响部署后的模型表现。由于训练集和测试/开发集之间的分布差异,模型可能会表现不佳。为了解决这个问题,你可以从测试/开发集获取一些数据点并将其引入到训练集中。确保原始图像主导各自的数据集,以防止出现不正确的结果。

如果训练集和开发集的分布不同,我们无法识别模型是否过拟合;在这种情况下,应引入一个新的训练-开发集来检查模型的过拟合情况。训练集和训练-开发集必须具有相同的分布。如果开发集和训练-开发集的误差差异很大,那么就存在数据不匹配的问题。为了解决这个问题,你需要进行手动误差分析,并在大多数情况下,收集更多的数据点。

注意

开发集与我们一直使用的验证集相同,我们有时称之为测试集,但那只是为了让你入门。还应该注意,我们仅在训练数据集上训练模型。

数据集的大小

开发集和测试集的大小应根据数据集的总体大小来确定。如果数据集的大小是 10,000 个数据点,那么 60%/20%/20%的划分会很好,因为测试集和开发集都有足够的数据点来准确衡量模型的性能。另一方面,如果数据集有 1,000,000 个数据点,那么 98%/1%/1%的划分就足够了,因为 10,000 个数据点已经足够评估模型的表现。

三个数据集的样本应该保持一致,以便我们在相同的环境中评估所有模型。为此,你可以在创建随机样本时设置一个“种子”值。设置随机数种子有助于每次运行实验时获得相同的随机数据划分。

处理未处理的数据集

当你开始处理更复杂且未经过多处理的数据集时,你会发现大多数情况下,你无法获得创建令人满意模型所需的所有数据。为了解决这个问题,你需要识别可以帮助你创建合格模型的外部数据集。你使用的附加数据可以有以下两种类型:

  • 相同数据的更多数据点:当模型由于数据集较小而过拟合时,这非常有用。如果无法获取更多数据点,可以使用更简单的模型——例如层数较少的神经网络或线性模型。

  • 来自不同来源的额外数据:有时候数据集中会缺少一些数据,例如数据集中城市的州或国家,或者数据集中列出的国家的宏观经济因素,如 GDP 和人均收入。此类数据可以轻松在互联网上找到,并可用于改进您创建的模型。

最佳实践是始终从探索性数据分析EDA)开始。EDA 帮助我们深入了解数据集,有助于识别最佳模型及可用于机器学习的变量。EDA 的另一个重要方面是检查数据是否存在异常。这可以确保数据在传输过程中没有发生错误。EDA 的结果可以与利益相关者共享,以确认数据的有效性。数据科学家在项目中可能需要多次回顾 EDA 步骤。

另一个需要牢记的事项是模型的应用场景。了解您的模型是用于实时处理还是批处理非常重要。这将帮助您选择合适的工具和模型。例如,如果实时处理是优先考虑的目标,那么您可能会使用一个能在不到一秒钟内产生结果的模型;而如果应用程序需要批处理,那么您可以使用那些需要几秒钟以上才能产生预测的复杂神经网络模型。

接下来,我们将探讨一些处理训练和进行超参数调优的最佳实践。在将数据拆分为训练集和测试集之前,始终对数据进行洗牌。另一个有助于更快收敛的做法是在训练过程中对训练数据进行洗牌。Keras 的fit函数有一个非常有用的参数,名为True,它会在每个训练周期前洗牌训练数据。需要记住的一个重要参数是随机数种子;它帮助数据科学家即使在随机洗牌和拆分的情况下,也能创建可重复的结果。要为 Keras 设置种子,请使用以下方法:

from numpy.random import seed
seed(1)
from tensorflow import set_random_seed
set_random_seed(1)

前两行设置了 NumPy 的随机种子,接下来的两行则为 TensorFlow 设置了种子,这是 Keras 使用的后端。

如果您正在处理一个大型数据集,建议先使用数据的子集来创建模型。尝试通过加深网络或使其更复杂来使模型过拟合。您可以使用正则化来限制模型过拟合数据。当您对模型有信心时,使用完整的训练数据并调整已创建的模型,以提高模型的性能。

Dropout 是一种非常强大的正则化方法;你应该尝试不同的 dropout 率,因为最优的 dropout 率因数据集不同而不同。如果 dropout 概率太低,效果就不会显现。另一方面,如果概率过高,模型就会开始欠拟合。通常,20%到 50%之间的 dropout 率效果最好。

学习率是一个重要的超参数。学习率过大会导致模型越过最优解,而学习率过小则会导致模型学习非常缓慢。如第五章《掌握结构化数据》中提到的,我们可以从较高的学习率开始,并在经过几步后降低学习率。

这有助于我们更快地达到最优点,同时由于步长减小,避免了模型越过解的情况。为了实现学习率的减少,我们可以使用 Keras 中的ReduceLROnPlateau回调函数。如果选择的指标停止改进,该回调函数会按照预定义的因子降低学习率。

注意

要进一步了解数据集,请参考文档:keras.io/callbacks/#…

from keras.callbacks import ReduceLROnPlateau
ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=10, min_delta=0.0001, min_lr=0)

我们将要监控的数量传递给monitor参数。factor指的是学习率需要减少的倍数;新的学习率将等于当前学习率乘以这个因子。patience是回调函数等待的 epochs 数量,等待后才会改变学习率。min_delta表示衡量模型在监控指标上改进的阈值。min_lr表示学习率的下限。

pandas Profiling

在前几章中,你学习了不同的探索结构化数据集的方法。EDA 在构建结构化数据模型时起着重要作用。执行 EDA 的步骤,如空值识别、相关性分析和计数唯一值等,通常不变,因此最好创建一个函数来完成这些任务,避免编写大量代码。pandas profiling 库正是做到了这一点:它接收一个 DataFrame,对数据进行分析并以交互式的输出形式展示结果。

输出包含相关列的以下信息:

  • 基本信息:包含关于变量类型、唯一值和缺失值的信息。

  • 分位数统计:包含关于最小值、Q1、中央値、Q3、最大值、范围和四分位距的信息。

  • 描述性统计:包含关于均值、众数、标准差、总和、中位数绝对偏差和变异系数的信息。

  • 最频繁的值:包含关于最常见值的计数以及其百分比频率的信息。

  • 直方图:包含关于数据集不同特征值频率的图表信息。

  • 相关性:这些突出显示了高度相关的变量,并建议将其移除。

要使用 pandas profiling,只需将数据框传递给 pandas_profiling 对象。使用以下代码:

import pandas_profiling
pandas_profiling.ProfileReport(df)

以下截图显示了我们在 第五章 中处理的电信流失数据集的 pandas profiling 输出的一部分,精通结构化数据

图 8.7:pandas profiling 输出的截图

](tos-cn-i-73owjymdk6/f92a793444ad47c5913d854a2b1557fd)

图 8.7:pandas profiling 输出的截图

您可以使用这个功能来探索我们在前几章中处理的数据集。pandas profiling 提供交互式输出,鼓励您去操作并玩转这些输出。

TensorBoard

TensorBoard 是一个可以用来查看训练日志并可视化模型准确率和损失度量的 Web 应用。它最初是为了与 TensorFlow 一起使用而创建的,但我们可以通过 Keras 中的 TensorBoard 回调 来使用 TensorBoard。要开始可视化,请创建 Keras 回调。使用以下代码来实现:

import keras
keras.callbacks.TensorBoard(log_dir='./logs', update_freq='epoch')

记住您在此处指定的日志目录;稍后您会需要它。您可以在 update_freq 中传递 'batch'、'epoch' 或整数值;这表示日志应写入的频率。下一步是启动 TensorBoard;为此,打开终端并运行以下命令:

tensorboard --logdir logs --port 6607

现在开始训练。不要忘记将回调传递给 fit 函数。TensorBoard 的第一个标签页显示了模型的训练日志。您可以在日志文件夹内创建多个子文件夹,以便在同一图表上获取不同模型的日志进行比较:

图 8.8:显示 TensorBoard 仪表盘的截图

](tos-cn-i-73owjymdk6/c975f32e19c448d8bf1cfc8e4a403324)

图 8.8:显示 TensorBoard 仪表盘的截图

在第二个标签页中,您可以可视化您创建的模型。下图展示了我们在上一章的第一个活动中创建的模型:

图 8.9:Keras 解释的模型

](tos-cn-i-73owjymdk6/e019a38aec23460f8d836c19dac1995e)

图 8.9:Keras 解释的模型

在 Jupyter Notebook 中可视化训练日志的另一种方法是使用 Matplotlib 绘制它们:

import matplotlib.pyplot as plt
plt.plot(model_details.history['acc'])
plt.plot(model_details.history['val_acc'])
plt.title('Cats vs. Dogs model accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train set', 'Dev set'], loc='upper left')
plt.show()

下图显示了我们在 活动 1 中使用的猫狗模型的训练集和测试集的准确率图:

图 8.10:模型的准确率日志

](tos-cn-i-73owjymdk6/bf546d5dd9f641f39d2700deca96587a)

图 8.10:模型的准确率日志

上面的准确率日志显示了训练集和开发集的准确率在不同的 epoch 上是如何变化的。正如你所看到的,开发集的准确率比训练集的准确率更为波动。这是因为模型没有见过这些例子,在初期的 epochs 中波动较大,但随着我们在更多的 epochs 上进行训练,模型变得更稳健,准确率波动会减小。

plt.plot(model_details.history['loss'])
plt.plot(model_details.history['val_loss'])
plt.title('Cats vs. Dogs model loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train set', 'Test set'], loc='upper left')
plt.show()

下图显示了我们在 活动 21 中使用的猫狗模型的训练集和测试集的损失图:

图 8.11:模型的损失日志

](tos-cn-i-73owjymdk6/1ac41ae1a1824c17b928bbc3a3674048)

图 8.11:模型的损失日志

类似于准确度日志,上面给出的损失日志显示了训练集和开发集的损失在不同 epochs 中的变化。第 19 个 epoch 附近的波峰表明,模型曾因过拟合于训练集而表现非常糟糕,但最终模型开始稳定,并在开发集上也给出了更好的结果。

如果你只关心模型日志,那么你可以使用之前给出的代码,在训练结束后绘制模型日志。然而,如果你正在训练一个需要较长时间的模型,建议使用 TensorBoard,因为它可以实时绘制训练损失和准确度。

AutoML

现在你已经创建了多个神经网络模型,你明白了构建表现良好的网络的两个主要组成部分。它们分别是:

  • 神经网络的架构

  • 神经网络的超参数

根据问题的不同,可能需要经过数十次迭代才能得到最佳网络。到目前为止,我们一直在手动创建架构并调优超参数。AutoML 可以帮助我们执行这些任务,它会为当前数据集搜索最优的网络和参数。Auto-Keras 是一个开源库,帮助我们在 Keras 上实现 AutoML。让我们通过一个练习来学习如何使用 Auto-Keras。

练习 59:使用 Auto-Keras 获取表现良好的网络

在本练习中,我们将利用 Auto-Keras 库,为 cats-vs-dogs 数据集(github.com/TrainingByP…

  1. 首先,创建一个加载图像标签的函数:

    def get_label(file):
        class_label = file.split('.')[0]
        if class_label == 'dog': label_vector = 0
        elif class_label == 'cat': label_vector = 1
        return label_vector
    
  2. 设置 SIZE,它是输入图像的维度(宽高相等的图像)。

    SIZE = 50
    
  3. 然后创建一个函数来读取图像及其标签。此处 PATH 变量包含训练数据集的路径。

    import os
    from PIL import Image
    import numpy as np
    from random import shuffle
    def get_data():
        data = []
        files = os.listdir(PATH)
        for image in tqdm(files):
            label_vector = get_label(image)
    
            img = Image.open(PATH + image).convert('L')
            img = img.resize((SIZE,SIZE))
    
            data.append([np.asarray(img),np.array(label_vector)])
    
        shuffle(data)
        return data
    
  4. 加载数据并将其划分为训练集和测试集:

    data = get_data()
    train = data[:7000]
    test = data[7000:]
    x_train = [data[0] for data in train]
    y_train = [data[1] for data in train]
    x_test = [data[0] for data in test]
    y_test = [data[1] for data in test]
    x_train = np.array(x_train).reshape(-1,SIZE,SIZE,1)
    x_test = np.array(x_test).reshape(-1,SIZE,SIZE,1)
    
  5. 现在,让我们开始使用 AutoML。

    首先,创建一个数组来设置 AutoKeras 的训练时间。时间一到,它会停止寻找最佳模型的过程:

    TRAINING_TIME = 60 * 60 * 1 # 1 hour
    

    我们将给 AutoKeras 一小时的时间来寻找最佳方法。

  6. 使用 AutoKeras 创建一个图像分类模型,并进行前一步中指定时间的训练:

    import autokeras as ak
    model = ak.ImageClassifier(verbose=True)
    model.fit(x_train, y_train, time_limit=TRAINING_TIME)
    model.final_fit(x_train, y_train, x_test, y_test, retrain=True)
    
  7. 输出将如下所示:

    图 8.12:图像分类模型
  8. 接下来,我们保存模型,以便以后可以再次使用它:

    model.export_autokeras_model("model.h5")
    
  9. 加载训练好的模型并使用它进行预测:

    from autokeras.utils import pickle_from_file
    model = pickle_from_file("model.h5")
    predictions = model.predict(x_test)
    
  10. 评估由 AutoKeras 创建的模型的准确性:

    score = model.evaluate(x_test, y_test)
    print("\nScore: {}".format(score))
    
  11. 模型的准确度如下:图 8.13:模型最终准确度

    图 8.13:模型最终准确度
  12. 我们成功地利用 autokeras 创建了一个图像分类器,用于检测提供的图像是猫还是狗。经过一小时的运行,这个模型的准确率为 72%,考虑到我们在第六章解码图像活动 22 中创建的模型准确率为 73%,这已经相当不错了。这显示了 AutoML 的强大功能,但有时我们在可接受的时间框架内可能无法获得足够好的结果。

使用 Keras 进行模型可视化

到目前为止,我们已经创建了一些神经网络模型,但还没有可视化它们。Keras 提供了一个非常实用的工具函数,可以绘制任何模型的图。要创建一个图形,首先定义模型,我们将使用第六章中的模型,解码图像,如下面的代码所示:

model = Sequential()

model.add(Conv2D(48, (3, 3), activation='relu', padding='same', input_shape=(50,50,1)))    
model.add(Conv2D(48, (3, 3), activation='relu'))    
model.add(MaxPool2D(pool_size=(2, 2)))
model.add(BatchNormalization())
model.add(Dropout(0.10))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(2, activation='softmax'))
model.summary()

然后使用 plot_model 将模型保存为图像,如以下代码所示。

from keras.utils import plot_model
plot_model(model, to_file='model.png', show_shapes=True)

show_shapes 参数会展示层的输入和输出形状。保存的图像如下:

图 8.14:由 Keras 创建的模型可视化

图 8.14:由 Keras 创建的模型可视化

活动 22:使用迁移学习预测图像

我们将创建一个项目,使用迁移学习来预测给定图片是狗还是猫。你将使用的基准模型是 InceptionV3\。我们将对这个模型进行微调,以适应我们的数据集,从而将模型调整为区分猫和狗。我们将使用 TensorBoard 实时监控训练指标,并使用本章中讨论的最佳实践。确保结果是可复现的:

  1. 重复你在前一个活动中的第 1 步所做的一切。

  2. 加载开发集和测试集,这些数据集将不会进行数据增强。

  3. 加载 Inception 模型并添加最终的全连接层。训练整个网络。

  4. 使用所有有用的回调函数。

  5. 使用 TensorBoard 可视化训练过程。

    注意

    这个活动的解决方案可以在第 391 页找到。

你可以使用以下代码片段绘制预测错误的图像,以了解模型的性能:

y_pred = model.predict(test_data[0])
incorrect_indices = np.nonzero(np.argmax(y_pred,axis=1) != np.argmax(test_data[1],axis=1))[0]
labels = ['dog', 'cat']
image = 5
plt.imshow(test_data[0][incorrect_indices[image]].reshape(SIZE, SIZE, CHANNELS),  cmap=plt.get_cmap('gray'))
plt.show()
print("Prediction: {0}".format(labels[np.argmax(y_pred[incorrect_indices[image]])]))

错误预测的图像如下:

图 8.15:错误预测的样本

图 8.15:错误预测的样本

总结

在本章中,我们介绍了迁移学习并利用它加速深度学习模型的创建。接着我们学习了训练集、开发集和测试集分开的重要性,并讨论了如何处理现实生活中的未处理数据集。之后,我们讲解了什么是 AutoML,以及如何以最少的工作量找到最优的网络。最后,我们学习了如何可视化神经网络模型和训练日志。

现在,你已经完成了本章的学习,具备了处理任何数据以创建机器学习模型的能力。

最后,完成本书后,你应该对数据科学的概念有一个深入的理解,并且能够使用 Python 语言处理不同的数据集来解决商业案例问题。你所学到的不同概念,包括预处理、数据可视化、图像增强和自然语言处理等,应该帮助你全面掌握如何处理数据。

第十九章:附录

关于

本节内容是为帮助您完成书中活动而包含的。它包括学生需要执行的详细步骤,以便完成并实现书中的目标。

第一章:数据科学与数据预处理简介

活动 1:使用银行营销订阅数据集进行预处理

解决方案

让我们对Bank Marketing Subscription数据集进行各种预处理任务。我们还将把数据集分为训练数据和测试数据。按照以下步骤完成此活动:

  1. 打开一个 Jupyter 笔记本并添加一个新单元格,导入 pandas 库并将数据集加载到 pandas 数据框中。首先需要导入该库,然后使用pd.read_csv()函数,如下所示:

    import pandas as pd
    Link = 'https://github.com/TrainingByPackt/Data-Science-with-Python/blob/master/Chapter01/Data/Banking_Marketing.csv'
    #reading the data into the dataframe into the object data
    df = pd.read_csv(Link, header=0)
    
  2. 要查找数据集中的行数和列数,请添加以下代码:

    #Finding number of rows and columns
    print("Number of rows and columns : ",df.shape)
    

    上述代码生成以下输出:

    图 1.60:数据集中的行数和列数

    图 1.60:数据集中的行数和列数
  3. 要打印所有列的列表,请添加以下代码:

    #Printing all the columns
    print(list(df.columns))
    

    上述代码生成以下输出:

    图 1.61:数据集中包含的列列表

    图 1.61:数据集中包含的列列表
  4. 要概览每一列的基本统计数据,如计数、均值、中位数、标准差、最小值、最大值等,可以添加以下代码:

    #Basic Statistics of each column
    df.describe().transpose()
    

    上述代码生成以下输出:

    图 1.62:每一列的基本统计数据

    图 1.62:每一列的基本统计数据
  5. 要打印每一列的基本信息,请添加以下代码:

    #Basic Information of each column
    print(df.info())
    

    上述代码生成以下输出:

    图 1.63:每一列的基本信息

    图 1.63:每一列的基本信息

    在上面的图中,可以看到没有任何列包含空值。此外,还提供了每一列的数据类型。

  6. 现在让我们检查缺失值和每个特征的类型。请添加以下代码来执行此操作:

    #finding the data types of each column and checking for null
    null_ = df.isna().any()
    dtypes = df.dtypes
    sum_na_ = df.isna().sum()
    info = pd.concat([null_,sum_na_,dtypes],axis = 1,keys = ['isNullExist','NullSum','type'])
    info
    

    查看下面图中的输出结果:

    图 1.64:每一列的信息,包括空值的数量和数据类型

    图 1.64:每一列的信息,包括空值的数量和数据类型
  7. 由于我们已经将数据集加载到data对象中,我们将从数据集中删除空值。要删除空值,可以添加以下代码:

    #removing Null values
    df = df.dropna()
    #Total number of null in each column
    print(df.isna().sum())# No NA
    

    查看下面图中的输出结果:

    图 1.65:无空值的数据集特征

    图 1.65:无空值的数据集特征
  8. 现在我们检查数据集中education列的频率分布。使用value_counts()函数来实现这一点:

    df.education.value_counts()
    

    查看下面图中的输出结果:

    图 1.66:教育列的频率分布

    图 1.66:education 列的频率分布
  9. 在前面的图中,我们可以看到数据集的education列有很多类别。我们需要减少这些类别,以便更好地建模。为了检查education列中的各种类别,我们使用unique()函数。输入以下代码来实现这一点:

    df.education.unique()  
    

    输出如下:

    图 1.67:education 列的各种类别

    图 1.67:education 列的各种类别
  10. 现在让我们将basic.4ybasic.9ybasic.6y这些类别合并为一个basic类别。为此,我们可以使用 pandas 的replace函数:

    df.education.replace({"basic.9y":"Basic","basic.6y":"Basic","basic.4y":"Basic"},inplace=True)
    
  11. 要检查分组后的类别列表,添加以下代码:

    df.education.unique()  
    

    图 1.68:education 列的各种类别

    图 1.68:education 列的各种类别

    在前面的图中,你可以看到basic.9ybasic.6ybasic.4y被合并为Basic

  12. 现在我们选择并执行适当的数据编码方法。添加以下代码来实现这一点:

    #Select all the non numeric data using select_dtypes function
    data_column_category = df.select_dtypes(exclude=[np.number]).columns
    

    前面的代码生成了以下输出:

    图 1.69:数据集的各个列

    图 1.69:数据集的各个列
  13. 现在我们定义一个包含数据中所有类别特征名称的列表。此外,我们循环遍历列表中的每个变量,获取虚拟变量编码的输出。添加以下代码来实现这一点:

    cat_vars=data_column_category
    for var in cat_vars:
        cat_list='var'+'_'+var
        cat_list = pd.get_dummies(df[var], prefix=var)
        data1=df.join(cat_list)
        df=data1
     df.columns
    

    前面的代码生成了以下输出:

    图 1.70:数据中类别特征的列表

    图 1.70:数据中类别特征的列表
  14. 现在我们忽略已经进行了编码的类别列。我们将只选择数值列和已编码的类别列。添加代码以实现此操作:

    #Categorical features
    cat_vars=data_column_category
    #All features
    data_vars=df.columns.values.tolist()
    #neglecting the categorical column for which we have done encoding
    to_keep = []
    for i in data_vars:
        if i not in cat_vars:
            to_keep.append(i)
    
    #selecting only the numerical and encoded catergorical column
    data_final=df[to_keep]
    data_final.columns
    

    前面的代码生成了以下输出:

    图 1.71:数值列和已编码类别列的列表

    图 1.71:数值列和已编码类别列的列表
  15. 最后,我们将数据拆分为训练集和测试集。添加以下代码来实现这一点:

    #Segregating Independent and Target variable
    X=data_final.drop(columns='y')
    y=data_final['y']
    from sklearn. model_selection import train_test_split
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
    print("FULL Dateset X Shape: ", X.shape )
    print("Train Dateset X Shape: ", X_train.shape )
    print("Test Dateset X Shape: ", X_test.shape )
    

    输出如下:

图 1.72:完整数据集、训练集和测试集的形状

图 1.72:完整数据集、训练集和测试集的形状

第二章:数据可视化

活动 2:折线图

解决方案

  1. 创建一个包含从一月到六月的六个字符串的列表,并将其保存为 x,使用以下代码:

    x = ['January','February','March','April','May','June']
    
  2. 创建一个包含 6 个值的列表,代表'Items Sold',其值从 1000 开始,每次增加 200,直到最终值为 2000,并将其保存为 y,如下所示:

    y = [1000, 1200, 1400, 1600, 1800, 2000]
    
  3. 使用以下代码绘制 y('Items Sold')与 x('Month')的折线图,线为虚线,标记为星形:

    plt.plot(x, y, '*:b')
    
  4. 使用以下代码将 x 轴设置为'Month':

    plt.xlabel('Month')
    
  5. 将 y 轴设置为'Items Sold',如下所示:

    plt.ylabel('Items Sold')
    
  6. 要将标题设置为'Items Sold has been Increasing Linearly',请参考以下代码:

    plt.title('Items Sold has been Increasing Linearly')
    

    查看以下截图,查看结果输出:

图 2.33:按月销售项目的折线图

图 2.33:按月销售项目的折线图

活动 3:条形图

解决方案

  1. 使用以下代码为x创建一个包含五个字符串的列表,表示获得最多冠军的 NBA 球队名称:

    x = ['Boston Celtics','Los Angeles Lakers', 'Chicago Bulls', 'Golden State Warriors', 'San Antonio Spurs']
    
  2. 使用以下代码为y创建一个包含五个值的列表,这些值对应于x中的字符串,表示'Titles Won':

    y = [17, 16, 6, 6, 5]
    
  3. xy放入数据框中,列名分别为'Team'和'Titles',如下所示:

    import pandas as pd
    
    df = pd.DataFrame({'Team': x,
                       'Titles': y})
    
  4. 使用以下代码对数据框按'Titles'进行降序排序,并将结果保存为 df_sorted:

    df_sorted = df.sort_values(by=('Titles'), ascending=False)
    
    注意

    如果我们使用ascending=True进行排序,图表中较大的值会出现在右侧。由于我们希望较大的值出现在左侧,我们将使用ascending=False

  5. 编写一个程序化的标题,并首先通过以下代码找到获得最多冠军的球队,并将其保存为team_with_most_titles对象:

    team_with_most_titles = df_sorted['Team'][0]
    
  6. 然后,使用以下代码检索获得最多冠军的球队的冠军数量:

    most_titles = df_sorted['Titles'][0]
    
  7. 最后,使用以下代码创建一个字符串'The Boston Celtics have the most titles with 17':

    title = 'The {} have the most titles with {}'.format(team_with_most_titles, most_titles)
    
  8. 使用以下代码绘制一个条形图,显示各球队的冠军数量:

    import matplotlib.pyplot as plt
    
    plt.bar(df_sorted['Team'], df_sorted['Titles'], color='red')
    
  9. 使用以下代码将 x 轴标签设置为'Team':

    plt.xlabel('Team')
    
  10. 使用以下代码将 y 轴标签设置为'Number of Championships':

    plt.ylabel('Number of Championships')
    
  11. 为了防止 x 轴刻度标签重叠,我们将它们旋转 45 度,请参考以下代码:

    plt.xticks(rotation=45)
    
  12. 将图表的标题设置为我们创建的程序化title对象,如下所示:

    plt.title(title)
    
  13. 使用以下代码将图表保存到当前工作目录下,文件名为'Titles_by_Team.png':

    plt.savefig('Titles_by_Team)
    
  14. 使用plt.show()打印图表。为了更好地理解这一点,请查看以下输出截图:图 2.34:NBA 球队拥有的冠军数量的条形图

    图 2.34:NBA 球队拥有的冠军数量的条形图
    注意

    当我们使用plt.show()将图表打印到控制台时,它会按预期显示;然而,当我们打开我们创建的名为'Titles_by_Team.png'的文件时,我们会看到它裁剪了 x 轴刻度标签。

    下图显示了裁剪了 x 轴刻度标签的条形图。

    图 2.35:裁剪了 x 轴刻度标签的'Titles_by_Team.png'

    图 2.35:裁剪了 x 轴刻度标签的'Titles_by_Team.png'
  15. 为了修复裁剪问题,在plt.savefig()中添加bbox_inches='tight'作为参数,如下所示:

    plt.savefig('Titles_by_Team', bbox_inches='tight')
    
  16. 现在,当我们从工作目录中打开保存的'Titles_by_Team.png'文件时,我们看到 x 轴刻度标签没有被裁剪。

    查看以下输出,查看最终结果:

图 2.36:未裁剪 x 轴刻度标签的'Titles_by_Team.png'

图 2.36:未裁剪 x 轴刻度标签的'Titles_by_Team.png'

活动 4:使用子图展示多种图表类型

解决方案

  1. 导入'Items_Sold_by_Week.csv'文件,并使用以下代码将其保存为Items_by_Week数据框对象:

    import pandas as pd
    
    Items_by_Week = pd.read_csv('Items_Sold_by_Week.csv')
    
  2. 导入Weight_by_Height.csv文件并将其保存为Weight_by_Height数据框对象,如下所示:

    Weight_by_Height = pd.read_csv('Weight_by_Height.csv')
    
  3. 使用以下代码生成一个包含 100 个正态分布数字的数组,作为直方图和箱形图的数据,并将其保存为 y:

    y = np.random.normal(loc=0, scale=0.1, size=100)
    
  4. 为了生成一个包含六个子图、按三行两列排列且不重叠的图形,请参考以下代码:

    import matplotlib.pyplot as plt
    
    fig, axes = plt.subplots(nrows=3, ncols=2)
    plt.tight_layout()
    
  5. 使用以下代码将相应的坐标轴标题设置为与图 2.32 中相同:

    axes[0,0].set_title('Line') 
    axes[0,1].set_title('Bar') 
    axes[1,0].set_title('Horizontal Bar') 
    axes[1,1].set_title('Histogram') 
    axes[2,0].set_title('Scatter') 
    axes[2,1].set_title('Box-and-Whisker') 
    

    图 2.37:标题、无重叠的空子图

    图 2.37:标题、无重叠的空子图
  6. LineBarHorizontal Bar坐标轴上,使用以下代码绘制Items_SoldWeek的关系:

    axes[0,0].plot(Items_by_Week['Week'], Items_by_Week['Items_Sold'])
    axes[0,1].bar(Items_by_Week['Week'], Items_by_Week['Items_Sold'])
    axes[1,0].barh(Items_by_Week['Week'], Items_by_Week['Items_Sold'])
    

    请在以下图中查看结果输出:

    图 2.38:添加的折线图、条形图和水平条形图

    图 2.38:添加的折线图、条形图和水平条形图
  7. HistogramBox-and-Whisker坐标轴上,使用以下代码绘制包含 100 个正态分布数字的数组:

    axes[1,1].hist(y, bins=20)axes[2,1].boxplot(y)
    

    结果输出如下所示:

    图 2.39:添加的直方图和箱形图

    图 2.39:添加的直方图和箱形图
  8. 使用以下代码在Weight_by_Height数据框的Scatterplot坐标轴上绘制WeightHeight的关系:

    axes[2,0].scatter(Weight_by_Height['Height'], Weight_by_Height['Weight'])
    

    请参阅这里的图示,以查看结果输出:

    图 2.40:添加的散点图

    图 2.40:添加的散点图
  9. 使用axes[row, column].set_xlabel('X-Axis Label')axes[row, column].set_ylabel('Y-Axis Label')分别标注每个子图的 x 轴和 y 轴。

    请参阅这里的图示,以查看结果输出:

    图 2.41:X 和 Y 轴已被标注

    图 2.41:X 和 Y 轴已被标注
  10. 使用figsize参数在子图函数中增加图形的大小,如下所示:

    fig, axes = plt.subplots(nrows=3, ncols=2, figsize=(8,8))
    
  11. 使用以下代码将图形保存为当前工作目录中的Six_Subplots

    fig.savefig('Six_Subplots')
    

    以下图显示了Six_Subplots.png文件:

图 2.42:Six_Subplots.png 文件

图 2.42:Six_Subplots.png 文件

第三章:通过 Scikit-Learn 介绍机器学习

活动 5:生成预测并评估多元线性回归模型的性能

解决方案

  1. 使用以下代码在测试数据上生成预测:

    predictions = model.predict(X_test)
    2.    Plot the predicted versus actual values on a scatterplot using the following code:
    import matplotlib.pyplot as plt
    from scipy.stats import pearsonr
    
    plt.scatter(y_test, predictions)
    plt.xlabel('Y Test (True Values)')
    plt.ylabel('Predicted Values')
    plt.title('Predicted vs. Actual Values (r = {0:0.2f})'.format(pearsonr(y_test, predictions)[0], 2))
    plt.show()
    

    请参阅这里的结果输出:

    图 3.33:来自多元线性回归模型的预测值与实际值的散点图

    图 3.33:来自多元线性回归模型的预测值与实际值的散点图
    注意

    在多元线性回归模型中,预测值与实际值之间的线性相关性(r = 0.93)比简单线性回归模型(r = 0.62)强得多。

  2. 为了绘制残差的分布,请参考这里的代码:

    import seaborn as sns
    from scipy.stats import shapiro
    
    sns.distplot((y_test - predictions), bins = 50)
    plt.xlabel('Residuals')
    plt.ylabel('Density')
    plt.title('Histogram of Residuals (Shapiro W p-value = {0:0.3f})'.format(shapiro(y_test - predictions)[1]))
    plt.show()
    

    请参阅这里的结果输出:

    图 3.34:多元线性回归模型的残差分布

    图 3.34:多元线性回归模型的残差分布
    注意

    我们的残差呈负偏态且非正态分布,但相比简单线性模型,这种偏态较小。

  3. 计算平均绝对误差、均方误差、均方根误差和 R 方,并将它们放入 DataFrame,如下所示:

    from sklearn import metrics
    import numpy as np
    
    metrics_df = pd.DataFrame({'Metric': ['MAE', 
                                          'MSE', 
                                          'RMSE', 
                                          'R-Squared'],
                              'Value': [metrics.mean_absolute_error(y_test, predictions),
                                          metrics.mean_squared_error(y_test, predictions),
                                        np.sqrt(metrics.mean_squared_error(y_test, predictions)),
                                        metrics.explained_variance_score(y_test, predictions)]}).round(3)
    print(metrics_df)
    

    请参考结果输出:

    图 3.35:多元线性回归模型的模型评估指标

图 3.35:多元线性回归模型的模型评估指标

与简单线性回归模型相比,多元线性回归模型在每个指标上表现更好。

活动 6:生成预测并评估调整后的逻辑回归模型性能

解决方案

  1. 使用以下代码生成降雨的预测概率:

    predicted_prob = model.predict_proba(X_test)[:,1]
    
  2. 使用 predicted_class = model.predict(X_test) 生成降雨的预测类别。

  3. 使用混淆矩阵评估性能,并使用以下代码将其保存为 DataFrame:

    from sklearn.metrics import confusion_matrix
    import numpy as np
    
    cm = pd.DataFrame(confusion_matrix(y_test, predicted_class))
    cm['Total'] = np.sum(cm, axis=1)
    cm = cm.append(np.sum(cm, axis=0), ignore_index=True)
    cm.columns = ['Predicted No', 'Predicted Yes', 'Total']
    cm = cm.set_index([['Actual No', 'Actual Yes', 'Total']])
    print(cm)
    

    图 3.36:我们逻辑回归网格搜索模型的混淆矩阵

    图 3.36:我们逻辑回归网格搜索模型的混淆矩阵
    注意

    很棒!我们将假阳性的数量从 6 降低到 2。此外,假阴性从 10 降低到了 4(请参见 练习 26)。请注意,结果可能会略有不同。

  4. 为了进一步评估,打印分类报告,如下所示:

    from sklearn.metrics import classification_report
    
    print(classification_report(y_test, predicted_class))
    

图 3.37:我们逻辑回归网格搜索模型的分类报告

图 3.37:我们逻辑回归网格搜索模型的分类报告

通过调整逻辑回归模型的超参数,我们能够在已经表现良好的逻辑回归模型基础上进一步优化。

活动 7:生成预测并评估 SVC 网格搜索模型的性能

解决方案

  1. 使用以下代码提取降雨的预测类别:

    predicted_class = model.predict(X_test)
    
  2. 使用以下代码创建并打印混淆矩阵:

    from sklearn.metrics import confusion_matrix
    import numpy as np
    
    cm = pd.DataFrame(confusion_matrix(y_test, predicted_class))
    cm['Total'] = np.sum(cm, axis=1)
    cm = cm.append(np.sum(cm, axis=0), ignore_index=True)
    cm.columns = ['Predicted No', 'Predicted Yes', 'Total']
    cm = cm.set_index([['Actual No', 'Actual Yes', 'Total']])
    print(cm)
    

    请查看结果输出:

    图 3.38:我们 SVC 网格搜索模型的混淆矩阵

    图 3.38:我们 SVC 网格搜索模型的混淆矩阵
  3. 生成并打印分类报告,如下所示:

    from sklearn.metrics import classification_report
    
    print(classification_report(y_test, predicted_class))
    

    请查看结果输出:

图 3.39:我们 SVC 网格搜索模型的分类报告

图 3.39:我们 SVC 网格搜索模型的分类报告

在这里,我们展示了如何使用网格搜索调整 SVC 模型的超参数。

活动 8:为决策树分类器准备数据

解决方案

  1. 导入 weather.csv 并使用以下代码将其存储为 DataFrame:

    import pandas as pd
    
    df = pd.read_csv('weather.csv')
    
  2. Description 列进行虚拟编码,如下所示:

    import pandas as pd
    
    df_dummies = pd.get_dummies(df, drop_first=True)
    
  3. 使用以下代码打乱 df_dummies

    from sklearn.utils import shuffle
    
    df_shuffled = shuffle(df_dummies, random_state=42)
    
  4. 按照以下步骤将 df_shuffled 分割为 X 和 y:

    DV = 'Rain'
    X = df_shuffled.drop(DV, axis=1)
    y = df_shuffled[DV]
    
  5. Xy 分割为测试数据和训练数据:

    from sklearn.model_selection import train_test_split
    
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42)
    
  6. 使用以下代码缩放 X_trainX_test

    from sklearn.preprocessing import StandardScaler
    
    model = StandardScaler()
    X_train_scaled = model.fit_transform(X_train)
    X_test_scaled = model.transform(X_test)
    

活动 9:生成预测并评估决策树分类器模型的表现

解决方案

  1. 使用以下代码生成预测的降雨概率:

    predicted_prob = model.predict_proba(X_test_scaled)[:,1]
    
  2. 使用以下代码生成降雨的预测类别:

    predicted_class = model.predict(X_test)
    
  3. 使用以下代码生成并打印混淆矩阵:

    from sklearn.metrics import confusion_matrix
    import numpy as np
    
    cm = pd.DataFrame(confusion_matrix(y_test, predicted_class))
    cm['Total'] = np.sum(cm, axis=1)
    cm = cm.append(np.sum(cm, axis=0), ignore_index=True)
    cm.columns = ['Predicted No', 'Predicted Yes', 'Total']
    cm = cm.set_index([['Actual No', 'Actual Yes', 'Total']])
    print(cm)
    

    请参考此处的结果输出:

    图 3.40:经过调优的决策树分类器模型的混淆矩阵

    图 3.40:经过调优的决策树分类器模型的混淆矩阵
  4. 按以下方式打印分类报告:

    from sklearn.metrics import classification_report
    print(classification_report(y_test, predicted_class))
    

    请参考此处的结果输出:

图 3.41:经过调优的决策树分类器模型的分类报告

图 3.41:经过调优的决策树分类器模型的分类报告

只有一个被错误分类的观测值。因此,通过在 weather.csv 数据集上调优决策树分类器模型,我们能够以极高的准确度预测降雨(或降雪)。我们可以看到,唯一的驱动特征是摄氏度温度。考虑到决策树通过递归分区进行预测,这一点是有意义的。

活动 10:调优随机森林回归模型

解决方案

  1. 按以下方式指定超参数空间:

    import numpy as np
    
    grid = {'criterion': ['mse','mae'],
            'max_features': ['auto', 'sqrt', 'log2', None],
            'min_impurity_decrease': np.linspace(0.0, 1.0, 10),
            'bootstrap': [True, False],
            'warm_start': [True, False]}
    
  2. 实例化 GridSearchCV 模型,使用以下代码优化解释方差:

    from sklearn.model_selection import GridSearchCV
    from sklearn.ensemble import RandomForestRegressor
    
    model = GridSearchCV(RandomForestRegressor(), grid, scoring='explained_variance', cv=5)
    
  3. 使用以下代码将网格搜索模型拟合到训练集(注意这可能需要一些时间):

    model.fit(X_train_scaled, y_train)
    

    请参阅此处的输出:

    图 3.42:经过调优的随机森林回归模型网格搜索的输出

    图 3.42:经过调优的随机森林回归模型网格搜索的输出
  4. 按以下方式打印调优后的参数:

    best_parameters = model.best_params_
    print(best_parameters)
    

    请参阅以下结果输出:

图 3.43:经过调优的随机森林回归模型网格搜索的超参数

图 3.43:经过调优的随机森林回归模型网格搜索的超参数

活动 11:生成预测并评估调优后的随机森林回归模型的表现

解决方案

  1. 使用以下代码在测试数据上生成预测:

    predictions = model.predict(X_test_scaled)
    
  2. 使用以下代码绘制预测值与实际值的相关性:

    import matplotlib.pyplot as plt
    from scipy.stats import pearsonr
    
    plt.scatter(y_test, predictions)
    plt.xlabel('Y Test (True Values)')
    plt.ylabel('Predicted Values')
    plt.title('Predicted vs. Actual Values (r = {0:0.2f})'.format(pearsonr(y_test, predictions)[0], 2))
    plt.show()
    

    请参考此处的结果输出:

    图 3.44:经过调优超参数的随机森林回归模型的预测值与实际值的散点图

    图 3.44:经过调优超参数的随机森林回归模型的预测值与实际值的散点图
  3. 按照以下步骤绘制残差的分布:

    import seaborn as sns
    from scipy.stats import shapiro
    
    sns.distplot((y_test - predictions), bins = 50)
    plt.xlabel('Residuals')
    plt.ylabel('Density')
    plt.title('Histogram of Residuals (Shapiro W p-value = {0:0.3f})'.format(shapiro(y_test - predictions)[1]))
    plt.show()
    

    请参考此处的结果输出:

    图 3.45:经过调优超参数的随机森林回归模型的残差直方图    调优超参数

    图 3.45:经过调优超参数的随机森林回归模型的残差直方图
  4. 使用以下代码计算指标,将其放入 DataFrame 中,并打印:

    from sklearn import metrics
    import numpy as np
    
    metrics_df = pd.DataFrame({'Metric': ['MAE', 
                                          'MSE', 
                                          'RMSE', 
                                          'R-Squared'],
                              'Value': [metrics.mean_absolute_error(y_test, predictions),
                                        metrics.mean_squared_error(y_test, predictions),
                                        np.sqrt(metrics.mean_squared_error(y_test, predictions)),
                                        metrics.explained_variance_score(y_test, predictions)]}).round(3)
    print(metrics_df)
    

    在此查看结果输出:

图 3.46:调优超参数后的随机森林回归模型的模型评估指标

图 3.46:调优超参数后的随机森林回归模型的模型评估指标

与多元线性回归相比,随机森林回归模型似乎表现不佳,表现为较大的 MAE、MSE 和 RMSE 值,以及较低的解释方差。此外,预测值与实际值之间的相关性较弱,残差也远离正态分布。然而,通过利用集成方法使用随机森林回归器,我们构建了一个能够解释 75.8%温度方差并预测温度(摄氏度+3.781 度)的模型。

第四章:降维与无监督学习

活动 12:集成 k-means 聚类与预测计算

解决方案

在玻璃数据集被导入、打乱并标准化之后(参见练习 58):

  1. 实例化一个空的数据框,附加每个模型,并使用以下代码将其保存为新的数据框对象labels_df

    import pandas as pd
    labels_df = pd.DataFrame()
    
  2. 使用以下代码在循环外导入KMeans函数:

    from sklearn.cluster import KMeans
    
  3. 完成 100 次迭代,如下所示:

    for i in range(0, 100):
    
  4. 使用以下代码保存一个具有两个簇(事先任意决定)的 KMeans 模型对象:

    model = KMeans(n_clusters=2)
    
  5. 使用以下代码拟合模型至scaled_features

    model.fit(scaled_features)
    
  6. 生成标签数组,并将其保存为标签对象,如下所示:

    labels = model.labels_
    
  7. 使用以下代码将标签存储为labels_df中的一列,列名为迭代名称:

    labels_df['Model_{}_Labels'.format(i+1)] = labels
    
  8. 在为每个 100 个模型生成标签后(参见活动 21),使用以下代码计算每一行的众数:

    row_mode = labels_df.mode(axis=1)
    
  9. row_mode分配给labels_df中的新列,如下代码所示:

    labels_df['row_mode'] = row_mode
    
  10. 查看labels_df的前五行

    print(labels_df.head(5))
    

图 4.24:labels_df 的前五行

图 4.24:labels_df 的前五行

我们通过迭代多个模型,保存每次迭代的预测结果,并将最终的预测结果设为这些预测结果的众数,从而大幅提高了对预测的信心。然而,这些预测是由使用预定簇数的模型生成的。除非我们事先知道簇的数量,否则我们需要发现最优的簇数来对观察结果进行分割。

活动 13:PCA 变换后按簇评估平均惯性

解决方案

  1. 实例化一个 PCA 模型,将n_components参数的值设置为best_n_components(即,记住,best_n_components = 6),如下所示:

    from sklearn.decomposition import PCA
    model = PCA(n_components=best_n_components)
    
  2. 将模型拟合到scaled_features并将其转化为六个组件,如下所示:

    df_pca = model.fit_transform(scaled_features)
    
  3. 使用以下代码将numpyKMeans函数导入循环外:

    from sklearn.cluster import KMeans
    import numpy as np
    
  4. 实例化一个空列表 inertia_list,我们将在每次迭代后使用以下代码将惯性值附加到该列表中:

    inertia_list = []
    
  5. 在内部的 for 循环中,我们将遍历 100 个模型,如下所示:

    for i in range(100):
    
  6. 使用以下代码构建我们的 KMeans 模型,n_clusters=x

    model = KMeans(n_clusters=x)
    
    注意

    x 的值将由外部循环决定,详细内容请参见此处。

  7. 如下所示,将模型拟合到 df_pca

    model.fit(df_pca)
    
  8. 获取惯性值并使用以下代码将其保存到对象惯性中:

    inertia = model.inertia_
    
  9. 使用以下代码将惯性附加到 inertia_list

    inertia_list.append(inertia)
    
  10. 进入外部循环后,使用以下代码实例化另一个空列表,以存储平均惯性值:

    mean_inertia_list_PCA = []
    
  11. 由于我们想要检查在 n_clusters 从 1 到 10 的 100 个模型中的平均惯性,我们将如下实例化外部循环:

    for x in range(1, 11):
    
  12. 在内部循环完成 100 次迭代后,将每个模型的惯性值附加到 inertia_list,计算该列表的平均值,并使用以下代码将对象保存为 mean_inertia

    mean_inertia = np.mean(inertia_list)
    
  13. 使用以下代码将 mean_inertia 附加到 mean_inertia_list_PCA

    mean_inertia_list_PCA.append(mean_inertia)
    
  14. 使用以下代码将 mean_inertia_list_PCA 打印到控制台:

    print(mean_inertia_list_PCA)
    
  15. 注意以下屏幕截图中的输出:

图 4.25: mean_inertia_list_PCA

图 4.25: mean_inertia_list_PCA

第五章: 精通结构化数据

活动 14: 训练和预测一个人的收入

解决方案

  1. 导入库并使用 pandas 加载收入数据集。首先,导入 pandas,然后使用 read_csv 读取数据。

    import pandas as pd
    import xgboost as xgb
    import numpy as np
    from sklearn.metrics import accuracy_score
    data = pd.read_csv("../data/adult-data.csv", names=['age', 'workclass', 'education-num', 'occupation', 'capital-gain', 'capital-loss', 'hours-per-week', 'income'])
    

    我们传递列名的原因是因为数据中没有这些列名。我们这样做是为了让我们的工作更轻松。

  2. 使用来自 sklearn 的 Label Encoder 对字符串进行编码。首先,导入 Label Encoder,然后逐一编码所有字符串类别列。

    from sklearn.preprocessing import LabelEncoder
    data['workclass'] = LabelEncoder().fit_transform(data['workclass'])
    data['occupation'] = LabelEncoder().fit_transform(data['occupation'])
    data['income'] = LabelEncoder().fit_transform(data['income'])
    

    在这里,我们对所有类别字符串数据进行了编码。我们还有另一种方法可以避免重复编写相同的代码。看看你能否找到它。

  3. 我们首先将因变量和自变量分开。

    X = data.copy()
    X.drop("income", inplace = True, axis = 1)
    Y = data.income
    
  4. 然后,我们将其分为 80:20 的训练集和测试集。

    X_train, X_test = X[:int(X.shape[0]*0.8)].values, X[int(X.shape[0]*0.8):].values
    Y_train, Y_test = Y[:int(Y.shape[0]*0.8)].values, Y[int(Y.shape[0]*0.8):].values
    
  5. 接下来,我们将它们转换为 DMatrix,这是该库支持的数据结构。

    train = xgb.DMatrix(X_train, label=Y_train)
    test = xgb.DMatrix(X_test, label=Y_test)
    
  6. 然后,我们使用以下参数通过 XGBoost 训练模型。

    param = {'max_depth':7, 'eta':0.1, 'silent':1, 'objective':'binary:hinge'} num_round = 50
    model = xgb.train(param, train, num_round)
    
  7. 检查模型的准确性。

    preds = model.predict(test)
    accuracy = accuracy_score(Y[int(Y.shape[0]*0.8):].values, preds)
    print("Accuracy: %.2f%%" % (accuracy * 100.0))
    

    输出如下:

图 5.36: 最终模型的准确性

图 5.36: 最终模型的准确性

活动 15: 预测客户流失

解决方案

  1. 使用 pandas 加载收入数据集。首先,导入 pandas,然后使用 read_csv 读取数据。

    import pandas as pd
    import numpy as np
    data = data = pd.read_csv("data/telco-churn.csv")
    
  2. customerID 变量不是必需的,因为任何未来的预测都会有一个唯一的 customerID,这使得该变量在预测中无用。

    data.drop('customerID', axis = 1, inplace = True)
    
  3. 使用 scikit 将所有类别变量转换为整数。下面给出一个例子。

    from sklearn.preprocessing import LabelEncoder
    data['gender'] = LabelEncoder().fit_transform(data['gender'])
    
  4. 检查数据集中变量的数据类型。

    data.dtypes
    

    变量的数据类型将如下所示:

    图 5.37: 变量的数据类型

    图 5.37:变量的数据类型
  5. 如你所见,TotalCharges是一个对象。所以,将TotalCharges的数据类型从对象转换为数值型。coerce会将缺失值设置为 null。

    data.TotalCharges = pd.to_numeric(data.TotalCharges, errors='coerce')
    
  6. 将数据框转换为 XGBoost 变量,并使用之前的练习作为参考,找到适合数据集的最佳参数。

    import xgboost as xgb
    import matplotlib.pyplot as plt
    X = data.copy()
    X.drop("Churn", inplace = True, axis = 1)
    Y = data.Churn
    X_train, X_test = X[:int(X.shape[0]*0.8)].values, X[int(X.shape[0]*0.8):].values
    Y_train, Y_test = Y[:int(Y.shape[0]*0.8)].values, Y[int(Y.shape[0]*0.8):].values
    train = xgb.DMatrix(X_train, label=Y_train)
    test = xgb.DMatrix(X_test, label=Y_test)
    test_error = {}
    for i in range(20):
        param = {'max_depth':i, 'eta':0.1, 'silent':1, 'objective':'binary:hinge'}
        num_round = 50
        model_metrics = xgb.cv(param, train, num_round, nfold = 10)
        test_error[i] = model_metrics.iloc[-1]['test-error-mean']
    
    plt.scatter(test_error.keys(),test_error.values())
    plt.xlabel('Max Depth')
    plt.ylabel('Test Error')
    plt.show()
    

    查看以下截图中的输出:

    图 5.38:电信流失数据集的最大深度与测试误差的关系图

    图 5.38:电信流失数据集的最大深度与测试误差的关系图

    从图中可以清楚地看到,最大深度为 4 时误差最小。因此,我们将使用这一深度来训练我们的模型。

  7. 使用我们在前一步中选择的max_depth参数创建模型。

    param = {'max_depth':4, 'eta':0.1, 'silent':1, 'objective':'binary:hinge'}
    num_round = 100
    model = xgb.train(param, train, num_round)
    preds = model.predict(test)
    from sklearn.metrics import accuracy_score
    accuracy = accuracy_score(Y[int(Y.shape[0]*0.8):].values, preds)
    print("Accuracy: %.2f%%" % (accuracy * 100.0))
    

    输出如下:

    图 5.39:最终准确率

    图 5.39:最终准确率
  8. 使用以下代码保存模型以供将来使用:

    model.save_model('churn-model.model')
    

活动 16:预测客户的购买金额

解决方案

  1. 使用 pandas 加载黑色星期五数据集。首先,导入pandas,然后使用read_csv读取数据。

    import pandas as pd
    import numpy as np
    data = data = pd.read_csv("data/BlackFriday.csv")
    
  2. User_ID变量不需要用于新用户 ID 的预测,因此我们将其删除。

    data.isnull().sum()
    data.drop(['User_ID', 'Product_Category_2', 'Product_Category_3'], axis = 1, inplace = True)
    

    产品类别变量有较高的空值比例,因此我们也会将其删除。

  3. 使用 scikit-learn 将所有分类变量转换为整数。

    from collections import defaultdict
    from sklearn.preprocessing import LabelEncoder, MinMaxScaler
    label_dict = defaultdict(LabelEncoder)
    data[['Product_ID', 'Gender', 'Age', 'Occupation', 'City_Category', 'Stay_In_Current_City_Years', 'Marital_Status', 'Product_Category_1']] = data[['Product_ID', 'Gender', 'Age', 'Occupation', 'City_Category', 'Stay_In_Current_City_Years', 'Marital_Status', 'Product_Category_1']].apply(lambda x: label_dict[x.name].fit_transform(x)) 
    
  4. 将数据拆分为训练集和测试集,并转换为嵌入层所需的格式。

    from sklearn.model_selection import train_test_split
    X = data
    y = X.pop('Purchase')
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=9)
    
    cat_cols_dict = {col: list(data[col].unique()) for col in ['Product_ID', 'Gender', 'Age', 'Occupation', 'City_Category', 'Stay_In_Current_City_Years', 'Marital_Status', 'Product_Category_1']}
    train_input_list = []
    test_input_list = []
    
    for col in cat_cols_dict.keys():
        raw_values = np.unique(data[col])
        value_map = {}
        for i in range(len(raw_values)):
            value_map[raw_values[i]] = i       
        train_input_list.append(X_train[col].map(value_map).values)
        test_input_list.append(X_test[col].map(value_map).fillna(0).values)
    
  5. 使用 Keras 中的嵌入层和全连接层创建网络,并进行超参数调整以获得最佳准确率。

    from keras.models import Model
    from keras.layers import Input, Dense, Concatenate, Reshape, Dropout
    from keras.layers.embeddings import Embedding
    cols_out_dict = {
        'Product_ID': 20,
        'Gender': 1,
        'Age': 2,
        'Occupation': 6,
        'City_Category': 1,
        'Stay_In_Current_City_Years': 2,
        'Marital_Status': 1,
        'Product_Category_1': 9
    }
    
    inputs = []
    embeddings = []
    
    for col in cat_cols_dict.keys():
    
        inp = Input(shape=(1,), name = 'input_' + col)
        embedding = Embedding(len(cat_cols_dict[col]), cols_out_dict[col], input_length=1, name = 'embedding_' + col)(inp)
        embedding = Reshape(target_shape=(cols_out_dict[col],))(embedding)
        inputs.append(inp)
        embeddings.append(embedding)
    
  6. 现在,我们在嵌入层之后创建一个三层网络。

    x = Concatenate()(embeddings)
    x = Dense(4, activation='relu')(x)
    x = Dense(2, activation='relu')(x)
    output = Dense(1, activation='relu')(x)
    
    model = Model(inputs, output)
    
    model.compile(loss='mae', optimizer='adam')
    
    model.fit(train_input_list, y_train, validation_data = (test_input_list, y_test), epochs=20, batch_size=128)
    
  7. 检查模型在测试集上的 RMSE。

    from sklearn.metrics import mean_squared_error
    y_pred = model.predict(test_input_list)
    np.sqrt(mean_squared_error(y_test, y_pred))
    

    RMSE 为:

    图 5.40:RMSE 模型

    图 5.40:RMSE 模型
  8. 可视化产品 ID 的嵌入。

    import matplotlib.pyplot as plt
    from sklearn.decomposition import PCA
    embedding_Product_ID = model.get_layer('embedding_Product_ID').get_weights()[0]
    pca = PCA(n_components=2) 
    Y = pca.fit_transform(embedding_Product_ID[:40])
    plt.figure(figsize=(8,8))
    plt.scatter(-Y[:, 0], -Y[:, 1])
    for i, txt in enumerate(label_dict['Product_ID'].inverse_transform(cat_cols_dict['Product_ID'])[:40]):
        plt.annotate(txt, (-Y[i, 0],-Y[i, 1]), xytext = (-20, 8), textcoords = 'offset points')
    plt.show()
    

    图表如下:

    图 5.41:聚类模型的图

    从图中可以看出,相似的产品已被模型聚集在一起。

  9. 保存模型以供将来使用。

    model.save ('black-friday.model')
    

第六章:解码图像

活动 17:预测图像是猫还是狗

解决方案

  1. 如果你查看数据集中的图像名称,你会发现狗的图像名称以 dog 开头,后面跟着'.'和数字,例如:"dog.123.jpg"。类似地,猫的图像名称以 cat 开头。让我们创建一个函数,从文件名中提取标签:

    def get_label(file):
        class_label = file.split('.')[0]
        if class_label == 'dog': label_vector = [1,0]
        elif class_label == 'cat': label_vector = [0,1]
        return label_vector
    

    然后,创建一个函数来读取、调整大小并预处理图像:

    import os
    import numpy as np
    from PIL import Image
    from tqdm import tqdm
    from random import shuffle
    
    SIZE = 50
    
    def get_data():
        data = []
        files = os.listdir(PATH)
    
        for image in tqdm(files): 
            label_vector = get_label(image) 
            img = Image.open(PATH + image).convert('L')
            img = img.resize((SIZE,SIZE)) 
            data.append([np.asarray(img),np.array(label_vector)])
    
        shuffle(data)
        return data
    

    这里的SIZE指的是我们输入模型的最终方形图像的尺寸。我们将图像调整为长度和宽度均为SIZE

    注意

    当运行os.listdir(PATH)时,你会发现所有猫的图像会先出现,紧接着是狗的图像。

  2. 为了让训练集和测试集中的两个类别具有相同的分布,我们将对数据进行洗牌。

  3. 定义图像的尺寸并读取数据。将加载的数据拆分为训练集和测试集:

    data = get_data()
    train = data[:7000]
    test = data[7000:]
    x_train = [data[0] for data in train]
    y_train = [data[1] for data in train]
    x_test = [data[0] for data in test]
    y_test = [data[1] for data in test]
    
  4. 将列表转换为 numpy 数组,并将图像重塑为 Keras 接受的格式:

    y_train = np.array(y_train)
    y_test = np.array(y_test)
    x_train = np.array(x_train).reshape(-1, SIZE, SIZE, 1)
    x_test = np.array(x_test).reshape(-1, SIZE, SIZE, 1)
    
  5. 创建一个使用正则化的 CNN 模型来进行训练:

    from keras.models import Sequential
    from keras.layers import Dense, Dropout, Conv2D, MaxPool2D, Flatten, BatchNormalization
    model = Sequential() 
    

    添加卷积层:

    model.add(Conv2D(48, (3, 3), activation='relu', padding='same', input_shape=(50,50,1)))    
    model.add(Conv2D(48, (3, 3), activation='relu'))  
    

    添加池化层:

    model.add(MaxPool2D(pool_size=(2, 2)))
    
  6. 使用以下代码添加批量归一化层和 dropout 层:

    model.add(BatchNormalization())
    model.add(Dropout(0.10))
    
  7. 将二维矩阵展平为一维向量:

    model.add(Flatten())
    
  8. 使用密集层作为模型的最终层:

    model.add(Dense(512, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(2, activation='softmax'))
    
  9. 编译模型并使用训练数据进行训练:

    model.compile(loss='categorical_crossentropy', 
                  optimizer='adam',
                  metrics = ['accuracy'])
    Define the number of epochs you want to train the model for:
    EPOCHS = 10
    model_details = model.fit(x_train, y_train,
                        batch_size = 128, 
                        epochs = EPOCHS, 
                        validation_data= (x_test, y_test),
                        verbose=1)
    
  10. 打印模型在测试集上的准确度:

    score = model.evaluate(x_test, y_test)
    print("Accuracy: {0:.2f}%".format(score[1]*100)) 
    

    图 6.39:测试集上的模型准确度

    图 6.39:测试集上的模型准确度
  11. 打印模型在训练集上的准确度:

    score = model.evaluate(x_train, y_train)
    print("Accuracy: {0:.2f}%".format(score[1]*100)) 
    

图 6.40:训练集上的模型准确度

图 6.40:训练集上的模型准确度

该模型在测试集上的准确度为 70.4%。训练集的准确度非常高,达到了 96%。这意味着模型已经开始出现过拟合。提高模型以获得最佳的准确度是留给你作为练习的部分。你可以使用之前练习中的代码绘制错误预测的图像,以了解模型的表现:

import matplotlib.pyplot as plt
y_pred = model.predict(x_test)
incorrect_indices = np.nonzero(np.argmax(y_pred,axis=1) != np.argmax(y_test,axis=1))[0]
labels = ['dog', 'cat']
image = 5
plt.imshow(x_test[incorrect_indices[image]].reshape(50,50),  cmap=plt.get_cmap('gray'))
plt.show()
print("Prediction: {0}".format(labels[np.argmax(y_pred[incorrect_indices[image]])]))

图 6.41:正则化的 CNN 模型错误预测狗

图 6.41:正则化的 CNN 模型错误预测狗

活动 18:识别和增强图像

解决方案

  1. 创建获取数据集图像和标签的函数:

    from PIL import Image
    def get_input(file):
        return Image.open(PATH+file)
    
    def get_output(file):
        class_label = file.split('.')[0]
        if class_label == 'dog': label_vector = [1,0]
        elif class_label == 'cat': label_vector = [0,1]
        return label_vector
    
  2. 创建预处理和增强图像的函数:

    SIZE = 50
    def preprocess_input(image):
        # Data preprocessing
        image = image.convert('L')
        image = image.resize((SIZE,SIZE))
    
        # Data augmentation
        random_vertical_shift(image, shift=0.2)
        random_horizontal_shift(image, shift=0.2)
        random_rotate(image, rot_range=45)
        random_horizontal_flip(image)
    
        return np.array(image).reshape(SIZE,SIZE,1)
    
  3. 实现增强函数,在传入图像时随机执行增强,并返回增强后的图像结果。

    这是水平翻转:

    import random
    def random_horizontal_flip(image):
        toss = random.randint(1, 2)
        if toss == 1:
            return image.transpose(Image.FLIP_LEFT_RIGHT)
        else:
            return image
    

    这是旋转:

    def random_rotate(image, rot_range):
        value = random.randint(-rot_range,rot_range)
        return image.rotate(value)
    

    这是图像平移:

    import PIL
    def random_horizontal_shift(image, shift):
        width, height = image.size
        rand_shift = random.randint(0,shift*width)
        image = PIL.ImageChops.offset(image, rand_shift, 0)
        image.paste((0), (0, 0, rand_shift, height))
        return image
     def random_vertical_shift(image, shift):
        width, height = image.size
        rand_shift = random.randint(0,shift*height)
        image = PIL.ImageChops.offset(image, 0, rand_shift)
        image.paste((0), (0, 0, width, rand_shift))
        return image
    
  4. 最后,创建一个生成器,用于生成用于训练模型的图像批次:

    import numpy as np
    def custom_image_generator(images, batch_size = 128):
        while True:
            # Randomly select images for the batch
            batch_images = np.random.choice(images, size = batch_size)
            batch_input = []
            batch_output = [] 
    
            # Read image, perform preprocessing and get labels
            for file in batch_images:
                # Function that reads and returns the image
                input_image = get_input(file)
                # Function that gets the label of the image
                label = get_output(file)
                # Function that pre-processes and augments the image
                image = preprocess_input(input_image)
    
                batch_input.append(image)
                batch_output.append(label)
    
            batch_x = np.array(batch_input)
            batch_y = np.array(batch_output)
    
            # Return a tuple of (images,labels) to feed the network
            yield(batch_x, batch_y)
    
  5. 创建加载测试数据集图像和标签的函数:

    def get_label(file):
        class_label = file.split('.')[0]
        if class_label == 'dog': label_vector = [1,0]
        elif class_label == 'cat': label_vector = [0,1]
        return label_vector
    

    这个get_data函数类似于我们在活动 1中使用的函数。这里的修改是,我们将图像列表作为输入参数,然后返回一个包含图像及其标签的元组:

    def get_data(files):
        data_image = []
        labels = []
        for image in tqdm(files):
    
            label_vector = get_label(image)
    
            img = Image.open(PATH + image).convert('L')
            img = img.resize((SIZE,SIZE))
    
            labels.append(label_vector)
            data_image.append(np.asarray(img).reshape(SIZE,SIZE,1))
    
        data_x = np.array(data_image)
        data_y = np.array(labels)
    
        return (data_x, data_y)
    
  6. 现在,创建训练集和测试集的划分,并加载测试数据集:

    import os
    files = os.listdir(PATH)
    random.shuffle(files)
    train = files[:7000]
    test = files[7000:]
    validation_data = get_data(test)
    
  7. 创建模型并进行训练:

    from keras.models import Sequential
    model = Sequential()
    

    添加卷积层

    from keras.layers import Input, Dense, Dropout, Conv2D, MaxPool2D, Flatten, BatchNormalization
    model.add(Conv2D(32, (3, 3), activation='relu', padding='same', input_shape=(50,50,1)))    
    model.add(Conv2D(32, (3, 3), activation='relu'))
    

    添加池化层:

    model.add(MaxPool2D(pool_size=(2, 2)))
    
  8. 添加批量归一化层以及一个 dropout 层:

    model.add(BatchNormalization())
    model.add(Dropout(0.10))
    
  9. 将二维矩阵展平为一维向量:

    model.add(Flatten())
    
  10. 使用密集层作为模型的最终层:

    model.add(Dense(512, activation='relu'))
    model.add(Dropout(0.5))
    
    model.add(Dense(2, activation='softmax'))
    
  11. 编译模型并使用你创建的生成器进行训练:

    EPOCHS = 10
    BATCH_SIZE = 128
    model.compile(loss='categorical_crossentropy', 
                  optimizer='adam',
                  metrics = ['accuracy']) 
    model_details = model.fit_generator(custom_image_generator(train, batch_size = BATCH_SIZE),
                        steps_per_epoch = len(train) // BATCH_SIZE, 
                        epochs = EPOCHS, 
                        validation_data= validation_data,
                        verbose=1) 
    

该模型的测试集准确率为 72.6%,相比于活动 21中的模型有所提升。你会发现训练准确率非常高,达到 98%。这意味着该模型已经开始过拟合,类似于活动 21中的模型。可能是由于数据增强不足所致。尝试更改数据增强参数,看看准确率是否有所变化。或者,你可以修改神经网络的架构以获得更好的结果。你可以绘制预测错误的图像,以了解模型的表现。

import matplotlib.pyplot as plt
y_pred = model.predict(validation_data[0])
incorrect_indices = np.nonzero(np.argmax(y_pred,axis=1) != np.argmax(validation_data[1],axis=1))[0]
labels = ['dog', 'cat']
image = 7
plt.imshow(validation_data[0][incorrect_indices[image]].reshape(50,50), cmap=plt.get_cmap('gray'))
plt.show()
print("Prediction: {0}".format(labels[np.argmax(y_pred[incorrect_indices[image]])]))

图 6.42:数据增强 CNN 模型错误预测一只猫

图 6.42:数据增强 CNN 模型错误预测一只猫

第七章:处理人类语言

活动 19:预测电影评论的情感

解决方案

  1. 使用 pandas 在 Python 中读取 IMDB 电影评论数据集:

    import pandas as pd
    data = pd.read_csv('../../chapter 7/data/movie_reviews.csv', encoding='latin-1')
    
  2. 将推文转换为小写字母,以减少唯一单词的数量:

    data.text = data.text.str.lower()
    
    注意:

    请记住,"Hello" 和 "hellow" 对计算机来说是不同的。

  3. 使用 RegEx 和 clean_str 函数清洗评论:

    import re
    def clean_str(string):
    
        string = re.sub(r"https?\://\S+", '', string)
        string = re.sub(r'\<a href', ' ', string)
        string = re.sub(r'&amp;', '', string) 
        string = re.sub(r'<br />', ' ', string)
        string = re.sub(r'[_"\-;%()|+&=*%.,!?:#$@\[\]/]', ' ', string)
        string = re.sub('\d','', string)
        string = re.sub(r"can\'t", "cannot", string)
        string = re.sub(r"it\'s", "it is", string)
        return string
    data.SentimentText = data.SentimentText.apply(lambda x: clean_str(str(x)))
    
  4. 接下来,从评论中去除停用词和其他频繁出现的不必要的词:

    注意:

    要了解我们如何找到这些内容,单词请参见练习 51

  5. 这一步将字符串转换为标记(在下一步中会派上用场):

    from nltk.corpus import stopwords
    from nltk.tokenize import word_tokenize,sent_tokenize
    stop_words = stopwords.words('english') + ['movie', 'film', 'time']
    stop_words = set(stop_words)
    remove_stop_words = lambda r: [[word for word in word_tokenize(sente) if word not in stop_words] for sente in sent_tokenize(r)]
    data['SentimentText'] = data['SentimentText'].apply(remove_stop_words)
    
  6. 使用前一步骤中创建的标记来创建评论的词嵌入。在这里,我们将使用 gensim 的 Word2Vec 来创建这些嵌入向量:

    from gensim.models import Word2Vec
    model = Word2Vec(
            data['SentimentText'].apply(lambda x: x[0]),
            iter=10,
            size=16,
            window=5,
            min_count=5,
            workers=10)
    model.wv.save_word2vec_format('movie_embedding.txt', binary=False)
    
  7. 将标记合并为一个字符串,然后删除任何在去除停用词后为空的评论:

    def combine_text(text):    
        try:
            return ' '.join(text[0])
        except:
            return np.nan
    
    data.SentimentText = data.SentimentText.apply(lambda x: combine_text(x))
    data = data.dropna(how='any')
    
  8. 使用 Keras 的 Tokenizer 对评论进行分词,并将其转换为数字:

    from keras.preprocessing.text import Tokenizer
    tokenizer = Tokenizer(num_words=5000)
    tokenizer.fit_on_texts(list(data['SentimentText']))
    sequences = tokenizer.texts_to_sequences(data['SentimentText'])
    word_index = tokenizer.word_index
    
  9. 最后,将推文填充到最多 100 个单词。这将删除超过 100 个单词限制后的任何单词,并在单词数少于 100 时填充 0:

    from keras.preprocessing.sequence import pad_sequences
    reviews = pad_sequences(sequences, maxlen=100)
    
  10. 加载创建的嵌入,使用在文本处理部分中讨论的 load_embedding 函数获取嵌入矩阵:

    import numpy as np
    
    def load_embedding(filename, word_index , num_words, embedding_dim):
        embeddings_index = {}
        file = open(filename, encoding="utf-8")
        for line in file:
            values = line.split()
            word = values[0]
            coef = np.asarray(values[1:])
            embeddings_index[word] = coef
        file.close()
    
        embedding_matrix = np.zeros((num_words, embedding_dim))
        for word, pos in word_index.items():
            if pos >= num_words:
                continue
            embedding_vector = embeddings_index.get(word)
            if embedding_vector is not None:
                embedding_matrix[pos] = embedding_vector
        return embedding_matrix
    
    embedding_matrix = load_embedding('movie_embedding.txt', word_index, len(word_index), 16)
    
  11. 使用 pandas 的 get_dummies 函数将标签转换为 one-hot 向量,并以 80:20 的比例将数据集分为测试集和训练集:

    from sklearn.model_selection import train_test_split
    labels = pd.get_dummies(data.Sentiment)
    X_train, X_test, y_train, y_test = train_test_split(reviews,labels, test_size=0.2, random_state=9)
    
  12. 创建神经网络模型,首先是输入层和嵌入层。该层将输入的单词转换为其嵌入向量:

    from keras.layers import Input, Dense, Dropout, BatchNormalization, Embedding, Flatten
    from keras.models import Model
    inp = Input((100,))
    embedding_layer = Embedding(len(word_index),
                        16,
                        weights=[embedding_matrix],
                        input_length=100,
                        trainable=False)(inp)
    
  13. 使用 Keras 创建其余的全连接神经网络:

    model = Flatten()(embedding_layer)
    model = BatchNormalization()(model)
    model = Dropout(0.10)(model)
    model = Dense(units=1024, activation='relu')(model)
    model = Dense(units=256, activation='relu')(model)
    model = Dropout(0.5)(model)
    predictions = Dense(units=2, activation='softmax')(model)
    model = Model(inputs = inp, outputs = predictions)
    
  14. 编译并训练模型 10 个 epoch。你可以修改模型和超参数,尝试获得更好的准确性:

    model.compile(loss='binary_crossentropy', optimizer='sgd', metrics = ['acc'])
    model.fit(X_train, y_train, validation_data = (X_test, y_test), epochs=10, batch_size=256)
    
  15. 使用以下方法计算模型在测试集上的准确性,以查看我们的模型在先前未见数据上的表现如何:

    from sklearn.metrics import accuracy_score
    preds = model.predict(X_test)
    accuracy_score(np.argmax(preds, 1), np.argmax(y_test.values, 1))
    

    模型的准确率是:

    图 7.39:模型准确性

    图 7.39:模型准确性
  16. 绘制模型的混淆矩阵,以便更好地理解模型的预测效果:

    y_actual = pd.Series(np.argmax(y_test.values, axis=1), name='Actual')
    y_pred = pd.Series(np.argmax(preds, axis=1), name='Predicted')
    pd.crosstab(y_actual, y_pred, margins=True)
    

    检查以下内容:

    图 7.40:模型的混淆矩阵(0 = 消极情感,1 = 积极情感)

    图 7.40: 模型的混淆矩阵(0 = 负面情感,1 = 正面情感)
  17. 使用以下代码检查模型的表现,查看随机评论上的情感预测:

    review_num = 111
    print("Review: \n"+tokenizer.sequences_to_texts([X_test[review_num]])[0])
    sentiment = "Positive" if np.argmax(preds[review_num]) else "Negative"
    print("\nPredicted sentiment = "+ sentiment)
    sentiment = "Positive" if np.argmax(y_test.values[review_num]) else "Negative"
    print("\nActual sentiment = "+ sentiment)
    

    检查你是否收到以下输出:

图 7.41: 来自 IMDB 数据集的评论

图 7.41: 来自 IMDB 数据集的评论

活动 20: 从推文中预测情感

解决方案

  1. 使用 pandas 读取推文数据集,并按照以下代码重命名列:

    import pandas as pd
    data = pd.read_csv('tweet-data.csv', encoding='latin-1', header=None)
    data.columns = ['sentiment', 'id', 'date', 'q', 'user', 'text']
    
  2. 删除以下列,因为我们不会使用它们。如果你想在尝试提高准确性时分析和使用它们,可以自行操作:

    data = data.drop(['id', 'date', 'q', 'user'], axis=1)
    
  3. 我们仅在数据的一个子集(400,000 条推文)上执行此活动,以节省时间。如果你愿意,可以处理整个数据集:

    data = data.sample(400000).reset_index(drop=True)
    
  4. 将推文转换为小写,以减少唯一单词的数量。请记住,"Hello" 和 "hellow" 对计算机来说是不同的:

    data.text = data.text.str.lower()
    
  5. 使用clean_str函数清洗推文:

    import re
    def clean_str(string):
        string = re.sub(r"https?\://\S+", '', string)
        string = re.sub(r"@\w*\s", '', string)
        string = re.sub(r'\<a href', ' ', string)
        string = re.sub(r'&amp;', '', string) 
        string = re.sub(r'<br />', ' ', string)
        string = re.sub(r'[_"\-;%()|+&=*%.,!?:#$@\[\]/]', ' ', string)
        string = re.sub('\d','', string)
        return string
    
    data.text = data.text.apply(lambda x: clean_str(str(x)))
    
  6. 移除推文中的所有停用词,就像在文本预处理部分所做的那样:

    from nltk.corpus import stopwords
    from nltk.tokenize import word_tokenize,sent_tokenize
    stop_words = stopwords.words('english')
    stop_words = set(stop_words)
    remove_stop_words = lambda r: [[word for word in word_tokenize(sente) if word not in stop_words] for sente in sent_tokenize(r)]
    data['text'] = data['text'].apply(remove_stop_words)
    
    def combine_text(text):    
        try:
            return ' '.join(text[0])
        except:
            return np.nan
    
    data.text = data.text.apply(lambda x: combine_text(x))
    
    data = data.dropna(how='any')
    
  7. 使用 Keras Tokenizer 对推文进行分词,并将其转换为数字:

    from keras.preprocessing.text import Tokenizer
    tokenizer = Tokenizer(num_words=5000)
    tokenizer.fit_on_texts(list(data['text']))
    sequences = tokenizer.texts_to_sequences(data['text'])
    word_index = tokenizer.word_index
    
  8. 最后,将推文填充为最多 50 个单词。这将删除超过 50 个单词后的任何单词,并在单词数少于 50 时添加 0:

    from keras.preprocessing.sequence import pad_sequences
    tweets = pad_sequences(sequences, maxlen=50)
    
  9. 使用load_embedding函数从下载的 GloVe 嵌入文件中创建嵌入矩阵:

    import numpy as np
    def load_embedding(filename, word_index , num_words, embedding_dim):
        embeddings_index = {}
        file = open(filename, encoding="utf-8")
        for line in file:
            values = line.split()
            word = values[0]
            coef = np.asarray(values[1:])
            embeddings_index[word] = coef
        file.close()
    
        embedding_matrix = np.zeros((num_words, embedding_dim))
        for word, pos in word_index.items():
            if pos >= num_words:
                continue
            embedding_vector = embeddings_index.get(word)
            if embedding_vector is not None:
                embedding_matrix[pos] = embedding_vector
        return embedding_matrix
    
    embedding_matrix = load_embedding('../../embedding/glove.twitter.27B.50d.txt', word_index, len(word_index), 50)
    
  10. 将数据集分割为训练集和测试集,比例为 80:20。你可以尝试不同的分割方式:

    from sklearn.model_selection import train_test_split  
    X_train, X_test, y_train, y_test = train_test_split(tweets, pd.get_dummies(data.sentiment), test_size=0.2, random_state=9)
    
  11. 创建 LSTM 模型来预测情感。你可以修改它以创建自己的神经网络:

    from keras.models import Sequential
    from keras.layers import Dense, Dropout, BatchNormalization, Embedding, Flatten, LSTM
    embedding_layer = Embedding(len(word_index),
                               50,
                               weights=[embedding_matrix],
                               input_length=50,
                                trainable=False)
    model = Sequential()
    model.add(embedding_layer)
    model.add(Dropout(0.5))
    model.add(LSTM(100, dropout=0.2))
    model.add(Dense(2, activation='softmax'))
    
    model.compile(loss='binary_crossentropy', optimizer='sgd', metrics = ['acc'])
    
  12. 训练模型。此处我们仅训练 10 个 epochs。你可以增加 epochs 的数量以尝试获得更好的准确性:

    model.fit(X_train, y_train, validation_data = (X_test, y_test), epochs=10, batch_size=256)
    
  13. 通过预测测试集中的几条推文的情感,检查模型的表现:

    preds = model.predict(X_test)
    review_num = 1
    print("Tweet: \n"+tokenizer.sequences_to_texts([X_test[review_num]])[0])
    sentiment = "Positive" if np.argmax(preds[review_num]) else "Negative"
    print("\nPredicted sentiment = "+ sentiment)
    sentiment = "Positive" if np.argmax(y_test.values[review_num]) else "Negative"
    print("\nActual sentiment = "+ sentiment)
    

    输出如下:

图 7.42: 正面(左)和负面(右)推文及其预测结果

图 7.42: 正面(左)和负面(右)推文及其预测结果

第八章:行业技巧和窍门

活动 21: 使用 InceptionV3 进行图像分类

解决方案

  1. 创建函数以获取图像和标签。此处的PATH变量包含训练数据集的路径。

    from PIL import Image
    def get_input(file):
        return Image.open(PATH+file)
    def get_output(file):
        class_label = file.split('.')[0]
        if class_label == 'dog': label_vector = [1,0]
        elif class_label == 'cat': label_vector = [0,1]
        return label_vector
    
  2. 设置SIZECHANNELSSIZE是方形图像输入的维度。CHANNELS是训练数据图像中的通道数。RGB 图像有 3 个通道。

    SIZE = 200
    CHANNELS = 3
    
  3. 创建一个函数来预处理和增强图像:

    def preprocess_input(image):
    
        # Data preprocessing
        image = image.resize((SIZE,SIZE))
        image = np.array(image).reshape(SIZE,SIZE,CHANNELS)
    
        # Normalize image 
        image = image/255.0
    
        return image
    
  4. 最后,开发生成批次的生成器:

    import numpy as np
    def custom_image_generator(images, batch_size = 128):
    
        while True:
            # Randomly select images for the batch
            batch_images = np.random.choice(images, size = batch_size)
            batch_input = []
            batch_output = [] 
    
            # Read image, perform preprocessing and get labels
            for file in batch_images:
                # Function that reads and returns the image
                input_image = get_input(file)
                # Function that gets the label of the image
                label = get_output(file)
                # Function that pre-processes and augments the image
                image = preprocess_input(input_image)
    
                batch_input.append(image)
                batch_output.append(label)
    
            batch_x = np.array(batch_input)
            batch_y = np.array(batch_output)
    
            # Return a tuple of (images,labels) to feed the network
            yield(batch_x, batch_y)
    
  5. 接下来,我们将读取验证数据。创建一个函数来读取图像及其标签:

    from tqdm import tqdm
    def get_data(files):
        data_image = []
        labels = []
        for image in tqdm(files):
            label_vector = get_output(image)
    
            img = Image.open(PATH + image)
            img = img.resize((SIZE,SIZE))
    
            labels.append(label_vector)
            img = np.asarray(img).reshape(SIZE,SIZE,CHANNELS)
            img = img/255.0
            data_image.append(img)
    
        data_x = np.array(data_image)
        data_y = np.array(labels)
    
        return (data_x, data_y)
    
  6. 读取验证文件:

    import os
    files = os.listdir(PATH)
    random.shuffle(files)
    train = files[:7000]
    test = files[7000:]
    validation_data = get_data(test)
    7\.    Plot a few images from the dataset to see whether you loaded the files correctly:
    import matplotlib.pyplot as plt
    plt.figure(figsize=(20,10))
    columns = 5
    for i in range(columns):
        plt.subplot(5 / columns + 1, columns, i + 1)
        plt.imshow(validation_data[0][i])
    

    这里展示了一些图像的随机样本:

    图 8.16: 加载数据集中的样本图像

    图 8.16: 加载数据集中的样本图像
  7. 加载 Inception 模型并传递输入图像的形状:

    from keras.applications.inception_v3 import InceptionV3
    base_model = InceptionV3(weights='imagenet', include_top=False, input_shape=(SIZE,SIZE,CHANNELS))
    
  8. 根据我们的问题添加输出的全连接层:

    from keras.layers import GlobalAveragePooling2D, Dense, Dropout
    from keras.models import Model
    x = base_model.output
    x = GlobalAveragePooling2D()(x)
    x = Dense(256, activation='relu')(x)
    x = Dropout(0.5)(x)
    predictions = Dense(2, activation='softmax')(x)
    
    model = Model(inputs=base_model.input, outputs=predictions)
    
  9. 接下来,编译模型,使其准备好进行训练:

    model.compile(loss='categorical_crossentropy', 
                  optimizer='adam',
                  metrics = ['accuracy'])
    And then perform the training of the model:
    EPOCHS = 50
    BATCH_SIZE = 128
    
    model_details = model.fit_generator(custom_image_generator(train, batch_size = BATCH_SIZE),
                        steps_per_epoch = len(train) // BATCH_SIZE, 
                        epochs = EPOCHS, 
                        validation_data= validation_data,
                        verbose=1)
    
  10. 评估模型并获取准确率:

    score = model.evaluate(validation_data[0], validation_data[1])
    print("Accuracy: {0:.2f}%".format(score[1]*100))
    

    准确率如下:

图 8.17:模型准确率

](tos-cn-i-73owjymdk6/eb360fc59c954491ae35980915aca2c4)

图 8.17:模型准确率

活动 22:使用迁移学习预测图像

解决方案

  1. 首先,设置随机数种子,以确保结果是可重复的:

    from numpy.random import seed
    seed(1)
    from tensorflow import set_random_seed
    set_random_seed(1)
    
  2. 设置 SIZECHANNELS

    SIZE 是输入图像的维度,CHANNELS 是训练数据图像中的通道数。RGB 图像有 3 个通道。

    SIZE = 200
    CHANNELS = 3
    
  3. 创建函数以获取图像和标签。这里的 PATH 变量包含训练数据集的路径。

    from PIL import Image
    def get_input(file):
        return Image.open(PATH+file)
    def get_output(file):
        class_label = file.split('.')[0]
        if class_label == 'dog': label_vector = [1,0]
        elif class_label == 'cat': label_vector = [0,1]
        return label_vector
    
  4. 创建一个函数来预处理和增强图像:

    def preprocess_input(image):
    
        # Data preprocessing
        image = image.resize((SIZE,SIZE))
        image = np.array(image).reshape(SIZE,SIZE,CHANNELS)
    
        # Normalize image 
        image = image/255.0
    
        return image
    
  5. 最后,创建生成器,它将生成批量数据:

    import numpy as np
    def custom_image_generator(images, batch_size = 128):
    
        while True:
            # Randomly select images for the batch
            batch_images = np.random.choice(images, size = batch_size)
            batch_input = []
            batch_output = [] 
    
            # Read image, perform preprocessing and get labels
            for file in batch_images:
                # Function that reads and returns the image
                input_image = get_input(file)
                # Function that gets the label of the image
                label = get_output(file)
                # Function that pre-processes and augments the image
                image = preprocess_input(input_image)
    
                batch_input.append(image)
                batch_output.append(label)
    
            batch_x = np.array(batch_input)
            batch_y = np.array(batch_output)
    
            # Return a tuple of (images,labels) to feed the network
            yield(batch_x, batch_y)
    
  6. 接下来,我们将读取开发集和测试集数据。创建一个函数来读取图像及其标签:

    from tqdm import tqdm
    def get_data(files):
        data_image = []
        labels = []
        for image in tqdm(files):
    
            label_vector = get_output(image)
    
            img = Image.open(PATH + image)
            img = img.resize((SIZE,SIZE))
    
            labels.append(label_vector)
            img = np.asarray(img).reshape(SIZE,SIZE,CHANNELS)
            img = img/255.0
            data_image.append(img)
    
        data_x = np.array(data_image)
        data_y = np.array(labels)
    
        return (data_x, data_y)
    
  7. 现在读取开发集和测试集文件。训练/开发/测试集的比例为 70%/15%/15%

    import random
    random.shuffle(files)
    train = files[:7000]
    development = files[7000:8500]
    test = files[8500:]
    development_data = get_data(development)
    test_data = get_data(test)
    
  8. 从数据集中绘制一些图像,检查是否正确加载了文件:

    import matplotlib.pyplot as plt
    plt.figure(figsize=(20,10))
    columns = 5
    for i in range(columns):
        plt.subplot(5 / columns + 1, columns, i + 1)
        plt.imshow(validation_data[0][i])
    

    查看以下截图中的输出:

    图 8.18:加载数据集中的样本图像

    ](tos-cn-i-73owjymdk6/fbf87aa4241a4d4ea5d406e1d78d9e73)

    图 8.18:加载数据集中的样本图像
  9. 加载 Inception 模型并传入输入图像的形状:

    from keras.applications.inception_v3 import InceptionV3
    base_model = InceptionV3(weights='imagenet', include_top=False, input_shape=(200,200,3))
    10\.  Add the output dense layer according to our problem:
    from keras.models import Model
    from keras.layers import GlobalAveragePooling2D, Dense, Dropout
    x = base_model.output
    x = GlobalAveragePooling2D()(x)
    x = Dense(256, activation='relu')(x)
    keep_prob = 0.5
    x = Dropout(rate = 1 - keep_prob)(x)
    predictions = Dense(2, activation='softmax')(x)
    
    model = Model(inputs=base_model.input, outputs=predictions)
    
  10. 这一次,我们将冻结模型的前五层,以帮助加快训练时间:

    for layer in base_model.layers[:5]:
        layer.trainable = False
    
  11. 编译模型,使其准备好进行训练:

    model.compile(loss='categorical_crossentropy', 
                  optimizer='adam',
                  metrics = ['accuracy'])
    
  12. 为 Keras 创建回调函数:

    from keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping, TensorBoard
    callbacks = [
        TensorBoard(log_dir='./logs',
                    update_freq='epoch'),
        EarlyStopping(monitor = "val_loss",
                     patience = 18,
                     verbose = 1,
                     min_delta = 0.001,
                     mode = "min"),
        ReduceLROnPlateau(monitor = "val_loss",
                         factor = 0.2,
                         patience = 8,
                         verbose = 1,
                         mode = "min"),
        ModelCheckpoint(monitor = "val_loss",
                       filepath = "Dogs-vs-Cats-InceptionV3-{epoch:02d}-{val_loss:.2f}.hdf5", 
                       save_best_only=True,
                       period = 1)]
    
    注意
    EPOCHS = 50
    BATCH_SIZE = 128
    model_details = model.fit_generator(custom_image_generator(train, batch_size = BATCH_SIZE),
                       steps_per_epoch = len(train) // BATCH_SIZE, 
                       epochs = EPOCHS, 
                       callbacks = callbacks,
                       validation_data= development_data,
                       verbose=1)
    

    以下是 TensorBoard 上的训练日志:

    图 8.19:TensorBoard 上的训练集日志

    ](tos-cn-i-73owjymdk6/622482bef7554133bae2797d0da74791)

    图 8.19:TensorBoard 上的训练集日志
  13. 现在,您可以通过将开发集的准确率作为指标来微调超参数。

    TensorBoard 工具显示了开发集的日志:

    图 8.20:TensorBoard 上的验证集日志

    图 8.20:TensorBoard 上的验证集日志

    可以从下图中观察到学习率的下降:

    图 8.21:TensorBoard 中的学习率日志

    ](tos-cn-i-73owjymdk6/9e4fd54e002843ebbda106f8601bd1db)

    图 8.21:TensorBoard 上的学习率日志
  14. 在测试集上评估模型并获取准确率:

    score = model.evaluate(test_data[0], test_data[1])
    print("Accuracy: {0:.2f}%".format(score[1]*100))
    

    为了完全理解,请参考以下输出截图:

图 8.22:模型在测试集上的最终准确率

](tos-cn-i-73owjymdk6/240abd5b6498412796bf1d714676c958)

图 8.22:模型在测试集上的最终准确率

如您所见,模型在测试集上的准确率为 93.6%,这与开发集的准确率(TensorBoard 训练日志中的 93.3%)不同。早停回调函数在开发集的损失没有显著改善时停止了训练,这帮助我们节省了时间。学习率在九个 epoch 后减少,这有助于训练,正如以下所示:

图 8.23:模型训练日志片段

图 8.23:模型训练日志片段

内容

  1. 前言

    1. 关于本书

      1. 关于作者

      2. 学习目标

      3. 读者群体

      4. 方法

      5. 最低硬件要求

      6. 软件要求

      7. 安装和设置

      8. 使用 Kaggle 加速实验

      9. 约定

      10. 安装代码包

  2. 第一章

  3. 数据科学和数据预处理简介

    1. 介绍

    2. Python 库

    3. 建立机器学习模型的路线图

    4. 数据表示

      1. 自变量和目标变量

      2. 练习 1:加载示例数据集并创建特征矩阵和目标矩阵

    5. 数据清洗

      1. 练习 2:删除缺失数据

      2. 练习 3:填补缺失数据

      3. 练习 4:查找并删除数据中的异常值

    6. 数据集成

      1. 练习 5:集成数据
    7. 数据转换

      1. 处理分类数据

      2. 练习 6:用数字简单替换分类数据

      3. 练习 7:使用标签编码将分类数据转换为数值数据

      4. 练习 8:使用独热编码将分类数据转换为数值数据

    8. 不同规模的数据

      1. 练习 9:使用标准缩放器方法实现缩放

      2. 练习 10:使用 MinMax 缩放器方法实现缩放

    9. 数据离散化

      1. 练习 11:连续数据的离散化
    10. 训练和测试数据

      1. 练习 12:将数据分割为训练和测试集

      2. 活动 1:使用银行营销订阅数据集进行预处理

    11. 监督学习

    12. 无监督学习

    13. 强化学习

    14. 性能指标

    15. 总结

  4. 第二章

  5. 数据可视化

    1. 介绍

    2. 功能方法

      1. 练习 13:功能方法 – 线图

      2. 练习 14:功能方法 – 在线图中添加第二条线

      3. 活动 2:线图

      4. 练习 15:创建条形图

      5. 活动 3:条形图

      6. 练习 16:功能方法 – 直方图

      7. 练习 17:功能方法 – 箱线图

      8. 练习 18:散点图

    3. 使用子图的面向对象方法

      1. 练习 19:使用子图绘制单线图

      2. 练习 20:使用子图绘制多条线图

      3. 活动 4:使用子图绘制多种图表类型

    4. 总结

  6. 第三章

  7. 通过 Scikit-Learn 介绍机器学习

    1. 介绍

    2. 线性和逻辑回归介绍

      1. 简单线性回归

      2. 练习 21:为线性回归模型准备数据

      3. 练习 22:拟合简单线性回归模型并确定截距和系数

      4. 练习 23:生成预测并评估简单线性回归模型的性能

    3. 多元线性回归

      1. 练习 24:拟合多元线性回归模型并确定截距和系数

      2. 活动 5:生成预测并评估多元线性回归模型的性能

    4. 逻辑回归

      1. 练习 25:拟合逻辑回归模型并确定截距和系数

      2. 练习 26:生成预测并评估逻辑回归模型的性能

      3. 练习 27:调优多元逻辑回归模型的超参数

      4. 活动 6:生成预测并评估调优后的逻辑回归模型性能

    5. 最大间隔分类(SVM)

      1. 练习 28:为支持向量分类器(SVC)模型准备数据

      2. 练习 29:使用网格搜索调优 SVC 模型

      3. 活动 7:生成预测并评估 SVC 网格搜索模型的性能

    6. 决策树

      1. 活动 8:为决策树分类器准备数据

      2. 练习 30:使用网格搜索调优决策树分类器

      3. 练习 31:通过编程提取决策树分类器网格搜索模型中的调优超参数

      4. 活动 9:生成预测并评估决策树分类模型的性能

    7. 随机森林

      1. 练习 32:为随机森林回归模型准备数据

      2. 活动 10:调优随机森林回归模型

      3. 练习 33:通过编程提取调优后的超参数并确定随机森林回归模型网格搜索中的特征重要性

      4. 活动 11:生成预测并评估调优后的随机森林回归模型的性能

    8. 总结

  8. 第四章

  9. 降维与无监督学习

    1. 简介

    2. 层次聚类分析(HCA)

      1. 练习 34:构建 HCA 模型

      2. 练习 35:绘制 HCA 模型并分配预测

    3. K-means 聚类

      1. 练习 36:拟合 k-means 模型并分配预测

      2. 活动 12:集成 k-means 聚类与计算预测

      3. 练习 37:通过 n_clusters 计算均值惯性

      4. 练习 38:通过 n_clusters 绘制均值惯性图

    4. 主成分分析(PCA)

      1. 练习 39:拟合 PCA 模型

      2. 练习 40:使用解释方差的阈值选择 n_components

      3. 活动 13:PCA 转换后评估每个聚类的均值惯性

      4. 练习 41:通过 n_clusters 的惯性进行视觉比较

    5. 使用线性判别分析(LDA)进行监督数据压缩

      1. 练习 42:拟合 LDA 模型

      2. 练习 43:在分类模型中使用 LDA 转换后的成分

    6. 总结

  10. 第五章

  11. 掌握结构化数据

    1. 介绍

    2. 提升算法

      1. 梯度提升机(GBM)

      2. XGBoost(极端梯度提升)

      3. 练习 44:使用 XGBoost 库进行分类

    3. XGBoost 库

      1. 控制模型过拟合

      2. 处理不平衡数据集

      3. 活动 14:训练并预测一个人的收入

    4. 外部内存使用

    5. 交叉验证

      1. 练习 45:使用交叉验证查找最佳超参数
    6. 保存和加载模型

      1. 练习 46:创建一个根据实时输入进行预测的 Python 脚本

      2. 活动 15:预测客户流失

    7. 神经网络

      1. 什么是神经网络?

      2. 优化算法

      3. 超参数

    8. Keras

      1. 练习 47:安装 Keras 库并使用其进行分类

      2. Keras 库

      3. 练习 48:使用神经网络预测鳄梨价格

    9. 分类变量

      1. 独热编码

      2. 实体嵌入

      3. 练习 49:使用实体嵌入预测鳄梨价格

      4. 活动 16:预测客户购买金额

    10. 总结

  12. 第六章

  13. 解码图像

    1. 介绍

    2. 图像

      1. 练习 50:使用全连接神经网络分类 MNIST
    3. 卷积神经网络

      1. 卷积层
    4. 池化层

    5. Adam 优化器

    6. 交叉熵损失

      1. 练习 51:使用 CNN 分类 MNIST
    7. 正则化

      1. Dropout 层

      2. L1 和 L2 正则化

      3. 批量归一化

      4. 练习 52:使用正则化改进图像分类(使用 CIFAR-10 图像)

    8. 图像数据预处理

      1. 归一化

      2. 转换为灰度图

      3. 将所有图像调整为相同大小

      4. 其他有用的图像操作

      5. 活动 17:预测图像是猫还是狗

    9. 数据增强

    10. 生成器

      1. 练习 53:使用图像增强对 CIFAR-10 图像进行分类

      2. 活动 18:识别并增强图像

    11. 总结

  14. 第七章

  15. 处理人类语言

    1. 介绍

    2. 文本数据处理

      1. 正则表达式

      2. 练习 54:使用正则表达式进行字符串清理

      3. 基本特征提取

      4. 文本预处理

      5. 练习 55:预处理 IMDB 电影评论数据集

      6. 文本处理

      7. 练习 56:使用 Gensim 创建词向量

      8. 活动 19:预测电影评论情感

    3. 循环神经网络(RNN)

      1. LSTM

      2. 练习 57:使用 LSTM 执行情感分析

      3. 活动 20:预测推文情感

    4. 总结

  16. 第八章

  17. 行业技巧与窍门

    1. 介绍

    2. 迁移学习

      1. 图像数据的迁移学习

      2. 练习 58:使用 InceptionV3 比较并分类图像

      3. 活动 21:使用 InceptionV3 进行图像分类

    3. 有用的工具和技巧

      1. 训练、开发和测试数据集

      2. 处理未处理的数据集

      3. pandas Profiling

      4. TensorBoard

    4. AutoML

      1. 练习 59:使用 Auto-Keras 获取高性能网络

      2. 使用 Keras 进行模型可视化

      3. 活动 22:使用迁移学习预测图像

    5. 总结

  18. 附录

    1. 第一章:数据科学与数据预处理简介

      1. 活动 1:使用银行营销订阅数据集进行预处理
    2. 第二章:数据可视化

      1. 活动 2:折线图

      2. 活动 3:条形图

      3. 活动 4:使用子图的多种绘图类型

    3. 第三章:通过 Scikit-Learn 介绍机器学习

      1. 活动 5:生成预测并评估多元线性回归模型的性能

      2. 活动 6:生成预测并评估调优后的逻辑回归模型性能

      3. 活动 7:生成预测并评估 SVC 网格搜索模型的性能

      4. 活动 8:为决策树分类器准备数据

      5. 活动 9:生成预测并评估决策树分类器模型的性能

      6. 活动 10:调优随机森林回归模型

      7. 活动 11:生成预测并评估调优后的随机森林回归模型的性能

    4. 第四章:降维与无监督学习

      1. 活动 12:集成 k-means 聚类与预测计算

      2. 活动 13:PCA 转换后按簇评估均值惯性

    5. 第五章:掌握结构化数据

      1. 活动 14:训练并预测一个人的收入

      2. 活动 15:预测客户流失

      3. 活动 16:预测客户的购买金额

    6. 第六章:解码图像

      1. 活动 17:预测图像是猫还是狗

      2. 活动 18:识别并增强图像

    7. 第七章:处理人类语言

      1. 活动 19:预测电影评论的情感

      2. 活动 20:从推文中预测情感

    8. 第八章:行业技巧与窍门

      1. 活动 21:使用 InceptionV3 分类图像

      2. 活动 22:使用迁移学习预测图像

地标

  1. 封面

  2. 目录