原文:annas-archive.org/md5/0095b5f3f49dd33558a193990b8e61a8

译者:飞龙

协议:CC BY-NC-SA 4.0

第八章:物联网的分布式 AI

分布式计算环境的进步和互联网的全球普及导致了分布式人工智能DAI)的出现。在本章中,我们将了解两个框架,一个是 Apache 的机器学习库MLlib),另一个是 H2O.ai,它们都为大规模、流式数据提供分布式和可扩展的机器学习ML)。本章将以 Apache 的 Spark 介绍开始,它是事实上的分布式数据处理系统。本章将涵盖以下主题:

  • Spark 及其在分布式数据处理中的重要性

  • 理解 Spark 架构

  • 学习 MLlib

  • 在深度学习管道中使用 MLlib

  • 深入了解 H2O.ai 平台

介绍

物联网(IoT)系统会生成大量数据;虽然在许多情况下可以从容分析数据,但对于某些任务(如安全、欺诈检测等),这种延迟是不可接受的。在这种情况下,我们需要的是一种在指定时间内处理大量数据的方法——解决方案是 DAI,多个集群中的机器以分布式方式处理大数据(数据并行)和/或训练深度学习模型(模型并行)。有许多方式可以执行 DAI,大多数方法是建立在或围绕 Apache Spark 的基础上。Apache Spark 于 2010 年发布,并采用 BSD 许可协议,如今它是大数据领域最大的开源项目。它帮助用户创建一个快速且通用的集群计算系统。

Spark 运行在 Java 虚拟机上,使得它可以在任何安装了 Java 的机器上运行,无论是笔记本电脑还是集群。它支持多种编程语言,包括 Python、Scala 和 R。许多深度学习框架和 API 围绕 Spark 和 TensorFlow 构建,旨在简化分布式人工智能(DAI)任务,例如TensorFlowOnSparkTFoS)、Spark MLlib、SparkDl 和 Hydrogen Sparkling(结合了 H2O.ai 和 Spark)。

Spark 组件

Spark 使用主从架构,其中一个中央协调器(称为Spark 驱动程序)和多个分布式工作节点(称为Spark 执行器)。驱动程序进程创建一个SparkContext对象,并将用户应用程序分解成更小的执行单元(任务)。这些任务由工作节点执行。工作节点之间的资源由集群 管理器管理。下图展示了 Spark 的工作原理:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/2b18990e-1d8c-4cb0-a01b-7e2c24272ba8.png

Spark 的工作原理

现在让我们逐一了解 Spark 的不同组件。下图展示了构成 Spark 的基本组件:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/ab3d925a-6e1b-426e-a3ba-9dbabe167138.png

构成 Spark 的组件

让我们简要看看在本章中我们将使用的一些组件,如下所示:

  • 弹性分布式数据集弹性分布式数据集RDDs)是 Spark 中的主要 API。它们表示一个不可变的、分区的数据集合,可以并行操作。更高层的 API 如 DataFrames 和 DataSets 是建立在 RDD 之上的。

  • 分布式变量:Spark 有两种类型的分布式变量:广播变量和累加器。它们由用户定义的函数使用。累加器用于将所有执行器中的信息聚合成共享结果。广播变量则是集群中共享的变量。

  • DataFrames:它是一个分布式的数据集合,非常类似于 pandas 中的 DataFrame。它们可以从各种文件格式中读取,并使用单个命令对整个 DataFrame 执行操作。它们分布在集群中。

  • :Spark 内置了用于 MLlib 和图形处理(GraphX)的库。在本章中,我们将使用基于 Spark 框架的 MLlib 和 SparkDl。我们将学习如何应用它们来进行机器学习预测。

Spark 是一个大话题,本书无法提供有关 Spark 的更多细节。我们建议感兴趣的读者参考 Spark 文档:spark.apache.org/docs/latest/index.html

Apache MLlib

Apache Spark MLlib 为机器学习提供了强大的计算环境。它提供了一个大规模分布式架构,使得运行机器学习模型更加快速高效。这还不是全部;它是开源的,并且拥有一个不断壮大的活跃社区,持续改进并提供最新的功能。它提供了流行的机器学习算法的可扩展实现,涵盖以下算法:

  • 分类:逻辑回归、线性支持向量机、朴素贝叶斯

  • 回归:广义线性回归

  • 协同过滤:交替最小二乘法

  • 聚类:K 均值

  • 分解:奇异值分解和主成分分析

它已被证明比 Hadoop MapReduce 更快。我们可以使用 Java、Scala、R 或 Python 编写应用程序。它还可以轻松与 TensorFlow 集成。

MLlib 中的回归

Spark MLlib 内置了回归的方法。为了能够使用 Spark 的内置方法,您需要在您的集群(独立集群或分布式集群)上安装pyspark。可以使用以下方式进行安装:

pip install pyspark

MLlib 库具有以下回归方法:

  • 线性回归:我们在前面的章节中已经学习了线性回归;我们可以使用在pyspark.ml.regression中定义的LinearRegression类来使用这种方法。默认情况下,它使用最小化平方误差和正则化。它支持 L1 和 L2 正则化以及它们的组合。

  • 广义线性回归:Spark MLlib 提供了指数族分布的子集,如高斯分布、泊松分布等。回归是通过GeneralizedLinearRegression类实例化的。

  • 决策树回归:可以使用DecisionTreeRegressor类进行决策树回归预测。

  • 随机森林回归:作为一种流行的机器学习方法,它们在RandomForestRegressor类中定义。

  • 梯度提升树回归:我们可以使用GBTRegressor类来使用决策树的集成方法。

此外,MLlib 还支持使用AFTSurvivalRegressionIsotonicRegression类进行生存回归和等温回归。

借助这些类,我们可以在不到 10 行代码的情况下构建回归(或如下一节所示的分类)机器学习模型。基本步骤如下:

  1. 构建 Spark 会话。

  2. 实现数据加载管道:加载数据文件,指定格式,并将其读取到 Spark DataFrame 中。

  3. 确定要用作输入的特征以及目标(可选择将数据集拆分为训练集/测试集)。

  4. 实例化所需的类对象。

  5. 使用fit()方法并将训练数据集作为参数。

  6. 根据所选择的回归器,你可以查看学习到的参数并评估拟合的模型。

我们使用线性回归模型来预测波士顿房价数据集(www.cs.toronto.edu/~delve/data/boston/bostonDetail.html),数据集为csv格式:

  1. 导入必要的模块。我们将使用LinearRegressor来定义线性回归类,使用RegressionEvaluator来评估训练后的模型,使用VectorAssembler来将特征合并为一个输入向量,使用SparkSession来启动 Spark 会话:
from pyspark.ml.regression import LinearRegression as LR
from pyspark.ml.feature import VectorAssembler
from pyspark.ml.evaluation import RegressionEvaluator

from pyspark.sql import SparkSession
  1. 接下来,使用SparkSession类启动一个 Spark 会话,代码如下:
spark = SparkSession.builder \
 .appName("Boston Price Prediction") \
 .config("spark.executor.memory", "70g") \
 .config("spark.driver.memory", "50g") \
 .config("spark.memory.offHeap.enabled",True) \
 .config("spark.memory.offHeap.size","16g") \
 .getOrCreate()
  1. 现在我们来读取数据;首先从给定路径加载数据,定义我们要使用的格式,最后将其读取到 Spark DataFrame 中,具体如下:
house_df = spark.read.format("csv"). \
    options(header="true", inferschema="true"). \
    load("boston/train.csv")
  1. 你可以看到现在内存中加载的 DataFrame 及其结构,见下图:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/6ec3ba28-bb23-4336-a1fc-d38953ce1723.png

  1. 类似于 pandas DataFrame,Spark DataFrame 也可以通过单一命令进行处理。让我们通过以下截图来进一步了解我们的数据集:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/316109bd-4504-4877-b9b8-09d4c053b456.png

  1. 接下来,我们定义要用于训练的特征;为此,我们使用VectorAssembler类。我们定义来自house_df DataFrame 的列,将其合并为输入特征向量和相应的输出预测(类似于定义X_trainY_train),然后执行相应的转换,具体如下:
vectors = VectorAssembler(inputCols = ['crim', 'zn','indus','chas',
    'nox','rm','age','dis', 'rad', 'tax',
    'ptratio','black', 'lstat'],
    outputCol = 'features')
vhouse_df = vectors.transform(house_df)
vhouse_df = vhouse_df.select(['features', 'medv'])
vhouse_df.show(5)

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/0c1de199-e1b3-4e5f-9f54-4a3b79e57c5d.png

  1. 数据集随后被分割为训练/测试数据集,代码如下所示:
train_df, test_df = vhouse_df.randomSplit([0.7,0.3])
  1. 现在数据集已经准备好,我们实例化LinearRegression类,并将其拟合到训练数据集上,如下所示:
regressor = LR(featuresCol = 'features', labelCol='medv',\
    maxIter=20, regParam=0.3, elasticNetParam=0.8)
model = regressor.fit(train_df)
  1. 我们可以获得线性回归的结果系数,如下所示:
print("Coefficients:", model.coefficients)
print("Intercept:", model.intercept)

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/1446b664-709e-4413-883e-4337b7bf15f5.png

  1. 该模型在训练数据集上提供了 RMSE 值为4.73r2值为0.71,共进行了21次迭代:
modelSummary = model.summary
print("RMSE is {} and r2 is {}"\ 
   .format(modelSummary.rootMeanSquaredError,\
    modelSummary.r2))
print("Number of Iterations is ",modelSummary.totalIterations)
  1. 接下来,我们在测试数据集上评估我们的模型;我们得到的 RMSE 为5.55,R2 值为0.68
model_evaluator = RegressionEvaluator(predictionCol="prediction",\
    labelCol="medv", metricName="r2")
print("R2 value on test dataset is: ",\
    model_evaluator.evaluate(model_predictions))
print("RMSE value is", model.evaluate(test_df).rootMeanSquaredError)

一旦工作完成,你应该使用stop()方法停止 Spark 会话。完整代码可以在Chapter08/Boston_Price_MLlib.ipynb中找到。r2值较低和 RMSE 较高的原因是我们考虑了训练数据集中的所有特征作为输入特征向量,而其中许多特征对房价的预测没有显著作用。尝试减少特征,保留与价格高度相关的特征。

MLlib 中的分类

MLlib 还提供了多种分类器;它提供了二项和多项逻辑回归分类器。决策树分类器、随机森林分类器、梯度提升树分类器、多层感知器分类器、线性支持向量机分类器和朴素贝叶斯分类器都得到了支持。每个分类器都在其各自的类中定义;有关详细信息,请参阅spark.apache.org/docs/2.2.0/ml-classification-regression.html。基本步骤与我们在回归案例中学到的相同;唯一的区别是,现在,模型评估的标准是准确率,而不是 RMSE 或 r2。

本节将为你展示如何使用 Spark MLlib 的逻辑回归分类器实现葡萄酒质量分类问题:

  1. 对于这个分类问题,我们将使用通过LogisticRegressor类提供的逻辑回归。像之前的例子一样,VectorAssembler将用于将输入特征合并为一个向量。在我们之前看到的葡萄酒质量数据集中(第一章,物联网与人工智能的原理与基础),质量是一个介于 0 到 10 之间的整数,我们需要对其进行处理。在这里,我们将使用StringIndexer来处理。

Spark 的一个伟大特点是我们可以将所有的预处理步骤定义为一个管道。当有大量的预处理步骤时,这非常有用。这里我们只有两个预处理步骤,但为了展示如何形成管道,我们将使用Pipeline类。我们将所有这些模块导入作为第一步,并创建一个 Spark 会话,代码如下所示:

from pyspark.ml.classification import LogisticRegression as LR
from pyspark.ml.feature import VectorAssembler
from pyspark.ml.feature import StringIndexer
from pyspark.ml import Pipeline

from pyspark.sql import SparkSession

spark = SparkSession.builder \
    .appName("Wine Quality Classifier") \
    .config("spark.executor.memory", "70g") \
    .config("spark.driver.memory", "50g") \
    .config("spark.memory.offHeap.enabled",True) \
    .config("spark.memory.offHeap.size","16g") \
    .getOrCreate()
  1. 我们将加载并读取winequality-red.csv数据文件,如下所示:
wine_df = spark.read.format("csv"). \
    options(header="true",\
    inferschema="true",sep=';'). \
    load("winequality-red.csv")
  1. 我们处理给定数据集中的quality标签,将其拆分为三个不同的类别,并将其作为新的quality_new列添加到现有的 Spark DataFrame 中,代码如下所示:
from pyspark.sql.functions import when
wine_df = wine_df.withColumn('quality_new',\
    when(wine_df['quality']< 5, 0 ).\
    otherwise(when(wine_df['quality']<8,1)\
    .otherwise(2)))
  1. 尽管修改后的质量quality_new已经是一个整数,我们可以直接将其用作标签。在这个例子中,我们添加了StringIndexer将其转换为数字索引,目的是为了说明。你可以使用StringIndexer将字符串标签转换为数字索引。我们还使用VectorAssembler将各列组合成一个特征向量。两个阶段通过Pipeline结合在一起,如下所示:
string_index = StringIndexer(inputCol='quality_new',\
    outputCol='quality'+'Index')
vectors = VectorAssembler(inputCols = \
    ['fixed acidity','volatile acidity',\
    'citric acid','residual sugar','chlorides',\
    'free sulfur dioxide', 'total sulfur dioxide', \
    'density','pH','sulphates', 'alcohol'],\
    outputCol = 'features')

stages = [vectors, string_index]

pipeline = Pipeline().setStages(stages)
pipelineModel = pipeline.fit(wine_df)
pl_data_df = pipelineModel.transform(wine_df)
  1. 在流水线处理之后得到的数据随后被拆分成训练数据集和测试数据集,如以下代码所示:
train_df, test_df = pl_data_df.randomSplit([0.7,0.3])
  1. 接下来,我们实例化LogisticRegressor类,并使用fit方法在训练数据集上进行训练,如下所示:
classifier= LR(featuresCol = 'features', \
    labelCol='qualityIndex',\
    maxIter=50)
model = classifier.fit(train_df)
  1. 在以下截图中,我们可以看到学习到的模型参数:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/7e2b0f57-da14-409a-ac9a-6eca299087e6.png

  1. 模型的准确率为 94.75%。我们还可以在以下代码中看到其他评估指标,如precision(精确度)、recall(召回率)、F 值、真阳性率和假阳性率:
modelSummary = model.summary

accuracy = modelSummary.accuracy
fPR = modelSummary.weightedFalsePositiveRate
tPR = modelSummary.weightedTruePositiveRate
fMeasure = modelSummary.weightedFMeasure()
precision = modelSummary.weightedPrecision
recall = modelSummary.weightedRecall
print("Accuracy: {} False Positive Rate {} \
    True Positive Rate {} F {} Precision {} Recall {}"\
    .format(accuracy, fPR, tPR, fMeasure, precision, recall))

我们可以看到,使用 MLlib 的葡萄酒质量分类器的性能与我们之前的方法相当。完整代码可以在 GitHub 仓库中的Chapter08/Wine_Classification_MLlib.pynb文件找到。

使用 SparkDL 进行迁移学习

前面几节讲解了如何使用 Spark 框架和其 MLlib 处理机器学习问题。然而,在大多数复杂任务中,深度学习模型提供了更好的性能。Spark 支持 SparkDL,这是一个在 MLlib 上运行的更高级 API。它在后台使用 TensorFlow,并且还需要 TensorFrames、Keras 和 TFoS 模块。

在本节中,我们将使用 SparkDL 进行图像分类。这将帮助你熟悉 Spark 对图像的支持。对于图像,正如我们在第四章《物联网的深度学习》中学到的,卷积神经网络CNNs)是事实上的选择。在第四章《物联网的深度学习》中,我们从头开始构建了 CNN,并且还了解了一些流行的 CNN 架构。CNN 的一个非常有趣的特点是,每个卷积层都学习识别图像中的不同特征,起到特征提取器的作用。较低的卷积层会过滤出基本形状,比如线条和圆形,而较高的层则过滤出更抽象的形状。这个特点可以用来利用在一组图像上训练的 CNN 来分类另一组类似领域的图像,只需要更改顶部的全连接层。这种技术被称为迁移学习。根据新数据集图像的可用性以及两个领域之间的相似性,迁移学习可以显著帮助减少训练时间,并且减少对大规模数据集的需求。

在 2016 年 NIPS 教程中,AI 领域的关键人物之一 Andrew Ng 提到,迁移学习将是下一个商业成功的推动力。在图像领域,通过使用在 ImageNet 数据上训练的 CNN 进行迁移学习,已经在其他领域的图像分类中取得了巨大的成功。目前,许多研究正在致力于将迁移学习应用于其他数据领域。您可以通过 Sebastian Ruder 的这篇博客文章了解迁移学习的基础:ruder.io/transfer-learning/

我们将采用 Google 提出的 CNN 架构 InceptionV3(arxiv.org/pdf/1409.4842.pdf),并使用在 ImageNet 数据集(www.image-net.org)上训练的模型,来识别道路上的车辆(目前我们仅限于公交车和小汽车)。

在开始之前,请确保以下模块已安装在您的工作环境中:

  • PySpark

  • TensorFlow

  • Keras

  • TFoS

  • TensorFrames

  • Wrapt

  • Pillow

  • pandas

  • Py4J

  • SparkDL

  • Kafka

  • Jieba

这些可以通过pip install命令在您的独立机器或集群中的机器上安装。

接下来,您将学习如何使用 Spark 和 SparkDL 进行图像分类。我们通过 Google 图像搜索截图了两种不同的花朵,雏菊和郁金香;雏菊有 42 张图片,郁金香有 65 张图片。在下面的截图中,您可以看到雏菊的样本截图:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/47e5e4e6-3443-4225-a3e7-823cc396503e.png

