Python Web 深度学习实用指南:第四部分

发布时间 2023-04-17 12:52:09作者: ApacheCN

原文:Hands-On Python Deep Learning for the Web

协议:CC BY-NC-SA 4.0

译者:飞龙

本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。

不要担心自己的形象,只关心如何实现目标。——《原则》,生活原则 2.3.c

第 4 节:生产中的深度学习(智能 Web 应用)

本节提供了不同的案例研究,显示了如何开发和部署深度学习 Web 应用(使用深度学习 API),并展示了使用深度学习保护 Web 应用安全的措施。

本节包括以下章节:

  • “第 9 章”,“启用深度学习的网站的通用生产框架”
  • “第 10 章”,“通过深度学习保护 Web 应用安全”
  • “第 11 章”,“DIY – Web DL 生产环境”
  • “第 12 章”,“使用 DL API 和客户支持聊天机器人创建 E2E Web 应用”

九、启用深度学习的网站的通用生产框架

在前面的章节中,我们已经在使用行业级云深度学习DL)API 的方面打下了基础,并且已通过实际示例了解了它们的使用。 在本章中,我们将介绍开发支持 DL 的网站的一般概述。 这将要求我们将到目前为止所学到的所有知识汇总在一起,以便我们可以将其用于实际的用例中。 在本章中,我们将学习如何通过首先准备数据集来构建用于生产的 DL Web 应用。 然后,我们将使用 Python 训练 DL 模型,然后使用 Flask 将 DL 模型包装在 API 中。

以下是本章的简要概述:

  • 定义我们的问题陈述
  • 将问题分为几个部分
  • 建立思维模型来绑定项目组件
  • 我们应该如何收集数据
  • 遵循我们项目的目录结构
  • 从头开始构建项目

技术要求

您可以通过这里访问本章中使用的代码。

要运行本章中使用的代码,您将需要以下软件:

  • Python 3.6+
  • Python PIL 库
  • NumPy
  • Pandas
  • 自然语言工具包NLTK
  • Flask 1.1.0+ 和以下版本的兼容版本:
    • FlaskForm
    • wtforms
    • flask_restful
    • flask_jsonpify

本章将介绍所有其他安装。

定义问题陈述

任何项目都应该以定义明确的问题陈述开始,否则项目开发必定会遭受损失。 从项目计划到项目成本,问题说明控制着整个项目开发流程中涉及的所有主要步骤。

例如,在基于 DL 的 Web 项目中,问题说明将使我们了解以下内容:

  • 确定我们需要哪种数据。
  • 就代码,计划和其他资源而言,将有多少复杂性。
  • 我们将开发什么样的用户界面。
  • 会有多少人参与,以便可以估计项目的人力等。

因此,为了使我们能够开始进一步的项目开发,确实需要定义明确的问题陈述。

想象一下,正在一家公司的 DL 工程师,该公司正计划建立一个推荐系统,以根据用户提供的标准从产品列表中推荐产品。 您的老板要求您基于此开发概念证明PoC)。 那么,我们应该怎么做呢? 如前所述,让我们首先定义问题陈述。

向最终推荐系统提供输入的主要实体是用户。 根据用户的首选项(现在称为输入特征首选项),系统将提供最符合其首选项的产品列表。 因此,长话短说,问题陈述可以写为:

“给定一组输入特征(用户偏好),我们的任务是建议产品列表。”

现在我们有一个定义明确的问题说明,接下来继续进行,并在下一节中建立后续步骤。

建立项目的心理模型

查看问题陈述,您可能会想打开浏览器并开始搜索一些数据集。 但是,要正确地开发项目,就需要进行明确的规划以逐步构建项目。 没有结构的项目无非是无舵船。 因此,我们将从一开始就对此保持谨慎。 我们将讨论将在我们的项目中扮演非常重要角色的模块。 这也包括一些精神上的考虑。 我喜欢将此阶段称为建立项目的心理模型。

让我们花一些时间进一步讨论问题陈述,以便弄清楚我们需要开发的基本模块。

我们的项目涉及根据用户的偏好向用户推荐产品。 因此,为了执行此建议,我们需要一个知道如何理解用户为其提供的偏好集的系统。 为了能够理解这些偏好,系统将需要某种我们将要实现 DL 的训练。 但是偏好呢? 他们看起来如何? 在需要人员参与的现实世界项目情况中,您经常会遇到这些问题。

现在,请三思而后行,并尝试思考在选择要购买的产品时通常要寻找的方面。 让我们在这里列出它们:

  • 产品的规格是什么? 如果我想穿大尺寸的 T 恤,不建议我穿小尺寸的 T 恤。
  • 产品的价格是多少? 用户资金有限,此推荐对他们的钱包有利吗?
  • 这个产品是什么牌子的? 用户经常对多家公司生产的类似产品有品牌偏好。

请注意,前面的指针没有任何特定的顺序。

因此,从上一节开始,我们开始了解我们所需要的东西,这是一个界面(在我们的情况下,本质上是一个网页),供用户提供其首选项。 考虑到这些首选项,我们的系统将预测一组最合适的产品。 这是 DL 部分发挥作用的地方。 正如我们将在前面的章节中回顾的那样,要使 DL 模型能够处理给定的问题,就需要对一些表示问题的数据进行尽可能严密的训练。 现在让我们讨论系统的数据部分。

我们有一个易于使用的数据集,该数据集是由 Amazon 提供并由 Stanford Network Analysis Project 团队创建的 Amazon Fine Food Reviews 数据集。 尽管数据集很大,但在本章中创建演示时,我们不会使用完整的数据集。 此处可能触发的一个直接问题是数据集的外观如何? 我们需要制定一个粗略的计划来决定以下内容:

  • 我们将选择哪些特征来构建数据集
  • 我们将在哪里收集数据

让我们对原始问题陈述进行一些增强,然后再继续进行。 这是原始的问题陈述:

“给定一组输入特征(用户偏好),我们的任务是建议产品列表。”

如果推荐不合格产品,用户将不会喜欢我们的系统。 因此,我们将对问题陈述进行一些修改,如下所示:

“给定一组输入特征(用户首选项),我们的任务是建议可能要购买的最佳产品清单。”

为了让我们的系统针对给定的标准推荐最佳产品列表,首先需要知道产品的平均等级。 除了平均评分之外,获取有关特定产品的以下信息(名称除外)将非常有用:

  • 技术指标
  • 产品种类
  • 卖方名称
  • 平均价格
  • 预计交货时间

在准备数据时,我们将寻找有关特定产品的先前指示。 现在是我们将从何处收集数据的问题。 答案是亚马逊! 亚马逊以其在电子商务行业中的服务而闻名,向我们提供各种产品和有关它们的信息,例如它们的等级,产品规格,商品价格等。 但是请说亚马逊不允许您直接将这些数据作为压缩文件下载。 为了以所需的形式从亚马逊获取数据,我们将不得不依靠网络抓取。

在讨论的这一点上,我们可以确定该项目的两个主要领域:

  • 接收用户偏好的界面
  • 代表我们正在处理的问题陈述的数据

对于 DL 建模,我们将从简单的,全连接,基于神经网络的架构开始。 从简单的模型开始逐步增加复杂性通常是有用的,因为它使代码库更易于调试。

因此,可以肯定地说,以下三个模块将在该项目中扮演重要角色:

  • 接口
  • 数据
  • DL 模型

希望您现在对开始进行项目开发有了一个不错的想法。 您现在可以从所涉及的框架中解决在此阶段您应该问什么问题以及可能需要考虑的问题。

我们不希望我们的推荐系统偏向于任何事物。 数据中可能隐藏了许多类型的偏差,并且自然而然地,它可能导致使用它的 DL 系统继承该偏差。

要了解有关机器学习系统中不同类型偏见的更多信息,建议您参考偏差类型。 在我们的案例中,一个令人吃惊的偏见例子是男性访问者获得平均推荐的产品推荐的情况。 这些建议可能仅基于其性别,而不基于任何其他访客浏览模式。 这可能是错误的,并且可能做错了。 但是像这样的实例会使我们的模型非常不合适。 在下一节中,我们将讨论一些要点,以了解如何避免数据出现偏差。

避免首先获得错误数据的机会

什么是错误数据? 我们只是在谈论错误值的数据吗? 答案是不。 除了具有错误或缺失值的数据外,错误数据还可能具有细微但严重的错误,这可能导致模型训练不充分甚至偏差。 因此,在训练模型之前,识别出此类错误数据并将其删除非常重要。 识别这些错误的主要方法有五种:

  • 寻找缺失的值。
  • 寻找似乎超出规模或可能性的值,即异常值。
  • 请勿在数据集中包含任何可能导致数据泄漏的功能。
  • 确保所有评估类别在数据集中都有相似数量的样本。
  • 确保您设计的问题解决方案本身不会带来偏差。

一旦明确了这些要点,我们就可以继续进行更具体的领域,在数据收集过程中我们需要注意这些领域。 重要的是,在数据收集期间要制定适当的计划,以牢记数据源的所有属性和问题陈述的要求。

假设您正在从亚马逊在美国的销售网点抓取产品数据,而最终在印度版本的亚马逊上搜索产品。 刮板可能会为您提供来自印度网点的数据,可能不适合推荐给美国居民。

此外,由于亚马逊以及类似的服务(例如 Flipkart)利用推荐系统为他们的客户定位最适合的产品,因此在数据收集期间,抓取工具不应成为此类建议的牺牲品。 重要的是,抓取工具应时不时地清除其上下文,并避免由于亚马逊实现的 AI 而产生偏见。

让我们以 Amazon Fine Food Reviews 数据集为例。 尽管乍看之下数据集看起来很平衡,但我们可以发现数据集中存在很多偏差。 考虑客户为评论产品而撰写的文字长度。 让我们根据它们的得分在图表中绘制它们。 下图显示了等级为 1 和 2 星的产品的图:

下图显示了评级为 3 星和 4 星的产品的图:

下图显示了评级为 5 星的产品的图:

请注意,越来越多的正面评论中有更多书面文字。 这将直接转换为数据集中的大多数单词,从而使用户获得更高的评分。 现在,考虑一种情况,用户撰写一篇冗长的评论,评分较低,并且对该产品普遍持消极看法。 由于我们的模型经过训练,可以将较长的评论与正面评价相关联,因此会将负面评论标记为正面。

最重要的是,如图所示,现实世界的数据可能包含许多边缘情况,如果未正确处理它们,您很可能会得到错误的模型。

如何不建立 AI 后端

考虑到 Web 应用可以发展的广泛性以及几乎所有其他平台对作为基于 Web 的服务运行的后端的强烈依赖,因此,对后端进行周密的考虑和正确执行非常重要。 即使在 PoC 阶段,基于 AI 的应用通常也不会很快响应或花费大量时间来训练新样本。

虽然我们将讨论使后端不因瓶颈而受阻的提示和技巧,但在为网站开发 AI 集成后端时,我们需要提出一些最好避免的指针 。

期望网站的 AI 部分是实时的

人工智能在计算上是昂贵的,不用说,这对于旨在以最快的时间为其客户提供服务的网站而言是不可取的。 虽然较小的模型或使用浏览器 AI(例如 TensorFlow.js 或其他库)可以提供实时 AI 响应的体验,但即使它们遇到客户端在慢速网络区域或使用低端设备的问题。 因此,浏览器内 AI 模型或轻量级 AI 模型几乎立即回复的两种方法都受设备配置和网络带宽的影响。 因此,理想情况下,应该对客户端做出快速响应的网站后端应该与处理 AI 模型响应的部分分开。 两者并行工作,应保持共同的数据存储和两者之间正确的交互方法,以使负责响应客户端的后端代码对 AI 模型部分的依赖性降低。

假设从网站传入的数据是理想的

即使与该项目相对应的网站或应用可能类似于理想的数据收集方法,但也不应假定来自该网站或应用的数据没有错误。 错误的网络请求,恶意连接或仅由用户提供的垃圾输入都可能导致数据不适合进行训练。 非恶意用户可能会遇到网络问题,并在短时间内刷新同一页面 10 到 20 次,这不应增加该页面基于查看的重要性。 从网站收集的所有数据必须根据模型的要求进行清理和过滤。 必须牢记,网站所面临的挑战几乎肯定会影响所收集数据的质量。

集成端到端 AI 的 Web 应用示例

现在,我们已经讨论了概述,以及在创建基于 AI 的网站后端时应避免的陷阱,让我们继续创建一个(尽管相当简单)来演示该解决方案的总体概述。

如上所述,我们将介绍以下步骤:

  • 根据问题陈述收集数据
  • 清理和预处理数据
  • 建立 AI 模型
  • 创建一个界面
  • 在界面上使用 AI 模型

虽然我们之前讨论了收集数据的陷阱,但在这里我们将简要讨论可用于完成任务的工具和方法。

数据收集与清理

从总体角度来看,出于收集数据的目的,可能有多个数据源。 您可以从网站上抓取数据,也可以下载一些准备好的数据集。 也可以采用其他方法,例如:

  • 在应用/网站运行时动态生成数据
  • 从应用或智能设备登录
  • 通过系统形式(例如测验或调查)直接从用户收集数据
  • 从调查机构收集数据
  • 通过特定方法(科学数据)和其他方法测得的观测数据

beautifulsoup是通常用于执行 Web 抓取的库。 Scrapy是另一种流行的工具,可以非常快速地使用。

数据清除将完全取决于您收集的数据形式,并且在本书的前几章中已进行了讨论。 我们将假定您能够将数据转换为适合您希望进行模型构建部分的格式。 对于本节中的其他主题,我们将使用一个名为 Amazon Fine Food Reviews 的准备好的数据集,可以从这里下载。提取下载的 ZIP 文件后,您将获得名为Reviews.csv的数据集。

这里是观察如何执行 Web 抓取和准备干净数据集的一个很好的起点。

建立 AI 模型

现在,我们将准备 AI 模型,该模型将根据用户的查询推荐产品。 为此,我们创建一个新的 Jupyter 笔记本。

进行必要的导入

首先,将所需的 Python 模块导入项目:

import numpy as np
import pandas as pd
import nltk
from nltk.corpus import stopwords 
from nltk.tokenize import WordPunctTokenizer
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer

# Comment below line if you already have stopwords installed
nltk.download('stopwords')

我们导入TfidfVectorizer以帮助我们创建用于执行自然语言处理的词频逆文档频率TF-IDF)向量。 TF-IDF 是在给定多个文档可能包含或不包含单词的情况下,单个文档中单词的重要性的数字量度。 在数字上,当单个单词在单个文档中频繁出现但在其他文档中不频繁出现时,它将增加重要性值。 TF-IDF 如此流行,以至于目前全球超过 80% 的基于自然语言的推荐系统都在使用它。

我们也正在导入WordPunctTokenizer。 标记器执行将文本分解为基本标记的功能。 例如,一个大的段落可能被分解为句子,然后进一步分解为单词。

读取数据集并准备清理函数

我们将读取具有ISO-8859-1编码的 Amazon Fine Food Reviews 数据集。 这仅是为了确保我们不会丢失评论文本中使用的任何特殊符号:

df = pd.read_csv('Reviews.csv', encoding = "ISO-8859-1")
df = df.head(10000)

由于数据集非常大,因此我们将本章的工作限制为数据集中的前 10,000 行。

我们将需要从文本中删除停用词,并过滤掉括号中的符号和其他文字不自然的符号。 我们将创建一个名为cleanText()的函数,该函数将执行停用词的过滤和删除:

import string
import re

stopwordSet = set(stopwords.words("english"))

def cleanText(line):
    global stopwordSet

    line = line.translate(string.punctuation)
    line = line.lower().split()

    line = [word for word in line if not word in stopwordSet and len(word) >= 3]
    line = " ".join(line)

    return re.sub(r"[^A-Za-z0-9^,!.\/'+-=]", " ", line) 

使用前面的函数,我们从文本中删除了停用词和所有少于三个字符的词。 我们已过滤掉标点符号,仅保留了文本中的相关字符。

提取所需的数据

数据集包含的数据超出了我们手头演示所需的数据。 我们将提取ProductIdUserIdScoreText列以准备我们的演示。 产品名称出于保密原因而被加密,就像用户名称被加密一样:

data = df[['ProductId', 'UserId', 'Score', 'Text']]

在数据科学中,保持数据加密和不包含个人信息是一项挑战。 从数据集中删除部分很重要,这样可以识别出数据集中的私有实体。 例如,您将需要从评论文本中删除人员和组织名称,以阻止识别产品和用户,尽管他们具有加密的产品和用户 ID。

应用文字清理

现在,我们将应用文本过滤和停用词删除函数来清理数据集中的文本:

%%time
data['Text'] = data['Text'].apply(cleanText)

显示执行任务所需的时间。

请注意,前面的代码块仅在 Jupyter 笔记本中有效,而在常规 Python 脚本中无效。 要在普通的 Python 脚本上运行它,请删除%%time命令。

将数据集分为训练和测试部分

由于我们只有一个数据集,因此我们将其分为两部分,特征和标签部分分开:

X_train, X_valid, y_train, y_valid = train_test_split(data['Text'], df['ProductId'], test_size = 0.2) 

我们将使用sklearn模块中的train_test_split()方法将数据集分为 80% 用于训练和 20% 用于测试。

汇总有关产品和用户的文本

现在,我们将按用户和产品 ID 汇总数据集的评论。 我们需要对每种产品进行审查,以确定哪种产品将是以下方面的理想选择:

user_df = data[['UserId','Text']]
product_df = data[['ProductId', 'Text']]
user_df = user_df.groupby('UserId').agg({'Text': ' '.join})
product_df = product_df.groupby('ProductId').agg({'Text': ' '.join})

同样,用户汇总的评论将帮助我们确定用户的喜好。

创建用户和产品的 TF-IDF 向量化器

现在,我们将创建两个不同的向量化程序,一个用于用户,另一个用于产品。 我们将需要这些向量化工具来确定用户需求与评论对任何给定产品的了解之间的相似性。 首先,我们将为用户创建向量化器并显示其形状:

user_vectorizer = TfidfVectorizer(tokenizer = WordPunctTokenizer().tokenize, max_features=1000)
user_vectors = user_vectorizer.fit_transform(user_df['Text'])
user_vectors.shape

然后,我们将为产品创建向量化器:

product_vectorizer = TfidfVectorizer(tokenizer = WordPunctTokenizer().tokenize, max_features=1000)
product_vectors = product_vectorizer.fit_transform(product_df['Text'])
product_vectors.shape

我们使用WordPunctTokenizer分解文本,并使用TfidfVectorizer对象的fit_transform方法准备向量,这些向量将单词词典映射到它们在文档中的重要性。

通过提供的评级创建用户和产品的索引

我们使用pandas模块的pivot_table方法来创建针对产品的用户评分矩阵。 我们将使用此矩阵执行矩阵分解以确定用户喜欢的产品:

userRatings = pd.pivot_table(data, values='Score', index=['UserId'], columns=['ProductId'])
userRatings.shape

我们还将将用户和产品的TfidfVectorizer向量转换为适合矩阵分解的矩阵:

P = pd.DataFrame(user_vectors.toarray(), index=user_df.index, columns=user_vectorizer.get_feature_names())
Q = pd.DataFrame(product_vectors.toarray(), index=product_df.index, columns=product_vectorizer.get_feature_names())

现在,我们可以创建矩阵分解函数。

创建矩阵分解函数

现在,我们将创建一个函数来执行矩阵分解。 矩阵分解已成为 2006 年 Netflix 奖挑战赛中用于推荐系统的流行算法系列。它是将用户项矩阵分解为两个低维矩形矩阵的集合的一系列算法,可以将这些矩阵相乘以恢复原始矩阵。 原始高阶矩阵:

def matrix_factorization(R, P, Q, steps=1, gamma=0.001,lamda=0.02):
    for step in range(steps):
        for i in R.index:
            for j in R.columns:
                if R.loc[i,j]>0:
                    eij=R.loc[i,j]-np.dot(P.loc[i],Q.loc[j])
                    P.loc[i]=P.loc[i]+gamma*(eij*Q.loc[j]-lamda*P.loc[i])
                    Q.loc[j]=Q.loc[j]+gamma*(eij*P.loc[i]-lamda*Q.loc[j])
        e=0
        for i in R.index:
            for j in R.columns:
                if R.loc[i,j]>0:
                    e= e + pow(R.loc[i,j]-np.dot(P.loc[i],Q.loc[j]),2)+lamda*(pow(np.linalg.norm(P.loc[i]),2)+pow(np.linalg.norm(Q.loc[j]),2))
        if e<0.001:
            break

    return P,Q

然后,我们执行矩阵分解并记录所花费的时间:

%%time
P, Q = matrix_factorization(userRatings, P, Q, steps=1, gamma=0.001,lamda=0.02)

之后,我们需要保存模型。

将模型另存为 Pickle

现在,在项目的root目录中创建一个名为api的文件夹。 然后,保存训练后的模型,该模型是用户产品评级矩阵分解后获得的低阶矩阵:

import pickle
output = open('api/model.pkl', 'wb')
pickle.dump(P,output)
pickle.dump(Q,output)
pickle.dump(user_vectorizer,output)
output.close()

将模型另存为二进制 Pickle 文件,使我们可以在将模型部署到网站的后端时将它们快速加载回内存中。

既然我们已经完成了预测模型的开发,那么我们将继续为应用构建接口。

建立界面

要为 Web 应用构建界面,我们需要考虑如何让用户与系统交互。 在我们的案例中,我们希望在用户提交搜索查询时根据其在搜索栏中搜索的内容为他们提供建议。 这意味着我们需要系统实时响应并即时生成建议。 为了构建该系统,我们将创建一个 API,该 API 会响应搜索查询。

创建一个 API 来回答搜索查询

我们将创建一个 API,该 API 接受 HTTP 请求形式的查询,并根据用户输入的搜索查询回复产品建议。 这样做,请按照下列步骤操作:

  1. 我们将从导入 API 所需的模块开始。 我们在上一节中讨论了这些导入的模块:
import numpy as np
import pandas as pd
from nltk.corpus import stopwords
from nltk.tokenize import WordPunctTokenizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_extraction.text import CountVectorizer
from flask import Flask, request, render_template, make_response
from flask_wtf import FlaskForm
from wtforms import StringField, validators
import io
from flask_restful import Resource, Api
import string
import re
import pickle
from flask_jsonpify import jsonpify
  1. 我们还将导入Flask模块以创建一个快速 HTTP 服务器,该服务器可以以 API 的形式在已定义的路由上使用。 我们将实例化Flask应用对象,如下所示:
DEBUG = True
app = Flask(__name__)
app.config['SECRET_KEY'] = 'abcdefgh'
api = Api(app)

应用配置中的SECRET_KEY的值由您决定。

  1. 然后,我们将创建一个class函数来处理从用户以搜索查询形式收到的文本输入:
class TextFieldForm(FlaskForm):
    text = StringField('Document Content', validators=[validators.data_required()])
  1. 为了封装 API 方法,我们将它们包装在Flask_Work类中:
class Flask_Work(Resource):
    def __init__(self):
        self.stopwordSet = set(stopwords.words("english"))
        pass
  1. 再次需要我们在模型创建期间使用的cleanText()方法。 它将用于清除和过滤用户输入的搜索查询:
    def cleanText(self, line): 
        line = line.translate(string.punctuation)
        line = line.lower().split()

        line = [word for word in line if not word in self.stopwordSet and len(word) >= 3]
        line = " ".join(line)

        return re.sub(r"[^A-Za-z0-9^,!.\/'+-=]", " ", line) 
  1. 我们为应用定义一个主页,该主页将从稍后在模板中创建的index.html文件加载:
    def get(self):
        headers = {'Content-Type': 'text/html'}
        return make_response(render_template('index.html'), 200, headers)
  1. 我们创建基于post方法的预测路由,该路由将在收到用户的搜索查询后以产品建议进行响应:
    def post(self):
        f = open('model.pkl', 'rb')
        P, Q, userid_vectorizer = pickle.load(f), pickle.load(f), pickle.load(f)
        sentence = request.form['search']
        test_data = pd.DataFrame([sentence], columns=['Text'])
        test_data['Text'] = test_data['Text'].apply(self.cleanText)
        test_vectors = userid_vectorizer.transform(test_data['Text'])
        test_v_df = pd.DataFrame(test_vectors.toarray(), index=test_data.index,
                                 columns=userid_vectorizer.get_feature_names())

        predicted_ratings = pd.DataFrame(np.dot(test_v_df.loc[0], Q.T), index=Q.index, columns=['Rating'])
        predictions = pd.DataFrame.sort_values(predicted_ratings, ['Rating'], ascending=[0])[:10]

        JSONP_data = jsonpify(predictions.to_json())
        return JSONP_data
  1. 我们将Flask_Work类附加到Flask服务器。 这样就可以在运行时完成脚本。 我们放置了一个 API,该 API 根据用户的搜索查询来建议产品:
api.add_resource(Flask_Work, '/')

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=4000, debug=True)

将此文件另存为main.py。 创建 API 脚本后,我们需要托管服务器。

  1. 为此,请在终端上运行以下命令:
python main.py

这将在端口4000上的计算机上启动服务器,如下所示:

但是,我们仍然需要准备一个用户界面来使用此 API。 我们将在以下部分中这样做。

创建一个使用 API​​ 的接口

现在,我们将创建一个简单,最少的 UI 来使用我们创建的 API。 本质上,我们将创建一个搜索栏,用户可以在其中输入所需的产品或产品规格,API 会根据用户的查询返回建议。 我们将不讨论构建 UI 的代码,但已将其包含在 GitHub 存储库中,该存储库可在这个页面中找到。

启动服务器后,该 UI 将在http://127.0.0.1:4000处可见,如“创建 API 回答搜索查询”部分的步骤 9 所示。

我们创建的界面如下所示:

用户输入搜索查询并获得建议,如下所示:

我们的应用没有保存用户会话的好处。 而且,它没有用于用户预期预算的参数,这通常是决定产品是否适合用户的决定因素。 将这些功能添加到 Web 应用并利用它们的好处很容易。

总结

总体而言,磨练 DL 功能的 Web 应用有几种设置方法,可通过 API,浏览器内 JavaScript 或通过将 DL 模型默默地嵌入到应用的后端来实现。 在本章中,我们了解了如何使用这些方法中最常见的方法(基于 API 的 DL Web 应用),同时,我们对如何设计类似的解决方案进行了粗略的概述。 我们介绍了确定问题陈述和后续解决方案所涉及的思考过程,以及在设计集成 DL 模型的 Web 应用时应避免的陷阱和痛点。

在下一章中,我们将讨论一个端到端项目,该项目出于安全目的将 DL 集成在 Web 应用上。 我们将了解 DL 如何帮助我们识别可疑活动并阻止垃圾邮件用户。

十、通过深度学习保护 Web 应用安全

一般而言,安全性对于任何网站以及所有软件而言都是至关重要的。 如今,安全威胁随着可用计算能力的提高和技术领域的发展而不断发展。 因此,重要的是网站必须采取最佳的安全措施以确保其数据和用户信息的安全。 从事在线商业活动的网站始终处于高风险之中,它们面对从未见过的安全攻击非常普遍。 对于基于规则的安全系统而言,新的攻击尤其难以识别和阻止。 因此,您可以查看由深度学习驱动的安全系统提供的选项,这些选项可以有效替代基于规则的系统,并且还能够正确识别和阻止新威胁。

本章讨论了一些技巧和技术,您可以使用这些技巧和技术通过使用 Python 进行深度学习来保护网站的安全。 我们将介绍 reCAPTCHA 和 Cloudflare,并讨论如何使用它们来增强网站的安全性。 我们还将向您展示如何使用基于深度学习的技术和 Python 后端,实现安全机制来检测网站上的恶意用户。 本章将涵盖以下主题:

  • reCAPTCHA 的故事
  • DIY – 在 Django 上进行恶意用户检测
  • 使用 Python 在 Web 应用中使用 reCAPTCHA
  • Cloudflare 和网站安全

我们将从 reCAPTCHA 的故事开始本章的讨论,reCAPTCHA 是 Google 创造的一种巧妙的工具,它改变了互联网。

技术要求

您可以在这个页面上访问本章的代码。

您需要以下软件来运行本章中的代码:

  • Python 3.6+
  • TensorFlow 1.14
  • Keras 与 TensorFlow 1.14 兼容
  • Django 2.x

reCAPTCHA 的故事

“对人类易如反掌” – 这是 reCAPTCHA 的口号,它陈述了一个简单的想法,即 reCAPTCHA 是一个系统,该系统确定应用或网站上的用户是真正的人类用户还是自动脚本 。 reCAPTCHA 是 CAPTCHA 技术的特定实现,CAPTCHA 技术是一种使用带有扭曲,弯曲的字母和数字的视觉效果,并要求用户解密视觉图像的内容并将其以纯格式写出的方法。

如果您在 2000 年代初期是普通的互联网用户,那么您可能会在许多网站上看到类似于以下验证码的图片:

CAPTCHA用于区分计算机和人类得完全自动化的公共图灵测试的首字母缩写。

在 Yahoo 的推广下,CAPTCHA 系统迅速在数百万个网站上使用。 但是,尽管此系统提供给网站的安全性得到了提高,但它很耗时,并且经常遭到流氓程序员的殴打。 人们常常每隔一段时间就会创建具有不同设计和视觉元素组合的新 CAPTCHA 系统。

同时,开发人员正在解决一个非常不同的问题-将印刷书籍和其他文本数字化。 一种快速的解决方案是扫描书籍。 也就是说,使用光学字符识别OCR)将书籍转换为初步的数字文本形式。 对于使用标准字体制成的打印内容,其扫描质量很好,转换效果很好。 但是,打印格式和手稿格式错误会影响转换精度。 人们越来越多地将图像上传到在线平台,以寻求从这些图像中提取文本并将其用于多种目的,例如确定图像中的内容,位置或提及的品牌。

CAPTCHA 的起源与多个组织的发明主张存在争议,但是 Luis von Ahn 在 2003 年创造了 CAPTCHA 这个词,后来他成为 reCAPTCHA 的创始人,该公司被 Google 收购。

众包服务的先驱 Luis von Ahn 使用 reCAPTCHA 程序来显示从印刷书籍扫描中裁切出来的非常小的文本块。 只有人类才能轻松解决这些挑战,自动化程序将失败。 同时,通过未知的众包活动,大量人类用户的贡献将这些书缓慢地数字化。 reCAPTCHA 仍然对用户构成困扰,但图书数字化的问题已解决。

随着时间的流逝,reCAPTCHA 演变为使用基于 AI 的系统来识别真实和虚假用户。 在撰写本书时,reCAPTCHA 由 Google 积极开发,目前处于其第三版本,该版本允许在网页背景中对用户进行无形验证,并且仅在无法成功验证用户时显示挑战 。 这为真正的用户节省了大量时间,并给机器带来了挑战。

我们现在将建立一个网站,以使用基于深度学习的模型和 reCAPTCHA 为网站提供安全元素。

恶意用户检测

网站上的恶意用户是任何试图执行未经授权执行任务的用户。 在当今世界,恶意用户所构成的威胁正呈指数级增长,黑客向公众暴露了来自几家全球高科技巨头,政府机构和其他私人公司的巨大个人信息数据库。 拥有可以自动缓解这些恶意攻击的系统非常重要。

为了识别示例 Web 应用中的恶意用户,我们创建了一个模型,该模型能够了解用户的常规行为,并且在任何情况下用户的行为与过去的使用情况发生显着变化时,都会发出警报。

异常检测是机器学习的流行分支。 它是一组算法,用于检测给定数据集中的数据样本,这些数据样本不会随大多数数据样本属性一起下降。 在狗窝里检测猫是异常检测。 异常检测以几种方式执行:

  • 通过列的最小最大范围
  • 通过找出数据图中的突然尖峰
  • 当数据绘制在高斯曲线下时,通过将位于端点的点标记为离群值(异常)

支持向量机,K 最近邻和贝叶斯网络是用于异常检测的一些最流行的算法。

我们如何定义网站用户的常规行为?

假设您使用的网站通常是使用笔记本电脑登录的。 通常,最多需要两次尝试才能成功登录该网站。 如果有一天您突然开始使用一台新笔记本电脑,则该登录名可能会是可疑的,并且可能是一种恶意尝试来入侵您的帐户。 如果新设备的位置是您最近或从未去过的地方,那就更是如此。 如果您尝试 10 次登录帐户,也将非常可疑。 处于任何可疑使用状态的状态是用户在网站上的通常行为。

有时,异常可能不是由于任何特定用户的不正常行为引起的。 由于服务器的更改,用户的正常流量以及他们的行为可能会更改。 在这种情况下,我们必须注意不要将所有用户标记为恶意用户。 另外,用户的不正常行为可能是由于黑客尝试以外的其他原因引起的。 如果真正的用户突然开始访问他们不应该访问的网站部分,则这是异常现象,需要防止。

在我们的示例网站中,我们将集成这样的系统。 为此,我们将检查网站的登录页面,在该页面上我们将尝试确定用户的登录是正常还是异常。 我们将考虑用户登录的页面,因为一个网站可能有多个登录页面,并尝试确定它是否是用户登录的常用页面。 如果用户尝试从通常不登录的页面登录,我们会将其标记为异常。 这只是检查异常用户的一个简单标准,范围为数百个其他参数。

基于 LSTM 的用于认证用户的模型

我们将本节分为两个主要子节:

  1. 建立安全检查模型
  2. 将模型作为 API 托管

让我们从第一部分开始。