以下截图展示了郁金香的样本图片:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/99141d8d-f0cd-46b7-9bf0-f20d83a22267.png

我们的数据集太小,因此如果从头开始构建 CNN,它无法提供任何有用的性能。在这种情况下,我们可以利用迁移学习。SparkDL 模块提供了一个简单方便的方式,通过DeepImageFeaturizer类使用预训练模型。它支持以下 CNN 模型(在 ImageNet 数据集(www.image-net.org)上预训练):

  • InceptionV3

  • Xception

  • ResNet50

  • VGG16

  • VGG19

我们将使用 Google 的 InceptionV3 作为我们的基础模型。完整的代码可以从 GitHub 仓库中的Chapter08/Transfer_Learning_Sparkdl.ipynb访问:

  1. 在第一步中,我们需要为 SparkDL 库指定环境。这是一个重要的步骤;如果没有它,内核将无法知道从哪里加载 SparkDL 包:
import os
SUBMIT_ARGS = "--packages databricks:spark-deep-learning:1.3.0-spark2.4-s_2.11 pyspark-shell"
os.environ["PYSPARK_SUBMIT_ARGS"] = SUBMIT_ARGS

即使在某些操作系统上通过pip安装 SparkDL 时,仍需要指定操作系统环境或 SparkDL。

  1. 接下来,让我们启动一个SparkSession,如下所示的代码:
from pyspark.sql import SparkSession
spark = SparkSession.builder \
    .appName("ImageClassification") \
    .config("spark.executor.memory", "70g") \
    .config("spark.driver.memory", "50g") \
    .config("spark.memory.offHeap.enabled",True) \
    .config("spark.memory.offHeap.size","16g") \
    .getOrCreate()
  1. 我们导入必要的模块并读取数据图像。除了读取图像路径,我们还将标签分配给 Spark DataFrame 中的每个图像,如下所示:
import pyspark.sql.functions as f
import sparkdl as dl
from pyspark.ml.image import ImageSchema
from sparkdl.image import imageIO
dftulips = ImageSchema.readImages('data/flower_photos/tulips').\
    withColumn('label', f.lit(0))
dfdaisy = ImageSchema.readImages('data/flower_photos/daisy').\
    withColumn('label', f.lit(1))
  1. 接下来,你可以看到两个数据框的前五行。第一列包含每张图像的路径,第二列显示其标签(是否属于雏菊(标签 1)或属于郁金香(标签 0)):

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/99b1dae8-6d59-4f48-92e9-e94b553da9a2.png

  1. 我们使用randomSplit函数将两个图像数据集划分为训练集和测试集(这始终是一种良好的做法)。通常,人们选择 60%—40%、70%—30%或 80%—20%的训练-测试数据集比例。我们在这里选择了 70%—30%的划分。为了训练,我们将两种花的训练图像合并到trainDF数据框中,将测试数据集图像合并到testDF数据框中,如下所示:
trainDFdaisy, testDFdaisy = dfdaisy.randomSplit([0.70,0.30],\
        seed = 123)
trainDFtulips, testDFtulips = dftulips.randomSplit([0.70,0.30],\
        seed = 122)
trainDF = trainDFdaisy.unionAll(trainDFtulips)
testDF = testDFdaisy.unionAll(testDFtulips)
  1. 接下来,我们使用InceptionV3作为特征提取器,后接逻辑回归分类器来构建管道。我们使用trainDF数据框来训练模型:
from pyspark.ml.classification import LogisticRegression
from pyspark.ml import Pipeline

vectorizer = dl.DeepImageFeaturizer(inputCol="image",\
        outputCol="features", modelName="InceptionV3")
logreg = LogisticRegression(maxIter=20, labelCol="label")
pipeline = Pipeline(stages=[vectorizer, logreg])
pipeline_model = pipeline.fit(trainDF)
  1. 现在我们在测试数据集上评估训练好的模型。我们可以看到,在测试数据集上,使用以下代码我们得到了 90.32%的准确率:
predictDF = pipeline_model.transform(testDF) #predict on test dataset

from pyspark.ml.evaluation import MulticlassClassificationEvaluator as MCE
scoring = predictDF.select("prediction", "label")
accuracy_score = MCE(metricName="accuracy")
rate = accuracy_score.evaluate(scoring)*100
print("accuracy: {}%" .format(round(rate,2)))
  1. 这里是两个类别的混淆矩阵:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/884fed21-8f17-44bc-8c0d-a1c3b39a3bcd.png

在不到 20 行代码的情况下,我们成功训练了模型并获得了 90.32%的良好准确率。请记住,这里使用的数据集是原始数据;通过增加数据集中的图像数量,并过滤掉低质量的图像,你可以提高模型的表现。你可以从官方 GitHub 仓库了解更多关于深度学习库 SparkDL 的内容:github.com/databricks/spark-deep-learning

介绍 H2O.ai

H2O 是由 H2O.ai 开发的一个快速、可扩展的机器学习和深度学习框架,采用开源 Apache 许可证发布。根据公司提供的详细信息,超过 9000 个组织和 80,000+名数据科学家使用 H2O 来满足他们的机器学习/深度学习需求。它使用内存压缩技术,即使在一个小型的机器集群中,也能处理大量数据。它支持 R、Python、Java、Scala 和 JavaScript 接口,甚至还内置了一个 Web 界面。H2O 可以在独立模式下运行,也可以在 Hadoop 或 Spark 集群中运行。

H2O 包括大量的机器学习算法,如广义线性模型、朴素贝叶斯、随机森林、梯度提升和深度学习算法。H2O 的最佳特点是,用户可以在几行代码中构建成千上万个模型,比较结果,甚至进行超参数调优。H2O 还拥有更好的数据预处理工具。

H2O 需要 Java,因此,请确保你的系统上已安装 Java。你可以使用PyPi安装 H2O 以在 Python 中使用,以下是安装代码:

pip install h2o

H2O AutoML

H2O 最令人兴奋的功能之一是AutoML,自动化机器学习。它旨在开发一个易于使用的机器学习接口,可以供非专业人士使用。H2O AutoML 自动化了训练和调优大量候选模型的过程。其界面设计如此简便,用户只需要指定数据集、输入输出特征以及他们希望在训练的总模型数量或时间限制方面设置的任何约束条件。其余的工作由 AutoML 本身完成;在指定的时间限制内,它会识别出表现最好的模型,并提供一个排行榜。通常,已训练的所有模型的集成模型——堆叠集成模型,会占据排行榜的顶端。对于高级用户,有大量选项可供使用;这些选项的详细信息以及它们的各种功能可以在docs.h2o.ai/h2o/latest-stable/h2o-docs/automl.html上找到。

要了解更多关于 H2O 的信息,您可以访问他们的网站:h2o.ai

H2O 中的回归

我们将首先展示如何在 H2O 中进行回归。我们将使用与之前在 MLlib 中使用的相同数据集,即波士顿房价数据集,来预测房屋的价格。完整的代码可以在 GitHub 上找到:Chapter08/boston_price_h2o.ipynb

  1. 完成该任务所需的模块如下:
import h2o
import time
import seaborn
import itertools
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from h2o.estimators.glm import H2OGeneralizedLinearEstimator as GLM
from h2o.estimators.gbm import H2OGradientBoostingEstimator as GBM
from h2o.estimators.random_forest import H2ORandomForestEstimator as RF
%matplotlib inline
  1. 在导入必要的模块后,第一步是启动一个h2o服务器。我们通过h2o.init()命令来完成这一操作。它首先检查是否已有现有的h2o实例,如果没有,它将启动一个新的实例。还可以通过指定 IP 地址和端口号作为init()函数的参数来连接到现有集群。在下面的截图中,您可以看到在独立系统上执行init()的结果:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/53f4cd2a-ca1f-4c61-b9f7-3b6252b263fd.png

  1. 接下来,我们使用h2oimport_file函数读取数据文件。它将文件加载到 H2O 数据框中,可以像使用 pandas 数据框一样轻松处理。我们可以很容易地使用cor()方法找到h2o数据框中不同输入特征之间的相关性:
boston_df = h2o.import_file("../Chapter08/boston/train.csv", destination_frame="boston_df")

plt.figure(figsize=(20,20))
corr = boston_df.cor()
corr = corr.as_data_frame()
corr.index = boston_df.columns
#print(corr)
sns.heatmap(corr, annot=True, cmap='YlGnBu',vmin=-1, vmax=1)
plt.title("Correlation Heatmap")

以下是波士顿房价数据集中不同特征之间相关性图的输出:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/4034fa0e-2e34-41ca-abd7-67bd6550ba9a.png

  1. 现在,和往常一样,我们将数据集分为训练集、验证集和测试集。定义要作为输入特征使用的特征(x):
train_df,valid_df,test_df = boston_df.split_frame(ratios=[0.6, 0.2],\
         seed=133)
features =  boston_df.columns[:-1]
  1. 完成这项工作后,过程非常简单。我们只需实例化来自 H2O 库的回归模型类,并使用train()函数,传入训练集和验证集数据作为参数。在train函数中,我们还需要指定输入特征(x)和输出特征(y)。在本例中,我们将所有可用的特征作为输入特征,房价medv作为输出特征。通过简单的打印语句,我们可以查看训练后模型的特征。接下来,你可以看到一个广义线性回归模型的声明及其在训练集和验证集上的训练结果:
model_glm = GLM(model_id='boston_glm')
model_glm.train(training_frame= train_df,\
         validation_frame=valid_df, \
         y = 'medv', x=features)
print(model_glm)

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/05ca2730-9046-4226-9f2a-0a3fde5fc9c4.png

  1. 训练后,下一步是检查在测试数据集上的表现,这可以通过model_performance()函数轻松完成。我们也可以将其应用于任何数据集:训练集、验证集、测试集或某些新的类似数据集:
test_glm = model_glm.model_performance(test_df)
print(test_glm)

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/37608bc5-7c4d-45e8-891e-00fbcf07a17d.png

  1. 如果我们想使用梯度提升估计回归模型或随机森林回归模型,我们将实例化相应的类对象;接下来的步骤保持不变。不同的是输出参数;在梯度提升估计器和随机森林回归的情况下,我们还会学习不同输入特征的相对重要性:
#Gradient Boost Estimator
model_gbm = GBM(model_id='boston_gbm')
model_gbm.train(training_frame= train_df, \
        validation_frame=valid_df, \
        y = 'medv', x=features)

test_gbm = model_gbm.model_performance(test_df)

#Random Forest
model_rf = RF(model_id='boston_rf')
model_rf.train(training_frame= train_df,\
        validation_frame=valid_df, \
        y = 'medv', x=features)

test_rf = model_rf.model_performance(test_df)
  1. 机器学习和深度学习中最难的部分是选择正确的超参数。在 H2O 中,通过其H2OGridSearch类,任务变得相当简单。以下代码片段在之前定义的梯度提升估计器上执行网格搜索,搜索超参数深度:
from h2o.grid.grid_search import H2OGridSearch as Grid
hyper_params = {'max_depth':[2,4,6,8,10,12,14,16]}
grid = Grid(model_gbm, hyper_params, grid_id='depth_grid')
grid.train(training_frame= train_df,\
        validation_frame=valid_df,\
        y = 'medv', x=features)
  1. H2O 的最佳部分是使用 AutoML 自动寻找最佳模型。让我们要求它在 10 个模型中为我们搜索,并且将时间限制为 100 秒。AutoML 将在这些参数下构建 10 个不同的模型,不包括堆叠集成模型。它将在最多 100 秒内运行,最终训练出堆叠集成模型:
from h2o.automl import H2OAutoML as AutoML
aml = AutoML(max_models = 10, max_runtime_secs=100, seed=2)
aml.train(training_frame= train_df, \
        validation_frame=valid_df, \
        y = 'medv', x=features)
  1. 我们回归任务的排行榜如下:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/63da4e07-dad8-4b77-b3a0-a6935ec13e70.png

排行榜中的不同模型可以通过各自的model_id进行访问。最佳模型通过 leader 参数进行访问。在我们的例子中,aml.leader代表最佳模型,即所有模型的堆叠集成模型。我们可以使用h2o.save_model函数将最佳模型保存为二进制格式或 MOJO 格式。

H2O 中的分类

相同的模型可以用于 H2O 中的分类,只需做一个改动;我们需要使用asfactor()函数将输出特征从数值型转为类别型。我们将对红酒的质量进行分类,并使用我们之前的红酒数据库(第三章,物联网中的机器学习)。我们需要导入相同的模块并启动 H2O 服务器。完整代码可在Chapter08/wine_classification_h2o.ipynb文件中找到:

  1. 下面是导入必要模块并启动 H2O 服务器的代码:
import h2o
import time
import seaborn
import itertools
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from h2o.estimators.glm import H2OGeneralizedLinearEstimator as GLM
from h2o.estimators.gbm import H2OGradientBoostingEstimator as GBM
from h2o.estimators.random_forest import H2ORandomForestEstimator as RF

%matplotlib inline

h2o.init()
  1. 下一步是读取数据文件。我们首先修改输出特征以适应两个类别(好酒和坏酒),然后使用asfactor()函数将其转换为类别变量。这是 H2O 中的一个重要步骤;因为我们在回归和分类中使用相同的类对象,它们要求回归时输出标签为数值型,分类时输出标签为类别型,如代码块所示:
wine_df = h2o.import_file("../Chapter08/winequality-red.csv",\
        destination_frame="wine_df")    
features = wine_df.columns[:-1]
print(features)
wine_df['quality'] = (wine_df['quality'] > 7).ifelse(1,0)
wine_df['quality'] = wine_df['quality'].asfactor()
  1. 接下来,将数据集分为训练集、验证集和测试集。我们将训练集和验证集输入到广义线性估计器中,唯一的改动是;我们需要指定family=binomial参数,因为这里我们只有两类分类:好酒和坏酒。如果你有超过两个类别,使用family=multinomial。记住,指定这个参数是可选的;H2O 会自动检测输出特征:
train_df,valid_df,test_df = wine_df.split_frame(ratios=[0.6, 0.2],\
        seed=133)    

model_glm = GLM(model_id='wine_glm', family = 'binomial')
model_glm.train(training_frame= train_df, \
        validation_frame=valid_df,\
        y = 'quality', x=features)
print(model_glm)
  1. 经过训练后,你可以查看模型在所有性能指标上的表现:准确率、精确度、召回率、F1 值和 AUC,甚至是混淆矩阵。你可以获取三种数据集(训练集、验证集和测试集)的所有指标。以下是从广义线性估计器获取的测试数据集的指标:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/485b7663-f7da-4308-aacc-2c9eef924c7f.png

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/9c6bc796-6352-41ab-bf64-9259a084c731.png

  1. 在不改变前面的代码的情况下,我们可以进行超参数调优并使用 H2O 的 AutoML 来获得更好的模型:
from h2o.automl import H2OAutoML as AutoML
aml = AutoML(max_models = 10, max_runtime_secs=100, seed=2)
aml.train(training_frame= train_df, \
        validation_frame=valid_df, \
        y = 'quality', x=features)

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/62356947-6833-41e5-9c11-5a6a2947e263.png

我们看到,在红酒质量分类中,最佳模型是 XGBoost。

概要

随着物联网的普及,生成的数据正在以指数速度增长。这些数据通常是非结构化的,且数量庞大,常被称为大数据。为应对庞大的数据集,已经提出了大量的框架和解决方案。一个有前景的解决方案是 DAI,将模型或数据分布在一组机器上。我们可以使用分布式 TensorFlow 或 TFoS 框架来进行分布式模型训练。近年来,出现了一些易于使用的开源解决方案。两个最受欢迎且成功的解决方案是 Apache Spark 的 MLlib 和 H2O.ai 的 H2O。在本章中,我们展示了如何在 MLlib 和 H2O 中为回归和分类任务训练机器学习模型。Apache Spark 的 MLlib 支持 SparkDL,后者为图像分类和检测任务提供了出色的支持。本章使用 SparkDL 通过预训练的 InceptionV3 对花卉图像进行分类。另一方面,H2O.ai 的 H2O 在处理数值型和表格数据时表现良好。它提供了一个有趣且实用的 AutoML 功能,甚至允许非专家用户在很少的细节输入下调优并搜索大量的机器学习/深度学习模型。本章涵盖了如何使用 AutoML 进行回归和分类任务的示例。

当在一组机器上工作时,充分利用这些分布式平台是非常有利的。随着计算和数据以可承受的价格转移到云端,将机器学习任务迁移到云端是有意义的。接下来的一章将介绍不同的云平台,以及如何使用它们来分析由您的物联网设备生成的数据。

第九章:个人和家庭物联网

现在,您已经掌握了机器学习ML)和深度学习DL)的知识,并学习了如何将其应用于大数据、图像任务、文本任务和时间序列数据,是时候探索您所学的算法和技术在实际中的应用了。本章及接下来的两章将集中介绍一些具体的案例研究。本章将重点讨论个人和家庭物联网IoT)的使用案例。我们将在本章中讨论以下内容:

  • 成功的物联网应用

  • 可穿戴设备及其在个人物联网中的作用

  • 如何通过机器学习监测心脏

  • 什么让家成为智能家居

  • 智能家居中使用的设备

  • 人工智能在预测人类活动识别中的应用

个人物联网

个人物联网主要由可穿戴设备主导,这些技术设备设计为佩戴在身体上,并与智能手机上的应用程序配合使用。第一款可穿戴设备是由美国 Time Computer Inc.(当时称为汉密尔顿手表公司)生产的 Pulsar 计算器手表。那时它是一款不连接互联网的独立设备。随着互联网的普及,能够连接互联网的可穿戴设备成为了一种潮流。预计可穿戴设备市场将从 2016 年约3.25亿台增长至 2020 年超过8.3亿台:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/11b5c44d-8c4c-4040-adeb-2c5498122d54.png

该图展示了 2016 至 2021 年间全球可穿戴设备的数量(数据来源:Statista)。随着越来越多的设备在线连接并持续生成数据,AI/ML 工具成为分析这些数据并做出明智决策的自然选择。在本节中,您将了解一些成功的个人物联网应用。

MIT 的 SuperShoes

当你用一只手拿着手机并通过Google Maps导航时,你有多少次觉得这种方式很繁琐?你有多少次希望能有一双能带你去任何地方的魔法拖鞋?由MIT Media Lab开发的 SuperShoes(www.media.mit.edu/projects/supershoes/overview/)几乎就像这些魔法拖鞋;它们使用户无需查看智能手机屏幕即可在街道上导航。

SuperShoes 具有灵活的鞋垫,在脚趾下嵌入了振动马达。它们通过无线连接到智能手机上的应用程序。该应用程序不仅允许用户与 SuperShoes 进行交互,还将用户的喜好、不喜欢的东西、爱好、商店、食物、人物、兴趣等存储在云账户中。振动马达产生的触觉刺激与用户进行沟通。一旦用户在应用程序中输入目的地,鞋子就开始工作。如果左脚趾有触觉刺激,用户应该向左转;如果右脚趾有触觉刺激,用户应该向右转。如果没有触觉刺激,用户则需要继续直行。如果两个脚趾都反复有触觉刺激,说明用户已经到达目的地。

除了导航,它还可以推荐附近的兴趣地点;用户可以在云端更新他们的喜好和不喜欢的事物。根据用户的喜好和不喜欢,SuperShoes 在用户接近推荐地点时会给出提示(两只脚趾同时被刺激)。SuperShoes 的另一个有趣功能是它可以提醒用户;如果用户附近有任务,它会提醒用户。

制作这款鞋所需的硬件非常简单,主要包括以下内容:

  • 三个振动触觉装置刺激脚趾

  • 用于感应步态的电容传感器

  • 一块微控制器,用于接收应用程序的命令,并相应地控制触觉刺激装置

  • 用于与智能手机连接的蓝牙设备

  • 为整个系统提供电力的电池

这一魔法由应用程序中的软件代码实现。您可以在此网站了解更多关于 SuperShoes 的信息:dhairyadand.com/works/supershoes

持续血糖监测

人工智能的一个主要应用领域是物联网(IoT)在医疗保健中的应用,其中最成功的商业应用之一就是持续监测人体血糖水平。雅培的 FreeStyle CGM、DexCom CGM 和美敦力的 CGM 是一些市面上可用的品牌。

连续血糖监测CGM)使糖尿病患者能够实时检查自己体内的血糖水平。它帮助他们在一段时间内监测血糖数据,这些数据还可以用于预测未来的血糖水平,从而帮助他们应对低血糖等情况。

在 CGM 中,通常将传感器放置在腹部皮肤下或粘贴在手臂背部。传感器将读数发送到连接的呼叫器或智能手机应用程序。该应用程序具有基于人工智能的算法,可以告知用户任何临床相关的血糖模式。数据的可用性不仅帮助用户主动管理血糖的升高和下降,还可以提供关于饮食、锻炼或疾病对血糖水平影响的见解。

传感器的使用寿命通常为 7 到 14 天,通常这个时间足够医疗人员了解个人的生活方式,并相应地建议调整。

使用 CGM 数据预测低血糖

一旦一个人拥有 CGM 数据,就可以使用 AI/ML 对其进行分析,以收集更多信息或预测低血糖。在本节中,我们将看到如何使用前面章节中学到的算法来构建一个血糖预测系统。

我们将基于 Sparacino 等人发表的论文《血糖浓度可以通过连续血糖监测传感器时间序列提前预测》(10.1109/TBME.2006.889774)构建我们的预测器。

在论文中,CGM 时间序列的血糖数据由一个时间序列模型描述;论文考虑了两种模型,一个是简单的一阶多项式,另一个是一阶自回归模型。模型参数在每个采样时间 t[s] 对过去的血糖数据进行拟合。这里,我们将使用在第三章《物联网中的机器学习》中学到的 scikit 线性回归器来实现简单的一阶多项式:

  1. 我们导入模块 pandas 来读取csv文件,Numpy 用于数据处理,Matplotlib 用于绘图,scikit-learn 用于线性回归器,如下所示:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
%matplotlib inline
  1. 将从 CGM 获得的数据保存在数据文件夹中并读取。我们需要两个值:血糖读数和对应的时间。我们使用的数据在两个 CSV 文件中提供,分别是ys.csv(包含血糖值)和ts.csv(包含对应的时间),如下所示:
# Read the data
ys = pd.read_csv('data/ys.csv')
ts = pd.read_csv('data/ts.csv')
  1. 根据论文,我们定义了预测模型的两个参数ph,即预测时间范围,和mu,即遗忘因子。有关这两个参数的更多细节,请参考前面提到的论文:
# MODEL FIT AND PREDICTION

# Parameters of the predictive model. ph is Prediction horizon, mu is Forgetting factor.
ph = 10 
mu = 0.98
  1. 我们创建数组来保存预测值,如下所示:
n_s = len(ys)

# Arrays to hold predicted values
tp_pred = np.zeros(n_s-1) 
yp_pred = np.zeros(n_s-1)
  1. 现在我们读取 CGM 数据,模拟实时采集,并预测ph分钟后的血糖水平。所有过去的数据都用于确定模型参数,但每个数据点的贡献不同,由分配给它的个体权重mu^k(表示距当前采样时间k时刻的样本权重)决定:
# At every iteration of the for loop a new sample from CGM is acquired.
for i in range(2, n_s+1):
    ts_tmp = ts[0:i]
    ys_tmp = ys[0:i]
    ns = len(ys_tmp)

    # The mu**k assigns the weight to the previous samples.
    weights = np.ones(ns)*mu
    for k in range(ns):
        weights[k] = weights[k]**k
    weights = np.flip(weights, 0)
    # MODEL
    # Linear Regression.
    lm_tmp = LinearRegression() 
    model_tmp = lm_tmp.fit(ts_tmp, ys_tmp, sample_weight=weights)

    # Coefficients of the linear model, y = mx + q 
    m_tmp = model_tmp.coef_
    q_tmp = model*tmp.intercept

*    # PREDICTION
    tp = ts.iloc[ns-1,0] + ph
    yp = m_tmp*tp + q_tmp

    tp_pred[i-2] = tp 
    yp_pred[i-2] = yp
  1. 我们可以看到预测滞后于实际数据。正常的血糖水平在70180之间。低于70,患者可能会出现低血糖,超过180则可能导致高血糖。让我们来看一下我们预测数据的图示:
# PLOT
# Hypoglycemia threshold vector. 
t_tot = [l for l in range(int(ts.min()), int(tp_pred.max())+1)]
hypoglycemiaTH = 70*np.ones(len(t_tot)) 
#hyperglycemiaTH = 180*np.ones(len(t_tot))

fig, ax = plt.subplots(figsize=(10,10))
fig.suptitle('Glucose Level Prediction', fontsize=22, fontweight='bold')
ax.set_title('mu = %g, ph=%g ' %(mu, ph))
ax.plot(tp_pred, yp_pred, label='Predicted Value') 
ax.plot(ts.iloc[:,0], ys.iloc[:,0], label='CGM data') 
ax.plot(t_tot, hypoglycemiaTH, label='Hypoglycemia threshold')
#ax.plot(t_tot, hyperglycemiaTH, label='Hyperglycemia threshold')
ax.set_xlabel('time (min)')
ax.set_ylabel('glucose (mg/dl)')
ax.legend()

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/df2045fe-1257-4d6e-84e0-713cd388dea0.png

  1. 以下代码的 RMSE 误差将为 27:
from sklearn.metrics import mean_squared_error as mse
print("RMSE is", mse(ys[1:],yp_pred))

代码位于Chapter09/Hypoglycemia_Prediction.ipynb笔记本中。葡萄糖预测系统已经出现在许多商业产品中。你也可以根据我们刚刚创建的模型来做一个类似的系统。你还可以使用人工神经网络做类似的预测,结果可能会更好(参考 www.ncbi.nlm.nih.gov/pubmed/20082589)。

心脏监测器

另一个非常有用的个人 AI 应用在物联网中的例子是心脏病的检测。现在有很多可穿戴设备可以用来监测和记录心率。这些数据可以用来预测任何有害的心脏状况。在这里,我们将采用 AI/ML 工具来预测心脏心律失常,这是一组心率不规律的情况;它可以是过快(每分钟超过 100 次)或过慢(每分钟低于 60 次)。使用的数据来自UCI 机器学习数据集archive.ics.uci.edu/ml/datasets/heart+Disease。该数据集包含 76 个属性,但并非所有属性都用于预测疾病的存在;每一行数据都有一个目标字段。它有五个可能的值 0–4,值 0 表示健康的心脏,其他任何值都表示有疾病。为了更好的准确性,问题可以被划分为二分类问题。该代码灵感来源于 Mohammed Rashad 的 GitHub 链接,并且以 GNU GPL 3.0 许可证共享:github.com/MohammedRashad/Deep-Learning-and-Wearable-IoT-to-Monitor-and-Predict-Cardiac-Arrhytmia。完整的代码可以通过 GitHub 仓库中的Chapter09/Heart_Disease_Prediction.ipynb文件访问:

  1. 和往常一样,第一步是导入必要的模块。由于我们现在要对患者进行心脏病与否的分类,因此我们需要一个分类器。为了简便起见,我们使用SVC分类器。你也可以尝试使用 MLP 分类器,代码如下所示:
# importing required libraries
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

from sklearn.svm import SVC
from sklearn import metrics
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
  1. 接下来,读取数据集,对数据集进行预处理,选择你将考虑的属性。我们从 76 个属性中选择了 13 个,然后将目标值从多类值转换为二分类。最后,数据被分割为训练集和测试集,如下所示:
# reading csv file and extracting class column to y.
dataset = pd.read_csv("data.csv")
dataset.fillna(dataset.mean(), inplace=True)

dataset_to_array = np.array(dataset)
label = dataset_to_array[:,57] # "Target" classes having 0 and 1
label = label.astype('int')
label[label>0] = 1 # When it is 0 heart is healthy, 1 otherwise

# extracting 13 features
dataset = np.column_stack((
    dataset_to_array[:,4] , # pain location
    dataset_to_array[:,6] , # relieved after rest
    dataset_to_array[:,9] , # pain type 
    dataset_to_array[:,11], # resting blood pressure
    dataset_to_array[:,33], # maximum heart rate achieve
    dataset_to_array[:,34], # resting heart rate 
    dataset_to_array[:,35], # peak exercise blood pressure (first of 2 parts) 
    dataset_to_array[:,36], # peak exercise blood pressure (second of 2 parts) 
    dataset_to_array[:,38], # resting blood pressure 
    dataset_to_array[:,39], # exercise induced angina (1 = yes; 0 = no) 
    dataset.age, # age 
    dataset.sex , # sex
    dataset.hypertension # hyper tension
 ))

print ("The Dataset dimensions are : " , dataset.shape , "\n")

# dividing data into train and test data
X_train, X_test, y_train, y_test = train_test_split(dataset, label, random_state = 223)
  1. 现在,我们定义要使用的模型。这里我们使用的是支持向量分类器,通过fit函数来训练数据集:
model = SVC(kernel = 'linear').fit(X_train, y_train)
  1. 让我们来看一下它在测试数据集上的表现:
model_predictions = model.predict(X_test)
# model accuracy for X_test 
accuracy = metrics.accuracy_score(y_test, model_predictions)
print ("Accuracy of the model is :" , 
    accuracy , "\nApproximately : ", 
    round(accuracy*100) , "%\n")
  1. 你可以看到,它提供了 74%的准确率,使用 MLP,我们可以进一步提高准确率。但请记住,在使用 MLP 分类器之前,务必对所有输入特征进行归一化处理。以下是我们训练的支持向量分类器在测试数据集上的混淆矩阵:
#creating a confusion matrix
cm = confusion_matrix(y_test, model_predictions)

import pandas as pd
import seaborn as sn
import matplotlib.pyplot as plt
%matplotlib inline
df_cm = pd.DataFrame(cm, index = [i for i in "01"],
columns = [i for i in "01"])
plt.figure(figsize = (10,7))
sn.heatmap(df_cm, annot=True)

以下输出显示了测试数据集的混淆矩阵:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/fe756965-f750-4f3a-a070-01330b4ac16d.png

你可以在相同的数据集上训练你的模型,并使用训练好的模型为你的朋友、家人或客户预测心脏状况。

数字助手

数字助手是最早设想的人工智能应用之一。最初的数字助手尝试并未取得成功。然而,随着智能手机的出现和普及,今天我们有了大量的数字助手,它们提供拨打电话、写短信、安排日程,甚至为你上网搜索等服务。你可以让它们推荐附近的餐厅、酒吧或其他类似的地方。

以下是一些流行的数字助手:

  • Siri:由苹果开发,允许用户拨打电话、添加日程、播放音乐或视频,甚至发送短信。如今,几乎所有的苹果产品上都提供语音激活界面。

  • Cortana:由微软创建,帮助你通过基于时间、地点甚至人物的提醒保持日程安排。你可以让 Cortana 为你订午餐,或者使用它与之合作的其他应用程序。它与 Edge 集成,并启用了一个配备 Cortana 的语音激活扬声器。

  • Alexa:由亚马逊开发,适用于亚马逊 Echo 智能音响。它可以播放音乐、制定待办事项清单、为你设置闹钟、播放有声书,并提供关于股票、天气等的实时信息。它还支持语音互动。

  • Google Assistant:这是一个语音控制的智能助手。它提供持续的对话功能,即一旦你开始讲话,它会在没有触发词的情况下继续听取后续请求,而无需重复说嘿,Google。它还可以识别不同人的语音特征,并根据个人的喜好和厌恶量身定制回答。它不仅可以在安卓智能手机上使用,还可以在 Google Home 上使用。

2018 年,谷歌更进一步,发布了 Google Duplex,它可以为你打电话并预定约会。它说话像人类一样,并且在交谈时能够理解上下文。

物联网与智能家居

我的一个密友一直担心他年迈的母亲,母亲独自待在家中,而他、妻子和孩子们都外出。当母亲的健康状况开始恶化时,他向我求助。解决方案很简单;他在每个房间安装了 CCTV 摄像头,并与手机应用程序进行了连接。摄像头通过互联网联网,现在,无论他身在何处,都可以查看家中的情况,确保母亲的安好。

闭路电视(CCTV)、智能照明、智能音箱等连接到互联网帮助家庭自动化许多任务,您获得的是智能家居。目前大多数智能家居系统通过语音命令界面工作,您可以使用一组命令控制特定设备。例如,在 Amazon 的 Echo Dot 中,您可以要求其搜索或播放特定歌曲。您可以要求 Apple 的 Siri 使用手机打电话给朋友,都可以通过简单的语音界面。大多数这些设备都在某种形式上使用 AI/ML,但通过使用 AI/ML,家庭自动化可以进一步发展。例如,对于我的朋友,可以训练 AI 系统从视频中识别活动,或者检测家庭入侵。可能性是无限的。有了正确的数据和足够的计算能力,您只受想象的限制。

在本节中,我们将看到一些现有的家庭自动化产品,并探讨如何进一步利用 AI 来增强自动化。

人体活动识别

最受关注的智能家居应用之一是人体活动识别HAR)。有许多公司试图开发能够追踪体育活动及其相应热量消耗的应用程序。健康与健身无疑是一个大生意。除了在健身和健康方面的应用外,HAR 在老年护理或康复中也很有用。进行 HAR 已有许多方法,以下是其中两种:

  • 使用摄像头(或雷达或类似设备)记录人类活动,并使用深度学习方法对其进行分类

  • 个人使用可穿戴传感器(类似于智能手机中的加速计)记录其数据,并用于预测活动

这两种方法各有优缺点。我们将在以下章节详细讨论它们。

使用可穿戴传感器进行 HAR

大量供应商提供带有健身追踪器的可穿戴手表和手镯。这些手表和手镯配备了 GPS、加速度计、陀螺仪、心率传感器和/或环境光传感器。通过传感器融合,它们结合这些传感器的输出来对活动进行预测。由于数据的时间性质,这是一个具有挑战性的时间序列分类任务。

Fitbit (www.fitbit.com/smarttrack),作为健身追踪器领域的领先公司,使用了它称之为SmartTrack的技术,能够识别连续运动或轻微运动的活动。它利用运动的强度和模式对活动进行分类。它将活动分为七类,如下所示:

  • 步行

  • 跑步

  • 有氧运动

  • 椭圆机

  • 户外骑行

  • 运动

  • 游泳

Apple Watch (www.apple.com/in/apple-watch-series-4/workout/) 对 Fitbit 构成了强有力的竞争。它运行在 iOS 操作系统上,具备跌倒检测功能,以及许多其他健康跟踪特性。通过分析手腕的轨迹和冲击加速度,它可以检测到是否发生跌倒,并能够发起紧急呼叫。Apple Watch 默认将活动分为三类:步行、锻炼和站立。锻炼(运动)则进一步分类到其他领域,如室内跑步、户外跑步、滑雪、单板滑雪、瑜伽,甚至徒步旅行。

如果你想尝试使用智能手机传感器制作类似的应用程序,首先你需要的数据。接下来,我们展示了一个使用随机森林实现的 HAR 方法,代码改编自罗切斯特大学的数据科学家 Nilesh Patil 的 GitHub 链接:github.com/nilesh-patil/human-activity-recognition-smartphone-sensors

数据集来自论文 Davide Anguita, Alessandro Ghio, Luca Oneto, Xavier Parra 和 Jorge L. Reyes-Ortiz. A Public Domain Dataset for Human Activity Recognition Using Smartphones. 2013 年 21 届欧洲人工神经网络、计算智能与机器学习研讨会,ESANN 2013。比利时布鲁日,2013 年 4 月 24-26 日。