构建用于认证有效性检查的模型

为了根据用户的登录活动对用户进行认证,我们将需要一个用于检查请求的 API。 我们可以使用以下步骤构建此模型:

  1. 让我们从开发认证模型开始,该模型确定用户是否未按常规方式进行操作。 我们首先在运行 Python 3.6+ 的 Jupyter 笔记本中导入必要的模块,如下所示:
import sys
import os
import json
import pandas
import numpy
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout
from keras.layers.embeddings import Embedding
from keras.preprocessing import sequence
from keras.preprocessing.text import Tokenizer
from collections import OrderedDict
  1. 现在,我们可以将数据导入到项目中。 我们将在使用数据集。 我们将数据集加载到项目中,如下所示:
file = 'data-full.csv'

df = pandas.read_csv(file, quotechar='|', header=None)
df_count = df.groupby([1]).count()
total_req = df_count[0][0] + df_count[0][1]
num_malicious = df_count[0][1]

print("Malicious request logs in dataset: {:0.2f}%".format(float(num_malicious) / total_req * 100))

您将看到一些有关数据的常规统计信息,如下所示:

您将看到数据包含文本,如下所示:

此观察很重要,我们将在以后的步骤中参考此屏幕快照。

  1. 但是,所有数据都是字符串格式。 我们需要将其转换为适当的值类型。 此外,数据集目前仅包含一个DataFrame; 我们将使用以下代码将其分为两部分:训练列和标签列:
df_values = df.sample(frac=1).values

X = df_values[:,0]
Y = df_values[:,1]
  1. 另外,由于只想使用数据集中与任务相关的特征,因此我们需要丢失一些列:
for index, item in enumerate(X):
    req = json.loads(item, object_pairs_hook=OrderedDict)
    del req['timestamp']
    del req['headers']
    del req['source']
    del req['route']
    del req['responsePayload']
    X[index] = json.dumps(req, separators=(',', ':'))
  1. 完成此操作后,我们现在可以继续对请求正文进行分词了。 分词是一种方法,其中我们将大段分解为句子,将句子分解为单词。 我们可以使用以下代码执行令牌化:
tokenizer = Tokenizer(filters='\t\n', char_level=True)
tokenizer.fit_on_texts(X)
  1. 完成分词后,我们将每个请求正文条目转换为向量。 这样做是因为我们需要数据的数字表示形式,以便计算机能够对其进行计算。 之后,我们进一步将数据集分为两部分-数据集的 75% 用于训练,其余部分用于测试。 同样,使用以下代码拆分标签列:
num_words = len(tokenizer.word_index)+1
X = tokenizer.texts_to_sequences(X)

max_log_length = 1024
split = int(len(df_values) * .75)

X_processed = sequence.pad_sequences(X, maxlen=max_log_length)
X_train, X_test = X_processed[0:split], X_processed[split:len(X_processed)]
Y_train, Y_test = Y[0:split], Y[split:len(Y)]

请记住,从步骤 2 开始,该数据主要包含文本。 当涉及文本数据时,很可能存在上下文和与之关联的特定顺序。

例如,考虑以下句子中的单词 - “Sachin Tendulkar 是伟大的板球运动员”。 为了传达预期的含义,不得更改单词的顺序。 在机器学习中处理文本数据时,这就是维护顺序和上下文的重要性所在的地方。

在我们的案例中,我们将使用一种特殊类型的循环神经网络-长短期记忆LSTM),它将学习识别常规的用户行为。

关于 LSTM 的详细讨论超出了本书的范围,但是如果您有兴趣,可以参考这里来详细了解它。

  1. 现在,我们使用以下代码添加层以及单词嵌入,这有助于维护数字编码文本和实际单词之间的关系:
clf = Sequential()
clf.add(Embedding(num_words, 32, input_length=max_log_length))
clf.add(Dropout(0.5))
clf.add(LSTM(64, recurrent_dropout=0.5))
clf.add(Dropout(0.5))
clf.add(Dense(1, activation='sigmoid'))

我们的输出是单个神经元,在非异常登录尝试或异常登录尝试的情况下,它们分别持有01

  1. 然后,我们使用以下代码编译模型并打印摘要:
clf.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
print(clf.summary())

产生了模型摘要,如下所示:

现在,我们准备继续训练模型:

  1. 我们使用模型的fit()方法,如下所示:
clf.fit(X_train, Y_train, validation_split=0.25, epochs=3, batch_size=128)
  1. 我们将快速检查模型所达到的准确率。 我们可以看到该模型在验证数据上的准确率超过 96%。 鉴于这是我们的第一个模型,这个分数非常可观。 我们可以使用以下代码检查模型的准确率:
score, acc = clf.evaluate(X_test, Y_test, verbose=1, batch_size=128)
print("Model Accuracy: {:0.2f}%".format(acc * 100))

您应该看到如下屏幕截图所示的输出:

  1. 让我们节省这些工作量。 我们将使用它们来创建用于验证用户身份的 API。 我们可以使用以下代码保存模型:
clf.save_weights('weights.h5')
clf.save('model.h5')

准备好模型后,我们现在可以将其作为 Flask API 进行托管。

托管自定义认证模型

现在,让我们创建 API,该 API 将接受用户的登录尝试并返回其对登录有效性的信心:

  1. 我们首先导入创建 Flask 服务器所需的模块,如下所示:
from sklearn.externals import joblib
from flask import Flask, request, jsonify
from string import digits

import sys
import os
import json
import pandas
import numpy
import optparse
from keras.models import Sequential, load_model
from keras.preprocessing import sequence
from keras.preprocessing.text import Tokenizer
from collections import OrderedDict
  1. 现在,我们需要从model训练步骤中导入保存的模型和权重。 一旦这样做,我们需要重新编译模型,并使用make_predict_function()方法使其模型成为predict函数:
app = Flask(__name__)

model = load_model('lstm-model.h5')
model.load_weights('lstm-weights.h5')
model.compile(loss = 'binary_crossentropy', optimizer = 'adam', metrics = ['accuracy'])
model._make_predict_function()
  1. 我们将使用数据清理函数在客户端应用的传入查询中去除数字和其他无用的文本:
def remove_digits(s: str) -> str:
    remove_digits = str.maketrans('', '', digits)
    res = s.translate(remove_digits)
    return res
  1. 接下来,我们在应用中创建/login路由,当用户尝试登录时,该路由将接受来自客户端应用的登录凭据和其他请求标头详细信息。请注意,我们仍然像在此过程中一样丢弃了一些额外的请求标头。 训练。
  2. 清理数据后,我们将其分词和向量化。 这些步骤与我们在训练期间进行的预处理相同。 这是为了确保对传入请求的处理与训练阶段完全相同:
@app.route('/login', methods=['GET, POST'])
def login():
    req = dict(request.headers)
    item = {}
    item["method"] = str(request.method)
    item["query"] = str(request.query_string)
    item["path"] = str(request.path)
    item["statusCode"] = 200
    item["requestPayload"] = []

    X = numpy.array([json.dumps(item)])
    log_entry = "store"

    tokenizer = Tokenizer(filters='\t\n', char_level=True)
    tokenizer.fit_on_texts(X)
    seq = tokenizer.texts_to_sequences([log_entry])
    max_log_length = 1024
    log_entry_processed = sequence.pad_sequences(seq, maxlen=max_log_length)

    prediction = model.predict(log_entry_processed)
    print(prediction)
    response = {'result': float(prediction[0][0])}
    return jsonify(response)

最后,应用以 JSON 形式返回对用户进行认证的信心。

  1. 要在所需端口上运行服务器,我们需要在脚本末尾添加以下行:
if __name__ == '__main__':
    app.run(port=9000, debug=True)
  1. 最后,我们将服务器脚本文件另存为main.py。 我们将通过在系统上使用以下命令来使服务器运行:
python main.py

这将启动 Flask 服务器,该服务器监听回送 IP 127.0.0.1和端口9000。 您可以轻松地将此脚本托管在云中的虚拟机上,并作为通用的安全检查点 API 将其提供给所有应用和网站。

现在,我们可以继续创建在 Django 框架上运行的 Web 应用。

一个使用 API​​ 的基于 Django 的应用

我们创建的使用用户认证检查 API 的网站将是一个简单的广告牌演示。 该网站将规定用户登录然后将帐单发布到广告牌。 尽管该应用很简单,但它包含基于深度学习的安全集成的两个主要功能-用户认证期间的异常检测以及账单发布期间 reCAPTCHA 的实现-避免垃圾邮件。

以下各节将讨论创建应用的步骤。

Django 项目设置

在本节中,我们将使用 Django。 在继续本节之前,请确保在系统上安装了有效的 Django。 您可以在“第 8 章”,“使用 python 在 Microsoft Azure 上进行深度学习”的“Django Web 开发简介”部分中找到 Django 的安装说明。

现在,我们将创建一个 Django 项目。 为此,我们使用以下命令:

django-admin startproject webapp

这将在当前文件夹中创建webapp目录。 我们将在此目录中添加所有将来的代码。 当前目录结构如下:

webapp/
    manage.py
    webapp/
        __init__.py
        settings.py
        urls.py
        wsgi.py
    db.sqlite3

完成此操作后,我们现在准备在项目内部创建一个应用,这将在下一部分中显示。

在项目中创建一个应用

如“第 8 章”,“在 Microsoft Azure 上使用 Python 进行深度学习”中所述,我们现在必须将应用添加到网站项目中。 为此,我们使用以下命令:

cd webapp
python manage.py startapp billboard

前面的命令将在项目中创建一个名为billboard的应用。 但是,我们仍然必须将此应用链接到项目。

将应用链接到项目

要将应用添加到项目中,我们需要将应用名称添加到项目设置文件中settings.py中的应用列表中,如以下代码所示。 在settings.py中,添加以下更改:

# Application definition

INSTALLED_APPS = [
    'billboard',  # <---- ADD THIS LINE
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

这样,我们准备在网站上创建路由。

向网站添加路由

要向项目添加路由,我们编辑webappurls.py文件:

from django.contrib import admin
from django.urls import path, include # <--- ADD 'include' module

urlpatterns = [
    path('', include('billboard.urls')), # <--- ADD billboard.urls path
    path('admin/', admin.site.urls),
]

但是,billboard.urls路径不存在。 我们将创建前进的道路。

在布告栏应用中创建路由处理文件

billboard文件夹中创建一个名为urls.py的新文件,如下所示:

from django.urls import path
from django.contrib.auth.decorators import login_required

from . import views

urlpatterns = [
    path('', login_required(views.board), name='View Board'),
    path('add', login_required(views.addbill), name='Add Bill'),
    path('login', views.loginView, name='Login'),
    path('logout', views.logoutView, name='Logout'),
]

将其另存为webapp/billboard/urls.py。 请注意,我们已将一些views项目导入此路由处理文件。 另外,我们使用了login_required方法。 这表明我们可以开始对网站进行认证。

添加和配置认证路由

要添加用于验证的路由,请在webapp/settings.py文件的末尾添加以下内容:

LOGIN_URL = "/login"
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/logout'

这些行表明我们将需要/login/logout路由。

创建登录页面

要创建登录页面,我们需要在广告牌应用中将/login路由添加到urls.py。 但是,我们已经做到了。 接下来,我们需要将loginView视图添加到布告栏应用的views.py文件中:

def loginView(request):
    if request.user.is_authenticated:
        return redirect('/')
    else:
        if request.POST:
            username = request.POST['username']
            password = request.POST['password']
            user = authenticate(request, username=username, password=password)
            ## MORE CODE BELOW THIS LINE

            ## MORE CODE ABOVE THIS LINE
            else:
                return redirect('/logout')
        else:
            template = loader.get_template('login.html')
            context = {}
            return HttpResponse(template.render(context, request))

前面的函数首先检查用户数据库中是否存在传递给用户名和密码的用户名和密码。 因此,将来,我们将需要一个用户模型来将用户存储在数据库文件db.sqlite3中,该文件是在项目创建步骤中创建的。

然后,该函数将调用认证检查模型 API,以验证用户登录是否正常。 验证按以下代码进行:

def loginView(request):
    ...
            ## MORE CODE BELOW THIS LINE            
            if user is not None:
                url = 'http://127.0.0.1:9000/login'
                values = { 'username': username, 'password': password }
                data = urllib.parse.urlencode(values).encode()
                req = urllib.request.Request(url, data=data)
                response = urllib.request.urlopen(req)
                result = json.loads(response.read().decode())
                if result['result'] > 0.20:
                    login(request, user)
                    return redirect('/')
                else:
                    return redirect('/logout')
            ## MORE CODE ABOVE THIS LINE
    ...

前面的代码块验证用户登录,如果发现用户登录无效,则执行注销操作,并将用户重定向回再次登录。

为此,我们需要向view.py文件添加一些必要的导入,如下所示:

from django.shortcuts import redirect
from django.contrib.auth import authenticate, login, logout

from django.http import HttpResponse
from django.template import loader

from django.conf import settings
from django.urls import reverse_lazy
from django.views import generic

from django.contrib.auth.models import User

import urllib
import ssl
import json

注意,我们还从django.contrib.auth导入了logout方法。 这将用于创建logout视图。

创建注销视图

现在,让我们创建logout视图。 这样做非常简单,如下所示:

def logoutView(request):
    logout(request)
    return redirect('/')

现在,让我们创建登录页面的模板。

创建登录页面模板

要创建模板,我们首先需要创建所需的文件夹。

billboard目录中创建一个名为templates的文件夹。 现在,目录结构将类似于以下代码:

webapp/
    manage.py
    webapp/
        __init__.py
        settings.py
        urls.py
        wsgi.py
    billboard/
        templates/
        ___init_.py
        admin.py
        apps.py
        models.py
        tests.py
        urls.py
        views.py

templates文件夹内,我们将放置模板文件。 首先创建base.html,我们将在所有其他模板中进行扩展。 这将包含CSSJS包含,以及页面的常规块结构。

我们已在这里提供了此文件的示例。

完成此操作后,我们准备创建login.html文件,该文件将执行将登录值发送到服务器的过程:

{% extends 'base.html' %}
{% block content %}
<div class="container">
    <div class="row">
        <div class="form_bg">
            <form method="post">
                {% csrf_token %}
                <h2 class="text-center">Login Page</h2>
                # WE'LL ADD MORE CODE BELOW THIS LINE
                ...
                # WE'LL ADD MORE CODE ABOVE THIS LINE
            </form>
        </div>
    </div>
</div>
{% endblock %}

注意,我们已经在前面的视图模板中扩展了base.html模板。

您可以在这个页面上阅读有关扩展 Django 模板的更多信息。

此登录页面中的表单发出POST请求,因此需要传递 CSRF 令牌。 现在,我们可以创建登录完成后呈现的页面。

广告牌页面模板

由于我们已经设置了base.html文件,因此我们可以简单地在board.html模板文件中对其进行扩展以创建广告牌显示页面:

{% extends 'base.html' %}
{% block content %}
<div class="container">
    <div class="row">
        {% for bill in bills %}
        <div class="col-sm-4 py-2">
            <div class="card card-body h-100">
                <h2>{{ bill.billName }}</h2>
                <hr>
                <p>
                    {{ bill.billDesc }}
                </p>
                <a href="#" class="btn btn-outline-secondary">{{ bill.user.username }}</a>
            </div>
        </div>
        {% endfor %}
    </div>
</div>
{% endblock %}

在前面的代码块中,我们遍历了广告牌数据库中所有可用的bills项目,并使用模板中的for循环显示了它们。 base.html模板的使用允许我们减少视图模板中的重复代码量。

此后,我们将创建一个页面,该页面具有将新账单添加到广告牌的代码。

添加到广告牌页面模板

要创建将帐单添加到广告牌的页面模板,我们使用以下代码创建add.html模板文件:

{% extends 'base.html' %}
{% block content %}
<div class="container">
    <div class="row">
        <div class="form_bg">
            <form method="post" id="form">
                {% csrf_token %}
                <h2 class="text-center">Add Bill</h2>
                <br />
                <div class="form-group">
                    <input type="text" class="form-control" id="billname" name="billname" placeholder="Bill Name">
                </div>
                <div class="form-group">
                    <input type="text" class="form-control" id="billdesc" name="billdesc" placeholder="Description">
                </div>
                <br />
                <div class="align-center">
                    <button type="submit" class="btn btn-success" id="save">Submit</button>
                </div>
            </form>
        </div>
    </div>
</div>
{% endblock %}

在前面的代码块中,我们扩展了base.html模板以添加允许我们添加帐单的表格。 注意form元素中 CSRF 令牌的使用。 在 Django 中,我们始终需要在发出 POST 请求时传递有效的 CSRF 令牌。

您可以在这个页面上了解有关 Django 中 CSRF 令牌的更多信息。

但是,等等,我们还没有添加视图来处理广告牌页面和添加账单页面。 让我们现在添加它们!

广告牌模型

我们需要添加视图以在广告牌页面上查看所有账单。 但是,为此,我们首先需要创建一个模型来保存所有账单。

models.py文件中,添加以下代码:

from django.utils.timezone import now
from django.contrib.auth.models import User

class Bills(models.Model):
    billName = models.CharField("Bill Name", blank=False, max_length=100, default="New Bill")
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    billDesc = models.TextField("Bill Description")
    billTime = models.DateTimeField(default=now, editable=False)

    class Meta:
        db_table = "bills"

在前面的代码中,我们创建了一个名为Bills的新模型。 这将存储用户在广告牌上添加的所有账单的详细信息。 user模型与此模型链接为外键。 将此文件另存为webapp/billboard/models.py

您可以在这个页面上了解有关外键和其他键的更多信息。

完成此操作后,我们现在可以在视图中使用Bills模型。

创建广告牌视图

要开始在应用中使用Bills模型,我们首先需要将其导入views.py文件。

view.py文件的顶部添加以下行:

from .models import Bills

然后,我们可以为广告牌添加视图,如下所示:

def board(request):
    template = loader.get_template('board.html')
    context = {}
    context["isLogged"] = 1

    Bill = Bills.objects.all()

    context["bills"] = Bill

    return HttpResponse(template.render(context, request))

接下来,我们需要创建用于添加账单的视图。

创建账单并添加视图

在此视图中,我们将创建账单。 如果对由addbill方法提供服务的路由提出了有效的POST请求,我们将创建一个新的Bill对象并将其保存到数据库中。 否则,我们显示用于向用户添加账单的表格。 让我们看看如何在以下代码中执行此操作:

def addbill(request):
    if request.POST:
            billName = request.POST['billname']
            billDesc = request.POST['billdesc']
            Bill = Bills.objects.create(billName=billName, user=request.user, billDesc=billDesc)
            Bill.save()
            return redirect('/')
    else:
        template = loader.get_template('add.html')
        context = {}
        context["isLogged"] = 1

        return HttpResponse(template.render(context, request))

但是,在使用该应用之前,我们仍然需要创建管理员用户。

创建管理员用户并对其进行测试

要创建管理员用户,我们使用以下命令:

 python manage.py createsuperuser

现在,我们可以使用以下命令来迁移数据库更改:

python manage.py makemigrations
python manage.py migrate

产生类似于以下内容的输出:

现在,让我们使用 reCAPTCHA 工具保护广告牌发布。

在 Python Web 应用中使用 reCAPTCHA

要将 reCAPTCHA 添加到网站,我们首先需要从 Google reCAPTCHA 控制台获取 API 密钥:

  1. 首先,登录到您的 Google 帐户,然后转到这里

  2. 接下来,点击右上角的“管理控制台”。

  3. 按照屏幕上显示的步骤将站点添加到控制台。 如果要在本地系统上进行测试,则必须指定127.0.0.1作为 URL 之一。

  4. 获取您的域的 API 密钥。

    您打开域的 API 密钥的屏幕应类似于以下屏幕截图:

  1. 现在,将密钥添加到 Web 应用的settings.py文件中,如下所示:
GOOGLE_RECAPTCHA_SECRET_KEY = '6Lfi6ncUAAAAANJYkMC66skocDgA1REblmx0-3B2'
  1. 接下来,我们需要将要加载的脚本添加到add.html模板中。 我们将其添加到广告牌应用页面模板中,如下所示:
<script src="https://www.google.com/recaptcha/api.js?render=6Lfi6ncUAAAAAIaJgQCDaR3s-FGGczzo7Mefp0TQ"></script>
<script>
    grecaptcha.ready(function() {
        grecaptcha.execute('6Lfi6ncUAAAAAIaJgQCDaR3s-FGGczzo7Mefp0TQ')
        .then(function(token) {
            $("#form").append('<input type="hidden" name="g-recaptcha-response" value="'+token+'" >');
        });
    });
</script>

{% endblock %}

请注意,此步骤中使用的密钥是客户端/站点密钥。

  1. 最后,我们需要在添加广告牌视图中验证 reCAPTCHA,如下所示:
def addbill(request):
    if request.POST:
        recaptcha_response = request.POST.get('g-recaptcha-response')
        url = 'https://www.google.com/recaptcha/api/siteverify'
        values = {  'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
                    'response': recaptcha_response}
        context = ssl._create_unverified_context()
        data = urllib.parse.urlencode(values).encode()
        req = urllib.request.Request(url, data=data)
        response = urllib.request.urlopen(req, context=context)
        result = json.loads(response.read().decode())
        if result['success']:
            # Do stuff if valid
    else:
        # Do actions when no request is made

您可以从这个页面中的上一个代码块中获取addbill方法的完整工作版本。

经过先前的更改,我们终于可以使用所有安全措施来测试运行该网站了。 运行以下命令以启动网站服务器:

python manage.py runserver

您应该能够看到网站的登录页面,如下所示:

请注意,此时,您将需要同时运行执行登录验证的 Flask 服务器。

登录后,您将看到在广告牌页面上贴有账单的页面。 转到“添加帐单”按钮以添加新帐单,如下所示:

请注意屏幕右下角的 reCAPTCHA 徽标。 这表明使用 reCAPTCHA 保护了页面免受垃圾邮件的侵扰。 如果您能够成功过帐,则显示已提交的帐单的广告牌。 否则,您将面临 reCAPTCHA 验证挑战。

Cloudflare 的网站安全

Cloudflare 是业界领先的 Web 基础架构和网站安全提供商。 它在网站及其用户之间创建了一层安全性和快速的内容交付,从而通过其服务器路由所有流量,从而实现了网站的安全性和其他功能。 2017 年,Cloudflare 为超过 1200 万个网站提供了 DNS 服务。 这些服务包括内容交付网络,分布式拒绝服务DDoS)攻击保护,黑客尝试保护以及其他互联网安全服务,例如水浸保护。