可在 UCI ML 网站上获取:archive.ics.uci.edu/ml/datasets/Human+Activity+Recognition+Using+Smartphones#

数据集中的每一条记录包含:

  • 来自加速度计的三轴加速度(总加速度)以及估算的身体加速度

  • 来自陀螺仪的三轴角速度

  • 一个包含 561 个特征的向量,包含时域和频域变量

  • 它的活动标签

  • 实验执行者的标识符

数据被分类为六个类别:

  • 躺卧

  • 坐姿

  • 站立

  • 步行

  • 向下行走

  • 向上行走

  1. 在这里,我们使用 scikit-learn 的随机森林分类器对数据进行分类。实现所需的模块在第一步中被导入:
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.ensemble import RandomForestClassifier as rfc
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
%matplotlib inline
  1. 我们读取数据并将其分为traintest数据集,如下所示:
data = pd.read_csv('data/samsung_data.txt',sep='|')
train = data.sample(frac=0.7,
        random_state=42)
test = data[~data.index.isin(train.index)]

X = train[train.columns[:-2]]
Y = train.activity
  1. 数据包含 561 个特征,但并非所有特征都同等重要。我们可以通过制作一个简单的随机森林分类器来选择更重要的特征,仅选择最重要的特征。在此实现中,分为两个步骤。首先,我们获取重要特征的列表,并按重要性降序排列。然后,通过网格超参数调优找到特征的数量和特征。超参数调优的结果显示在曲线上。我们可以看到,大约 20 个特征后,使用以下代码,袋外OOB)精度没有显著提高:
randomState = 42
ntree = 25

model0 = rfc(n_estimators=ntree,
random_state=randomState,
n_jobs=4,
warm_start=True,
oob_score=True)
model0 = model0.fit(X, Y)

# Arrange the features in ascending order
model_vars0 = pd.DataFrame(
    {'variable':X.columns,
    'importance':model0.feature_importances_})

model_vars0.sort_values(by='importance',
    ascending=False,
    inplace=True)

# Build a feature vector with most important 25 features

n = 25
cols_model = [col for col in model_vars0.variable[:n].values]

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/192c852f-e7d6-4b50-a10e-07a0fbe2b223.png

  1. 我们还可以在下图中看到前 25 个特征的平均重要性:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/a50b2557-fe4d-4eec-a2b8-ae21cbf41606.png

  1. 同样,我们可以超调树的数量参数。在这里,我们将特征限制为四个重要特征:
n_used = 4
cols_model = [col for col in model_vars0.variable[:n_used].values]\
     + [model_vars0.variable[6]]
X = train[cols_model]
Y = train.activity

ntree_determination = {}
for ntree in range(5,150,5):
    model = rfc(n_estimators=ntree,
        random_state=randomState,
        n_jobs=4,
        warm_start=False,
        oob_score=True)
model = model.fit(X, Y)
ntree_determination[ntree]=model.oob_score_

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/8ca940bc-92b6-464e-953f-1f6c67d35399.png

  1. 因此,我们可以看到,具有大约四个重要特征和50棵树的随机森林能够提供良好的 OOB 准确率。因此,我们的最终模型如下:
model2 = rfc(n_estimators=50,
    random_state=randomState,
    n_jobs=4,
    warm_start=False,
    oob_score=True)
model2 = model2.fit(X, Y)
  1. 这样会得到 94%的测试数据准确率。接下来,您可以看到测试数据集的混淆矩阵:
test_actual = test.activity
test_pred = model2.predict(test[X.columns])
cm = confusion_matrix(test_actual,test_pred)
sns.heatmap(data=cm,
     fmt='.0f',
     annot=True,
     xticklabels=np.unique(test_actual),
     yticklabels=np.unique(test_actual))

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/5b71c386-b294-4b2f-8887-92cf66ef4cc7.png

完整代码和数据探索可在 GitHub 仓库中找到,文件路径为Chapter09/Human_activity_recognition_using_accelerometer.ipynb。使用加速度计数据的优势在于,它是从可穿戴设备收集的,因此无需在现场进行安装。另一个优势是它是文本数据,因此比视频数据所需的计算资源更少。

来自视频的 HAR

检测人类活动的另一种方法是通过视频。在这种情况下,我们必须使用诸如 CNN 这样的深度学习模型来获得良好的结果。Ivan Laptev 和 Barbara Caputo 提供了一个适用于分类视频的良好数据集,网址为:www.nada.kth.se/cvap/actions/。该数据集包含六种类型的动作:步行、慢跑、跑步、拳击、挥手和拍手,且在不同的场景下录制。每个视频都是使用 25fps 的相机录制的,空间分辨率为 160 × 120,平均长度为四秒。数据集中总共有 599 个视频,每个类别大约 100 个。

视频数据的一个问题是它在计算上非常昂贵,因此,减少数据集的大小非常重要,以下是几种减少数据集的方法:

  • 由于颜色在活动检测中并不起作用,因此可以将图像从三通道彩色图像转换为二维灰度图像。

  • 视频时长为四秒,且每秒 25 帧,其中大部分帧包含冗余数据,因此我们可以将帧数从(25 × 4 = 100)帧减少到每秒 5 帧,从而得到 20 帧。(如果每个视频提取的总帧数固定,会更好)。

  • 将单个帧的空间分辨率从 160 × 120 降低。

接下来,在建模时,我们应该使用三维卷积层。假设我们每个视频只取了 20 帧,并将每帧的大小缩减到 128 × 128,那么一个样本将是:20 × 128 × 128 × 1,这对应的是一个具有单通道的 20 × 128 × 128 的体积。

智能照明

提到智能家居时,首先想到的家庭自动化应用是使用智能灯。目前大多数智能照明系统都提供了通过智能手机应用或互联网来控制灯光的开关,以及灯光的强度。有些还允许你改变灯光的颜色/色调。运动探测灯是今天几乎所有家庭的标准配置,能够在检测到任何运动后自动开启:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/45ffbdaf-d76a-455d-a42c-f3c4ca885eb8.png

听力障碍人士使用的智能灯根据情况变化颜色

使用人工智能,我们可以使这些智能灯更加智能。在紧急情况下,它们可以被编程成相互协作,引导你走向正确的出口。对于听力障碍的人,智能灯可以用来替代警报,例如,火灾警报响起时显示红灯,遇到入室盗窃时显示橙灯,当有人按门铃时显示欢迎的绿色灯。借助如果这样,那么那样IFTTT)等服务,你可以建立更智能、更复杂的支持系统。

IFTTT 提供一个免费的服务来控制你的设备。一个设备(或服务)的动作可以触发一个或多个其他设备。使用起来非常简单,你只需在 IFTTT 网站创建一个小程序:ifttt.com,选择你想用作触发器的设备(点击选择)或服务,并将其与 IFTTT 账户关联。接下来,你选择(点击选择)当触发器激活时,哪个服务或设备应该采取行动。该网站包含成千上万的预制小程序,让你的工作更加轻松。

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/84e7219c-8800-479b-af5b-65fa2780892d.png

个性化智能灯系统的算法

这些只是你可以用现有智能灯做的一些例子。但如果你喜欢冒险并准备将新传感器与这些智能灯进行接口,你可以为自己打造一盏个性化的灯,它会根据人的精神活动改变其色调/强度。当你感到困倦时,它会变暗,而在你工作时,它则会全亮,但当你和朋友们交谈、共度时光时,它会提供一个愉悦的色调。听起来有些离谱?其实不然,你可以首先使用一种 AI 算法,通过视频(或可穿戴的健身追踪器)检测人体活动,并将其分类为三种状态:工作、休闲和睡眠,然后利用其输出控制智能灯的色调/强度。

家庭监控

家庭监控是一个非常有用且迫切需要的应用。随着单亲家庭和老龄化人口的增加,安全和监控的需求不仅限于外部环境,还需要在家庭内部进行。许多公司正在尝试使用视频提供室内监控。一个成功的实施案例是由 DeepSight AILabs 公司开发的,他们开发了专有软件SuperSecure;这是一个与任何闭路电视系统、任何摄像头、任何分辨率兼容的通用后期解决方案,将其转变为AI 驱动的智能监控解决方案,以高准确度检测潜在威胁,并触发即时警报以挽救生命和保护资产。

当您尝试实施自己的家庭监控时,我们在使用视频实施 HAR 时讨论的要点也同样适用。

智能家居仍处于初级阶段,主要原因是它们涉及高昂的拥有成本和互连设备的不灵活性。通常,一个特定的系统完全由一个公司管理。如果某些原因导致公司关闭,消费者就会陷入困境。解决方案将是允许开源家庭自动化硬件和软件。有关家庭自动化领域的挑战和机遇的一篇有趣文章是微软研究的一篇文章,Home Automation in the Wild: Challenges and Opportunities (www.microsoft.com/en-us/research/publication/home-automation-in-the-wild-challenges-and-opportunities/)。

总结

本章的重点是个人和家庭的 AI 驱动物联网解决方案。智能手机的大规模使用使得可穿戴传感器成为每个人都可以接触到的设备,导致了大量的个人应用的出现。在这一章节中,我们探讨并实施了一些成功的个人和家庭 AI 驱动的物联网解决方案。我们了解了麻省理工学院的 SuperShoes,这是一种可以自主找到目的地路径的鞋子。我们了解了连续血糖监测系统,并编写了代码来预测高血糖。本章还展示了个性化心率监测器如何实施。

尽管智能家居仍处于初级阶段,本章探讨了一些最流行和有用的智能家居解决方案。介绍了 HAR,这是一种位于智能家居和个人物联网边界的应用。我们使用 scikit-learn 编写了一些代码,用于根据加速度计获取的数据分类活动。本章介绍了一些酷炫的智能照明应用,并讨论了使用视频进行家庭监控。

在接下来的章节中,我们将研究一些案例研究,其中从物联网传感器获得的数据被用来提高工业生产和效率。

第十章:工业物联网的 AI 应用

来自不同背景的公司如今意识到人工智能AI)的重要性,因此正在将其纳入到各自的生态系统中。本章重点介绍一些成功的 AI 驱动的工业物联网解决方案。到本章结束时,您将涵盖以下内容:

  • AI 驱动的物联网解决方案如何改变行业

  • 不同行业提供 AI 驱动的数据分析,以提高生产效率、优化物流和改善客户体验

  • 预防性维护

  • 基于飞机引擎传感器数据实现预防性维护的代码

  • 电力负荷预测

  • 实现一个 TensorFlow 代码来执行短期负荷预测

AI 驱动的工业物联网简介

物联网、机器人技术、大数据和机器学习ML)的融合正在为工业企业创造巨大的机遇,也带来了显著的挑战。

低成本传感器、多云平台和强大的边缘基础设施的可用性使得各行业采用 AI 变得更加容易且具有盈利性。这种 AI 驱动的工业物联网正在改变公司提供产品和服务、以及与客户和合作伙伴互动的方式。

AI 驱动的工业物联网的一个有前景的领域是预防性维护。直到现在,工业公司通常采用反应式维护方式,即根据固定的时间表进行维护(如每六个月),或者仅在某些设备停止运作时才进行维护。例如,一家物流公司可能会对其车队中的每辆车辆进行半年一次的服务检查,并按计划更换某些部件或整车。这种反应性维护常常浪费时间且费用高昂。应用 AI 算法在问题发生之前预测异常和故障,可以节省大量时间。

另一个 AI 驱动的工业物联网可以实现奇迹的领域是人类与机器人之间的协作。机器人已经是工业物联网生态系统的一部分;它们在生产线和仓库中工作,执行那些特别重复或对人类工人来说危险的任务。目前矿业行业中使用的半自动化卡车、火车和装载机通常是通过预设程序、固定轨道和/或远程人工操作来引导的。

在许多工业场景中,云计算所引入的延迟可能是不可接受的,在这种情况下,需要边缘计算基础设施。

为了让您了解 AI 驱动的工业物联网的普及和应用,以下是一些提供工业物联网服务和解决方案的热门 AI 初创企业名单:

  • Uptake Technologies Inc:总部位于芝加哥的初创公司,由 Brad Keywell 于 2014 年共同创立,开发用于监控和分析工业设备实时数据的软件,并利用这些数据提高机械的性能和维护效率。该公司计划将其业务扩展到能源、铁路、石油天然气、矿业和风能等重型行业 (www.uptake.com/)。

  • C3.ai:由 Thomas Siebel 领导的领先大数据、物联网和人工智能应用提供商,在 Forrester Research 2018 年工业物联网波段报告中被评为物联网平台领导者。公司成立于 2009 年,成功地为能源管理、网络效率、欺诈检测和库存优化等领域的工业提供服务 (c3.ai)。

  • Alluvium:由*《Machine Learning for Hackers》*的作者 Drew Conway 于 2015 年创立,Alluvium 使用机器学习和人工智能帮助工业公司实现运营稳定并改善生产。他们的旗舰产品 Primer 帮助公司从传感器的原始和精炼数据中识别有用的洞察力,使他们能够在操作故障发生之前预测它们 (alluvium.io)。

  • Arundo Analytics:由 Jakob Ramsøy 领导,成立于 2015 年,Arundo Analytics 提供将实时数据与机器学习和其他分析模型相连接的服务。他们的产品可以扩展已部署的模型,创建和管理实时数据管道 (www.arundo.com)。

  • Canvass Analytics:它通过基于实时运营数据的预测分析,帮助企业做出关键的业务决策。Canvass AI 平台从工业设备、传感器和操作系统生成的数百万个数据点中提炼出模式和相关性,从而创造新的洞察力。由 Humera Malik 领导,Canvass Analytics 成立于 2016 年 (www.canvass.io)。

这还不是结束,像 Amazon 和 Google 这样的软件技术巨头也在物联网领域投入大量资金和基础设施。Google 利用预测建模来降低数据中心成本,而 PayPal 则使用机器学习来发现欺诈交易。

一些有趣的应用案例

来自不同背景的大量公司正在意识到将数据分析和人工智能融入其生态系统的重要性和影响。从提高运营、供应链和维护效率到提升员工生产力,再到创建新的商业模式、产品和服务,人工智能已经在各个领域得到了探索。以下,我们列出了一些人工智能驱动物联网在工业中的有趣应用案例:

  • 预测性维护:在预测性维护中,使用人工智能算法预测设备故障的发生时间。这样,公司可以提前进行维护,从而减少停机时间。在接下来的部分中,我们将详细讨论预防性维护如何帮助行业,以及它可以采取的各种方式。

  • 资产追踪:也叫资产管理,这是一种跟踪关键物理资产的方法。通过跟踪关键资产,公司可以优化物流、维持库存水平并发现任何低效之处。传统上,资产追踪限于在资产上添加 RFID 或条形码,从而跟踪其位置。然而,凭借人工智能算法的支持,现在可以进行更积极的资产追踪。例如,风力发电站可以感知风速、风向甚至温度的变化,并利用这些参数将每台风机调整到最佳方向,以最大化发电量。

  • 车队管理与维护:运输行业在车队管理中已经使用人工智能约十年,通过优化路线来提高效率。如今,许多低成本传感器的可用性和边缘计算设备的进步使运输公司能够收集并利用这些传感器接收到的数据,不仅能够通过更好的车对车通信和预防性维护优化物流,还能提高安全性。通过安装如困倦检测等系统,因疲劳或分心导致的危险行为能够被检测到,司机会被提醒采取应对措施。

使用人工智能的预测性维护

重型机械和设备是任何行业的支柱,和所有物理对象一样,它们会逐渐退化、老化并发生故障。最初,公司通常采取反应式维护,即在设备发生故障后才进行维护。这往往会导致计划外的停机时间。对于任何行业来说,计划外的停机时间都会导致资源紧张,显著降低效率、生产力,进而减少利润。为了解决这些问题,行业开始转向预防性维护。

在预防性维护中,定期按预定的时间间隔进行例行检查。预防性维护要求记录设备及其定期维护计划。第三次工业革命中,计算机引入到工业领域,使得维护和更新这些记录变得更加容易。虽然预防性维护可以避免大多数计划外的停机,但它仍然不是最理想的替代方案,因为定期检查可能会造成不必要的开支。下图展示了四次工业革命的示例:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/43713621-93d7-4bd5-a566-6b8ef8defa0c.png

根据创作共用许可协议共享的图像:(commons.wikimedia.org/wiki/File:Industry_4.0.png)

当前自动化和数字化的趋势推动了第四次工业革命,也称为工业 4.0。这使得企业能够部署机器对机器M2M)和机器对人M2H)的通信,以及基于 AI 的分析算法,从而实现预测性维护,能够利用历史数据预测设备故障的发生。预测性维护策略极大地简化了企业资源的维护和管理。

预测性维护的主要思想是根据条件监测数据预测设备何时可能发生故障。传感器用于监控设备在正常运行中的状态和性能,依据设备的不同,可能会使用不同类型的传感器。以下是一些常见的条件监测参数/传感器值:

  • 振动传感器,主要用于检测泵和电机的错位、不平衡、机械松动或磨损。

  • 电流/电压传感器,用于测量供电电机的电流和电压。

  • 超声波分析,用于检测管道系统或储罐中的泄漏,或可动部件的机械故障以及电气设备的故障。

  • 红外热成像,用于识别温度波动。

  • 用于检测液体质量的传感器(例如,在葡萄酒的情况下,传感器用于检测葡萄酒中不同元素的存在)。

实施预测性维护,最重要的是识别需要监控的条件。接着,部署所需的传感器来监控这些条件。最后,收集来自传感器的数据以构建模型。

使用长短期记忆(LSTM)进行预测性维护。

为了演示预测性维护,我们将使用 Azure ML 提供的模拟数据(gallery.azure.ai/Collection/Predictive-Maintenance-Template-3)。数据集包含以下三个文件:

根据数据源提供的数据描述,训练数据(train_FD001.txt)由多个多变量时间序列组成,以周期作为时间单位,每个周期有 21 个传感器读数。可以假设每个时间序列是从不同的相同类型引擎生成的。假定每个引擎在开始时具有不同程度的初始磨损和制造差异,这些信息未知于用户。在这些模拟数据中,引擎被假定在每个时间序列开始时正常运行。在一定时间段内开始退化,退化进展并增加幅度。当达到预定义的阈值时,引擎被认为不再适合继续操作。换句话说,每个时间序列中的最后一个周期可以视为相应引擎的故障点。以样本训练数据为例,id=1 的引擎在周期 192 失败,而 id=2 的引擎在周期 287 失败。

测试数据(test_FD001.txt)与训练数据具有相同的数据结构。唯一的区别在于数据不指示故障发生的时间点(换句话说,最后一个时间段不表示故障点)。以样本测试数据为例,id=1 的引擎从周期 1 运行到周期 31。未显示该引擎在故障前还能运行多少个周期。

地面真实数据(RUL_FD001.txt)提供了测试数据中引擎剩余工作周期的数量。以示例地面真实数据为例,测试数据中 id=1 的引擎在故障前可以再运行 112 个周期。

由于这是时间序列数据,我们将使用长短期记忆网络LSTM)来分类引擎在某个时间段内是否会失败。这里呈现的代码基于 Umberto Griffo 提供的实现,GitHub 链接如下:(github.com/umbertogriffo/Predictive-Maintenance-using-LSTM):

  1. 实施预测性维护所需的模块在第一步导入。我们还为随机计算设置种子,以便结果可重现:
import keras
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import os

# Setting seed for reproducibility
np.random.seed(1234) 
PYTHONHASHSEED = 0

from sklearn import preprocessing
from sklearn.metrics import confusion_matrix, recall_score, precision_score
from keras.models import Sequential,load_model
from keras.layers import Dense, Dropout, LSTM
  1. 让我们读取数据并分配列名,如下所示的代码:
# read training data - It is the aircraft engine run-to-failure data.
train_df = pd.read_csv('PM_train.txt', sep=" ",
         header=None)
train_df.drop(train_df.columns[[26, 27]], 
        axis=1, 
        inplace=True)
train_df.columns = ['id', 'cycle', 'setting1',
         'setting2', 'setting3', 's1', 's2',
         's3', 's4', 's5', 's6', 's7', 's8',
         's9', 's10', 's11', 's12', 's13', 
        's14', 's15', 's16', 's17', 's18', 
        's19', 's20', 's21']

train_df = train_df.sort_values(['id','cycle'])

# read test data - It is the aircraft engine operating data without failure events recorded.
test_df = pd.read_csv('PM_test.txt', 
        sep=" ", header=None)
test_df.drop(test_df.columns[[26, 27]], 
        axis=1, 
        inplace=True)
test_df.columns = ['id', 'cycle', 'setting1', 
        'setting2', 'setting3', 's1', 's2', 's3',
         's4', 's5', 's6', 's7', 's8', 's9', 
        's10', 's11', 's12', 's13', 's14',
         's15', 's16', 's17', 's18', 's19', 
        's20', 's21']

# read ground truth data - It contains the information of true remaining cycles for each engine in the testing data.
truth_df = pd.read_csv('PM_truth.txt', 
        sep=" ", 
        header=None)
truth_df.drop(truth_df.columns[[1]], 
        axis=1, 
        inplace=True)
  1. 作为第一步,我们预测引擎在某个时间段内是否会失败,因此我们的标签将是 10,即这将是一个二元分类问题。为了创建二元标签,我们预处理数据并创建一个新的剩余寿命RUL)标签。我们还创建一个名为 label1 的二元变量,指示特定引擎是否会在 w1 个周期内失败。最后,数据(非传感器)被归一化,如下所示:
# Data Labeling - generate column RUL(Remaining Usefull Life or Time to Failure)
rul = pd.DataFrame(train_df.groupby('id')
        ['cycle'].max()).reset_index()
rul.columns = ['id', 'max']
train_df = train_df.merge(rul, 
        on=['id'], 
        how='left')
train_df['RUL'] = train_df['max'] -     train_df['cycle']
train_df.drop('max', 
        axis=1, 
        inplace=True)

# Let us generate label columns for training data
# we will only use "label1" for binary classification, 
# The question: is a specific engine going to fail within w1 cycles?
w1 = 30
w0 = 15
train_df['label1'] = np.where(train_df['RUL'] <= w1, 1, 0 )

# MinMax normalization (from 0 to 1)
train_df['cycle_norm'] = train_df['cycle']
cols_normalize = train_df.columns.difference
        (['id','cycle','RUL','label1'])
min_max_scaler = preprocessing.MinMaxScaler()
norm_train_df = pd.DataFrame(min_max_scaler.
        fit_transform(train_df[cols_normalize]), 
        columns=cols_normalize, 
        index=train_df.index)
join_df = train_df[train_df.columns.
        difference(cols_normalize)].
        join(norm_train_df)
train_df = join_df.reindex(columns = train_df.columns)

train_df.head()

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/db9d096a-4f3b-4f94-8bfa-f43be21b0d05.png

  1. 对测试数据集执行类似的预处理操作,唯一的变化是——RUL 值是从真实数据中获取的:
# MinMax normalization (from 0 to 1)
test_df['cycle_norm'] = test_df['cycle']
norm_test_df = pd.DataFrame(
        min_max_scaler.
        transform(test_df[cols_normalize]), 
        columns=cols_normalize,     
         index=test_df.index)
test_join_df = test_df[test_df.
        columns.difference(cols_normalize)].
        join(norm_test_df)
test_df = test_join_df.
        reindex(columns = test_df.columns)
test_df = test_df.reset_index(drop=True)

# We use the ground truth dataset to generate labels for the test data.
# generate column max for test data
rul = pd.DataFrame(test_df.
        groupby('id')['cycle'].max()).
        reset_index()
rul.columns = ['id', 'max']
truth_df.columns = ['more']
truth_df['id'] = truth_df.index + 1
truth_df['max'] = rul['max'] + truth_df['more']
truth_df.drop('more', 
        axis=1, 
        inplace=True)

# generate RUL for test data
test_df = test_df.merge(truth_df, 
        on=['id'], how='left')
test_df['RUL'] = test_df['max'] - test_df['cycle']
test_df.drop('max', 
        axis=1, 
        inplace=True)

# generate label columns w0 and w1 for test data
test_df['label1'] = np.where
        (test_df['RUL'] <= w1, 1, 0 )
test_df.head()

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/af874577-0db2-4421-9166-23f0ab836a8a.png

  1. 由于我们使用 LSTM 进行时间序列建模,我们创建了一个函数,该函数将根据窗口大小生成要输入 LSTM 的序列。我们选择的窗口大小为50。我们还需要一个函数来生成相应的标签:
# function to reshape features into 
# (samples, time steps, features) 
def gen_sequence(id_df, seq_length, seq_cols):
    """ Only sequences that meet the window-length
    are considered, no padding is used. This 
    means for testing we need to drop those which 
    are below the window-length. An alternative
    would be to pad sequences so that
    we can use shorter ones """

    # for one id we put all the rows in a single matrix
    data_matrix = id_df[seq_cols].values
    num_elements = data_matrix.shape[0]
    # Iterate over two lists in parallel.
    # For example id1 have 192 rows and 
    # sequence_length is equal to 50
    # so zip iterate over two following list of 
    # numbers (0,112),(50,192)
    # 0 50 -> from row 0 to row 50
    # 1 51 -> from row 1 to row 51
    # 2 52 -> from row 2 to row 52
    # ...
    # 111 191 -> from row 111 to 191
    for start, stop in zip(range(0, num_elements-seq_length), range(seq_length, num_elements)):
        yield data_matrix[start:stop, :]

def gen_labels(id_df, seq_length, label):
    # For one id we put all the labels in a 
    # single matrix.
    # For example:
    # [[1]
    # [4]
    # [1]
    # [5]
    # [9]
    # ...
    # [200]] 
    data_matrix = id_df[label].values
    num_elements = data_matrix.shape[0]
    # I have to remove the first seq_length labels
    # because for one id the first sequence of 
    # seq_length size have as target
    # the last label (the previus ones are 
    # discarded).
    # All the next id's sequences will have 
    # associated step by step one label as target. 
    return data_matrix[seq_length:num_elements, :]
  1. 现在让我们为我们的数据生成训练序列和对应的标签,代码如下:
# pick a large window size of 50 cycles
sequence_length = 50

# pick the feature columns 
sensor_cols = ['s' + str(i) for i in range(1,22)]
sequence_cols = ['setting1', 'setting2', 
        'setting3', 'cycle_norm']
sequence_cols.extend(sensor_cols)

# generator for the sequences
seq_gen = (list(gen_sequence
        (train_df[train_df['id']==id], 
        sequence_length, sequence_cols)) 
        for id in train_df['id'].unique())

# generate sequences and convert to numpy array
seq_array = np.concatenate(list(seq_gen)).
        astype(np.float32)
print(seq_array.shape)

# generate labels
label_gen = [gen_labels(train_df[train_df['id']==id], 
        sequence_length, ['label1']) 
        for id in train_df['id'].unique()]
label_array = np.concatenate(label_gen).
        astype(np.float32)
print(label_array.shape)
  1. 我们现在构建一个包含两个 LSTM 层和一个全连接层的 LSTM 模型。该模型用于二分类训练,因此它尝试减少二元交叉熵损失。我们使用Adam优化器来更新模型参数:
nb_features = seq_array.shape[2]
nb_out = label_array.shape[1]

model = Sequential()

model.add(LSTM(
     input_shape=(sequence_length, nb_features),
     units=100,
     return_sequences=True))
model.add(Dropout(0.2))

model.add(LSTM(
     units=50,
     return_sequences=False))
model.add(Dropout(0.2))

model.add(Dense(units=nb_out,
     activation='sigmoid'))
model.compile(loss='binary_crossentropy', 
    optimizer='adam', 
    metrics=['accuracy'])

print(model.summary())

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/39a6a841-8fcb-499c-8944-b60c0a07e23e.png

  1. 我们训练模型,结果如下所示:
history = model.fit(seq_array, label_array, 
        epochs=100, batch_size=200, 
        validation_split=0.05, verbose=2,
         callbacks = [keras.callbacks.
            EarlyStopping(monitor='val_loss', 
            min_delta=0, patience=10, 
            verbose=0, mode='min'),
        keras.callbacks.
            ModelCheckpoint
            (model_path,monitor='val_loss',     
            save_best_only=True, 
            mode='min', verbose=0)])    
  1. 经过训练的模型在测试数据集上的准确率为 98%,在验证数据集上的准确率为 98.9%。精度值为0.96,召回率为1.0,F1 分数为0.98。不错吧!下图显示了训练模型的这些结果:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/d3461ac4-07d5-4701-9a62-a70015086c06.png

我们可以使用相同的数据来预测飞机发动机的 RUL 值,也就是预测发动机的故障时间。这将是一个回归问题,我们现在可以使用 LSTM 模型进行回归。最初的步骤将与之前相同,但从第五步开始会有所变化。虽然生成的输入数据序列将与之前保持一致,但目标将不再是二进制标签,而是使用 RUL 作为回归模型的目标:

  1. 我们使用相同的gen_labels()函数创建目标值。我们还使用gen_sequence()函数创建了一个验证集:
# generate labels
label_gen = [gen_labels(train_df[train_df['id']==id],
        sequence_length, ['RUL']) 
        for id in train_df['id'].unique()]
label_array = np.concatenate(label_gen).astype(np.float32)

# val is a list of 192 - 50 = 142 bi-dimensional array 
# (50 rows x 25 columns)
val=list(gen_sequence(train_df[train_df['id']==1], 
        sequence_length, sequence_cols))
  1. 创建一个 LSTM 模型。我们在训练过程中使用r2作为评估指标,因此我们使用 Keras 的自定义指标功能和我们自己的指标函数:
def r2_keras(y_true, y_pred):
     """Coefficient of Determination 
     """
     SS_res = K.sum(K.square( y_true - y_pred ))
     SS_tot = K.sum(K.square( y_true - K.mean(y_true) ) )
     return ( 1 - SS_res/(SS_tot + K.epsilon()) )

# Next, we build a deep network. 
# The first layer is an LSTM layer with 100 units followed by 
# another LSTM layer with 50 units. 
# Dropout is also applied after each LSTM layer to control 
# overfitting. 
# Final layer is a Dense output layer with single unit and linear 
# activation since this is a regression problem.
nb_features = seq_array.shape[2]
nb_out = label_array.shape[1]

model = Sequential()
model.add(LSTM(
     input_shape=(sequence_length, nb_features),
     units=100,
     return_sequences=True))
model.add(Dropout(0.2))
model.add(LSTM(
     units=50,
     return_sequences=False))
model.add(Dropout(0.2))
model.add(Dense(units=nb_out))
model.add(Activation("linear"))
model.compile(loss='mean_squared_error', optimizer='rmsprop',metrics=['mae',r2_keras])

print(model.summary())

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/48c70894-7fbe-4469-be8a-77a44b46f56c.png

  1. 在训练数据集上训练模型,结果如下所示:
# fit the network
history = model.fit(seq_array, label_array, epochs=100, 
    batch_size=200, validation_split=0.05, verbose=2,
    callbacks = [keras.callbacks.EarlyStopping
    (monitor='val_loss', min_delta=0, patience=10, 
    verbose=0, mode='min'),
    keras.callbacks.ModelCheckpoint
    (model_path,monitor='val_loss', 
    save_best_only=True, mode='min', 
    verbose=0)])
  1. 训练后的模型在测试数据集上提供了r2值为 0.80,在验证数据集上为 0.72。我们可以通过超参数调优来改善我们的结果。接下来,您可以看到训练过程中训练和验证数据集的损失:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/6285b89e-5545-4260-9e20-e9297f4e6d08.png

要运行此代码,请确保您的 TensorFlow 版本为 1.4 及以上,Keras 版本为 2.1.2。如果您的 Keras 版本更高,请首先使用pip uninstall keras卸载它,然后使用pip install keras==2.1.2重新安装。

完整的代码,包括二分类和回归模型,已上传至 GitHub 仓库,Chapter10/Predictive_Maintenance_using_LSTM.ipynb。我们还可以创建一个模型,确定故障是否会在不同的时间窗口发生,例如,故障发生在窗口*(1,w[0])*或窗口(w[0+1], w[1])天内,依此类推。这将变成一个多分类问题,数据需要相应地进行预处理。你可以在 Azure AI Gallery 中阅读更多关于这个预测性维护模板的信息:gallery.azure.ai/Experiment/Predictive-Maintenance-Step-2A-of-3-train-and-evaluate-regression-models-2

预测性维护的优缺点

根据 GE 的一份调查报告(www.gemeasurement.com/sites/gemc.dev/files/ge_the_impact_of_digital_on_unplanned_downtime_0.pdf),停机时间会对石油和天然气行业的性能产生负面影响。这不仅仅是石油和天然气行业,所有行业都是如此。因此,为了减少停机时间,提高效率,采用预测性维护至关重要。然而,建立预测性维护系统的成本相当高,但一旦预测性维护系统建立得当,它有助于提供多个具有成本效益的好处,例如:

  • 最小化设备维护所需的时间

  • 最小化因维护而丧失的生产时间

  • 最后,备件成本也得到了最小化

成功的预测性维护可以在积极的方面重塑整个公司

工业中的电力负荷预测

电力目前是国内和工业领域最重要的能源载体。由于与燃料不同,电力难以存储且存储成本高,因此需要精确地将电力的生成与需求进行耦合。因此,电力负荷预测至关重要。根据时间范围(预测范围),电力负荷预测可分为以下三类:

  • 短期负荷预测:预测的时间范围为一小时到几周

  • 中期负荷预测:预测持续时间从几周到几个月不等

  • 长期负荷预测:在这里,预测从几个月到几年

根据需求和应用,可能需要规划其中一个或所有之前的负荷预测类别。近年来,短期负荷预测STLF)领域进行了大量的研究工作。STLF 能够通过提供准确的未来负荷预测手段来帮助工业界,从而有助于精确规划、降低运营成本,进而提高利润并提供更可靠的电力供应。STLF 基于历史数据(通过智能电表获取)和预测的天气条件,预测未来的能源需求。

负荷预测问题是一个回归问题。它可以作为时间序列问题或静态模型进行建模。将负荷预测建模为时间序列数据是最常见的选择。使用时间序列建模,我们可以使用标准的机器学习时间序列模型,如 ARIMA,或者我们可以利用深度学习模型,如循环神经网络和 LSTM。

有关电力负荷预测中使用的各种策略和模型的全面回顾,请参考这篇论文:

Fallah, S., Deo, R., Shojafar, M., Conti, M., and Shamshirband, S. (2018). 智能能源管理网格中的能源负荷预测的计算智能方法:现状、未来挑战和研究方向。Energies, 11(3), 596。

使用 LSTM 进行 STLF