2014 年,Cloudflare 报告减轻了对客户的 400 Gib/s DDoS 攻击,随后不久又于次年进行了 500 Gib/s 的攻击。 在记录的任何网站上,最大的攻击是在 GitHub 上,该站点面临 1.4Tb/s 的 DDoS 泛洪。 GitHub 使用的是 Akamai Prolexic(Cloudflare 的替代产品),并且能够承受攻击,仅下降了 10 分钟,然后完全恢复正常。 Cloudflare 免费为其所有用户提供 DDoS 防护。

要开始在您的网站上部署 Cloudflare 服务,您需要将 Cloudflare 设置为用户和托管服务器之间的中间层。 下图描述了 Cloudflare 如何位于网络上:

因此,Cloudflare 会自动在基本范围内(通过 Google 的 reCAPTCHA 帮助我们检测以前创建了自定义解决方案的垃圾邮件和恶意用户)(在免费层中,在更高层中具有更强大的解决方案) 升级时)。 因此,对于一小群开发人员而言,将他们的安全需求推向 Cloudflare 的系统并确保他们免受许多安全漏洞的侵害是非常直观和简单的。

总结

在本章中,我们了解了如何使用 Cloudflare 的服务为网站提供安全性。 我们还看到了如何创建可与 Web 应用和其他安全服务(例如 reCAPTCHA)集成使用的安全 API。 任何规模的网站都必须采取这些安全措施,以使其网站服务正常运行,这一点至关重要。 近年来发生了重大漏洞,而 AI 驱动系统尝试了无数漏洞,这些漏洞由于不是问题而没有成为新闻。 使用深度学习进行安全性研究是一个紧迫的话题,并且相信在不久的将来,安全系统都将完全依靠深度学习来识别和消除威胁。

在下一章中,我们将讨论如何建立生产级深度学习环境。 我们将讨论您可以遵循的架构设计,具体取决于它们的大小要求以及最新的服务提供商和工具。

十一、DIY - Web DL 生产环境

在先前的章节中,我们了解了如何使用一些著名的深度学习DL)平台,例如 Amazon Web ServicesAWS) , Google Cloud PlatformGCP)和 Microsoft Azure,以在我们的 Web 应用中启用 DL。 然后,我们看到了如何使用 DL 使网站安全。 但是,在生产中,挑战通常不仅是建立预测模型,当您要更新已经向用户发送响应的模型时,就会出现真正的问题。 在替换模型文件的 30 秒或 1 分钟内,您可能损失多少时间和业务? 如果有为每个用户定制的模型怎么办? 这甚至可能意味着数十亿美元的模型用于 Facebook 之类的平台。

您需要确定的解决方案来更新生产中的模型。 另外,由于摄取的数据可能不是采用训练的格式,因此您需要定义数据流,以便以无缝方式将其变形以供使用。

在本章中,我们将讨论更新生产模型的方法以及选择每种方法的思路。 我们将从简要概述开始,然后演示一些用于创建 DL 数据流的著名工具。 最后,我们将实现自己的在线学习或增量学习演示,以建立更新生产模型的方法。

我们将在本章介绍以下主题:

  • 生产方法中的 DL 概述
  • 在生产中部署 ML 的流行工具
  • 实现 DL Web 生产环境演示
  • 将项目部署到 Heroku
  • 安全性,监视和表现优化

技术要求

您可以在这个页面上访问本章的代码。

您需要以下软件来运行本章中使用的代码:

  • Python 3.6+
  • Flask 1.1.12+

所有其他安装将在本章中进行。

生产方法中的 DL 概述

无论是 DL 还是经典的机器学习ML),在生产中使用模型时,都会遇到挑战。 主要原因是数据助长了机器学习,并且数据会随着时间而变化。 在生产中部署 ML 模型时,由于数据会随着时间不断变化,因此会每隔一定间隔对其进行重新训练。 因此,当您考虑基于生产的目的时,对 ML 进行再训练不是奢侈的事情,而是必需品。 DL 只是 ML 的一个子字段,它也不例外。 机器学习模型有两种流行的训练方法:批量学习和在线学习,尤其是在生产中。

我们将在下一部分中讨论在线学习。 在本节中,让我们自我介绍批量学习的概念。 在批量学习中,我们首先在特定数据块上训练 ML 模型,然后在对该数据块进行训练后,再为模型提供下一个数据块,此过程将继续进行,直到所有数据块都用完为止。 这些块称为批量。

在现实生活中的项目中,您将一直在处理大量数据。 一次将这些数据集放入内存中并不理想。 在这种情况下,批量学习对我们有帮助。 使用批量学习有一些缺点,我们将在下一节中介绍它们。 您可能想知道(也可能不是),但是是的,只要在本书中训练神经网络,我们就会执行批量学习。

就像训练一样,批量的概念也可以应用于服务 ML 模型。 在这里服务 ML 模型意味着使用机器模型对看不见的数据点进行预测。 这也称为推理。 现在,模型服务可以分为两种类型:在线服务和在线服务,其中在线服务需要在模型与数据点相遇时做出预测(在这里我们无法承受延迟),离线服务则首先需要收集一批数据点,然后通过模型运行批量以获得预测。 请注意,在第二种情况下,我们可以选择一些延迟。

请注意,还有一些工程方面直接与生产 ML 系统相关。 讨论这些内容不在本书的讨论范围之内,但是 GCP 小组鼓励您在线查看课程。

让我们尝试使用下图总结并进一步理解前面的讨论:

此图描述了 AI 后端的要求以及可能影响您选择的解决方案选择的各种参数。 我们将在下一节中讨论该图中所有可用的方面和选择。

因此,我们在生产中的 DL 实现中通常可以找到四种主要类型的解决方案:

  • Web API 服务
  • 在线学习
  • 批量预测
  • AutoML

让我们详细研究它们中的每一个。

Web API 服务

我们有一个模型,该模型由后端上的单独脚本训练,然后存储为模型,然后部署为基于 API 的服务。 在这里,我们正在寻找一种按需产生结果,但训练是离线进行的解决方案(不在负责响应客户端查询的那部分代码的执行范围内)。 Web API 一次响应单个查询并产生单个结果。

迄今为止,这是在生产中部署 DL 的最常用方法,因为它允许数据科学家离线进行准确的训练,并使用简短的部署脚本来创建 API。 在本书中,我们主要进行了这种部署。

在线学习

通过后端进行的按需预测的另一种形式是在线学习。 但是,在这种方法中,学习是在服务器脚本执行期间进行的,因此该模型随每个相关查询而不断变化。 尽管这种方法是动态的并且不太可能过时,但它通常不如静态的 Web API 准确。 在线学习也一次产生一个结果。

在本章中,我们演示了在线学习的示例。 在接下来的部分中,我们将讨论有助于在线学习的工具。

批量预测

在这种方法中,许多预测一次完成并存储在服务器上,随时可以在用户需要时提取和使用。 但是,作为静态训练方法,此方法允许离线训练模型,因此类似于 Web API,为训练提供了更高的准确率。

换句话说,批量预测可以理解为 Web API 的批量版本。 但是,API 不提供这些预测。 相反,预测是从数据库中存储和获取的。

AutoML

进行预测只是将 DL 投入生产的整个过程的一部分。 数据科学家还负责清理和组织数据,创建管道以及进行优化。 Auto ML 是一种无需执行此类重复任务的方法。

Auto ML 是一种批量预测方法,无需人工干预。 因此,数据通过管道传递,并且定期更新预测。 因此,此方法比批量预测方法提供了更多最新的预测。

现在让我们讨论一些工具,这些工具可以快速实现我们介绍的某些方法。

在生产中部署 ML 的流行工具

在本节中,我们将讨论一些用于将 ML 放入生产系统中的流行工具。 这些工具提供的核心工具是使学习-预测-反馈流程自动化,并有助于监视模型的质量和表现。 尽管很有可能为此创建自己的工具,但强烈建议您根据软件要求使用以下任何工具。

让我们开始讨论creme

creme

creme是一个 Python 库,可让我们有效地执行在线学习。 在实际研究creme之前,让我们简要讨论一下在线学习本身:

在在线学习中,机器学习模型一次只针对一个实例进行训练,而不是针对一批数据进行训练(这也称为批量学习)。 为了能够欣赏在线学习的使用,了解批量学习的弊端很重要:

  • 在生产中,我们需要随着时间的推移在新数据上对 ML 模型进行重新训练。 批量学习迫使我们这样做,但这是有代价的。 代价不仅在于计算资源,还在于从头开始重新训练模型的事实。 从头开始训练模型在生产环境中并不总是有用的。
  • 数据的特征和标签会随时间变化。 批量学习不允许我们训练可以支持动态特征和标签的 ML 模型。

这正是我们需要使用在线学习的地方,这使我们能够执行以下操作:

  • 一次仅使用一个实例训练 ML 模型。 因此,我们将不需要大量数据来训练 ML 模型。 可以使用可用的数据立即对其进行训练。
  • 使用动态特征和标签训练 ML 模型。

在线学习还有其他几个名称,但是它们都具有相同的作用:

  • 增量学习
  • 顺序学习
  • 迭代学习
  • 核心学习

如前所述,creme是用于执行在线学习的 Python 库。 保留在 ML 工具箱中是一件非常有用的事情,尤其是在处理生产环境时。 creme受 scikit-learn(这是 Python 中非常流行的 ML 库)的启发,它非常易于使用。 要全面了解creme,建议您在这个页面上查看creme的官方 GitHub 存储库。

够说话了! 让我们继续,首先安装creme。 可以通过使用以下命令来完成:

pip install creme

要获取creme的最新版本,可以使用以下命令:

pip install git+https://github.com/creme-ml/creme
# Or through SSH:
pip install git+ssh://git@github.com/creme-ml/creme.git

通过执行以下步骤,让我们看一个简单的示例:

  1. 我们首先从creme模块进行一些必要的导入:
from creme import compose
from creme import datasets
from creme import feature_extraction
from creme import metrics
from creme import model_selection
from creme import preprocessing
from creme import stats
from creme import neighbors

import datetime as dt

请注意,creme的命名约定与sklearn库的命名约定相似,以提供更轻松的迁移体验。

  1. 然后,我们将creme模块本身提供的数据集提取到数据变量中:
data = datasets.Bikes()

我们将处理此数据集,其中包含有关骑车共享的信息。

尽管数据集包含在creme库中,但您可以在这个页面上了解有关此数据集的更多信息。

  1. 接下来,我们使用creme构建管道,如下所示:
model = compose.Select("humidity", "pressure", "temperature")
model += feature_extraction.TargetAgg(by="station", how=stats.Mean())
model |= preprocessing.StandardScaler()
model |= neighbors.KNeighborsRegressor()

注意使用|=+=运算符。 creme使使用这些运算符成为可能,这使得对数据管道的理解非常直观。 通过使用以下命令,我们可以获得在前面的代码块中构建的管道的详细表示:

model

上一条命令的输出如下所示:

Pipeline([('TransformerUnion', TransformerUnion (
 Select (
 humidity
 pressure
 temperature
 ),
 TargetAgg (
 by=['station']
 how=Mean ()
 target_name="target"
 )
 )), ('StandardScaler', StandardScaler (
 with_mean=True
 with_std=True
 )), ('KNeighborsRegressor', KNeighborsRegressor([]))])