在这里,我们展示了使用 LSTM 进行短期负荷预测的代码。用于训练和测试的数据来自 UCI ML 网站(archive.ics.uci.edu/ml/datasets/Individual+household+electric+power+consumption#)。STLF 的代码已从 GitHub 进行适配(github.com/demmojo/lstm-electric-load-forecast):

  1. 我们导入必要的模块并设置随机种子,代码如下所示:
import time
from keras.layers import LSTM
from keras.layers import Activation, Dense, Dropout
from keras.models import Sequential, load_model
from numpy.random import seed

from tensorflow import set_random_seed
set_random_seed(2) # seed random numbers for Tensorflow backend
seed(1234) # seed random numbers for Keras
import numpy as np
import csv
import matplotlib.pyplot as plt

%matplotlib inline
  1. 定义加载数据并将其转换为适合 LSTM 输入的序列的工具函数:
def load_data(dataset_path, sequence_length=60, prediction_steps=5, ratio_of_data=1.0):
    # 2075259 is the total number of measurements 
    # from Dec 2006 to Nov 2010
    max_values = ratio_of_data * 2075259

    # Load data from file
    with open(dataset_path) as file:
        data_file = csv.reader(file, delimiter=";")
        power_consumption = []
        number_of_values = 0
        for line in data_file:
            try:
                power_consumption.append(float(line[2]))
                number_of_values += 1
            except ValueError:
                pass

            # limit data to be considered by 
            # model according to max_values
            if number_of_values >= max_values: 
                break

    print('Loaded data from csv.')
    windowed_data = []
    # Format data into rolling window sequences
    # for e.g: index=0 => 123, index=1 => 234 etc.
    for index in range(len(power_consumption) - sequence_length): 
            windowed_data.append(
            power_consumption[
            index: index + sequence_length])

    # shape (number of samples, sequence length)
    windowed_data = np.array(windowed_data)

    # Center data
    data_mean = windowed_data.mean()
    windowed_data -= data_mean
    print('Center data so mean is zero 
            (subtract each data point by mean of value: ', 
            data_mean, ')')
    print('Data : ', windowed_data.shape)

    # Split data into training and testing sets
    train_set_ratio = 0.9
    row = int(round(train_set_ratio * windowed_data.shape[0]))
    train = windowed_data[:row, :]

    # remove last prediction_steps from train set
    x_train = train[:, :-prediction_steps] 
    # take last prediction_steps from train set
    y_train = train[:, -prediction_steps:] 
    x_test = windowed_data[row:, :-prediction_steps]

    # take last prediction_steps from test set
    y_test = windowed_data[row:, -prediction_steps:] 

    x_train = np.reshape(x_train, 
            (x_train.shape[0], x_train.shape[1], 1))
    x_test = np.reshape(x_test, 
            (x_test.shape[0], x_test.shape[1], 1))

    return [x_train, y_train, x_test, y_test, data_mean]
  1. 构建 LSTM 模型,我们所构建的模型包含两个 LSTM 层和一个全连接层:
def build_model(prediction_steps):
    model = Sequential()
    layers = [1, 75, 100, prediction_steps]
    model.add(LSTM(layers[1], 
        input_shape=(None, layers[0]), 
        return_sequences=True)) # add first layer
    model.add(Dropout(0.2)) # add dropout for first layer
    model.add(LSTM(layers[2], 
        return_sequences=False)) # add second layer
    model.add(Dropout(0.2)) # add dropout for second layer
    model.add(Dense(layers[3])) # add output layer
    model.add(Activation('linear')) # output layer 
    start = time.time()
    model.compile(loss="mse", optimizer="rmsprop")
    print('Compilation Time : ', time.time() - start)
    return model
  1. 训练模型,代码如下所示:
def run_lstm(model, sequence_length, prediction_steps):
    data = None
    global_start_time = time.time()
    epochs = 1
    ratio_of_data = 1 # ratio of data to use from 2+ million data points
    path_to_dataset = 'data/household_power_consumption.txt'

    if data is None:
        print('Loading data... ')
        x_train, y_train, x_test, y_test, result_mean = load_data(path_to_dataset, sequence_length,
                                                                  prediction_steps, ratio_of_data)
    else:
        x_train, y_train, x_test, y_test = data

    print('\nData Loaded. Compiling...\n')

    model.fit(x_train, y_train, batch_size=128, epochs=epochs, validation_split=0.05)
    predicted = model.predict(x_test)
    # predicted = np.reshape(predicted, (predicted.size,))
    model.save('LSTM_power_consumption_model.h5') # save LSTM model

    plot_predictions(result_mean, prediction_steps, predicted, y_test, global_start_time)

    return None

sequence_length = 10 # number of past minutes of data for model to consider
prediction_steps = 5 # number of future minutes of data for model to predict
model = build_model(prediction_steps)
run_lstm(model, sequence_length, prediction_steps)
  1. 从以下图表中,我们可以看到我们的模型做出了良好的预测:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/cb3ab15b-14e4-4a5b-9ed6-d6ff41d61856.png

完整的代码可以在 GitHub 上找到:Chapter10/Electrical_load_Forecasting.ipynb

总结

在这一章中,我们看到,AI 驱动的物联网对工业界产生了重大影响。从制造业、物流、农业、采矿到新产品和服务的创造,AI 触及了各个领域。我们可以合理假设,AI 驱动的工业物联网将改变并颠覆当前的商业流程和模式,带来更好的发展。

下一章将展示 AI 和物联网如何帮助塑造更好的城市。

第十一章:智能城市物联网(AI for Smart Cities IoT)

本章将向读者介绍智能城市。通过案例研究,将展示如何将本书中学到的概念应用于开发各种智能城市组件。在阅读本章时,您将学习以下内容:

  • 什么是智能城市?

  • 智能城市的基本组件

  • 全球各地的城市正在实施智能解决方案

  • 建设智能城市面临的挑战

  • 编写代码以从旧金山犯罪数据中检测犯罪描述

我们为什么需要智能城市?

根据联合国数据(population.un.org/wup/DataQuery/),到 2050 年底,世界人口将达到 97 亿(9.7 × 10⁹)。预计其中约 70%将是城市人口,许多城市的人口将超过 1000 万。这是一个巨大的数字,随着人口的增长,我们不仅迎来了新的机会,同时也面临许多独特的挑战:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/fb2f565d-ca0e-47c7-94db-211787c81fe8.png

预测的世界人口(数据来源:联合国)

最困难的挑战是如何让所有居民都能获得资源和能源,同时避免环境恶化。目前,城市消耗了全球 75%的资源和能源,并产生了 80%的温室气体;尽管绿色能源的趋势在增长,但我们都知道地球的资源,如食物和水,是有限的。另一个关键挑战是行政管理;随着人口的增加,需要采取策略来防止卫生问题、缓解交通拥堵和遏制犯罪。

许多这些问题可以通过使用 AI 支持的物联网来解决。利用技术进步可以为城市居民创造新的体验,并使他们的日常生活更加舒适和安全。这催生了智能城市的概念。

根据 techopedia(www.techopedia.com/definition/31494/smart-city)的定义,智能城市是利用信息和通信技术提升城市服务(如能源和交通)质量和性能的城市,从而减少资源消耗、浪费和整体成本。Deakin 和 AI Waer 列出了四个有助于定义智能城市的因素:

  • 在城市基础设施中使用广泛的电子和数字技术

  • 利用信息和通信技术ICT)来转变生活和工作环境

  • 将 ICT 嵌入政府系统

  • 实施将人们和信息通信技术(ICT)结合在一起的实践和政策,以促进创新并增强其提供的知识

因此,智能城市不仅拥有信息通信技术(ICT),而且还以一种积极影响居民的方式使用技术。

Deakin 和 AI Waer 的论文定义了智慧城市,并聚焦于所需的转型:

Deakin, M., 和 Al Waer, H.(2011)。从智能到智慧城市《智能建筑国际》, 3**(3), 140-152

人工智能AI)与物联网(IoT)共同具有应对城市人口过度增长所带来的关键挑战的潜力;它们可以帮助解决交通管理、医疗、能源危机等诸多问题。物联网数据和人工智能技术可以改善智慧城市中市民和企业的生活。

智慧城市的组成部分

智慧城市有许多 AI 驱动的物联网技术应用场景,从维护更健康的环境到提升公共交通和安全。在下面的图表中,您可以看到一些智慧城市的应用场景:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/c082b197-29a4-41e3-a1bd-cb96713a4773.png

智慧城市组成部分

本节将概述一些最受欢迎的应用场景——其中一些已经在全球各地的智慧城市中得到了实施。

智能交通管理

人工智能和物联网可以实施智能交通解决方案,确保智慧城市的居民能够尽可能安全、高效地从一个地点到达另一个地点。

洛杉矶,作为世界上最为拥堵的城市之一,已实施智能交通解决方案以控制交通流量。它已安装了路面传感器和闭路电视摄像头,将关于交通流量的实时更新发送到中央交通管理系统。来自传感器和摄像头的数据流被分析,并通知用户交通拥堵和信号灯故障的情况。2018 年 7 月,洛杉矶市在每个交叉口进一步安装了先进交通控制器ATC)机柜。通过启用车与基础设施通信V2I)和 5G 连接功能,这使得它们能够与具备交通信号灯信息功能的汽车(如 Audi A4 或 Q7)进行通信。您可以通过洛杉矶智慧交通系统的官方网站了解更多信息(dpw.lacounty.gov/TNL/ITS/)。

启动嵌入传感器的自动化车辆可以提供车辆的位置和速度;它们可以与智能交通信号灯直接通信,防止交通拥堵。此外,利用历史数据,可以预测未来的交通情况,并加以利用防止可能的拥堵。

智能停车

住在城市中的任何人都一定感受到过找停车位的困难,尤其是在假期期间。智能停车可以缓解这一难题。通过在停车位地面嵌入路面传感器,智能停车解决方案能够判断停车位是否空闲,并创建实时停车地图。

阿德莱德市在 2018 年 2 月安装了智能停车系统,并推出了一款移动应用程序:Park Adelaide,该应用将为用户提供准确的实时停车信息。该应用可以让用户定位、支付,甚至远程延长停车时长。它还会提供可用停车位的导航、停车管理信息,并在停车时段即将结束时发出提醒。阿德莱德市的智能停车系统旨在改善交通流量,减少交通拥堵,并减少碳排放。智能停车系统的详细信息可通过阿德莱德市官网查看(www.cityofadelaide.com.au/city-business/why-adelaide/adelaide-smart-city/smart-parking)。

旧金山交通管理局SAFTA)实施了 SFpark 智能停车系统(sfpark.org)。他们使用无线传感器实时检测计时停车位的占用情况。SFpark 于 2013 年推出,已将工作日的温室气体排放减少了 25%,交通量下降,驾驶员寻找停车位的时间减少了 50%。SAFTA 还报告称,通过简化停车缴费过程,损失因停车计时器损坏而减少,停车相关收入增加了约 190 万美元。

在伦敦,西敏市(iotuk.org.uk/smart-parking/#1463069773359-c0d6f90f-4dca)与 Machina Research(machinaresearch.com/login/?next=/forecasts/usecase/)合作,在 2014 年建立了智能停车系统。此前,驾驶员平均需要等待 12 分钟,导致了拥堵和污染,但自从安装了智能停车系统后,驾驶员无需等待,可以通过手机找到可用的停车位。这不仅减少了拥堵和污染,还提高了收入。

智能废物管理

垃圾收集及其妥善管理和处理是城市的重要服务。城市人口的增长要求采用更好的智能垃圾管理方法。一个智能城市应全面解决其垃圾管理问题。采用人工智能(AI)进行智能回收和垃圾管理可以提供可持续的垃圾管理系统。在 2011 年,芬兰公司 ZenRobotics(zenrobotics.com/)展示了如何利用计算机视觉和人工智能(机器人)来训练机器人,从传送带上分拣和挑选可回收材料。自那时以来,我们取得了长足的进展;许多公司提供智能垃圾管理解决方案,城市和建筑物也开始采纳这些方案。领导者和社区建设者对于智能城市基础设施部署的潜在好处有着日益增长的意识。

巴塞罗那的垃圾管理系统(ajuntament.barcelona.cat/ecologiaurbana/en/services/the-city-works/maintenance-of-public-areas/waste-management-and-cleaning-services/household-waste-collection)是一个很好的案例研究。他们在垃圾桶上安装了传感器和设备,这些设备可以向有关部门发送警报通知,一旦垃圾桶即将被填满,相关部门就会派遣垃圾收集车。他们在每个地区都保持有单独的垃圾桶,分别用于纸张、塑料、玻璃和食品垃圾。巴塞罗那的管理部门已经建立了一个由地下真空管道连接的容器网络,这些管道能够吸走垃圾并将其送到处理单元;这也消除了垃圾车收集垃圾的需求。

另一个好的案例研究是丹麦的垃圾管理(www.smartbin.com/tdc-denmark-cisco-showcase-the-future-of-smart-city-waste-collection/),由 SmartBin 提供。SmartBin 与丹麦最大的电信服务商 TDC 及思科(Cisco)合作,为一系列垃圾桶安装了传感器,这些传感器与城市数字平台集成。此外,路灯和交通信号灯也安装了传感器,这些传感器将数据发送到市政厅的控制台。这些传感器收集的实时数据帮助清洁服务更有效地规划垃圾收集路线;他们只需要去那些需要清空的地方。

在阿联酋沙迦安装了十个太阳能驱动的 Bigbelly 垃圾桶,并配备了 Wi-Fi 单元;他们计划在不久的将来部署数百个这样的智能垃圾桶,以实现可持续发展目标。

智能警务

不幸的是,犯罪是无处不在的。每个城市都有警察力量,致力于抓捕罪犯并降低犯罪率。智能城市同样需要警务:智能警务,指的是执法机构采用基于证据、数据驱动的策略,这些策略既有效、又高效、且经济。智能警务的概念大约于 2009 年出现,主要受限于预算约束。推动智能警务概念的根本思想来自赫尔曼·戈德斯坦(威斯康星大学,1979 年)。他认为,警察不应将犯罪事件视为孤立事件,而应将其视为具有历史和未来的公开问题系统。

在美国,司法援助局BJA)资助了许多智能警务倡议SPI),根据其研究结果,这些倡议显著减少了暴力犯罪。SPI 侧重于警察与研究合作伙伴的合作,研究合作伙伴负责持续的数据收集和分析,监控数据,参与解决方案的开发,并评估其影响。这些倡议帮助警察识别出以下内容:

  • 犯罪热点

  • 常犯罪犯

新加坡也已启动了其智能国家计划。几乎在城市的每个角落都安装了摄像头和传感器。通过这些设备获取的视频流,能够识别出哪些地方有人在禁烟区吸烟,或者从高楼上闲逛。摄像头使当局能够监控人群密度、公共场所的清洁情况,甚至追踪所有登记车辆的确切位置。这些摄像头的影像流被输入到一个名为虚拟新加坡的在线平台,该平台提供有关城市实时运作的信息。

智能照明

街灯是必要的,但它们消耗大量能源。智能照明系统可以帮助提高街灯的能效。除此之外,灯柱还可以配备额外的传感器,或作为 Wi-Fi 网络热点。

一个可以帮助在任何城市安装智能照明的发明是 CitySense (www.tvilight.com/citysense/),这是一款屡获殊荣的街道灯运动传感器,具有集成的无线照明控制功能。CitySense 为恶劣的外部环境设计,提供按需自适应照明。灯具可以根据行人、自行车或汽车的存在调整亮度。它通过实时网状网络触发邻近灯光,并在人体周围创建一个安全的光圈。它还配备智能过滤器,能够过滤掉由小动物或树木移动引起的干扰。该系统可以自动检测任何灯具故障,并触发维护请求。荷兰的梵高村已将 CitySense 应用于其智能街道照明系统。

值得一提的是巴塞罗那的照明大师计划,它报告了街道照明功耗的显著降低。大约在 2014 年,城市的大多数灯柱都安装了 LED 灯,并且在灯柱中安装了物联网驱动的传感器。传感器会在街道空旷时自动调暗灯光,这有助于降低能源消耗。此外,这些灯柱还充当 Wi-Fi 网络热点,并配备了监测空气质量的传感器。

智能治理

智能城市的主要目的是为其居民创造一个舒适便捷的生活。因此,智能城市基础设施在没有智能治理的情况下是不完整的。智能治理意味着利用信息和通信技术,通过不同利益相关者(包括政府和公民)之间更好的合作来提高决策质量。智能治理可以被视为智能、开放和参与性政府的基础。这需要重新塑造政府、公民和其他社会行为者的角色,并探索新技术来构建新的治理模式,包括新的关系、新的流程和新的政府结构。智能治理能够利用数据、证据和其他资源来改进决策,并能够交付满足公民需求的成果。这将提升决策过程并提高公共服务的质量。

使物联网适应智能城市及其必要步骤

建设智能城市不是一项一日之功,也不是某个人或某个组织的工作。这需要许多战略合作伙伴、领导者,甚至是公民的共同协作。这种协作的动态超出了本书的范围,但由于本书面向人工智能爱好者和工程师,我们来探讨一下人工智能社区能做些什么,哪些领域为我们提供了职业或创业的机会。任何物联网平台都必然需要以下内容:

  • 用于收集数据的智能设备网络(传感器、摄像头、执行器等)

  • 可以从低功耗物联网设备收集数据、存储数据并将其安全地转发到云端的现场(云)网关

  • 用于汇聚多个数据流并将其分发到数据湖和控制应用程序的流数据处理器

  • 存储所有原始数据的数据湖,甚至包括那些当前看似无价值的数据

  • 一个可以清理和结构化收集到的数据的数据仓库

  • 用于分析和可视化传感器收集数据的工具

  • 用于基于长期数据分析自动化城市服务的 AI 算法和技术,并寻找提高控制应用程序性能的方法

  • 用于向物联网执行器发送命令的控制应用程序

  • 用于连接智能设备和公民的用户应用程序

除此之外,还会有关于安全性和隐私的问题,服务提供商必须确保这些智能服务不会对市民的福祉构成威胁。服务本身应该易于使用和操作,以便市民能够采纳它们。

如你所见,这为 AI 工程师提供了很多就业机会。物联网生成的数据需要被处理,要真正从中受益,我们需要超越监控和基础分析。AI 工具将被用来识别传感器数据中的模式和隐藏的关联。利用机器学习/人工智能工具分析历史传感器数据可以帮助识别趋势,并基于这些趋势创建预测模型。然后,这些模型可以被控制应用使用,向物联网设备的执行器发送命令。

建设智能城市的过程将是一个迭代的过程,每次迭代都会增加更多的处理和分析。以智能交通信号灯为例,让我们看看如何逐步改进它。

与传统交通信号灯相比,我们的智能交通信号灯会根据交通流量调整信号时间。我们可以使用历史交通数据来训练模型,以揭示交通模式并调整信号时间,从而最大化平均车速,避免拥堵。这种独立的智能交通信号灯很好,但还不够。如果一个地区发生了拥堵,那如果路上的驾驶员可以被告知避免这条路线,那就太好了。为了实现这一点,我们可以增加一个额外的处理系统;它通过交通信号灯的传感器数据识别拥堵,并使用车辆或驾驶员智能手机的 GPS,告知靠近拥堵区域的驾驶员避开该路线。

下一步,交通信号灯可以增加更多传感器,比如可以监测空气质量的传感器,然后训练模型以确保在达到临界空气质量之前生成警报。

开放数据的城市

在过去的十年里,世界各地的许多城市都建立了开放数据门户。这些开放数据门户不仅帮助市民保持信息通畅,对于 AI 开发者来说也是一大福音,因为数据是驱动 AI 的动力。我们来看看一些有趣的数据门户及其提供的数据。

这篇文章在《福布斯》上列出了 90 个拥有开放数据的美国城市: https://www.forbes.com/sites/metabrown/2018/04/29/city-governments-making-public-data-easier-to-get-90-municipal-open-data-portals/#4542e6f95a0d

亚特兰大市 大亚特兰大快速交通局数据

亚特兰大都市快速交通局 (MARTA) 发布了实时公共交通数据,旨在为开发者提供机会,开发定制的 web 和移动应用程序。MARTA 平台为开发者提供了资源,供他们访问数据并利用这些数据开发应用程序 (www.itsmarta.com/app-developer-resources.aspx)。

通用交通数据格式 (GTFS) 用于提供数据。GTFS 是一个用于公共交通时刻表和地理信息的标准格式。它由一系列文本文件组成,每个文件描述了交通信息的特定方面:停靠点、路线、行程及类似的计划数据。

MARTA 还通过 RESTful API 提供数据。要访问 API,你需要安装 MARTA-Python,这是一个用于访问 MARTA 实时 API 的 Python 库。可以使用 pip 安装该 Python 库:

pip install tox

在使用 API 之前,你需要注册并申请 API 密钥 (www.itsmarta.com/developer-reg-rtt.aspx)。API 密钥将存储在 MARTA_API_KEY 环境变量中。要设置 MARTA_API_KEY,你可以使用以下命令:

在 Windows 上,使用以下命令:

set MARTA_API_KEY=<your_api_key_here>

在 Linux/MAC 上,使用以下命令:

export MARTA_API_KEY=<your_api_key_here>

它提供了两个主要的封装函数 get_buses()get_trains(),这两个函数都接受关键字参数来过滤结果:

from marta.api import get_buses, get_trains

# To obtain list of all buses
all_buses = get_buses()

# To obtain a list of buses by route
buses_route = get_buses(route=1)

# To obtain list of all trains
trains = get_trains()

# To obtain list of trains specified by line
trains_red = get_trains(line='red')

# To obtain list of trains by station
trains_station = get_trains(station='Midtown Station')

# To obtain list of trains by destination
trains_doraville = get_trains(station='Doraville')

# To obtain list of trains by line, station, and destination
trains_all = get_trains(line='blue', 
            station='Five Points Station', 
            destination='Indian Creek')

get_buses()get_trains() 函数分别返回 BusTrain 字典对象。

芝加哥 “Things Array” 数据

Things Array (AoT) 项目于 2016 年启动,项目内容包括在灯杆上安装一个传感器盒网络。传感器收集有关环境和城市活动的实时数据。生成的数据可以通过批量下载以及 API 提供给开发者和爱好者。

传感器部署在多个地理区域,每个部署区域被称为 项目,其中最大部署位于芝加哥,属于名为芝加哥的项目。

部署的物理设备被称为 节点,每个节点通过其独特的序列号 VSN 进行标识。这些节点通过网络连接在一起。节点中包含 传感器,这些传感器观察环境的各个方面,如温度、湿度、光强度和颗粒物。传感器记录的信息称为 观测数据

这些观测数据存在冗余,并可以通过 API 获取原始形式的数据。节点和观测、传感器和观测之间存在一对多的关系。项目、节点和传感器之间也存在多对多的关系。有关 AoT 项目的完整数据和详细信息,可以从芝加哥市开放数据门户访问:data.cityofchicago.org/

使用旧金山犯罪数据检测犯罪

旧金山市也有一个开放数据门户(datasf.org/opendata/),提供来自不同部门的在线数据。在本节中,我们使用提供大约 12 年(从 2003 年 1 月到 2015 年 5 月)的犯罪报告数据集,数据涵盖了旧金山市所有社区,并训练一个模型来预测发生的犯罪类别。共有 39 个离散的犯罪类别,因此这是一个多类别分类问题。

我们将使用 Apache 的 PySpark,并利用其易于使用的文本处理功能来处理这个数据集。所以第一步是创建一个 Spark 会话:

  1. 第一步是导入必要的模块并创建 Spark 会话:
from pyspark.ml.classification import LogisticRegression as LR
from pyspark.ml.feature import RegexTokenizer as RT
from pyspark.ml.feature import StopWordsRemover as SWR
from pyspark.ml.feature import CountVectorizer
from pyspark.ml.feature import OneHotEncoder, StringIndexer, VectorAssembler
from pyspark.ml import Pipeline
from pyspark.sql.functions import col
from pyspark.sql import SparkSession

spark = SparkSession.builder \
        .appName("Crime Category Prediction") \
        .config("spark.executor.memory", "70g") \
        .config("spark.driver.memory", "50g") \
        .config("spark.memory.offHeap.enabled",True) \
        .config("spark.memory.offHeap.size","16g") \
        .getOrCreate()
  1. 我们加载存储在 csv 文件中的数据集:
data = spark.read.format("csv"). \
        options(header="true", inferschema="true"). \
        load("sf_crime_dataset.csv")

data.columns

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/6c1c284b-45df-4548-b81f-20a7bc721b63.png

  1. 数据包含九个列:[Dates, Category, Descript, DayOfWeek, PdDistrict, Resolution, Address, X, Y],我们只需要 CategoryDescript 字段来构建训练集和测试集:
drop_data = ['Dates', 'DayOfWeek', 'PdDistrict', 'Resolution', 'Address', 'X', 'Y']
data = data.select([column for column in data.columns if column not in drop_data])

data.show(5)

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/c152b827-eb82-4da6-8034-543376bfc6ba.png

  1. 现在我们拥有的数据集包含文本数据,因此我们需要进行文本处理。三个重要的文本处理步骤是:对数据进行分词、去除停用词以及将词向量化。我们将使用 RegexTokenizer,它使用正则表达式将句子分词成一个单词列表,由于标点符号或特殊字符不会对含义产生任何影响,我们只保留包含字母数字内容的单词。像 the 这样的词在文本中非常常见,但对上下文没有任何意义。我们可以使用内置的 StopWordsRemover 类去除这些词(也叫做 停用词)。我们使用标准的停用词 ["http","https","amp","rt","t","c","the"]。最后,通过使用 CountVectorizer,我们将单词转换为数字向量(特征)。正是这些数字特征将作为输入来训练模型。我们的数据输出是 Category 列,但它也是文本的,并且有 36 个不同的类别,因此我们需要将其转换为独热编码向量;PySpark 的 StringIndexer 可以轻松完成这个转换。我们将所有这些转换步骤添加到数据 Pipeline 中:
# regular expression tokenizer
re_Tokenizer = RT(inputCol="Descript", 
            outputCol="words", pattern="\\W")    

# stop words
stop_words = ["http","https","amp","rt","t","c","the"] 
stop_words_remover = SWR(inputCol="words", 
            outputCol="filtered").setStopWords(stop_words)

# bag of words count
count_vectors = CountVectorizer(inputCol="filtered",
         outputCol="features", vocabSize=10000, minDF=5)

#One hot encoding the label
label_string_Idx = StringIndexer(inputCol = "Category", 
                outputCol = "label")

# Create the pipeline
pipeline = Pipeline(stages=[re_Tokenizer, stop_words_remover,
             count_vectors, label_string_Idx])

# Fit the pipeline to data.
pipeline_fit = pipeline.fit(data)
dataset = pipeline_fit.transform(data)

dataset.show(5)

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/d9823162-cb34-401b-acf6-176b75e524ad.png

  1. 现在,数据已经准备好,我们将其分成训练集和测试集:
# Split the data randomly into training and test data sets.
(trainingData, testData) = dataset.randomSplit([0.7, 0.3], seed = 100)
print("Training Dataset Size: " + str(trainingData.count()))
print("Test Dataset Size: " + str(testData.count()))
  1. 让我们为此拟合一个简单的逻辑回归模型。在测试数据集上,它提供了 97% 的准确率。耶!
# Build the model
logistic_regrssor = LR(maxIter=20, 
                regParam=0.3, elasticNetParam=0)
# Train model with Training Data
model = logistic_regrssor.fit(trainingData)

# Make predictions on Test Data
predictions = model.transform(testData)

# evaluate the model on test data set
evaluator = MulticlassClassificationEvaluator(predictionCol="prediction")
evaluator.evaluate(predictions)

完整的代码可在 GitHub 仓库 Chapter11/SF_crime_category_detection.ipynb Jupyter Notebook 中找到。

挑战与好处

人工智能正在改变城市的运作、交付和维护公共设施的方式,从照明、交通到连接性和健康服务。然而,采用技术时,如果技术之间无法高效协同工作或与其他城市服务无法整合,可能会成为阻碍因素。因此,考虑到改造性解决方案非常重要。

另一个需要关注的重要事项是合作。为了让城市真正从智能城市的潜力中受益,必须改变思维方式。各级政府应进行长期规划,并跨多个部门协作。所有人——包括技术专家、地方政府、企业、环保人士以及公众——都必须携手合作,才能让城市成功转型为智能城市。

尽管预算可能是一个大问题,但世界各地多个城市成功实施智能城市组件的成果表明,通过正确的实施,智能城市更加经济。智能城市的转型不仅创造了就业机会,还能帮助保护环境、减少能源支出并创造更多收入。巴塞罗那市就是一个典型的例子;通过实施物联网系统,预计创造了 47,000 个就业岗位,节省了 4,250 万欧元的水费,并通过智能停车每年额外创收 3,650 万欧元。我们可以清楚地看到,城市可以从利用人工智能驱动的物联网解决方案的技术进步中受益良多。

概要

基于人工智能的物联网解决方案可以帮助连接城市并管理多个基础设施和公共服务。本章介绍了智能城市的多种应用场景,从智能照明和道路交通到互联公共交通和废物管理。从成功的案例研究中,我们还了解到,智能城市可以减少能源成本、优化自然资源的使用、提高城市安全性,并创造更健康的环境。本章列出了一些开放的城市数据门户及其提供的信息。我们使用本书中学到的工具,对 12 年间旧金山的犯罪报告数据进行分类。最后,本章讨论了建设智能城市的一些挑战与好处。

第十二章:综合所有内容

现在,我们已经理解并实现了不同的人工智能AI)/机器学习ML)算法,是时候将它们结合起来,了解每种算法最适合哪种类型的数据,并同时理解每种数据类型所需的基本预处理。在本章结束时,你将了解以下内容:

  • 可以输入模型的不同类型数据

  • 如何处理时间序列数据

  • 文本数据的预处理

  • 可以对图像数据进行的不同转换

  • 如何处理视频文件

  • 如何处理语音数据

  • 云计算选项

处理不同类型的数据

数据有各种各样的形式、大小和类型:推文、每日股价、每分钟的心跳信号、相机拍摄的照片、通过 CCTV 获取的视频、音频录音等。每种数据都包含信息,当这些数据经过正确的处理并与合适的模型结合使用时,我们可以分析这些数据,并获得关于潜在模式的高级信息。在本节中,我们将介绍每种数据类型在输入模型之前所需的基本预处理,以及可以使用的模型。

时间序列建模

时间是许多有趣的人类行为的基础,因此,AI 驱动的物联网系统必须知道如何处理时间相关的数据。时间可以显式地表示,例如,通过定期捕获数据,其中时间戳也是数据的一部分,或者隐式地表示,例如,在语音或书面文本中。能够捕捉时间相关数据中固有模式的方法称为时间序列建模

在定期间隔捕获的数据是时间序列数据,例如,股价数据就是时间序列数据。让我们来看一下苹果股票价格数据;这些数据可以从 NASDAQ 网站下载(www.nasdaq.com/symbol/aapl/historical)。或者,你可以使用pandas_datareader模块直接下载数据,通过指定数据源来实现。要在你的工作环境中安装pandas_datareader,可以使用以下命令:

pip install pandas_datareader
  1. 以下代码从 2010 年 1 月 1 日到 2015 年 12 月 31 日,从 Yahoo Finance 下载苹果公司股票价格:
import datetime
from pandas_datareader import DataReader
%matplotlib inline

Apple = DataReader("AAPL", "yahoo", 
        start=datetime.datetime(2010, 1, 1), 
        end=datetime.datetime(2015,12,31)) 
Apple.head()
  1. 下载的 DataFrame 提供了每个工作日的HighLowOpenCloseVolumeAdj Close值:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/1fb0ab65-15be-41bb-b84b-0aca162443a4.png

  1. 现在我们来绘制图表,如下所示:
close = Apple['Adj Close']
plt.figure(figsize= (10,10))
close.plot()
plt.ylabel("Apple stocj close price")
plt.show()

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/fa7e0db3-3e92-49f9-a9ef-bf5e5a396a44.png

要能够建模时间序列数据,我们需要识别几个要素:趋势、季节性和稳定性。

  1. 趋势是指找出在平均情况下,测量值是否随着时间的推移而减少(或增加)。找到趋势最常见的方法是绘制移动平均,如下所示:
moving_average = close.rolling(window=20).mean()

plt.figure(figsize= (10,10))
close.plot(label='Adj Close')
moving_average.plot(label='Moving Average Window 20')
plt.legend(loc='best')
plt.show()

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/860eb6d8-e51e-418e-a446-c6d9a88a5876.png

  1. 我们可以看到,使用窗口为 20,上升和下降趋势。 对于时间序列建模,我们应该去趋势化数据。 去趋势化可以通过从原始信号中减去趋势(移动平均值)来完成。 另一种流行的方法是使用一阶差分方法,即取相邻数据点之间的差异:
fod = close.diff()
plt.figure(figsize= (10,10))
fod.plot(label='First order difference')
fod.rolling(window=40).mean().\
        plot(label='Rolling Average')
plt.legend(loc='best')
plt.show()

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/5730da71-8b00-4cf1-8b44-a59920e3cab6.png

  1. 季节性是与时间相关的高低规律重复出现的模式(例如,正弦系列)。 最简单的方法是在数据中找到自相关。 找到季节性后,您可以通过将数据差分到与季节长度相对应的时间滞来移除它:
# Autocorrelation
plt.figure(figsize= (10,10))
fod.plot(label='First order difference')
fod.rolling(window=40).mean().\
        plot(label='Rolling Average')
fod.rolling(window=40).corr(fod.shift(5)).\
        plot(label='Auto correlation')
plt.legend(loc='best')
plt.show()

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/d024cf46-d51b-45f2-a1d4-307cf981e712.png

  1. 最后一件事是确保系列是否平稳,即系列的均值不再是时间的函数。 数据的平稳性对于时间序列建模至关重要。 我们通过消除数据中存在的任何趋势或季节性来实现平稳性。 一旦数据平稳,我们可以使用回归模型对其进行建模。

传统上,时间序列数据是使用自回归和移动平均模型(如 ARMA 和 ARIMA)进行建模的。 要了解更多关于时间序列建模的信息,感兴趣的读者可以参考这些书籍:

  • Pandit, S. M., and Wu, S. M. (1983). 带应用的时间序列与系统分析(Vol. 3). 纽约:约翰·威利。

  • Brockwell, P. J., Davis, R. A., and Calder, M. V. (2002). 时间序列和预测简介(Vol. 2). 纽约:斯普林格出版社。

对于任何时间序列数据,平稳性都是一个重要的特性,无论您是使用传统的时间序列建模还是深度学习模型。 这是因为,如果一个系列具有平稳性(即使是弱平稳性),那么它意味着数据在时间上具有相同的分布,因此可以在时间上进行估计。 如果您计划使用诸如 RNN 或 LSTM 之类的深度学习模型,则在确认时间序列的平稳性后,此外,您需要对数据进行归一化,并使用滑动窗口转换将系列转换为输入-输出对,以便进行回归。 使用 scikit-learn 库和 NumPy 可以非常容易地完成这一操作:

  1. 让我们对close DataFrame 进行归一化。 归一化确保数据位于01之间。 请注意,以下图与前述步骤 3close DataFrame 的图表相同,但y轴比例现在不同:
# Normalization
from sklearn.preprocessing import MinMaxScaler
def normalize(data):
    x = data.values.reshape(-1,1)
    pre_process = MinMaxScaler()
    x_normalized = pre_process.fit_transform(x)
    return x_normalized

x_norm = normalize(close)

plt.figure(figsize= (10,10))
pd.DataFrame(x_norm, index = close.index).plot(label="Normalized Stock prices")
plt.legend(loc='best')
plt.show()

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/ea95f634-5716-4007-9e07-689e5f4b1095.png

  1. 我们定义了一个window_transform()函数,它将数据系列转换为一系列输入-输出对。 例如,您想构建一个 RNN,该 RNN 将前五个值作为输出,并预测第六个值。 然后,您选择window_size = 5