我们还可以使用以下命令来直观地看到该管道:

model.draw()

这将产生以下图形:

  1. 最后,我们运行训练并以数据集的每 30,000 行间隔获取得分指标。 在生产服务器上,此代码将导致每 1 分钟进行批量预测:
model_selection.progressive_val_score(
 X_y=data,
 model=model,
 metric=metrics.RMSE(),
 moment='moment',
 delay=dt.timedelta(minutes=1),
 print_every=30_000
)

因此,creme凭借清晰的语法和调试功能,可以非常轻松地在生产中创建批量预测和在线学习部署。

现在,我们将讨论另一个流行的工具 -- Airflow。

Airflow

作为一名有效的 ML 练习者,您将需要以编程方式处理诸如上一个工作流之类的工作流,并且还必须能够使其自动化。 Airflow 为您提供了一个有效执行此操作的平台。 此链接是摘自 Airflow 的官方网站。 Airflow 是一个用于以编程方式编写,安排和监视工作流的平台。

这样做的主要优点是,有向无环图DAG)上表示的任务可以轻松地分布在可用资源(通常称为工作器)上。 这也使可视化整个工作流变得更加容易,这非常有帮助,尤其是当工作流非常复杂时。 如果您需要复习 DAG,请访问这个页面中的文章。 当您很快看到此实现时,这将变得更加清晰。

在设计 ML 工作流程时,您需要考虑许多不同的事物,例如:

  • 数据收集管道
  • 数据预处理管道
  • 使数据可用于 ML 模型
  • ML 模型的训练和评估管道
  • 模型的部署
  • 监控模型以及其他内容

现在,让我们继续执行以下行来安装 Airflow:

pip install apache-airflow

尽管 Airflow 是基于 Python 的,但是绝对可以使用 Airflow 来定义为不同任务包含不同语言的工作流。

安装完成后,您可以调用 Airflow 的管理面板并查看其上的 DAG 列表,以及对其进行管理并触发许多其他有用的功能,如下所示:

  1. 为此,您必须首先初始化数据库:
airflow initdb
  1. 您应该看到在SQLite3数据库上创建了许多表。 如果成功,您将能够使用以下命令启动 Web 服务器:
airflow webserver

在浏览器中打开http://localhost:8080。 您将看到一个屏幕,如以下屏幕截图所示:

提出了许多示例 DAG。 您可以尝试运行它们以进行简短播放!

现在让我们讨论一个非常流行的工具,称为 AutoML。

AutoML

DL 或 AI 解决方案不仅限于在 Jupyter 笔记本中构建工业应用中的尖端精确模型。 形成 AI 解决方案需要几个步骤,首先是收集原始数据,将数据转换为可用于预测模型的格式,创建预测,围绕模型构建应用以及在生产中监视和更新模型。 AutoML 旨在通过自动化预部署任务来自动化此过程。 通常,AutoML 主要是关于数据编排和贝叶斯超参数优化。 AutoML 有时仅表示完全自动化的学习渠道。

H2O.ai提供了一个可用于 AutoML 的著名库,称为H2O.AutoML。 要使用它,我们可以使用以下命令进行安装:

# Using Conda installer
conda install -c h2oai h2o

# Using PIP installer
pip install -f http://h2o-release.s3.amazonaws.com/h2o/latest_stable_Py.html h2o

H2O.AutoML的语法与其他流行的 ML 库相似,因此非常易于理解。

实现 DL Web 演示环境

现在,我们将深入研究构建示例生产应用,该应用在后端使用在线学习。 我们将基于 Cleveland 数据集创建一个可以预测心脏病的应用。 然后,我们将将此模型部署到基于云容器的服务 Heroku。 最后,我们将演示该应用的在线学习功能。

您可以通过这里来找到有关 Heroku 的更多信息。

让我们列出我们将涉及的步骤:

  1. 在 Jupyter 笔记本上建立预测模型。
  2. 为 Web 应用构建一个可以预测保存的模型的后端。
  3. 为 Web 应用构建一个前端,该前端在模型上调用增量学习。
  4. 在服务器端逐步更新模型。
  5. 将应用部署到 Heroku。

我们将从第零步开始; 也就是说,观察数据集。

UCI 心脏病数据集包含 303 个样本,每个样本具有 76 个属性。 但是,有关数据集的大多数研究工作都集中在具有 13 个属性的克利夫兰数据集的简化版本上,如下所示:

  • 年龄
  • 性别
  • 胸痛类型:
    • 典型的心绞痛
    • 非典型心绞痛
    • 非心绞痛
    • 无症状
  • 静息血压
  • 血清胆固醇,mg/dl
  • 空腹血糖 >120 mg/dl
  • 静息心电图结果:
    • 正常
    • 患有 ST-T 波异常(T 波倒置和/或 ST 升高或降低 >0.05 mV)
    • 根据 Estes 的标准显示的可能或确定的左心室肥大
  • 达到最大心率
  • 运动诱发的心绞痛
  • Oldpeak:运动引起的相对于休息的 ST 抑制
  • 运动高峰的 ST 段的斜率
  • 荧光检查着色的主要血管数目(0-3)
  • Thal:3:正常;6:固定缺陷;7:可逆缺陷

最后会有一列,这是我们将要预测的目标。 这将使当前问题在正常患者和受影响患者之间进行分类。

您可以在这个页面上了解有关克利夫兰数据集的更多信息。

现在让我们开始构建心脏病检测模型。

建立预测模型

在本小节中,我们将从使用 Keras 构建简单的神经网络开始,该网络将从给定的输入中分类患者患心脏病的可能性。

步骤 1 – 导入必要的模块

我们首先导入所需的库:

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
np.random.seed(5)

我们已经导入了pandasnumpy模块。 伴随着这些,我们从 scikit-learn 库中导入了train_test_split方法,以帮助我们将数据集快速分为训练和测试部分。

步骤 2 – 加载数据集并观察

让我们加载数据集,假设它存储在名为data的文件夹中,该文件夹与包含 Jupyter 笔记本的目录位于同一目录级别:

df = pd.read_csv("data/heart.csv")

我们将快速观察DataFrame以查看是否所有列均已正确导入:

df.head(5)

这将在 Jupyter 笔记本中产生以下输出:

我们可以观察到这 14 列,并查看它们是否已正确导入。 基本的探索性数据分析EDA)将显示该数据集不包含任何缺失值。 但是,原始的 UCI 克利夫兰数据集确实包含与我们使用的版本相反的缺失值,该版本已经过预处理,可以在互联网上以这种形式轻松获得。 您可以在 GitHub 上本章的存储库中找到它的副本

步骤 3 – 分离目标变量

现在,我们将从数据集中拼接出目标变量,如下所示:

X = df.drop("target",axis=1)
y = df["target"]

接下来,我们将对特征进行缩放。

步骤 4 – 对特征执行缩放

正如您可能在上一步的数据集样本中观察到的,训练列中的值不在相同或可比较的范围内。 我们将在列上执行缩放以使它们达到统一的范围分布,如下所示:

from sklearn.preprocessing import StandardScaler

X = StandardScaler().fit_transform(X)

目标在01的范围内,因此不需要缩放。

步骤 5 – 将数据集分为测试和训练数据集

然后,使用下面的代码行将数据集分为训练和测试部分:

X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.20,random_state=0)

我们已将 20% 的数据集分配给测试目的。

步骤 6 – 在 sklearn 中创建神经网络对象

接下来,我们通过实例化MLPClassifier对象的新对象来创建分类器模型的实例:

from sklearn.neural_network import MLPClassifier

clf = MLPClassifier(max_iter=200)

我们已将最大迭代次数设置为200。 如果收敛较早发生,则可能无法实现。

步骤 7 – 执行训练

最后,我们进行训练并注意观察到的方法的准确率:

for i in range(len(X_train)):
    xt = X_train[i].reshape(1, -1)
    yt = y_train.values[[i]]
    clf = clf.partial_fit(xt, yt, classes=[0,1])
    if i > 0 and i % 25 == 0 or i == len(X_train) - 1:
        score = clf.score(X_test, y_test)
        print("Iters ", i, ": ", score)

Jupyter 笔记本中前面代码块的输出如下:

我们可以看到,在对处理后的数据集中的所有 241 个样本进行训练之后,预期准确率将达到 83.60%。 注意前面代码块中的partial_fit方法。 这是模型的一种方法,可以将简单的样本拟合到模型中。 实际上,更常用的fit方法是partial_fit方法的包装器,迭代整个数据集并在每次迭代中训练一个样本。 它是我们使用 scikit-learn 库进行的增量学习演示的最有用的部分之一。

为了快速查看模型提供输出的格式,我们运行以下代码块:

# Positive Sample
clf.predict(X_test[30].reshape(-1, 1).T)

# Negative Sample
clf.predict(X_test[0].reshape(-1, 1).T)

获得以下输出:

注意,预测输出为0的样本表示该人没有心脏病,而输出为1的样本表示该人患有心脏病。

现在,我们将开始将此 Jupyter 笔记本转换为可以按需执行增量学习的脚本。 但是,我们将首先构建该项目的前端,以便我们可以从后端了解需求。

实现前端

我们将在这里采用一种自下而上的方法,并首先设计示例应用的前端。 这样做只是为了理解为什么我们在后端脚本中编写一些方法与前面几章中的方法有所不同。 很明显,在开发实际应用时,首先要创建后端脚本。

我们将有一个非常简化的前端,仅包括一个调用应用增量训练的按钮和一个占位符,用于显示在给定数量的样本下训练的模型的准确率得分。

让我们快速浏览一下我们正在构建的内容:

您可能会从我们将要构建的应用的上述屏幕截图中解释,我们将有两个按钮-一个将训练数据集中的训练样本中的 25 个样本添加到部分训练的模型中,另一个将训练重置为 0 个样本(即, 实际上,在实现中使用 1 个样本,以避免由 0 引起的常见错误;但这对演示的影响很小。

让我们创建一个名为app的 Flask 项目文件夹。 然后,我们创建templates文件夹并在其中创建index.html。 在app文件夹中创建另一个名为app.py的文件。 我们将在此文件夹中创建更多文件,以在 Heroku 上进行部署。

我们不会编写index.html文件的完整代码,但是我们将看看通过 Ajax 触发器调用后端 API 的两个函数。

您可以在这个页面中找到完整的代码。

观察index.html中的109116行:

.... 
$("#train-btn").click(function() {
     $.ajax({
         type: "POST",
         url: "/train_batch",
         dataType: "json",
         success: function(data) {
             console.log(data);
....

前面的 JavaScript(jQuery)代码片段在具有train-btn ID 的按钮上创建了click处理器。 它在后端调用/train_batch API。 我们将在开发后端时创建此 API。

此文件中另一个有趣的代码块是138145行:

....
$("#reset-btn").click(function() {
     $.ajax({
         type: "POST",
         url: "/reset",
         dataType: "json",
         success: function(data) {
             console.log(data);
....

在这里,我们在具有reset-btn ID 的按钮上设置了click处理器,以向/reset API 发出请求。 这是增量学习的一个容易被遗忘的方面,它要求减少训练。 也就是说,它将训练后的模型重置为未训练状态。

现在,我们知道了需要在后端构建的 API。 让我们在下一部分中构建它们!

实现后端

在本节中,我们将创建所需的 API 以及用于演示的服务器脚本。 编辑项目根文件夹中的app.py文件:

  1. 首先,我们将对脚本进行一些必要的导入:
from flask import Flask, request, jsonify, render_template

import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neural_network import MLPClassifier

np.random.seed(5)

请注意,此处的导入与我们在 Jupyter 笔记本中创建模型时进行的导入非常相似。 这是由于我们仅将 Jupyter 笔记本代码转换为用于后端演示的服务器脚本这一事实而解释的。

  1. 然后,我们将数据集加载到 pandas DataFrame上:
df = pd.read_csv("data/heart.csv")
  1. 我们将快速遍历其余代码,在其中拆分数据集,缩放列并在一定数量的样本上训练模型:
X = df.drop("target",axis=1)
y = df["target"]

X = StandardScaler().fit_transform(X)
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.20,random_state=0)

clf = MLPClassifier(max_iter=200)

for i in range(100):
    xt = X_train[i].reshape(1, -1)
    yt = y_train.values[[i]]
    clf = clf.partial_fit(xt, yt, classes=[0,1])
    if i > 0 and i % 25 == 0 or i == len(X_train) - 1:
        score = clf.score(X_test, y_test)
        print("Iters ", i, ": ", score)

注意,在前面的代码中,我们在数据集中的100样本上训练模型。 这将使模型相当准确,但显然还有改进的余地,我们将使用/train_batch API 触发该改进,该 API 将为模型训练增加 25 个样本。

  1. 让我们设置一些变量来使用脚本,以及实例化Flask服务器对象:
score = clf.score(X_test, y_test)

app = Flask(__name__)

start_at = 100
  1. 现在,我们将创建/train_batch API,如下所示:
@app.route('/train_batch', methods=['GET', 'POST'])
def train_batch():
    global start_at, clf, X_train, y_train, X_test, y_test, score
    for i in range(start_at, min(start_at+25, len(X_train))):
        xt = X_train[i].reshape(1, -1)
        yt = y_train.values[[i]]
        clf = clf.partial_fit(xt, yt, classes=[0,1])

    score = clf.score(X_test, y_test)

    start_at += 25

    response = {'result': float(round(score, 5)), 'remaining': len(X_train) - start_at}

    return jsonify(response)

train_batch()函数通过25样本或数据集的其余样本来增加对模型的学习。 它返回数据集 20% 测试分割上模型的当前分数。 再次注意用于 25 次迭代的partial_fit方法的用法。

  1. 接下来,我们将创建/reset API,它将模型重置为未训练状态:
@app.route('/reset', methods=['GET', 'POST'])
def reset():
    global start_at, clf, X_train, y_train, X_test, y_test, score
    start_at = 0
    del clf
    clf = MLPClassifier(max_iter=200)
    for i in range(start_at, start_at+1):
        xt = X_train[i].reshape(1, -1)
        yt = y_train.values[[i]]
        clf = clf.partial_fit(xt, yt, classes=[0,1])

    score = clf.score(X_test, y_test)

    start_at += 1

    response = {'result': float(round(score, 5)), 'remaining': len(X_train) - start_at}

    return jsonify(response)

该 API 再次返回重置后的模型得分。 假设数据集在其类别中是平衡的,这应该是预期的(非常差)。

  1. 现在让我们编写代码来启动此应用的 Flask 服务器:
@app.route('/')
def index():
    global score, X_train
    rem = (len(X_train) - start_at) > 0

    return render_template("index.html", score=round(score, 5), remain = rem)

if __name__ == '__main__':
    app.run()
  1. 完成此操作后,我们准备通过从控制台运行该应用来测试该应用是否正常运行。 为此,请打开一个新的终端窗口,然后在app目录中输入以下命令:
python app.py

服务器运行后,您可以在http://localhost:5000上查看应用。

最后,我们将项目部署到 Heroku。

将项目部署到 Heroku

在本节中,我们将研究如何将演示应用部署到 Heroku。 在以下步骤中,我们将在 Heroku 上创建一个帐户,并将所需的修改添加到代码中,从而使其有资格在平台上托管:

  1. 首先,访问这里以获取 Heroku 的登录屏幕。 如果您还没有用户帐户,则可以完成注册过程以免费创建一个:

  1. 现在,我们将创建一个Procfile文件。 在此步骤中,我们在app目录中创建一个名为Procfile的空白文件。 创建完成后,我们向其添加以下行:
web: gunicorn app:app

该文件在将项目部署到 Heroku 的过程中使用。 上一行指示 Heroku 系统使用gunicorn服务器并运行名为app.py的文件。

  1. 然后,我们冻结项目的需求。 Heroku 寻找requirements.txt文件来自动下载并安装项目所需的包。 要创建需求列表,请在终端中使用以下命令:
pip freeze > requirements.txt

这将在项目的根文件夹中名为requirements.txt的文件中创建包列表。

您可能要保留一些包,使其不包含在requirements.txt文件中。 处理此类项目的一个好方法是使用虚拟环境,以便环境中仅提供所需的包,因此requirements.txt仅包含它们。 但是,此解决方案可能并不总是可行的。 在这种情况下,请随时手动编辑requirements.txt并删除包含与项目无关的包的行。

该项目的目录结构当前应如下所示:

app/
---- templates/
-------- index.html
---- Procfile
---- requirements.txt
---- app.py
  1. 现在,我们需要在本地系统上安装 Heroku CLI。 按照这里提供的说明在系统上安装 Heroku。
  2. 接下来,我们将在目录上初始化git。 为此,请在项目的根目录中使用以下命令:
git init
  1. 然后,我们在项目上初始化 Heroku 版本管理。 我们打开一个终端窗口,然后导航到项目目录。 使用以下命令初始化 Heroku 为该项目提供的版本管理器,并将其注册到您当前登录的用户中:
heroku create

该命令将通过显示将承载您的项目的 URL 结束。 随之显示.git URL,该 URL 用于跟踪项目的版本。 您可以从此.git URL 推/拉,以更改项目并触发重新部署。 输出将类似于以下内容:

https://yyyyyy-xxxxxx-ddddd.herokuapp.com/ | https://git.heroku.com/yyyyyy-xxxxxx-ddddd.git
  1. 接下来,我们将文件添加到git并推送到 Heroku。 现在您可以将文件推送到 Heroku git项目进行部署。 我们使用以下命令:
git add .
git commit -m "some commit message"
git push heroku master

这将创建部署,您将看到很长的输出流。 流是项目部署期间发生的事件的日志,包括安装包,确定运行时以及启动监听脚本。 获得成功的部署消息后​​,您将能够在上一步中的 Heroku 提供的 URL 上查看您的应用。 如果您不记得它,可以使用以下命令来触发它从终端在浏览器中打开:

heroku open

现在,您应该在默认浏览器中看到带有已部署代码的新窗口或选项卡打开。 如果发生任何问题,您将能够在 Heroku 仪表板中看到部署日志,如下所示:

这是在部署本章中介绍的代码时来自失败构建的实际屏幕截图。 您应该能够在日志末尾找出错误。

如果构建成功部署,您将在日志末尾看到成功部署消息。

安全措施,监控技术和表现优化

在本节中,我们将讨论可以集成到生产中的 DL 解决方案中的安全措施,监视技术和表现优化。 这些功能对于维护依赖于 AI 后端的解决方案至关重要。 虽然我们在前面的章节中讨论了 DL 所促进的安全方法,但我们将讨论可能对 AI 后端造成的安全威胁。

对 AI 后端的最大安全威胁之一是来自嘈杂的数据。 在生产中使用 AI 的大多数方法中,定期检查训练数据集中是否有新类型的噪声非常重要。

对于所有喜欢 Python pickle库的开发人员来说,这是一条非常重要的信息:

上面的屏幕截图来自官方 Python 文档

为了演示一个简单的示例,说明为什么在生产中进行酸洗可能会很危险,请考虑以下 Python 代码:

data = """cos
    system
    (S'rm -ri ~'
    tR.
"""

pickle.loads(data)

前面的代码所做的很简单-它试图清除您的主目录。

警告:任何运行上述代码的人应对其操作结果承担全部责任。

前面的示例和相关警告暗示了 AI 后端和几乎每个自动化系统中的一般安全威胁-不可信输入的危害。 因此,重要的是要正确验证可能在模型中输入的任何数据(无论是在训练还是测试中),以确保不会对系统造成任何严重问题。

对生产中的模型进行连续监视也很重要。 模型通常会过时和过时,并且冒着过一会儿做出过时的预测的风险。 重要的是要检查 AI 模型所做的预测的相关性。 考虑一个只了解 CD-ROM 和软盘的人。 随着时间的流逝,我们想到了 USB 驱动器和固态磁盘。 此人将无法对最近的设备做出任何明智的决定。 同样,从 2000 年代初开始针对​​文本转储训练的自然语言处理NLP)模型将无法理解有人问Can you please WhatsApp me the wiki link for Avengers: Endgame?的对话。

最后,您如何才能对 AI 后端的表现进行优化?

Web 开发人员最关心这个问题。 生产中的所有东西都必须快如闪电。 加快生产中 AI 模型速度的一些技巧如下:

  • 将数据集分解为可以进行准确预测的最少数量的特征。 这是由几种算法(例如主成分分析和其他启发式方法)执行的特征选择的核心思想。 通常,并非所有输入到系统中的数据都是相关的,或者仅是稍微相关的,才能基于该数据进行预测。
  • 考虑将模型托管在启用了自动缩放功能的单独的功能强大的云服务器上。 这将确保您的模型不会在为网站的页面提供服务时浪费资源,而只会处理基于 AI 的查询。 自动缩放将解决后端工作负载突然增加或急剧减少的问题。
  • 在线学习和自动 ML 方法受数据集大小的影响而变得缓慢。 确保您有适当的约束条件,不允许动态学习系统搅动的数据量爆炸。

总结

在本章中,我们介绍了可用于在生产中部署 DL 模型的方法。 我们详细研究了不同的方法以及一些著名的工具,这些工具有助于简化在此处的生产部署和模型管理。 我们介绍了使用 Flask 和sklearn库进行在线学习的示例。 我们还讨论了部署后的条件以及一些最常见任务的示例。

在下一章中,我们将使用集成到网站中的 Dialogflow 演示端到端示例应用(客户支持聊天机器人)。

十二、使用 DL API 和客户支持聊天机器人创建 E2E Web 应用

在本章中,我们将汇总在本书前几章中已学会使用的几种工具和方法,并介绍一些出色的新工具和技术。 本章涵盖企业的一个非常重要的方面-客户支持。 对于一家新兴企业,客户支持会不断精疲力竭,难以跟上。 通常,通过参考文档或公司在其网站上提供的一组常见问题解答,可以轻松回答客户提出的问题,但是客户通常不会仔细阅读它们。 因此,最好有一个自动化层,其中最常见的查询将由一个聊天机器人来回答,该聊天机器人在一天中始终可用并且响应迅速。

本章讨论如何使用 Dialogflow 创建聊天机器人来解决一般的客户支持查询,以及如何将其集成到基于 Django 的网站中。 此外,聊天机器人还将从将单独托管的 Django API 中获得答案。 我们将探索实现机器人个性的方法,并介绍一种实现文本到语音TTS)和语音到文本(STT)的用户界面。通过 Web 语音 API,该接口将神经网络直接部署到用户的浏览器。

我们将在本章介绍以下主题:

  • NLP 简介

  • 聊天机器人简介

  • 创建具有客户支持代表个性的 Dialogflow 机器人

  • 使用 ngrok 促进本地主机上的 HTTPS API

  • 使用 Django 创建测试 UI 来管理公司内的订单

  • 使用 Web Speech API 在网页上进行语音识别和语音合成

我们将从先前各章中学到的知识中汲取见识,并在此基础上加以借鉴,同时修改一些概念并在此过程中引入新的概念。 让我们从理解自然语言处理NLP)开始。

技术要求

您可以在这个页面上访问本章的代码。

您需要以下软件来运行本章中使用的代码:

  • Python 3.6+
  • Django 2.x

本章将介绍所有其他安装。

NLP 简介

NLP 是机器学习和深度学习应用中最受欢迎的也是最令人兴奋的领域之一,它是指为理解和生成人类语言而开发的一系列技术和方法。 NLP 的目标始于理解人类语言文本的含义,并扩展到生成人类语言,从而使生成的句子有意义并且对阅读该文本的人类有意义。 NLP 已在构建系统中找到了主要用途,该系统能够以自然语言的形式直接从人类接收指令和请求,例如聊天机器人。 但是,聊天机器人还需要以自然语言进行响应,这是 NLP 的另一个方面。

让我们研究一些与 NLP 相关的常用术语。

语料库

在学习 NLP 时,您经常会遇到语料库。 用外行的术语来说,语料库是任何一位作者或文学体裁的著作的集合。 在 NLP 的研究中,对语料库的词典定义进行了一些修改,可以表示为书面文本文档的集合,以便可以通过任何选择的度量将它们全部归类。 这些指标可能是作者,出版者,类型,写作类型,时间范围以及与书面文本相关的其他特征。

例如,莎士比亚作品集或任何论坛上针对任何给定主题的话题都可以被视为语料库。

词性

当我们将一个句子分解成其组成词,并对该句子中每个词对句子整体含义的贡献进行定性分析时,我们执行确定词性的动作。 因此,词性是基于句子中单词对句子含义的贡献而提供给它们的符号。

在英语中,我们通常有八种类型的词性-动词,名词,代词,形容词,副词,介词,连接词和感叹词。

例如,在句子Ram is reading a book.中,Ram是名词和主语,reading是单词和动作,而book是名词和宾语。

您可以在这个页面上阅读有关词性的更多信息。 您可以尝试在这个页面上找出自己句子的词性。

分词

分词是将文档分解为句子并将句子分解为单词的过程。 这很重要,因为如果任何计算机程序都试图将整个文档作为单个字符串处理,这将是计算上的噩梦,因为与处理字符串相关的资源密集型。

此外,非常罕见的是,需要一次阅读所有句子才能理解整个文档的含义。 通常,每个句子都有自己独立的含义,可以通过统计方法将其与文档中的其他句子同化,以确定任何文档的整体含义和内容。

同样,我们经常需要将句子分解为单词,以便更好地处理句子,以便可以概括句子的含义并从其中每个单词单独列出的字典中导出。

词干提取和词形还原

在 NLP 中,词干提取和词形还原是紧密相关的术语,但有细微但显着的差异。 两种方法的目的都是确定任何给定单词所源自的词根,以便该词根的任何派生词都可以与字典中的词根匹配。

词干提取是一个基于规则的过程,在该过程中,单词会被修剪,有时还会附加指示其词根的修饰符。 但是,词干提取有时可能会产生人类词典中不存在的词根,因此对人类读者毫无意义。

词形还原是将单词转换为词典中给出的词形或词根的过程。 因此,单词的最初含义可以从人类词典中获得,使词形还原的文本比词干提取的文本更易于使用。 此外,词形还原在确定其正确的词性之前考虑了词在任何给定句子中的词性,词干提取算法会忽略该词性。 使得词形还原比词干提取更具有上下文感知能力。

词袋

计算机不可能直接处理和使用文本。 因此,在将所有文本输入机器学习模型之前,必须将其转换为数字。 将文本更改为数字数组的过程,以便可以在任何时间点从转换后的文本中检索最重要的原始文本,这称为特征提取或编码。 词袋BoW)是一种流行的简单技术,用于对文本执行特征提取。

与 BoW 实现相关的步骤如下:

  1. 从文档中提取所有唯一的单词。
  2. 用文档中所有唯一的单词创建一个向量。
  3. 根据单词向量中是否存在任何单词,将每个文档转换为布尔数组。

例如,考虑以下三个文档:

  1. Ram is a boy.
  2. Ram is a good boy.
  3. Ram is not a girl.

这些文档中存在的唯一词可以在向量中列出为["Ram","is","a","boy","good","not","girl"]

因此,每个句子可以按如下方式转换:

  1. [1, 1, 1, 1, 0, 0, 0]
  2. [1, 1, 1, 1, 1, 0, 0]
  3. [1, 1, 1, 0, 0, 1, 1]

您将观察到 BoW 往往会丢失有关每个单词出现在句子中的位置或其对句子有什么意义的信息。 因此,BoW 是一种非常基本的特征提取方法,可能不适用于需要上下文感知的多个应用。

相似度

相似度是任何两个给定句子的相似度的量度。 它在计算机科学领域以及维护记录的任何地方都是非常流行的操作,用于搜索正确的文档,在任何文档中搜索单词,认证和其他应用。

有两种方法可以计算两个给定文档之间的相似度。 Jaccard 索引是最基本的形式之一,它根据两个文档中相同令牌总数占文档中唯一令牌总数的百分比来计算两个文档的相似性。

余弦相似度是另一个非常流行的相似度指数,通过使用 BoW 或任何其他特征提取技术将两个文档的向量转换为向量后形成的余弦来计算。

考虑到这些概念,让我们继续研究聊天机器人,这是 NLP 最受欢迎的应用形式之一。

聊天机器人简介

聊天机器人是 NLP 应用的一部分,专门处理会话接口。 这些界面还可以扩展其工作以处理基本的命令和动作,在这些情况下,它们被称为基于语音的虚拟助手。 最近,随着专用设备(如 Google 的 Google Home 和 Alexa)的推出,基于语音的虚拟助手正在兴起。

聊天机器人可以以多种形式存在。 他们并不需要仅以虚拟助手的身份出现。 您可以在游戏中与聊天机器人对话,尝试在特定方向绘制故事剧情,也可以与一些公司用来在社交媒体平台(例如 Twitter 或 Facebook)上回复其客户的社交聊天机器人进行交互。 聊天机器人可以看作是在交互式语音响应IVR)系统上移动的系统,它们具有增强的智能和对未知输入的响应能力,有时仅使用回退响应,有时甚至利用提供的输入进行响应。

虚拟助手也可以存在于网站上,为访问者提供指导和帮助。 诸如此类的助手经常在网站上找到,主要是为消费者查询提供即时支持。 您一定已经注意到几个销售产品或服务的网站上的“问问题”或“可以帮助您”聊天框,通常在屏幕的右下角。 他们经常使用自动聊天机器人代替真实的人来回答查询。 仅在查询过于复杂而无法由自动客户支持聊天机器人回答的情况下,查询才会转移到真实的人。

创建对话式 UI 本身就是一门艺术。 您需要能够使用清晰但对口语很自然的单词。 您可以通过这里了解有关创建对话式用户界面的更多信息。

在下一部分中,我们将创建一个充当客户支持智能体的聊天机器人。

创建具有客户支持代表个性的 Dialogflow 机器人

Dialogflow 是用于创建聊天机器人的非常流行的工具。 类似于 Wit.ai,Botpress,Microsoft Bot Framework 和其他一些可用于创建聊天机器人的即时部署服务,Dialogflow 还具有与 Google Cloud PlatformGCP),并可以将 Dialogflow 智能体用作 Google 助手的操作,该助手可在数十亿个 Android 设备上本地运行。

Dialogflow 以前称为 Api.ai。 在被 Google 收购之后,它被重命名,并且自那时以来,它的受欢迎程度和可扩展性都在增长。 该平台可以非常轻松地与多个平台集成,例如 Facebook Messenger,Telegram,Slack,Line,Viber 和其他几个主要的通信平台。

我们将在本章中开发的项目将遵循以下架构图:

我们将使用上图中未提及的几个库和服务。 我们将在项目过程中介绍它们,并讨论为什么对我们了解它们很有趣。

Dialogflow 入门

要开始使用 Dialogflow,您应该访问官方网站,进入首页,该页面显示了产品信息和文档链接。 研究您要学习的任何产品或服务的文档始终是一个好主意,因为它包含软件的全部工作和功能。 我们将在本章的后续部分中参考文档中的部分。

您可以在这个页面上找到 Dialogflow 文档。

Dialogflow 与 GCP 紧密集成,因此我们必须首先创建一个 Google 帐户。 为此,请转到这里创建一个帐户。 如果您是第一次使用 Dialogflow 使用您的帐户,则可能需要为您的 Google 帐户提供许多权限。

让我们继续进行探索和了解 Dialogflow 帐户创建过程以及 UI 各个部分的步骤。

步骤 1 – 打开 Dialogflow 控制台

您需要单击页面右上角的“转到控制台”按钮。 或者,您可以在浏览器中输入https://dialogflow.cloud.google.com/。 如果您是初次使用,您将看到如下屏幕:

仪表板会提示您创建一个新智能体。

第 2 步 - 创建新智能体

现在,我们将创建一个 Dialogflow 智能体。 就 Dialogflow 而言,智能体是聊天机器人的别称。 它是接收,处理和响应用户提供的所有输入的智能体。

单击“创建智能体”按钮,然后根据您的喜好填写有关智能体的必要信息,其中包括智能体的名称,默认语言,时区和 Google 项目名称。

如果您在此步骤之前没有使用过 GCP,则必须创建一个项目。 我们已经在 “第 6 章”,“使用 Python 在 Google Cloud Platform 上进行深度学习”中,讨论了 GCP 项目的创建。 或者,您可以简单地让 GCP 在创建智能体时自动为您创建一个新项目。

步骤 3 – 了解仪表板

成功创建 Dialogflow 智能体后,将为您提供一个仪表板,如以下屏幕截图所示:

在左侧,您可以看到一个菜单,其中包含构成聊天机器人的各种组件。 该菜单将非常有用,您应该仔细阅读其所有内容,以确保您了解菜单项中我们所指的内容。 当我们使用诸如“单击实体”之类的句子时,是指我们希望您单击此菜单中的“实体”项。

中心部分将包含不同的内容,具体取决于单击菜单中的哪个组件。 默认情况下,当您打开 Dialogflow 控制台时,它包含聊天机器人的意图列表。 目的是什么?

意图是用户希望通过对聊天机器人的任何说话来执行的动作。 例如,当用户说Bring me a cup of coffee时,他们的意图是让聊天机器人“喝咖啡”:

在最右边,提供了一个面板来随时测试聊天机器人。 您可以编写任何想要用来测试聊天机器人的响应的输入文本,并且会向您显示一系列信息以及聊天机器人产生的响应。

考虑以下测试输入和响应:

当用户输入What is my order status时,聊天机器人将答复,询问所涉及订单的订单 ID。 这与CheckOrderStatus意图匹配,并且需要名为OrderId的参数。 在开发过程中,我们将在整个项目中定期使用此控制台来调试聊天机器人。

虽然在先前的屏幕截图中,我们已经为您显示了一个带有意图的预配置智能体,但是您新创建的智能体此时将没有任何自定义意图。 让我们创建它们!

步骤 4 – 建立意图

现在,让我们创建两个意图。 一种意图将为用户提供帮助,另一种意图将对用户提供的订单 ID 的状态进行检查。

步骤 4.1 – 创建HelpIntent

在此子步骤中,单击左侧菜单中“意图”项目右侧的+按钮。 您将看到一个空白的意向创建表单。

您可以在意向创建表单中看到以下标题:

为此,在[Intent Name]中填写HelpIntent

现在,按照以下步骤完成此意图创建。

步骤 4.1.1 – 输入HelpIntent的训练短语

现在,我们需要定义可能调用此行动意图的短语。 为此,请单击“训练短语”标题并输入一些样本训练短语,如下所示:

对意图进行任何更改时,请确保单击“保存”。

步骤 4.1.2 – 添加响应

为了以这种意图响应用户查询,我们需要定义可能的响应。 单击“意图创建”表单中的“响应”标题,然后向查询中添加示例响应,如下所示:

保存意图。 一旦完成构建,我们就可以通过输入类似于我们为此目的定义的训练短语的输入来测试聊天机器人。

步骤 4.1.3 – 测试意图

让我们测试HelpIntent。 在右侧测试面板中,输入Can you help me?。 智能体产生以下响应:

请注意上述屏幕截图底部的匹配意图。 由于HelpIntent已成功匹配输入,训练短语中未明确定义该输入,因此我们可以得出结论,该智能体运作良好。

为什么业务代表响应尚未接受过训练的输入很重要? 这是因为在针对特定意图测试座席时,我们希望确保与该训练短语完全或紧密匹配的所有言语都与该意图匹配。 如果它与期望的目的没有紧密相关的查询,则需要提供更多的训练短语,并检查座席的其他任何目的中是否有任何冲突的训练。

现在,我们有一个意图告诉用户该聊天机器人可以做什么—即检查订单状态—现在创建一个可以实际检查订单状态的意图。

步骤 4.2 – 创建CheckOrderStatus意图

单击“创建意图”按钮,然后将意图的名称输入为CheckOrderStatus

步骤 4.2.1 – 输入CheckOrderStatus意图的训练短语

为此,我们输入以下训练短语:

  1. What is the status for order id 12345?
  2. When will my product arrive?
  3. What has happened to my order?
  4. When will my order arrive?
  5. What's my order status?

请注意,第一个训练短语与其他短语不同,因为它包含一个订单 ID。

我们需要能够将其标识为订单 ID,并使用它来获取订单状态。

步骤 4.2.2 – 从输入中提取并保存订单 ID

CheckOrderStatus目的的第一个训练短语中,双击 12345 并弹出一个菜单,如下所示:

选择@sys.number,然后将参数名称输入为OrderId。 您的训练短语如下所示:

但是有时,就像其余的训练短语一样,用户不会在没有提示的情况下提及订单 ID。 让我们添加一个提示以及一种在找到订单 ID 时将其存储的方法。

步骤 4.2.3 – 存储参数并提示是否找到

向下滚动到意图创建表单中的“动作和参数”标题。 输入OrderId作为参数名称和值,然后选中需要的复选框。 以下屏幕截图应类似于您当前屏幕上的屏幕截图:

OrderId参数的右侧,单击“定义提示”以添加此参数的提示。 示例提示可能是Sure, could you please let me know the Order ID? It looks like 12345!

我们希望在出现此提示后,用户一定会说出订单 ID,然后该 ID 将与该意图的第一个训练短语匹配。

此后,我们需要为此目的定义响应。

步骤 4.2.4 – 通过履行CheckOrderStatus意向打开响应

请记住,此意图需要从获得的订单 ID 中获取订单状态。 在这种情况下,恒定的响应集将无法达到目的。 因此,我们将在意图创建表单中使用“实现”标题。

向下滚动并为此目的启用实现方法 Webhook。 现在,此部分应如下所示:

完全填充使您的 Dialogflow 智能体可以查询外部 API,以生成该智能体必须做出的响应。 与智能体接收到的查询相关联的元数据被发送到外部 API,该 API 然后了解并决定需要给出查询的响应。 这对于通过聊天机器人进行动态响应很有用。

现在,我们必须定义此 webhook 来使用订单 ID 处理订单状态的获取。

步骤 5 – 创建一个 webhook

现在,我们将创建一个 Webhook,该 Webhook 将在 Firebase 云控制台上运行并调用一个外部 API,该 API 位于我们的订单管理门户中。

单击菜单栏中的“实现项目”。 系统会为您提供打开 Webhook 或使用 Firebase Cloud Functions 的选项。 打开内联编辑器。 您的屏幕将类似于以下屏幕截图:

我们将自定义内联编辑器中存在的两个文件。

第 6 步 – 创建 Firebase Cloud Functions

Firebase Cloud Functions 在 Firebase 平台上运行,并按您在创建 Dialogflow 智能体期间选择或创建的 GCP 项目的规定计费。 您可以在这个页面上了解有关 Cloud Functions 的更多信息。

步骤 6.1 – 将所需的包添加到package.json

在内联编辑器的package.json文件中,我们将requestrequest-promise-native包添加到依赖项中,如下所示:

"dependencies": {
    "actions-on-google": "^2.2.0",
    "firebase-admin": "^5.13.1",
    "firebase-functions": "^2.0.2",
    "dialogflow": "^0.6.0",
    "dialogflow-fulfillment": "^0.5.0",
    "request": "*",
    "request-promise-native": "*"
  }

这些包将在构建智能体的过程中自动获取,因此您无需显式执行任何命令来安装它们。

步骤 6.2 – 向index.js添加逻辑

我们将添加调用订单管理系统 API 所需的代码。 在dialogflowFirebaseFulfillment对象定义内添加以下函数:

function checkOrderStatus(){
    const request = require('request-promise-native');
    var orderId = agent.parameters.OrderId;
    var url = "https://example.com/api/checkOrderStatus/"+orderId;
    return request.get(url)
        .then(jsonBody => {
            var body = JSON.parse(jsonBody);
            agent.add("Your order is: " + body.order[0].order_status);
            return Promise.resolve(agent);
        })
        .catch(err => {
            agent.add('Unable to get result');
            return Promise.resolve(agent);
        });
  }

在文件末尾,就在结束dialogflowFirebaseFulfillment对象定义之前,在调用 webhook 调用以生成响应之前,将先前创建的函数的映射添加到 Dialogflow 智能体中匹配的意图。

  let intentMap = new Map();
  intentMap.set('Default Welcome Intent', welcome);
  intentMap.set('Default Fallback Intent', fallback);
  intentMap.set('CheckOrderStatus', checkOrderStatus);
  agent.handleRequest(intentMap);

现在,单击“部署”以部署此函数。 您将在屏幕的右下角收到有关部署状态的通知。 等待部署并完成构建。

第 7 步 – 向机器人添加个性

为机器人添加个性,更多地是关于如何选择响应方式以及如何通过智能体中的响应和提示推动对话。

例如,尽管在上一个示例中我们选择了一个非常标准的对用户输入的响应,但是通过在响应中使用真实的语言或其他装饰元素,我们肯定可以使它更加有趣。 如果我们不是直接显示响应获取 API 的输出,而是添加了会话修饰符(例如Great, now let me see where your order is...),并且在将响应获取和加载到智能体过程中,使 Fulfillment 函数生成了会话填充符,这将显得非常现实。 作为almost there...just getting there...hmmm, let me see...和其他填充剂,取决于情况的要求。

您还可以使用 Dialogflow 的 Small Talk 模块为聊天机器人设置一些有趣的琐事。 要使用它,请单击左侧的“闲聊”菜单项并启用闲聊。 您可以添加一些有趣的响应,让您的机器人在遇到特定查询时会做出如下所示:

闲聊对于在聊天机器人中添加非常独特的个性非常有用!

在下一步中,我们将创建一个 UI,以直接从订单管理网站与此聊天机器人进行交互。 但是,由于我们谈论的是基于 REST API 的接口,因此我们很可能将这个 UI 与为订单管理系统创建的 API 分开托管。

此云函数调用您将需要创建的 HTTPS API。 在下一节中,我们将学习如何创建一个可以在本地计算机上处​​理 HTTPS 请求的 API。

使用 ngrok 改进本地主机上的 HTTPS API

您将需要创建自己的订单管理系统 API 才能使 Cloud Functions 脚本正常工作,以便它可以从 API 中获取订单状态。 您可以在这个页面中找到快速样本。 您的 API 必须在 HTTPS URL 上运行。 为此,您可以使用 PythonAnywhere 和 ngrok 之类的服务。 尽管 PythonAnywhere 将代码托管在其服务器上并提供固定的 URL,但是 ngrok 可以安装并在本地运行以向localhost提供转发地址。

假设您必须在系统的端口8000上为订单管理 API 运行 Django 项目,并且现在希望提供 HTTPS URL 以便进行测试; 您可以按照以下步骤使用 ngrok 轻松做到这一点:

  1. 下载 ngrok 工具。

首先,转到这里,然后单击顶部导航菜单中的“下载”按钮。 根据需要选择正确的工具版本,并将其下载到系统中。

  1. 创建一个帐户。

接下来,在网站上注册一个帐户,然后转到仪表板。 您可以使用 GitHub 或 Google 认证来快速设置您的帐户。

您将看到以下仪表板:

由于您已经下载并安装了该工具,因此可以直接跳至连接您的帐户。

  1. 将您的 ngrok 帐户与您的工具关联。

复制 ngrok 仪表板在连接帐户部分下给出的命令-它包含您帐户的 authtoken,并在运行时将系统上的 ngrok 工具连接到网站上的 ngrok 帐户。

然后,我们准备移至localhost端口。

  1. 设置 ngrok 地址以转发到localhost

最后,使用以下命令开始将对随机生成的 ngrok URL 的所有请求转发到localhost

ngrok http 8000

只要您保持终端打开,ngrok 服务就会启动并保持活动状态。 您应该在屏幕上看到类似于以下屏幕截图的输出:

对您的 ngrok URL 的所有请求都将记录在终端上。 您可以在请求日志上方表格的Forwarding行中找到您的 ngrok URL。 请注意,httphttps端口都正在转发。 现在,您可以使用在本地计算机上运行的 API 服务来从 Firebase 进行调用,后者仅允许 HTTPS 调用。

使用 Django 创建测试 UI 来管理订单

我们之前在本书中使用了 Django,即在“第 8 章”,“在 Microsoft Azure 上使用 Python 进行深度学习”和“第 10 章”,“使用深度学习的应用保护网络安全”。 因此,我们将跳过有关 Django 如何工作以及如何开始使用它的实质性细节。 让我们直接研究创建可以与您的声音进行交互的 UI!

如果尚未在系统上安装 Django,请按照“第 8 章”,“在 Microsoft Azure 上使用 Python 进行深度学习”的“Django Web 开发的简介”部分。

第 1 步 - 创建 Django 项目

每个 Django 网站都是一个项目。 要创建一个,请使用以下命令:

django-admin startproject ordersui

使用以下目录结构创建名为ordersui的目录:

ordersui/
| -- ordersui/
|         __init.py__
|         settings.py
|         urls.py
|         wsgi.py
| -- manage.py

让我们继续为该项目创建模块。

第 2 步 – 创建使用订单管理系统 API 的应用

请记住,每个 Django 项目都由几个协同工作的 Django 应用组成。 现在,我们将在该项目中创建一个 Django 应用,该应用将使用订单管理系统 API,并提供一个 UI 来查看 API 数据库中包含的内容。 这对于验证 Dialogflow 智能体是否正常工作很重要。

在新终端或命令提示符中使用cd命令切换到ordersui目录。 然后,使用以下命令创建一个应用:

python manage.py startapp apiui

这将在ordersui Django 项目应用目录中创建具有以下结构的目录:

apiui/ 
| -- __init__.py
| -- admin.py
| -- apps.py
| -- migrations/
|         __init__.py
| -- models.py
| -- tests.py
| -- views.py

在开始开发模块之前,让我们在下一部分中定义一些项目级设置。

第 3 步 – 设置settings.py

现在,我们将进行ordersui/settings.py文件中所需的一些配置。

步骤 3.1 – 将 apiui 应用添加到已安装应用的列表中

INSTALLED_APPS列表中,添加apiui应用,如下所示:

# Application definition

INSTALLED_APPS = [
 'apiui',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
]

Django 框架仅包含INSTALLED_APPS指令中列出的运行时应用,如前面的代码中所示。 我们还需要为项目定义数据库连接,这将在下一部分中显示。

步骤 3.2 – 删除数据库设置

由于此 UI 中不需要数据库连接,因此我们将删除数据库连接设置配置。

注释掉DATABASES词典,如下所示:

# Database
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases

# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }

保存文件。 完成此操作后,我们将设置一个 URL 路由以指向apiui路由。

步骤 4 – 将路由添加到 apiui

更改ordersui/urls.py中的代码以添加路径,以将路径设置文件包含在apiui应用内。 您的文件将包含以下代码:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
 path('', include('apiui.urls')),
]

保存文件。 在项目级别设置路由之后,我们将需要在模块级别设置路由,就像在下一节中所做的那样。

步骤 5 – 在 apiui 应用中添加路由

现在,我们已指示项目使用apiui URL 路由,我们需要创建此应用所需的文件。 在apiui目录中创建一个名为urls.py的文件,其内容如下:

from django.urls import path

from . import views

urlpatterns = [
 path('', views.indexView, name='indexView'),
 path('<int:orderId>', views.viewOrder, name='viewOrder'),
]

保存文件。 现在,我们已经指定了应用中可用的路由,我们需要为每个路由创建视图,就像我们在下一节中所做的那样。

步骤 6 – 创建所需的视图

在我们创建的路由中,我们提到了两个视图-indexView,它不带任何参数; viewOrder,它带一个名为orderId的参数。 在apiui目录中创建一个名为views.py的新文件,然后按照以下步骤创建所需的视图。

步骤 6.1 – 创建indexView

该路由将仅显示放置在订单管理系统上的订单。 我们使用以下代码:

from django.shortcuts import render, redirect
from django.contrib import messages
import requests

def indexView(request):
 URL = "https://example.com/api/"
 r = requests.get(url=URL)
 data = r.json()
 return render(request, 'index.html', context={'orders': data['orders']})

我们将在以下部分中创建viewOrder视图。

步骤 6.2 – 创建viewOrder

如果我们以/orderId的形式将订单 ID 传递到同一/路由,则我们应该返回订单的状态。 使用以下代码:

def viewOrder(request, orderId):
 URL = "https://example.com/api/" + str(orderId)
 r = requests.get(url=URL)
 data = r.json()
 return render(request, 'view.html', {'order': data['order']})

我们已经完成了创建该项目所需的不同视图的工作; 但是,我们尚未创建将要渲染的模板。 让我们创建下一部分中所需的模板。

步骤 7 – 创建模板

在我们先前定义的视图中,我们使用了两个模板-index.htmlview.html。 但是为了使它们与设计同步显示,我们还将设置一个base.html模板,它将作为 UI 中其余视图模板的主模板。

由于模板大多只是 HTML 模板,对网站的重要内容影响不大,因此我们在这里提供了这些文件的代码。 您必须将模板文件保存在apiui目录内名为templates的文件夹中。

在此阶段,您将能够使用以下命令启动 Django 项目服务器并在浏览器中检出网站:

python manage.py runserver

现在我们的服务器正在运行,我们将在下一部分中围绕它创建一个语音界面。

使用 Web Speech API 的网页上的语音识别和语音合成

Web 开发领域中一项最新且非常令人兴奋的开发是 Web Speech API 的引入。 虽然 Google 已在桌面和 Android 的 Google Chrome 浏览器中全面支持 Web Speech API,但 Safari 和 Firefox 仅提供部分实现。 Web Speech API 主要包含两个组件:

  • 语音合成:更广为人知的 TTS。 它执行为任何给定文本生成语音旁白的动作。
  • 语音识别:也称为 STT。 它执行识别用户说出的单词并将其转换为相应文本的功能。

您可以浏览 Web 语音 API 的非常详细的文档,该文档可从 Mozilla 文档页面获得。 您可以在这个页面上找到 Google 提供的技术演示:

在以下步骤中,我们将基于 Web Speech API 的“问问题”按钮添加到我们的网站 UI 中。

步骤 1 – 创建按钮元素

此部分中的所有代码都必须放入 UI 的base.html模板中,以便它可以在网站的所有页面上使用。

我们使用以下代码快速创建一个按钮,该按钮的“提问”文本将位于整个站点的网页的右下角:

<div id="customerChatRoot" class="btn btn-warning">Ask a question</div>

现在,我们将需要初始化和配置 Web Speech API,就像在下一节中所做的那样。

步骤 2 – 初始化 Web Speech API 并执行配置

网页加载完成后,我们需要初始化 Web Speech API 对象并为其设置必要的配置。 为此,请使用以下代码:

$(document).ready(function(){
            window.SpeechRecognition = window.webkitSpeechRecognition || window.SpeechRecognition;
            var finalTranscript = '';
            var recognition = new window.SpeechRecognition();
            recognition.interimResults = false;
            recognition.maxAlternatives = 10;
            recognition.continuous = true;
            recognition.onresult = (event) => {
               // define success content here 
            }

            // click handler for button here
        });

您可以看到我们已经初始化了一个 Web SpeechRecognition API 对象,然后对其进行了一些配置。 让我们尝试了解以下配置:

  • recognition.interimResults(布尔值)指示 API 是应该尝试识别临时结果还是要说出的单词。 这将增加我们的用例的开销,因此将其关闭。 在转录速度比转录准确率更重要的情况下,例如在为讲话人生成实时转录时,将其打开会更有益。
  • recognition.maxAlternatives(数字)告诉浏览器可以为同一语音段生成多少个替代项。 在浏览器不太清楚说了什么并且可以为用户提供选择正确识别的选项的情况下,这很有用。
  • recognition.continuous(布尔值)告诉浏览器是必须连续捕获音频还是在一次识别语音后停止音频。

但是,我们尚未定义执行 STT 后收到结果时执行的代码。 为此,我们向recognition.onresult函数添加了代码,如下所示:

              let interimTranscript = '';
              for (let i = event.resultIndex, len = event.results.length; i < len; i++) {
                let transcript = event.results[i][0].transcript;
                if (event.results[i].isFinal) {
                  finalTranscript += transcript;
                } else {
                  interimTranscript += transcript;
                }
              }
              goDialogFlow(finalTranscript);

              finalTranscript = '';

前面的代码块在用户讲话时创建一个临时笔录,当说出更多单词时,该笔录会不断更新。 当用户停止讲话时,临时笔录将附加到最终笔录中,并传递给处理与 Dialogflow 交互的功能。 从 Dialogflow 智能体收到响应后,将为来自用户的下一个语音输入重置最终笔录。

请注意,我们已将用户语音的最终识别成绩单发送给名为goDialogFlow()的函数。 让我们定义这个函数。

步骤 3 – 调用 Dialogflow 智能体

获得用户基于语音的查询的文本版本后,将其发送到 Dialogflow 智能体,如下所示:

function goDialogFlow(text){
            $.ajax({
                type: "POST",
                url: "https://XXXXXXXX.gateway.dialogflow.cloud.ushakov.co",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                data: JSON.stringify({ 
                    "session": "test",
                    "queryInput": {
                    "text": {
                        "text": text,
                        "languageCode": "en"
                        }
                    } 
                }),
                success: function(data) {
                    var res = data.queryResult.fulfillmentText;
                    speechSynthesis.speak(new SpeechSynthesisUtterance(res));
                },
                error: function() {
                    console.log("Internal Server Error");
                }
            }); 
        }

您会发现,当 API 调用成功时,我们使用 SpeechSynthesis API 向用户说出结果。 它的用法比 SpeechRecognition API 更为简单,因此是出现在 Firefox 和 Safari 中的第一个。

注意上一个函数中使用的 API URL。 当前可能看起来很奇怪,您可能想知道我们从何处获得此 URL。 我们所做的基本上是跳过使用终端设置 Dialogflow 智能体服务帐户配置的要求,该终端始终位于脚本正在处理的系统本地,因此很难传输。

要为您的项目获得相似的 URL,请遵循以下步骤; 否则,请跳过“步骤 4”并直接进入“步骤 5”。

步骤 4 – 通过 Ushakov 在 Dialogflow Gateway 上创建 Dialogflow API 智能体

转到这里。 您将看到一个界面,如下所示:

Dialogflow Gateway 促进了语音 UI 和 Dialogflow 智能体之间的交互。 在我们的项目作为静态网站托管的情况下,这非常有用。 Dialogflow 网关围绕 Dialogflow API 提供了简化的 API 包装器,并且非常易于使用。

您必须创建一个帐户才能开始使用 Dialogflow,如下一节所示。

步骤 4.1 – 在 Dialogflow 网关上创建帐户

单击“入门”,开始在平台上创建帐户。 系统会要求您使用您的 Google 帐户登录。 确保使用与以前创建 Dialogflow 智能体相同的帐户。

步骤 4.2 – 为 Dialogflow 智能体项目创建服务帐户

我们先前在“第 6 章”,“使用 Python 在 Google Cloud Platform 上进行深度学习”中详细讨论了如何为 GCP 项目创建服务帐户。 为链接到 Dialogflow 智能体的项目创建一个新的服务密钥,如下所示:

成功创建密钥后,将弹出一个对话框,通知您密钥已保存到计算机中,如下所示:

服务帐户凭据以 JSON 的形式下载到本地系统,其名称如前面的屏幕快照所示。

现在,我们将使用该服务帐户凭据文件将 Dialogflow Gateway 连接到我们的 Dialogflow 智能体。

步骤 4.3 – 将服务密钥文件上传到 Dialogflow Gateway

在 Dialogflow Gateway 控制台上,您会找到“上传密钥”按钮。 单击它以上传您生成的服务帐户密钥文件。 上传后,控制台将显示您的 Dialogflow API 智能体 URL,如下所示:

我们将在先前定义的函数中使用网关 URL。

步骤 5 – 为按钮添加点击处理器

最后,我们向“提问”按钮添加click处理器,以便它可以触发用户输入的语音识别以及 Dialogflow 智能体的输出合成。

在“步骤 2”中定义的文档ready函数中,添加以下click处理器代码:

$('#customerChatRoot').click(function(){
 recognition.start();
 $(this).text('Speak!');
});

现在,当麦克风开始收听用户输入时,按钮文本将变为Speak!,提示用户开始讲话。

尝试在您的设置上测试该网站,然后查看如何使其正常工作!

总结

在本章中,我们结合了多种技术,提出了一个端到端项目,该项目展示了将深度学习应用于网站的最快速发展的方面之一。 我们介绍了 Dialogflow,Dialogflow 网关,GCP IAM,Firebase Cloud Functions 和 ngrok 等工具。 我们还演示了如何构建基于 REST API 的 UI,以及如何使用 Web Speech API 对其进行访问。 Web 语音 API 尽管目前尚处于起步阶段,但它是 Web 浏览器中使用的一项前沿技术,并且有望在未来几年中快速增长。

可以肯定地说,Web 深度学习具有巨大的潜力,并将成为许多即将开展的业务成功的关键因素。 在下一章中,我们将探讨深度学习中用于 Web 开发的一些最热门的研究领域,以及我们如何计划以最佳方式取得进展。

十三、附录:Web 深度学习的成功案例和新兴领域

通常重要的是要知道其他人正在使用任何技术做什么,以了解其适用性的规模以及它可以承诺的投资回报。 本章介绍了一些最著名的网站,这些网站的产品很大程度上依赖于利用深度学习的力量。 本章还讨论了可以使用深度学习增强的 Web 开发中的一些关键研究领域。 本章将帮助您更深入地研究 Web 技术和深度学习的融合,并激发您提出自己的智能 Web 应用。

本章包括两个主要部分:

  • Quora 和 Duolingo 等组织在其产品中应用了深度学习的成功案例
  • 深度学习中的一些关键新兴领域,例如阅读理解,音频搜索等

让我们开始吧!

成功的故事

在本节中,我们将简要介绍一些以 AI 为核心以促进业务增长的产品/公司。 在此值得注意的是,整个产品或服务是否基于任何 AI 技术或算法并不重要; 仅在其中的一小部分或具有特定功能的情况下使用 AI 即可提高产品的实用性,从而提高客户对产品的广泛使用。 有时,您甚至可能没有在产品的任何功能中使用 AI,相反,您可能仅使用它来执行数据分析并提出预期趋势,以确保您的产品符合即将到来的趋势。 让我们看一下这些公司扩大规模后对它们有用的方法。

Quora

在 Quora 之前,已经有很多问答网站和论坛。 在互联网历史上的某个时刻,在线论坛被视为无法再改进的东西; 但是,Quora 提出了一些使用深度学习进行的调整,以帮助他们快速胜过其他论坛。 以下是他们实现的调整:

  • 他们使贡献者能够使用“问与答”功能在发布任何问题后立即请求答案。 这使问题更容易到达相关主题专家,他们迅速给出了答案,并使该平台响应更快,更准确。
  • 他们使用自然语言处理NLP)屏蔽了写得不好的问题和答案。 这引入了具有高质量内容的自动审核论坛的概念。
  • 确定任何给定问题-答案线程的标签和相关文章使发现类似问题变得容易。 这使 Quora 用户花费大量时间阅读与他们相似的问题的答案,只是为了在他们每个人中找到新的信息。
  • Quora Digest 时事通讯是根据用户的兴趣精心策划的文章集,几乎总是成功地将用户带回了平台:

Quora 在某个时间点成为(现在仍然算是)互联网上最令人上瘾的社交平台。 他们使用了一个简单的问答网站,并使用深度学习将其转变为一个了不起的平台。 您可以通过这里检出平台。

Duolingo

学习新语言一直是一项艰巨的任务。 当 Duolingo 于 2012 年投放市场时,它带来了一个越来越重要和广泛的术语-人工智能。 他们将记忆单词和语法规则等平凡的东西转换为微型游戏,这些微型游戏对每个用户的反应不同。 Duolingo AI 考虑了人脑的时间特性。 他们制定了关于一个人可能很快忘记他/她学到的单词的研究。 他们称此概念为半衰期回归,并用它来增强对它预测用户在任何给定时间点会忘记的单词的了解。

这在他们的支持下取得了巨大的成功,使 Duolingo 成为移动应用商店中最受欢迎的应用之一。 他们的网站也是非正统设计的经典例子,广受好评。 您可以通过这里了解有关 Duolingo 的更多信息。

Spotify

音频播放器已经存在很长时间了,但是没有人将 Spotify 带到桌面上。 Spotify 使用深度学习来确定用户希望在任何给定时间点收听的歌曲。 多年来,他们的 AI 取得了突飞猛进的发展,根据用户最近播放的歌曲来建议整个播放列表。 Spotify 的迅速崛起激发了许多试图做到这一点并试图赶上 Spotify 受欢迎程度的产品。

Spotify 还引入了一项非常强大的功能-根据音频样本搜索歌曲。 这是一个即时热门功能; 许多用户下载 Spotify 只是因为他们不记得他们正在听的一首好听的歌曲的名字,所以想迅速找出它的名字。 您只需记录附近正在播放的歌曲的音频并将其馈送到 Spotify 即可知道正在播放的歌曲。

Google 搜索/照片

尽管云图像存储是 Dropbox 等公司提供的现有解决方案,但 Google Photos 通过将 AI 纳入方程式,彻底改变了云图像存储空间。 Google 相册由于其令人惊叹的功能,例如以下内容,已被全球数十亿人采用:

  • 人脸识别:此功能存在于名为 Picasa 的较早的 Google 产品中,该产品被认为是 Google Photos 的前身。
  • 向导:Google 相册自动确定在同一事件或场合拍摄的照片。 然后,它尝试创建有关图片的电影,或者只是触摸图像以使其看起来更好。 有时,Google 相册还会用看起来似乎是连续的照片来创建动画 GIF。
  • 文档和模因的识别:Google 相册建议其用户归档旧文档,屏幕截图和模因。 这对于节省设备存储空间非常有帮助:

Google 相册由于在后台使用了深度学习,因此在个人在线画廊方面处于市场领先地位。 如果您想了解更多信息,请访问这里

在本节中,我们看了一些受深度学习极大影响的产品。 在下一部分中,我们将看到一些新兴领域,其中深度学习似乎会带来很多积极成果。

重点新兴领域

在前面的部分中,我们看到了几家公司如何结合基于深度学习的技术来改进其产品。 在本节中,我们将讨论当前正在大量研究的一些领域,并且我们将通过 Web 开发的角度看到它们的影响力。

音频搜索

假设您在一家酒吧中,并且喜欢现场乐队播放的歌曲。 在您的脑海中,您知道自己曾经听过这首歌,但是无法回忆起这首歌的名字。 如果您有一个可以听这首歌并搜索其名称的系统,那不是很好吗? 欢迎来到音频搜索引擎的世界!

有很多现有的音频搜索引擎,其中声音搜索(由 Google Assistant 提供)是最受欢迎的搜索引擎之一。 您可能还想看看 Shazam。 在以下屏幕截图中,您可以看到通过声音搜索产生的示例音频搜索结果:

为了使系统根据接收到的音频信号执行音频搜索,系统首先需要处理该信号,这被称为音频信号处理。 然后,系统将处理后的信号与其现有的成千上万首歌曲的数据库进行比较。 在将信号与现有数据库进行比较之前,使用神经网络对其进行特定表示,通常将其称为指纹。 但是,这仍然是一个活跃的研究领域,我强烈建议您阅读这个页面上的文章,详细了解这些技术。

阅读理解

您是否曾经希望搜索引擎能为您提供搜索查询的答案,而不是找到可能包含搜索查询答案的资源的合适链接? 好吧,如果系统通过阅读理解进行编程,那么现在就有可能实现这一目标。 让我们看下面的屏幕截图,以了解这意味着什么:

如果您仔细地注意到,我们甚至都没有将 Sachin Tendulkar 的父亲的陈述作为疑问。 现代系统有足够的能力自行推断出这样的属性。

现在,为了能够理解具有阅读理解能力的系统(或机器)的深度,请说您想在执行网络搜索后找到问题的答案。 这是您需要经历的多步骤过程:

  1. 首先,用相关的关键字制定搜索查询,然后搜索引擎执行搜索。
  2. 然后,搜索引擎为您提供给定搜索查询的相关文档列表。
  3. 您仔细阅读这些文档,根据自己的理解整理其中的信息,然后得出结论。

本质上,仍然存在许多手动的步骤,而且这个问题仍然存在:我们是否可以设计一个系统来自动为我们找到合适答案的过程? 现有的搜索引擎为我们提供了给定搜索查询的相关文档列表,但不足以开发能够实际产生搜索查询答案的系统。 简而言之,这样的系统需要执行以下操作:

  1. 遵循相关文件的结构。
  2. 理清这些文档中提供的内容。
  3. 得出最终答案。

让我们简化一下问题。 假设对于一个给定的问题,我们已经有了相关段落的列表,现在我们需要开发一种系统,该系统实际上可以从这些段落中理解并为我们提供给定问题的明确答案。 在阅读理解系统中,神经网络通常学会捕捉给定问题与相关段落之间的深层语义关系,然后制定最终答案。

您可能已经知道,诸如 Google 搜索,必应等之类的搜索引擎已经具备阅读理解能力。

在社交媒体上检测假新闻

随着社交媒体的飞速发展,从来没有新闻。 社交媒体已轻松成为我们新闻的主要来源之一; 但是,通常不能保证其真实性。 并非您在社交媒体上偶然发现的每篇新闻都是真实的,可以肯定地说,其中有很多是假的。 这种现象的后果可能非常令人震惊,并且确实可以导致虐待,暴力等行为。

少数组织和机构正试图与此作斗争,并使人们意识到新闻报道的真实性。 考虑到我们每天在社交媒体上看到的新闻数量众多,这项任务可能非常繁琐。 因此,现在的问题变成了我们可以利用机器学习的力量来自动检测假新闻吗? 实际上,这是一个活跃的研究领域,尚无可大规模解决此问题的实际应用。

但是,以下是各个小组使用经典机器学习和深度学习方法进行的一些研究:

鼓励您在这个页面上查看调查报告,该报告提供了有关各种假新闻检测技术的综合指南,并讨论了有关该主题的相关研究。 另一方面,一家名为 Varia 的德国初创公司正试图以一种独特的方式解决假新闻问题。 他们没有提供新闻的真实性,而是提供了某些新闻的不同观点。 换句话说,他们正在提供透视服务。 要了解更多信息,您绝对应该在这个页面中进行检查。

总结

在本书的最后一章中,我们试图激发您构建下一个深度学习项目并将其在 Web 平台上使用。 您可能对更多这样的公司的故事感兴趣,这些公司使用 AI 转变了业务并统治了市场空间。 如果您浏览几乎所有访问的网站,它们都会以某种方式使用人工智能和深度学习的元素,无论是推荐系统还是广告形式(又是促销推荐系统)。 然后,我们介绍了深度学习领域中即将出现的主题,这些主题正在寻找在不久的将来在网站上实现的主题。 如果您能根据这些主题中的任何一个来提供服务,那就太好了!