# Create window from the normalized data
def window_transform(series, window_size):
    X = []
    y = []

    # Generate a sequence input/output pairs from series
    # x= <s1,s2,s3,s4,s5,... s_n> y = s_n+1 and so on
    for i in range(len(series) - window_size):
    X.append(series[i:i+window_size])
    y.append(series[i+window_size])

    # reshape each 
    X = np.asarray(X)
    X.shape = (np.shape(X)[0:2])
    y = np.asarray(y)
    y.shape = (len(y),1)

    return X,y

window_size = 7
X,y = window_transform(x_norm,window_size = window_size)

请参阅 GitHub 存储库,Chapter-12/time_series_data_preprocessing.ipynb,查看本节的完整代码。

预处理文本数据

语言在我们日常生活中扮演着非常重要的角色。对我们来说,阅读书面文本是非常自然的,但计算机呢?它们能读取文本吗?我们能让深度学习模型根据旧的模式生成新的文本吗?例如,如果我说,“昨天,我在星巴克喝了 ____”,我们大多数人都能猜出空白处是“咖啡”,但是我们的深度学习模型能做到吗?答案是肯定的;我们可以训练我们的深度学习模型来猜测下一个词(或字符)。然而,深度学习模型运行在计算机上,而计算机只理解二进制,只有 0 和 1。因此,我们需要一种方法来处理文本数据,以便将其转换为计算机易于处理的形式。此外,尽管“cat”、“CAT”和“Cat”有不同的 ASCII 表示,但它们表示的意思相同;这对我们来说很容易理解,但要让模型将它们视为相同,我们需要对文本数据进行预处理。本节将列出文本数据的必要预处理步骤,您将学习如何在 Python 中实现:

  1. 在这一节中,我们将考虑来自我最喜欢的科幻小说《基地》的小段文本,作者是艾萨克·阿西莫夫。该文本位于foundation.txt文件中。第一步是,读取文本:
f = open('foundation.txt')
text = f.read()
print(text)
  1. 文本处理的下一步是清洗数据。我们保留文本中相关的部分。在大多数情况下,标点符号不会为文本增加额外的含义,因此我们可以放心地将其去除:
# clean data
import re
# remove Punctuation
text = re.sub(r"[^a-zA-Z0-9]", " ", text) 
print(text)
  1. 清洗数据后,我们需要对文本进行规范化处理。在文本处理过程中,规范化文本意味着将所有文本转换为相同的大小写,通常是小写。为了遵循惯例,我们将文本转换为小写:
# Normalize text
# Convert to lowercase
text = text.lower() 
print(text)
  1. 一旦文本被规范化,下一步是对文本进行分词。我们可以将文本分割为单词令牌或句子令牌。为了做到这一点,您可以使用split函数,或者使用功能强大的 NLTK 模块。如果您的系统中没有安装 NLTK,可以通过pip install nltk进行安装。在接下来的例子中,我们使用 NLTK 的单词分词器来完成这项任务:
import os
import nltk
nltk.download('punkt') 
from nltk.tokenize import word_tokenize

# Split text into words using NLTK
words_nltk = word_tokenize(text)
print(words_nltk)
  1. 根据您拥有的文本类型和所做的工作,您可能需要去除停用词。停用词是出现在大多数文本样本中的词,因此不会为文本的上下文或意义增加任何信息。例如,the、a 和 an。您可以声明自己的停用词,也可以使用 NLTK 提供的停用词。在这里,我们从文本中移除english语言的stopwords
from nltk.corpus import stopwords
nltk.download('stopwords')
#Remove stop words
words = [w for w in words \
        if w not in stopwords.words("english")]

  1. 另一个可以在文本数据上进行的操作是词干提取和词形还原。这些操作用于将单词转换为规范形式:
from nltk.stem.porter import PorterStemmer

# Reduce words to their stems
stemmed = [PorterStemmer().stem(w) for w in words]
print(stemmed)

from nltk.stem.wordnet import WordNetLemmatizer

# Reduce words to their root form
lemmed = [WordNetLemmatizer().lemmatize(w) for w in words]
print(lemmed)

您可以通过 GitHub 访问包含此代码的笔记本:Chapter12/text_processing.ipynb

图像数据增强

Python 有 OpenCV,它为图像提供了非常好的支持。OpenCV 可以从 Conda 通道和 PyPi 下载安装。一旦使用 OpenCV 的imread()函数读取图像,图像就表示为一个数组。如果图像是彩色的,则通道以 BGR 顺序存储。数组中的每个元素表示相应像素值的强度(这些值的范围在 0 到 255 之间)。

假设你已经训练了一个模型来识别一个球:你给它展示一个网球,它能识别为球。接下来我们展示的这张球的图像是在缩放之后拍摄的:我们的模型还能识别它吗?一个模型的效果取决于它所训练的数据集,因此,如果模型在训练时看到了缩放后的图像,它将很容易识别出缩放后的球是一个球。一种确保数据集中有这些图像的方法是隐式地包含这些变化图像,然而,由于图像是作为数组表示的,我们可以进行数学变换来重新缩放、翻转、旋转,甚至改变强度。在现有训练图像上执行这些变换以生成新图像的过程叫做数据增强。使用数据增强的另一个好处是,您可以增加训练数据集的大小(当与数据生成器一起使用时,我们可以获得无限的图像)。

大多数深度学习库都提供了标准的 API 来进行数据增强。在 Keras(keras.io/preprocessing/image/)中,有ImageDataGenerator,在 TensorFlow-TfLearn 中,我们有ImageAugmentation。TensorFlow 也有操作符来执行图像转换和变换(www.tensorflow.org/api_guides/python/image)。在这里,我们将看看如何使用 OpenCV 强大的库进行数据增强,并创建我们自己的数据生成器:

  1. 我们导入了必要的模块:OpenCV 用于读取和处理图像,numpy用于矩阵操作,Matplotlib 用于可视化图像,shuffle来自 scikit-learn 用于随机打乱数据,以及 Glob 用于查找目录中的文件:
import cv2 # for image reading and processsing
import numpy as np
from glob import glob
import matplotlib.pyplot as plt
from sklearn.utils import shuffle
%matplotlib inline
  1. 我们读取了必要的文件。对于这个示例,我们从 Google 图像搜索中下载了一些前美国总统巴拉克·奥巴马的图像:
img_files = np.array(glob("Obama/*"))
  1. 我们创建了一个函数,可以在图像中随机引入以下任意变形:在 0 到 50 度范围内随机旋转,随机改变图像强度,随机将图像水平和垂直平移最多 50 个像素,或者随机翻转图像:
def distort_image(img, rot = 50, shift_px = 40):
    """
    Function to introduce random distortion: brightness, flip,
    rotation, and shift 
    """
    rows, cols,_ = img.shape
    choice = np.random.randint(5)
    #print(choice)
    if choice == 0: # Randomly rotate 0-50 degreee
        rot *= np.random.random() 
        M = cv2.getRotationMatrix2D((cols/2,rows/2), rot, 1)
        dst = cv2.warpAffine(img,M,(cols,rows))
    elif choice == 1: # Randomly change the intensity
        hsv = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
        ratio = 1.0 + 0.4 * (np.random.rand() - 0.5)
        hsv[:, :, 2] = hsv[:, :, 2] * ratio
        dst = cv2.cvtColor(hsv, cv2.COLOR_HSV2RGB)
    elif choice == 2: # Randomly shift the image in horizontal and vertical direction
        x_shift,y_shift = np.random.randint(-shift_px,shift_px,2)
        M = np.float32([[1,0,x_shift],[0,1,y_shift]])
        dst = cv2.warpAffine(img,M,(cols,rows))
    elif choice == 3: # Randomly flip the image
        dst = np.fliplr(img)
    else:
        dst = img

    return dst
  1. 在下图中,您可以看到前述函数在我们数据集中随机选择的图像上的结果:

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/e35d972d-8a55-4be5-88d9-647b3aaee380.png

  1. 最后,您可以使用 Python 的yield创建数据生成器,生成您需要的任意数量的图像:
# data generator
def data_generator(samples, batch_size=32, validation_flag = False):
    """
    Function to generate data after, it reads the image files, 
    performs random distortions and finally 
    returns a batch of training or validation data
    """
    num_samples = len(samples)
    while True: # Loop forever so the generator never terminates
 shuffle(samples)
        for offset in range(0, num_samples, batch_size):
            batch_samples = samples[offset:offset+batch_size]
            images = []

            for batch_sample in batch_samples:
                if validation_flag: # The validation data consists only of center image and without distortions
                    image = cv2.imread(batch_sample)
                    images.append(image)
                    continue
                else: # In training dataset we introduce distortions to augment it and improve performance
                    image = cv2.imread(batch_sample)
                    # Randomly augment the training dataset to reduce overfitting
                    image = distort_image(image)
                    images.append(image)

        # Convert the data into numpy arrays
        X_train = np.array(images)

        yield X_train 

train_generator = data_generator(img_files,  batch_size=32)

Chapter12/data_augmentation.ipynb文件包含了这一部分的代码。

处理视频文件

视频本质上是静态图像(帧)的集合,因此,如果我们能够从视频中提取图像,就可以将我们信任的 CNN 网络应用到这些图像上。唯一需要做的就是将视频转换为帧列表:

  1. 我们首先导入必要的模块。我们需要 OpenCV 来读取视频并将其转换为帧。我们还需要math模块进行基本的数学运算,以及 Matplotlib 来可视化这些帧:
import cv2 # for capturing videos
import math # for mathematical operations
import matplotlib.pyplot as plt # for plotting the images
%matplotlib inline
  1. 我们使用 OpenCV 函数读取视频文件,并通过属性标识符5来获取视频的帧率(docs.opencv.org/2.4/modules/highgui/doc/reading_and_writing_images_and_video.html#videocapture-get):
videoFile = "video.avi" # Video file with complete path
cap = cv2.VideoCapture(videoFile) # capturing the video from the given path
frameRate = cap.get(5) #frame rate
  1. 我们通过read()函数逐帧读取视频中的所有帧。虽然我们每次只读取一帧,但我们只保存每秒的第一帧。这样,我们可以覆盖整个视频,同时减少数据大小:
count = 0
while(cap.isOpened()):
    frameId = cap.get(1) #current frame number
    ret, frame = cap.read()
    if (ret != True):
        break
    if (frameId % math.floor(frameRate) == 0):
        filename ="frame%d.jpg" % count
        count += 1
        cv2.imwrite(filename, frame)

cap.release()
print ("Finished!")
  1. 让我们来可视化一下我们保存的第五帧:
img = plt.imread('frame5.jpg') # reading image using its name
plt.imshow(img)

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/7aa195c7-3649-451f-ad8c-5a1145c049e1.png

本代码所用的视频文件来自 Ivan Laptev 和 Barbara Caputo 维护的网站(www.nada.kth.se/cvap/actions/)。代码可以在 GitHub 上找到:Chapter12/Video_to_frames.ipynb

使用 CNN 进行视频分类的最佳论文之一是 Andrej Karpathy 等人撰写的大规模视频分类与卷积神经网络。你可以在这里访问:www.cv-foundation.org/openaccess/content_cvpr_2014/html/Karpathy_Large-scale_Video_Classification_2014_CVPR_paper.html

音频文件作为输入数据

另一个有趣的数据类型是音频文件。将语音转换为文本或分类音频声音的模型以音频文件作为输入。如果你想处理音频文件,那么你需要使用librosa模块。处理音频文件的方法有很多;我们可以将其转换为时间序列并使用循环神经网络。另一种取得良好结果的方法是将其作为一维或二维图案,并训练 CNN 进行分类。一些采用这种方法的优秀论文如下:

  • Hershey, S., Chaudhuri, S., Ellis, D. P., Gemmeke, J. F., Jansen, A., Moore, R. C., 和 Slaney, M. (2017 年 3 月). 用于大规模音频分类的 CNN 架构. 在声学、语音和信号处理(ICASSP)2017 年 IEEE 国际会议(第 131-135 页)。IEEE.

  • Palaz, D., Magimai-Doss, M., 和 Collobert, R. (2015). 基于 CNN 的语音识别系统分析,使用原始语音作为输入。在第十六届国际语音通信协会年会上。

  • Zhang, H., McLoughlin, I., and Song, Y. (2015, April). 使用卷积神经网络进行稳健的声音事件识别。在《声学、语音与信号处理》(ICASSP),2015 年 IEEE 国际会议中(第 559-563 页)。IEEE。

  • Costa, Y. M., Oliveira, L. S., and Silla Jr, C. N. (2017). 使用声谱图对卷积神经网络进行音乐分类的评估。应用软计算,52,28–38。

我们将使用librosa模块读取音频文件,并将其转换为一维声音波形和二维声谱图。你可以通过以下方式在你的 Anaconda 环境中安装librosa

pip install librosa
  1. 在这里,我们将导入numpymatplotliblibrosa。我们将从librosa数据集中获取示例音频文件:
import librosa
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# Get the file path to the included audio example
filename = librosa.util.example_audio_file()
  1. librosa的加载函数返回音频数据,表示为一维 NumPy 浮点数组的时间序列。我们可以将它们用作时间序列,甚至用作 CNN 的一维模式:
input_length=16000*4
def audio_norm(data):
    # Function to Normalize
    max_data = np.max(data)
    min_data = np.min(data)
    data = (data-min_data)/(max_data-min_data) 
    return data

def load_audio_file(file_path, 
            input_length=input_length):
    # Function to load an audio file and 
    # return a 1D numpy array 
    data, sr = librosa.load(file_path, sr=None)

    max_offset = abs(len(data)-input_length)
    offset = np.random.randint(max_offset)
    if len(data)>input_length:
        data = data[offset:(input_length+offset)]
    else:
        data = np.pad(data, (offset, 
            input_size - len(data) - offset), 
            "constant")    

    data = audio_norm(data)
    return data
  1. 以下是归一化后的一维音频波形图:
data_base = load_audio_file(filename)
fig = plt.figure(figsize=(14, 8))
plt.title('Raw wave ')
plt.ylabel('Amplitude')
plt.plot(np.linspace(0, 1, input_length), data_base)
plt.show()

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/058703e1-2a99-474e-b3d6-6aa9d4e0d830.png

  1. librosa还有一个melspectrogram函数,我们可以使用它来生成梅尔声谱图,该图可以作为 CNN 的二维图像使用:
def preprocess_audio_mel_T(audio, sample_rate=16000, 
        window_size=20, #log_specgram
        step_size=10, eps=1e-10):

    mel_spec = librosa.feature.melspectrogram(y=audio,
             sr=sample_rate, n_mels= 256)
    mel_db = (librosa.power_to_db(mel_spec,
         ref=np.max) + 40)/40
    return mel_db.T

def load_audio_file2(file_path,
             input_length=input_length):
    #Function to load the audio file  
    data, sr = librosa.load(file_path, sr=None)

    max_offset = abs(len(data)-input_length)
    offset = np.random.randint(max_offset)
    if len(data)>input_length:
        data = data[offset:(input_length+offset)]
    else:
        data = np.pad(data, (offset, 
            input_size - len(data) - offset),
            "constant")

    data = preprocess_audio_mel_T(data, sr)
    return data
  1. 这是相同音频信号的梅尔声谱图:
data_base = load_audio_file2(filename)
print(data_base.shape)
fig = plt.figure(figsize=(14, 8))
plt.imshow(data_base)

https://github.com/OpenDocCN/freelearn-dl-pt7-zh/raw/master/docs/hsn-ai-iot/img/d3217b50-224b-4b88-8a53-957f64dd20fb.png

你可以在 GitHub 仓库中的Chapter12/audio_processing.ipynb文件找到示例的代码文件。

云计算

将 AI 算法应用于物联网生成的数据需要计算资源。随着大量云平台以具有竞争力的价格提供服务,云计算提供了一个具有成本效益的解决方案。在如今众多的云平台中,我们将讨论三大云平台提供商,它们占据了大部分市场份额:Amazon Web ServiceAWS)、Google Cloud PlatformGCP)和 Microsoft Azure。

AWS

Amazon 提供几乎所有云计算功能,从云数据库、云计算资源,到云分析,甚至是建立安全数据湖的空间。它的物联网核心允许用户将设备连接到云端。它提供一个统一的仪表盘,可以用来控制你注册的服务。它按小时收费,提供这些服务已有近 15 年。Amazon 不断升级其服务,提供更好的用户体验。你可以通过其网站了解更多关于 AWS 的信息:aws.amazon.com/

它允许新用户免费使用其许多服务整整一年。

Google Cloud Platform

Google Cloud Platform (cloud.google.com/) 也提供了众多服务。它提供云计算、数据分析、数据存储,甚至云 AI 产品,用户可以使用这些预训练模型和服务来生成自定义的模型。该平台允许按分钟计费。它提供企业级安全服务。Google Cloud 控制台是访问和控制所有 GCP 服务的唯一入口。GCP 为第一年提供 $300 的信用额度,让你可以免费访问其所有服务。

Microsoft Azure

Microsoft Azure 也提供了各种云服务。Microsoft 云服务的最大特点是其易用性;你可以轻松地将其与现有的 Microsoft 工具集成。与 AWS 相比,它声称成本低五倍。像 AWS 和 GCP 一样,Azure 也提供了价值 $200 的一年免费试用。

你可以使用这些云服务来开发、测试和部署你的应用程序。

总结

本章重点提供了处理不同类型数据的工具以及如何为深度学习模型准备这些数据。我们从时间序列数据开始。本章接着详细介绍了文本数据如何进行预处理。本章展示了如何执行数据增强,这是一项对图像分类和物体检测至关重要的技术。接着,我们进入了视频处理部分;我们展示了如何从视频中提取图像帧。然后,本章介绍了音频文件;我们从音频文件中生成了时间序列和梅尔频谱图。最后,我们讨论了云平台,并介绍了三大云服务提供商的功能和服务。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