使用谷歌人工智能开放图像的对象检测
学会打造自己的自动驾驶汽车!!!….开玩笑
你上一次只用脸登录手机是什么时候?或者点击了一张与一些朋友的自拍,并使用了 Snapchat 滤镜,在你的脸上放置了一些花哨的狗耳朵?你知道吗,这些很酷的功能是由一个奇特的神经网络实现的,它不仅可以识别照片中有一张脸,还可以检测耳朵应该去哪里。从某种意义上说,你的手机可以“看到”你,它甚至知道你长什么样!
帮助计算机‘看’的技术叫做“计算机视觉”。近年来,由于计算能力的爆炸使得深度学习模型更快更可行,计算机视觉应用变得越来越普遍。许多公司,如亚马逊、谷歌、特斯拉、脸书和微软,都在大力投资这项技术及其应用。
计算机视觉任务
我们关注两个主要的计算机视觉任务——图像分类和目标检测。
- ****图像分类专注于将图像分组到预定义的类别中。为了实现这一点,我们需要有我们感兴趣的类的多个图像,并训练计算机将像素数字转换为符号。这只是说电脑看到猫的照片,说里面有猫。
- ****物体检测利用图像分类器来计算出图像中存在什么以及在哪里。通过使用卷积神经网络(CNN ),这些任务变得更加容易,这使得在图像的一次通过中检测多个类别成为可能。
For more details on the difference in such tasks, please reference the following article.
计算机视觉很酷!
认识到未来许多有趣的数据科学应用将涉及图像工作,我和我的初露头角的数据科学家团队决定在 Kaggle 上举办的谷歌人工智能开放图像挑战赛上一试身手。我们认为这是接触神经网络和卷积的绝佳机会,有可能给我们的教授和同学留下深刻印象。这个挑战为我们提供了 170 万张图片,带有 500 个对象类的1200 万个包围盒标注(它们相对于图片的 X 和 Y 坐标)。你可以在这里找到数据。****
我们强烈推荐任何想了解 CNN 的人去读吴恩达的关于卷积神经网络的课程。
弄脏我们的手!
探索性数据分析 —与所有数据分析一样,我们开始探索我们拥有哪些图像以及我们需要检测的对象类型。
Frequency of Classes in the Training Dataset
快速浏览训练图像可以发现,就出现的次数而言,某些物体比其他物体更具存在感。上图显示了前 43 名班级的分布情况。很明显,这是一个巨大的差距,需要以某种方式解决。为了节省时间和金钱(GPU 成本很高:( )我们选择了前面提到的 43 个对象类和包含这些对象的大约 300K 图像的子集。对于训练数据中的每个对象类,我们有大约 400 张图像。
选择对象检测算法
我们考虑了各种算法,如 VGG、盗梦空间,但最终选择了 YOLO 算法,因为它的速度、计算能力和大量在线文章可以指导我们完成这个过程。面对计算和时间的限制,我们做了两个关键的决定-
- 使用被训练来识别某些物体的 YOLO v2 模型。
- 利用迁移学习来训练最后一个卷积层,以识别以前未见过的对象,如吉他、房子、男人/女人、鸟等。
对 YOLO 的投入
YOLO 算法需要一些特定的输入-
- 输入图像尺寸 — YOLO 网络设计用于特定的输入图像尺寸。我们发送了尺寸为 608 * 608 的图像。
- 班级数量 — 43。这是定义 YOLO 输出尺寸所必需的。
- 锚箱— 要使用的锚箱的数量和尺寸。
- 置信度和 IoU 阈值 —定义选择哪些锚框以及如何在锚框之间挑选的阈值。
- 带有边框信息的图像名称——对于每张图像,我们需要以如下所示的特定格式向 YOLO 提供其中的内容
Sample input for YOLO
下面是 YOLO 输入的代码片段
Inputs into YOLO
YOLO v2 架构
该架构如下所示——它有 23 个卷积层,每个卷积层都有自己的批量归一化、漏 RELU 激活和最大池。
Representation of the actual YOLO v2 architecture.
这些层试图从图像中提取多个重要特征,以便可以检测到各种类别。为了对象检测的目的,YOLO 算法将输入图像分成 1919 的网格,每个网格具有 5 个不同的锚框。然后,它尝试检测每个网格单元中的类,并将一个对象分配给每个网格单元的 5 个锚定框之一。锚定框的形状不同,旨在为每个网格单元捕捉不同形状的对象。*
YOLO 算法为每个定义的锚定框输出一个矩阵(如下所示)
假设我们必须为 43 个类训练算法,我们得到的输出维数为:
这些矩阵给我们观察每个锚盒中的对象的概率,以及该对象是什么类的概率。为了过滤掉不具有任何类或者具有与一些其他框相同的对象的锚框,我们使用两个阈值— IoU 阈值来过滤掉捕获相同对象的锚框,以及置信度阈值来过滤掉不包含任何具有高置信度的类的框。
下面是 YOLO v2 架构最后几层的示意图:
Last few layers of YOLO v2 architecture (Only for illustration purposes)
迁移学习
转移学习是指获得一个已经训练好的神经网络来分类图像,并将其用于我们的特定目的。这节省了我们的计算时间,因为我们不需要训练大量的权重——例如,我们使用的 YOLO v2 模型有大约 5000 万个权重——在我们使用的谷歌云实例上,训练可能需要 4-5 天。
为了成功实施迁移学习,我们必须对我们的模型进行一些更新:
- 输入图像尺寸— 我们下载的型号使用的输入图像尺寸为 416416。由于我们训练的一些对象非常小——鸟、鞋——我们不想把输入图像挤压得太厉害。为此,我们使用大小为 608608 的输入图像。**
- 网格大小— 我们更改了网格大小的尺寸,以便它将图像划分为 1919 个网格单元,而不是我们下载的模型的默认 1313。**
- 输出层— 由于我们在不同数量的类别 43 和 80 上进行训练,而原始模型是在这些类别上进行训练的,因此输出层被更改为输出矩阵维度,如上所述。
我们重新初始化了 YOLO 的最后一个卷积层的权重,以在我们的数据集上对其进行训练,最终帮助我们识别唯一的类。下面是相同的代码片段-
Re-initializing the last convolution layer of YOLO
价值函数
在任何目标检测问题中,我们都希望在一幅图像中用一个高置信度来识别位于右侧位置的右侧目标。成本函数有 3 个主要组成部分:
- ****分类损失:如果检测到物体,是类别条件概率的平方误差。因此,损失函数仅在对象存在于网格单元中时惩罚分类错误。
- ****定位损失:它是预测的边界框位置和尺寸与地面真实框的平方误差,如果这些框负责检测物体的话。为了补偿边界框坐标预测的损失,我们使用一个正则化参数(ƛcoord).此外,为了确保较大框中的小偏差没有较小框中的小偏差重要,该算法使用边界框宽度和高度的平方根。
- ****置信度损失:是包围盒置信度得分的平方误差。大多数盒子不负责检测物体,因此该等式被分成两部分,一部分用于检测物体的盒子,另一部分用于其余的盒子。正则项λnoobj(默认值:0.5)应用于后一部分,以降低未检测到对象的框的权重。
关于成本函数的详细信息,请随意参考 YOlO 的原文。
YOLO 的妙处在于,它使用的误差易于使用优化函数进行优化,如随机梯度下降(SGD)、带动量的 SGD 或 Adam 等。下面的代码片段显示了我们用于优化成本函数的参数。
Training algorithm for YOLO (Adam optimizer)
输出精度-平均精度(地图得分):
在对象检测中有许多指标来评估模型,对于我们的项目,我们决定使用 mAP 得分,这是所有 IoU 阈值上不同召回值的最大精度的平均值。为了理解 mAP,我们将快速回顾一下 precision、recall 和 union 上的交集)。
精确度和召回率
精度衡量正确的正面预测的百分比。回忆是所有可能结果中真正肯定的比例。这两个值是反向相关的,并且还依赖于您为模型设置的模型得分阈值(在我们的例子中,它是置信度得分)。它们的数学定义如下:
并集上的交集
IoU 衡量两个区域之间有多少重叠,等于重叠面积与并集面积之比。这测量你的预测(从你的物体探测器)与地面事实(真实物体边界)相比有多好。总而言之,mAP 得分是所有 IoU 阈值的平均 AP。
结果
********
结论
物体检测不同于其他计算机视觉任务。您可以使用预先训练的模型,并根据需要进行编辑以满足您的需求。你可能需要 GCP 或另一个允许更高计算能力的平台。数学很难,看别人文章,不及格快。
经验教训
一开始,我们发现该模型无法预测许多类别,因为许多类别只有少量训练图像,这导致了不平衡的训练数据集。因此,我们决定只使用最流行的 43 个类,这不是一个完美的方法,但每个类至少有 500 张图片。然而,我们预测的可信度仍然很低。为了解决这个问题,我们选择了包含目标类的图像。
物体检测是一个非常具有挑战性的话题,但是不要害怕,尽量从各种在线开放资源中学习,比如 Coursera、YouTube 教学视频、GitHub 和 Medium。所有这些免费的智慧可以帮助你在这个令人惊叹的领域取得成功!
未来工作——继续或改进
- 在更多类别上训练模型,以检测更多种类的对象。为了达到这个目标,我们需要首先解决不平衡数据的问题。一个潜在的解决方案是,我们可以用这些更稀有的类收集更多的图像。
a .数据扩充 —稍微改变现有图像以创建新图像
b .图像复制 —我们可以多次使用相同的图像来训练特定稀有类上的算法
c . Ensemble——在流行类上训练一个模型,在稀有类上训练另一个模型,并使用两者的预测。
2.此外,我们可以尝试不同型号的合奏,如 MobileNet、VGG 等。这是也用于对象检测的卷积神经网络算法。
如果你想详细了解我们团队的代码,这里有 GitHub 的链接。请随时提供任何反馈或意见!
通过在 GitHub 上创建一个帐户,为 bandiatindra/Object-Detection 项目开发做出贡献。
github.com](https://github.com/bandiatindra/Object-Detection-Project)****
使用谷歌人工智能开放图像的对象检测
学会打造自己的自动驾驶汽车!!!….开玩笑
Atindra Bandi、Alyson Brown、Sagar Chadha、Amy Dang 和 Jason Su 的项目
Photo by Erik Mclean on Unsplash
你上一次只用脸登录手机是什么时候?或者点击了一张与一些朋友的自拍,并使用了 Snapchat 滤镜,在你的脸上放置了一些花哨的狗耳朵?你知道吗,这些很酷的功能是由一个奇特的神经网络实现的,它不仅可以识别照片中有一张脸,还可以检测耳朵应该去哪里。从某种意义上说,你的手机可以“看到”你,它甚至知道你长什么样!
帮助计算机“看”的技术被称为“计算机视觉”。近年来,由于计算能力的爆炸使得深度学习模型更快更可行,计算机视觉应用变得越来越普遍。许多公司,如亚马逊、谷歌、特斯拉、脸书和微软,都在大力投资这项技术及其应用。
计算机视觉任务
我们关注两个主要的计算机视觉任务——图像分类和目标检测。
- 图像分类专注于将图像分组到预定义的类别中。为了实现这一点,我们需要有我们感兴趣的类的多个图像,并训练计算机将像素数字转换为符号。这只是说电脑看到猫的照片,说里面有猫。
- 对象检测利用图像分类器来找出图像中存在的内容和位置。通过使用卷积神经网络(CNN ),这些任务变得更加容易,这使得在图像的一次通过中检测多个类别成为可能。
For more details on the difference in such tasks, please reference the following article.
计算机视觉很酷!
认识到未来许多有趣的数据科学应用将涉及图像工作,我和我的初露头角的数据科学家团队决定在 Kaggle 上举办的谷歌人工智能开放图像挑战赛上一试身手。我们认为这是接触神经网络和卷积的绝佳机会,有可能给我们的教授和同学留下深刻印象。这个挑战为我们提供了 170 万张图片和 1200 万张包围盒标注(它们相对于图片的 X 和 Y 坐标)的 500 个对象类。你可以在这里找到数据。
我们强烈推荐任何想了解 CNN 的人去读吴恩达的关于卷积神经网络的课程。
弄脏我们的手!
探索性数据分析 —和所有的数据分析一样,我们开始探索我们拥有的图像和我们需要探测的物体类型。
Frequency of Classes in the Training Dataset
快速浏览训练图像可以发现,就出现的次数而言,某些物体比其他物体更具存在感。上图显示了前 43 名班级的分布情况。很明显,这是一个巨大的差距,需要以某种方式解决。为了节省时间和金钱(GPU 成本很高:( )我们选择了前面提到的 43 个对象类和包含这些对象的大约 300K 图像的子集。对于训练数据中的每个对象类,我们有大约 400 张图像。
选择对象检测算法
我们考虑了各种对象检测算法,包括 VGG、盗梦空间和 YOLO,但最终选择了 YOLO 算法,因为它的速度、计算能力和大量在线文章可以指导我们完成这个过程。面对计算和时间的限制,我们做了两个关键的决定-
- 使用被训练来识别某些物体的 YOLO v2 模型。
- 利用迁移学习来训练最后一个卷积层,以识别以前未见过的对象,如吉他、房子、男人/女人、鸟等。
对 YOLO 的投入
YOLO 算法需要一些特定的输入-
- 输入图像尺寸 — YOLO 网络设计用于特定的输入图像尺寸。我们发送了尺寸为 608 * 608 的图像。
- 班数 — 43。这是定义 YOLO 输出尺寸所必需的。
- 锚箱— 要使用的锚箱的数量和尺寸。
- 置信度和 IoU 阈值 —定义选择哪些锚框以及如何在锚框之间挑选的阈值。
- 带边框信息的图像名称 —对于每张图像,我们需要以如下所示的特定格式向 YOLO 提供图像中的内容
Sample input for YOLO
下面是 YOLO 输入的代码片段
Inputs into YOLO
YOLO v2 架构
该架构如下所示——它有 23 个卷积层,每个卷积层都有自己的批量归一化、漏 RELU 激活和最大池。
Representative of the actual YOLO v2 architecture.
这些层试图从图像中提取多个重要特征,以便可以检测到各种类别。为了对象检测的目的,YOLO 算法将输入图像分成 1919 的网格,每个网格具有 5 个不同的锚框。然后,它尝试检测每个网格单元中的类,并将一个对象分配给每个网格单元的 5 个锚定框之一。锚定框的形状不同,旨在为每个网格单元捕捉不同形状的对象。*
YOLO 算法为每个定义的锚定框输出一个矩阵(如下所示)
假设我们必须为 43 个类训练算法,我们得到的输出维数为:
这些矩阵给我们观察每个锚盒中的对象的概率,以及该对象是什么类的概率。为了过滤掉不具有任何类别或者具有与一些其他框相同的对象的锚框,我们使用两个阈值— IoU 阈值来过滤掉捕获相同对象的锚框,以及置信度阈值来过滤掉不包含任何具有高置信度的类别的框。
下面是 YOLO v2 架构最后几层的插图:
Last few layers of YOLO v2 architecture (Only for illustration purposes)
迁移学习
转移学习是指获得一个已经训练好的神经网络来分类图像,并将其用于我们的特定目的。这节省了我们的计算时间,因为我们不需要训练大量的权重——例如,我们使用的 YOLO v2 模型有大约 5000 万个权重——在我们使用的谷歌云实例上,训练可能需要 4-5 天。
为了成功实施迁移学习,我们必须对我们的模型进行一些更新:
- 输入图像尺寸— 我们下载的型号使用的输入图像尺寸为 416416。由于我们训练的一些对象非常小——鸟、鞋——我们不想把输入图像挤压得太厉害。为此,我们使用大小为 608608 的输入图像。**
- 网格大小— 我们更改了网格大小的尺寸,以便它将图像划分为 1919 个网格单元,而不是我们下载的模型的默认 1313。**
- 输出层— 由于我们训练的是不同数量的类 43,而不是原始模型训练的 80,因此输出层被更改为输出矩阵维度,如上所述。
我们重新初始化了 YOLO 的最后一个卷积层的权重,以在我们的数据集上训练它,最终帮助我们识别独特的类。下面是相同的代码片段-
Re-initializing the last convolution layer of YOLO
价值函数
在任何对象检测问题中,我们都希望在图像中以高置信度识别在正确位置的正确对象。成本函数有 3 个主要组成部分:
- ****分类损失:是类别条件概率的平方误差,如果检测到物体。因此,损失函数仅在对象存在于网格单元中时惩罚分类错误。
- ****定位损失:它是预测的边界框位置和尺寸与地面真实框的平方误差,如果这些框负责检测物体的话。为了补偿边界框坐标预测的损失,我们使用一个正则化参数(ƛcoord).此外,为了确保较大框中的小偏差没有较小框中的小偏差重要,该算法使用边界框宽度和高度的平方根。
- ****置信度损失:是包围盒置信度得分的平方误差。大多数盒子不负责检测物体,因此等式被分成两部分,一部分用于检测物体的盒子,另一部分用于其余的盒子。正则项λnoobj(默认值:0.5)应用于后一部分,以降低未检测到对象的框的权重。
请随意参考原始 YOlO 论文以获得成本函数的详细信息。
YOLO 的妙处在于,它使用的误差易于使用优化函数进行优化,如随机梯度下降(SGD)、带动量的 SGD 或 Adam 等。下面的代码片段显示了我们用于优化成本函数的参数。
Training algorithm for YOLO (Adam optimizer)
输出精度—平均精度(地图得分):
在对象检测中有许多指标来评估模型,对于我们的项目,我们决定使用 mAP 得分,这是所有 IoU 阈值上不同召回值的最大精度的平均值。为了理解 mAP,我们将快速回顾一下 precision、recall 和 union 上的交集)。
精度&召回
精度衡量正确的正面预测的百分比。回忆是所有可能结果中真正肯定的比例。这两个值是反向相关的,并且还依赖于您为模型设置的模型得分阈值(在我们的例子中,它是置信度得分)。它们的数学定义如下:
交集超过联合(借据)
IoU 衡量两个区域之间有多少重叠,等于重叠面积与并集面积之比。这测量你的预测(从你的物体探测器)与地面事实(真实物体边界)相比有多好。总而言之,mAP 得分是所有 IoU 阈值的平均 AP。
结果
********
结论
物体检测不同于其他计算机视觉任务。您可以使用预先训练的模型,并根据需要进行编辑以满足您的需求。你可能需要 GCP 或另一个允许更高计算能力的平台。数学很难,看别人文章,不及格快。
经验教训
一开始,我们发现该模型无法预测许多类别,因为许多类别只有少量训练图像,这导致了不平衡的训练数据集。因此,我们决定只使用最流行的 43 个类,这不是一个完美的方法,但每个类至少有 500 张图片。然而,我们预测的可信度仍然很低。为了解决这个问题,我们选择了包含目标类的图像。
物体检测是一个非常具有挑战性的话题,但是不要害怕,尽量从各种在线开放资源中学习,比如 Coursera、YouTube 教学视频、GitHub 和 Medium。所有这些免费的智慧可以帮助你在这个令人惊叹的领域取得成功!
未来工作——继续或改进
- 在更多类别上训练模型,以检测更多种类的对象。为了达到这个目标,我们需要首先解决不平衡数据的问题。一个潜在的解决方案是,我们可以用这些更稀有的类收集更多的图像。
a .数据扩充 —稍微改变现有图像以创建新图像
b .图像复制 —我们可以多次使用相同的图像来训练特定稀有类上的算法
c . Ensemble——在流行类上训练一个模型,在稀有类上训练另一个模型,并使用两者的预测。
2.此外,我们可以尝试不同型号的合奏,如 MobileNet、VGG 等。这是也用于对象检测的卷积神经网络算法。
如果你想详细了解我们团队的代码,这里有 GitHub 的链接。请随时提供任何反馈或意见!
通过在 GitHub 上创建一个帐户,为 bandiatindra/Object-Detection 项目开发做出贡献。
github.com](https://github.com/bandiatindra/Object-Detection-Project)****
用 10 行代码进行对象检测
本教程的第二部分用于检测您的自定义对象,可通过此 链接 获得。
人工智能的重要领域之一是计算机视觉。计算机视觉是计算机和软件系统的科学,可以识别和理解图像和场景。计算机视觉也是由图像识别、物体检测、图像生成、图像超分辨率等多方面组成。由于大量的实际使用案例,对象检测可能是计算机视觉最深刻的方面。在本教程中,我将简要介绍现代对象检测的概念、软件开发人员面临的挑战、我的团队提供的解决方案以及执行高性能对象检测的代码教程。
对象检测是指计算机和软件系统在图像/场景中定位对象并识别每个对象的能力。目标检测已经广泛应用于人脸检测、车辆检测、行人计数、网页图像、安全系统和无人驾驶汽车。在实践的许多领域中,也可以使用对象检测的许多方式。像所有其他计算机技术一样,物体检测的广泛创造性和惊人用途肯定来自计算机程序员和软件开发人员的努力。
在应用程序和系统中使用现代对象检测方法,以及基于这些方法构建新的应用程序并不是一项简单的任务。对象检测的早期实现涉及到经典算法的使用,比如流行的计算机视觉库 OpenCV 所支持的算法。然而,这些经典算法无法在不同条件下达到足够的性能。
深度学习在 2012 年的突破和快速采用带来了现代和高精度的对象检测算法和方法,如 R-CNN、Fast-RCNN、Faster-RCNN、RetinaNet 以及快速但高精度的算法和方法,如 SSD 和 YOLO。使用这些方法和算法,基于深度学习,也是基于机器学习,需要大量的数学和深度学习框架的理解。有数以百万计的专业计算机程序员和软件开发人员想要集成和创建使用对象检测的新产品。但是,由于理解和实际使用这项技术的额外和复杂的途径,他们无法接触到这项技术。
我的团队在几个月前就意识到了这个问题,这也是为什么我和约翰·奥拉芬瓦(T0)构建了(T2、T3、T4、T5)这个 python 库,让程序员和软件开发人员只需几行代码就能轻松地将最先进的计算机视觉技术集成到他们现有的和新的应用程序中。
ImageAI——一个 python 库,旨在使开发人员能够使用独立的计算机构建应用程序和系统…
github.com](https://github.com/OlafenwaMoses/ImageAI)
要使用 **ImageAI、**执行对象检测,您只需
- 在您的计算机系统上安装 Python
- 安装 ImageAI 及其依赖项
3.下载对象检测模型文件
4.运行示例代码(只有 10 行)
现在我们开始吧。
- 安装 Python 3.7.6 和 pip
(如果您已经安装了 Python 3.7.6,请跳过本节)
发布日期:2019 年 12 月 18 日现在 Python 3.7 有了更新的 bugfix 版本,取代了 3.7.6,Python 3.8 是…
www.python.org](https://www.python.org/downloads/release/python-376/)
- 安装 ImageAI 和依赖关系
(如果您已经安装了库,请跳过本节中的任何安装说明)
-张量流
pip install tensorflow==2.4.0
-其他
pip install keras==2.4.3 numpy==1.19.3 pillow==7.0.0 scipy==1.4.1 h5py==2.10.0 matplotlib==3.3.2 opencv-python keras-resnet==0.2.0
安装 ImageAI 库
pip install imageai --upgrade
3) 通过链接下载用于物体检测的 RetinaNet 模型文件。
太好了。现在,您已经安装了依赖项,可以开始编写第一个对象检测代码了。创建一个 Python 文件并给它命名(例如 FirstDetection.py ),然后将下面的代码写入其中。将 RetinaNet 模型文件和要检测的图像复制到包含 python 文件的文件夹中。
FirstDetection.py
然后运行代码,等待结果在控制台中打印出来。一旦结果被打印到控制台,转到你的 FirstDetection.py 所在的文件夹,你会发现保存了一个新的图像。看看下面的 a 2 图像样本和检测后保存的新图像。
检测前:
Image Credit: alzheimers.co.uk
Image Credit: Wikicommons
检测后:
上图控制台结果:
人:55 岁。59560.85858588666
人:53500 . 65858586666
人:69 . 58668686667
人:76 岁。59660.88868888666
自行车:80。58880 . 68888888881
人:83。58860 . 88888888881
人:89 . 48868889889
卡车:63 . 48666866667
人:60 岁。59660.66666666661
人:77 岁。59670.88878888671
公共汽车:98。59860 . 88988989881
卡车:84 人。38880 . 48888888881
汽车:71 . 48868686861
上图控制台结果:
人:71 岁。59860.88868888861
人:59650 . 68585858666
人:59860 . 68586868661
人:75 岁。59860.88888888686
摩托车:60 辆。56660 . 68686868661
公共汽车:99。39960 . 68989898991
小汽车:74 . 486868687687
人:67 . 58666866667
人:63 . 58668686667
人:78 岁。59860.88888888886
人:62 . 58666866667
人:72 . 59868686786
人:60 岁。59660.66668666661
人:81 岁。58680.88888888881
摩托车:50 辆。55660 . 68686868661
摩托车:58 辆。58860 . 68888888861
人:71 . 58686868671
自行车:91。59860 . 68888889861
摩托车:85。48860 . 88888888881
现在让我们解释一下这 10 行代码是如何工作的。
在上面的 3 行中,我们在第一行导入了 ImageAI 对象检测类,在第二行导入了 python os 类,并在第三行定义了一个变量来保存 python 文件、RetinaNet 模型文件和图像所在的文件夹的路径。
在上面的 5 行代码中,我们在第一行定义了我们的对象检测类,在第二行将模型类型设置为 RetinaNet,在第三行将模型路径设置为我们的 RetinaNet 模型的路径,在第四行将模型加载到对象检测类,然后在第五行调用检测函数并解析输入图像路径和输出图像路径。
在上面的 2 行代码中,我们迭代了第一行中由检测器. detectobjectsfroimage函数返回的所有结果,然后在第二行中打印出图像中检测到的每个对象的模型名称和百分比概率。
ImageAI 支持对象检测过程的许多强大定制。其中之一是提取图像中检测到的每个对象的图像的能力。如下所示,通过简单地将额外的参数extract _ detected _ objects = True解析到detectobjectsfroimage函数中,对象检测类将为图像对象创建一个文件夹,提取每个图像,将每个图像保存到创建的新文件夹中,并返回一个额外的数组,该数组包含每个图像的路径。
让我们将它应用到第一个图像,并从下面的结果中看到一些图像:
所有行人的照片都已经提取好了。我没有把它们都包括进去,因为它们会占用不必要的空间。
要检测你自己类型的物体,请访问下面链接的教程。
关于在您自己的数据集上训练对象检测模型的分步教程
medium.com](https://medium.com/deepquestai/train-object-detection-ai-with-6-lines-of-code-6d087063f6ff)
如果您想了解更多有用和实用资源的链接,请访问下面链接的物体检测指南。
现在我们知道了一点什么是对象检测,不同类型的对象检测之间的区别…
www.fritz.ai](https://www.fritz.ai/object-detection/) [## 对象检测算法和库- neptune.ai
对象检测在图像中找到并识别事物,这是深度学习的最大成就之一…
海王星. ai](https://neptune.ai/blog/object-detection-algorithms-and-libraries)
ImageAI 提供了更多有用的功能,可用于定制和生产部署对象检测任务。支持的一些功能包括:
-
**调整最小概率:**默认情况下,检测到的概率百分比小于 50 的物体不会被显示或报告。对于高确定性情况,您可以增加该值;对于需要检测所有可能对象的情况,您可以减少该值。
-
**自定义对象检测:**使用提供的 CustomObject 类,您可以告诉检测类报告对一个或几个唯一对象的检测。
-
**检测速度:**您可以通过将检测速度设置为“快”、“更快”和“最快”来减少检测图像所需的时间。
-
**输入类型:**您可以指定并解析一幅图像的文件路径、Numpy 数组或一幅图像的文件流作为输入图像
-
输出类型:您可以指定detectobjectsfroimage函数应该以文件或 Numpy 数组的形式返回图像
你可以在官方的 GitHub 知识库上找到关于如何利用上述功能的所有细节和文档,以及包含在 ImageAI 中的其他计算机视觉功能。ImageAI 是由 DeepQuest AI 开发的开源项目。
在设备和云上提供 AI APIs。
deepquestai.com](https://deepquestai.com)
https://github.com/OlafenwaMoses/ImageAI
如果你觉得这篇文章很有帮助并且喜欢,请给它一个掌声。此外,请随意与朋友和同事分享。
你有什么问题、建议或者想要联系我吗?给我发一封电子邮件到 guymodscientist@gmail.com。我也可以通过账号@OlafenwaMoses 在 twitter 上联系,通过 https://www.facebook.com/moses.olafenwa 在脸书联系。
基于深度学习的航空图像目标检测
想象你在一个内陆国家,一种传染病已经传播开来。政府已经垮台,反叛者正在全国流窜。如果你是这种情况下的军队,你如何在这种环境下做决定?你如何能完全理解眼前的情况?
几个月前,北约组织了一个创新挑战赛,提出了这个场景和这些问题。我们决定接受挑战,目标是在数据过滤/融合、可视化和预测分析领域找到创新的解决方案。
对于那些不知道的人来说,北约是 29 个北美和欧洲国家的政府间军事联盟。它构成了一个集体防御体系,其独立成员国同意共同防御,以应对任何外部方的攻击。
北约没有为挑战提供任何数据,所以我们必须自己寻找。最终,我们提出的解决方案使用了各种不同的技术,包括航空图像的计算机视觉、新闻和社交媒体上的自然语言处理、地理数据处理,当然还有精美的图表。
在这篇文章中(最初发表在 Dataiku 的 blo g 上),我们将专注于最技术性的部分:空中图像的目标检测,浏览我们使用的数据类型,采用的架构,以及解决方案的工作方式,最后是我们的结果。如果你有兴趣从更高的层面来看这个项目,就在这里结束。
1.数据集
对于项目的目标检测部分,我们使用了由劳伦斯利弗莫尔国家实验室提供的 Cars Overhead 和上下文 (COWC)数据集。它以在六个不同地点拍摄的航空影像为特色:
- 加拿大多伦多
- 新西兰塞尔温
- 德国波茨坦和瓦欣根*
- 哥伦布(俄亥俄州)*和美国犹他州
*我们最终没有使用哥伦布和 Vaihingen 的数据,因为图像是灰度的。
该数据集提供了具有良好分辨率(每像素 15 厘米)的大图像(最大 4 平方公里),并具有每辆汽车的中心定位。正如在这篇中型文章中所建议的,我们假设汽车的平均尺寸为 3 米。我们创建了以每个汽车中心为中心的盒子,以实现我们在看不见的图像中预测盒子(即汽车)位置的最终目标。
Figure 1: An example image from the COWC dataset
2.建筑
为了在这些大型航拍图像中检测汽车,我们使用了 RetinaNet 架构。这篇论文于 2017 年由脸书博览会发表,获得了 2017 年 ICCV 最佳学生论文。
目标检测架构分为两类:单级和两级。
两阶段架构首先将潜在对象分为两类:前景或背景。然后将所有前景的潜在对象分类到更细粒度的类中:猫、狗、汽车等。这种两阶段方法非常慢,但当然也能产生最佳精度。最著名的两级架构是 Faster-RCNN 。
另一方面,单级架构没有这个潜在前景对象的预选步骤。它们通常不太准确,但也更快。RetinaNet 的单级架构是个例外:在拥有单级速度的同时达到了两级性能!
在下面的图 2 中,您可以看到各种对象检测架构的比较。
Figure 2: Performance of object detection algorithms
RetinaNet 由几个组件组成。我们将尝试描述数据是如何通过每一步进行转换的。
Figure 3: The RetinaNet architecture
2.1.卷积网络
首先有一个ResNet-50。和每一个卷积神经网络 (CNN)一样,它以一幅图像为输入,通过几个卷积核进行处理。每个内核的输出都是一个特征图——第一个特征图捕获高级特征(如线条或颜色)。我们在网络中越往下走,由于合并图层的原因,要素地图就变得越小。虽然它们更小,但是它们也代表了更细粒度的信息(比如一只眼睛,一只狗的耳朵,等等。).输入图像有三个通道(红、蓝、绿),但是每一个后续的特征图都有几十个通道!它们中的每一个都代表了它捕捉到的不同类型的特征。
一个公共分类器获取 ResNet 的最后一个特征图(形状为(7, 7, 2048)
),在每个通道上应用平均池(结果为(1, 1, 2048)
),并通过 softmax 将其提供给一个完全连接的层。
2.2.特征金字塔网络
RetinaNet 没有在 ResNet 之后增加一个分类器,而是增加了一个 特征金字塔网络 (FPN)。通过从 ResNet 中选取不同图层的要素地图,它提供了丰富的多比例尺要素。
Figure 4: The lateral connection between the backbone and the FPN
然而,ResNet 的第一批特征地图可能过于粗糙,无法提取任何有用的信息。正如您在图 4 中看到的,更小、更精确的特征地图与更大的特征地图结合在一起。我们首先对较小的样本进行上采样,然后将其与较大的样本相加。存在几种上采样方法;这里,上采样是用最近邻法完成的。
FPN 的每一层以不同的尺度编码不同种类的信息。因此,他们中的每一个都应该参与目标检测任务。FPN 将 ResNet 的第三(512 channels
)、第四(1024 channels
)和第五(2048 channels
)块的输出作为输入。第三个是第四个的一半大小,第四个是第五个的一半。
我们应用了逐点卷积(具有1x1
内核的卷积)来使每个级别的通道数一致化为256
。然后,我们将较小的级别向上采样两倍,以匹配较大级别的维度。
2.3.锚
在每个 FPN 级别,几个锚点 围绕 FPN 的特征地图移动。锚点是具有不同大小和比例的矩形,如下所示:
Figure 5: A sample of anchors of different sizes and ratios
这些锚点是潜在对象的基本位置。存在五种尺寸和三种比率,因此有 15 个独特的锚。这些锚也根据 FPN 层级的维度进行缩放。这些唯一的锚被复制在特征地图中所有可能的位置上。其结果是K
总锚。
让我们暂时把这些锚放在一边。
2.4.回归和分类
每个 FPN 的水平被馈送到两个完全卷积网络 (FCN),这是仅由卷积和池构成的神经网络。为了充分利用每个 FPN 级别拥有不同类型信息的事实,这两个 fcn 在所有级别之间共享!卷积层与输入大小无关;只有它们的内核大小有关系。因此,虽然每个 FPN 的特征地图具有不同的大小,但是它们都可以被馈送到相同的 fcn。
第一个 FCN 是回归分支。它预测K x 4
*(每个锚点的 x1,y1,x2,y2)*值。这些值是增量,稍微修改了原始锚点,使它们更适合潜在的对象。所有潜在对象现在都将具有以下类型的坐标:
(x1 + dx1, y1 + dy1, x2 + dx2, y2 + dy2)
用x?
和y?
,锚点的固定坐标,和dx?
、dy?
,回归分支产生的增量。
我们现在有了所有对象的最终坐标——也就是所有潜在的对象。他们还没有被归类为背景或汽车,卡车等。
第二个 FCN 是分类分支。这是一个多标签问题,其中分类器预测具有 sigmoid 的K x N
( N
是类的数量)潜在对象。
2.5.删除重复项
此时我们有了K x 4
坐标和K x N
类分数。我们现在有一个问题:对于同一个类,检测同一个对象的几个盒子是很常见的!
Figure 6: Several boxes have been detected for a single car.
因此,对于每个类(即使它不是最高分的类),我们应用一个非最大抑制。Tensorflow 提供了一个函数来做这件事:
tf.image.non_max_suppression(boxes, scores, max_output_size, iou_threshold)
这种方法的要点是,它将删除重叠的框(如图 6 所示),只保留一个。它还使用scores
来保存最可能的盒子。
对上面 Tensorflow 方法的输入参数的一般评论:max_output_size
对应于我们最终想要的最大盒子数—假设是 300 个。iou_threshold
是一个介于 0 和 1 之间的浮点数,描述了可接受的最大重叠率。
Figure 7: Figure 6 after the non-max-suppression has been applied.
2.6.保留最可能的类
相同位置相同类别的重复框现在被移除。对于剩余的每个箱子,我们只保留得分最高的类别(汽车、卡车等)。).如果没有一个类的分数高于一个固定的阈值(我们使用了0.4
),那么它就被认为是背景的一部分。
2.7.焦点损失
所有这些听起来可能很复杂,但这并不新鲜——仅仅有好的准确性是不够的。RetinaNet 的真正改进是它的损失:焦点损失。没有潜在对象预选的单级架构被背景对象的高频率所淹没。焦点损失通过给予分类良好的例子(通常是背景)较低的权重来处理它。
Figure 8: We define Pt, the confidence to be right
在图 8 中,我们定义了Pt
,即二元分类中正确的置信度。
Figure 9: The Focal Loss
在图 9 中,我们通过因子(1 — Pt)^y
对交叉熵损失-log(Pt)
进行建模。这里,y
是在 0 和 5 之间振荡的调制因子。分类良好的例子有一个高的Pt
,因此一个低的因素。因此,分类良好的示例的损失非常低,并迫使模型学习更难的示例。从图 10 中可以看出损失受到了多大的影响。
Figure 10: The focal loss under various modulating factors
3.履行
我们使用了 Fizyr 的 RetinaNet 的优秀的 Keras 实现。我们还编写了一个新的生成器,用熊猫的数据帧代替 CSV 文件。
Code block 1: The Generator taking Pandas DataFrame.
如您所见,**没有注释的图像保留在训练阶段。**它们仍然有助于我们算法的训练,因为它迫使算法不能到处看到汽车(即使没有任何汽车)。
我们在可可上使用了一个预训练的 RetinaNet,然后针对 COWC 数据集对其进行了微调。只有两个 fcn 为这项新任务进行了再培训,而 ResNet 主干网和 FPN 被冻结。
您可以在下面的代码块 2 中看到如何加载 RetinaNet 并编译它。注意,在加载砝码时添加skip_mismatch=True
很重要!在 COCO 上创建的权重有 80 个类,但是在我们的例子中只有 1 个类,因此锚的数量是不同的。
Code block 2: Loading the RetinaNet and compile it.
我们仍然需要处理一些事情,那就是每个图像的巨大重量。来自 COWC 数据集的图像高达 4 平方公里,或 13k 像素宽和高。这些大图片重达 300 兆字节。将如此大的图像输入我们的视网膜是不切实际的。因此,我们将图像切割成 1000x1000 像素(或 150x150 米)的小块。
然而,错过汽车是愚蠢的,因为它们在两个补丁之间被切断。因此,为了避免这个问题,我们制作了一个 1000x1000 像素的滑动窗口,它以 800 像素的步长移动。这样,两个相邻的补片之间就有 200 像素宽的重叠。
这就导致了另一个问题:我们可能会检测两次汽车。为了消除重复,我们在将小补丁绑定在一起时应用了非最大抑制。事实上,这意味着我们有两次非最大值抑制:在 RetinaNet 和之后,将小补片绑定在一起。对于第二个非最大值抑制,我们使用了来自 PyImageSearch 的 Numpy 版本:
Code block 3: PyImageSearch’s non-max suppression. [source]
在处理航空影像时,我们可以使用大量的数据增强。首先,我们可以翻转横轴和纵轴。我们也可以将图像旋转任意角度。如果影像的比例不一致(无人机到地面的距离可能不恒定),随机缩放图片也很有用。
4.结果
你可以在下面的图 11 和图 12 中看到我们的 RetinaNet 在这张看不见的盐湖城图片上的表现。
Figure 11: 13,000 detected cars in a 4 square kilometer area of Salt Lake City
Figure 12: A zoom in of Figure 11
5.我们和好了吗?
如何评价自己的表现?
准确度不够;我们需要看看我们得到了多少假阳性和假阴性。如果我们到处检测汽车,我们会有很多假阳性,但如果我们错过了大多数汽车,那就有很多假阴性。
召回测量前者,而精确测量后者。最后, f1 得分是这两个指标的组合。
Code block 4: Computing the precision, recall, and F1-score
然而,我们并不期望我们的 RetinaNet 在准确的像素点上检测到汽车。因此,我们正在计算被检测车辆和地面实况车辆的 Jaccard 指数,如果它大于选择的阈值,我们认为该车辆被正确检测。请注意,Jaccard 索引通常也称为交集-并集 (IoU):
Code block 5: The Jaccard index
Figure 13: True Positive (green), False Positive (yellow), and False Negative (red)
您可以在图 13 中看到一个示例,其中绘制了真阳性、假阳性和假阴性。
注意,四个误报中,有两个是垃圾箱,一个是重复的,还有一个居然是……一辆车!事实上,正如在每个数据集中一样,在基本事实注释中可能会有一些错误。
在图 12 中,f1 值为 0.91。通常在更多的城市环境中,f1 分数大约为 0.95。我们的模型所犯的主要错误是将建筑物顶部的通风井视为汽车。对于模型的辩护,没有建筑知识,这是很难看到的。
6.结论
对于 NATO challenge,我们不仅使用航空图像中的汽车检测,而且这是项目的主要技术部分。
哦…我们忘记告诉你挑战结果了吗?
颁发了三个奖项:北约奖(去诺福克旅游),法国奖(25000 美元),德国奖(去柏林旅游)。
我们同时获得了北约和法国奖!
你可以在这里阅读更多关于这个项目的高层信息(包括我们使用的所有数据和方法论)。
Figure 14: General Maurice, Supreme Commander Mercier, and our team
原载于大台库博客《来自战壕的数据》2018 年 6 月 22 日 【链接】 。这篇文章是我在 Dataiku 实验室实习时写的,这个项目是我作为首席技术人员做的许多项目之一。
每周精选
使用神经网络进行物体检测——使用 keras 的简单教程
由约翰尼斯·里克 — 10 分钟阅读。
图像分析是深度学习中最突出的领域之一。图像很容易生成和处理,它们正是机器学习的正确数据类型:对人类来说容易理解,但对计算机来说很难。毫不奇怪,图像分析在深度神经网络的历史中发挥了关键作用。
你不能编造这些东西…或者,你能吗?
到埃里克森 — 10 分钟读取。
2016 年 11 月 7 日,我们见证了篮球史上最伟大的时刻之一。金州勇士队的斯蒂芬·库里打破了一场比赛最多三分球的记录。但是,他做的不止这些。这是一种回归——库里一直在努力,就在一场比赛前,他和他的勇士队输给了湖人队。
Word2Vec (skip-gram model): 直觉 & 在 TF 中实现
通过Manish Chablani—7&2 分钟读取。
skip-gram 神经网络模型的最基本形式实际上非常简单。训练一个只有一个隐藏层的简单神经网络来执行某项任务,但是我们实际上不会将该神经网络用于我们训练它的任务!相反,目标实际上只是学习隐藏层的权重——我们将看到这些权重实际上是我们试图学习的“单词向量”。
如果出租车旅行是萤火虫:13 亿次纽约出租车旅行被绘制
由 Ravi Shekhar — 9 分钟读取。
纽约市出租车和豪华轿车委员会(TLC)公开发布了一个从 2009 年 1 月到 2016 年 6 月的出租车出行数据集,其中包含起点和终点的 GPS 坐标。
我们能复制大脑吗?
由Eugenio culrciello—15 分钟阅读。
本月的 IEEE Spectrum 有一个关于合成大脑的故事。在这篇文章中,我将回顾这个故事,并对探索的现状进行评论:在合成系统中复制人脑。
神经网络中使用的优化算法类型和优化梯度下降的方法
安尼施·辛格·瓦利亚,13 分钟。
您是否曾经想过,通过更新模型参数,如权重和偏差值,为您的神经网络模型使用哪种优化算法来产生稍好且更快的结果。
黄砖路线图
通过彼得·斯威尼 — 7 分钟读取。
每个伟大的项目都需要路线图。对许多人来说,通往人工智能的道路需要对人类智能的深刻理解。如果这看起来很明显,你会惊讶于这个故事是如何展开的,以及你的专业知识在其中可能扮演的关键角色。
深度学习中的对立例子
由格雷戈里城堡 — 9 分钟阅读。
这篇文章将包含与我在上次深度学习会议上的演讲基本相同的信息。我觉得随着越来越多的领域开始在关键系统中使用深度学习,让人们意识到神经网络如何被愚弄以产生奇怪和潜在危险的行为是很重要的。
美德信号还是新闻阅读?参议员在推特上相互追随的原因探究
通过 Viet Vu — 7 分钟读取。
当你上唐纳德·特朗普的推特时,你首先注意到的一件事是他关注的账户很少。截至 2017 年 6 月 13 日,这一数字为 45。新闻 文章的号对他关注的账号进行了报道。
用神经网络进行目标检测——使用 keras 的简单教程
TLDR: 一个非常轻量级的图像目标检测教程。我们将引导简单的图像,并对它们应用越来越复杂的神经网络。最终,该算法将能够检测出形状和颜色各异的多个物体(如下图)。你应该对神经网络有一个基本的了解。
图像分析是深度学习中最突出的领域之一。图像很容易生成和处理,它们正是机器学习的正确数据类型:对人类来说容易理解,但对计算机来说很难。毫不奇怪,图像分析在深度神经网络的历史中发挥了关键作用。
在这篇博文中,我们将探讨对象检测——找出图像中的对象。例如,想象一辆自动驾驶汽车需要检测路上的其他汽车。目标检测有很多复杂的算法。它们通常需要庞大的数据集、非常深的卷积网络和很长的训练时间。为了使本教程易于理解,我们将应用两个简化:1)我们不使用真实的照片,而是具有抽象几何形状的图像。这允许我们引导图像数据并使用更简单的神经网络。2)我们预测每个图像中固定数量的对象。这使得整个算法变得非常非常简单(除了一些技巧之外,它实际上出奇的简单)。在帖子的最后,我将概述如何扩展这种方法来检测图像中的更多对象。
我试图使本教程尽可能简单:我将一步一步来,从检测单个对象开始。对于每一步,都有一个 Jupyter 笔记本,在这个 github repo 中有完整的代码。您不需要下载任何额外的数据集。代码是用 Python plus keras 编写的,所以即使对初学者来说,网络也应该容易理解。此外,我使用的网络(大部分)是非常简单的前馈网络,所以你可以在几分钟内训练它们。
检测单个物体
让我们从简单的开始:我们将预测单个矩形的边界框。为了构建“图像”,我创建了一组 8×8 的 numpy 数组,将背景设置为 0,并将数组中的一个随机矩形设置为 1。下面举几个例子(白色为 0,黑色为 1):
神经网络是一个非常简单的前馈网络,只有一个隐藏层(没有卷积,没有花哨)。它以展平后的图像(即 8×8 = 64 个值)作为输入,预测包围盒的参数(即左下角的坐标 x 和 y,宽度 w 和高度 h)。在训练期间,我们简单地通过均方误差(MSE)进行预测到期望边界框的回归。我在这里使用了 adadelta 作为优化器——它基本上是标准的随机梯度下降,但是具有自适应的学习速率。这是一个非常好的实验选择,因为你不需要在超参数优化上花费太多时间。以下是该网络在 keras 中的实现方式:
model = Sequential([
Dense(200, input_dim=64),
Activation('relu'),
Dropout(0.2),
Dense(4)
])
model.compile('adadelta', 'mse')
我用 40k 张随机图像训练了这个网络 50 个时期(在我笔记本电脑的 CPU 上大约 1 分钟),得到了几乎完美的结果。下面是上面图像中预测的边界框(它们是在训练过程中展示的):
很好,不是吗?你可以看到,我还在每个边界框上方绘制了 IOU 值:这个索引被称为IintersectionOverUnion,并测量预测和实际边界框之间的重叠。它的计算方法是将相交面积(下图中的红色)除以并集面积(蓝色)。IOU 介于 0(无重叠)和 1(完全重叠)之间。在上面的实验中,我得到了平均 0.9 的近乎完美的 IOU(基于保留的测试数据)。本节代码在本 Jupyter 笔记本中。
检测多个物体
预测单个对象没那么有趣,所以让我们添加另一个矩形。基本上,我们使用与上面相同的方法:用 8x8 numpy 阵列引导图像,并训练前馈神经网络来预测两个边界框(即向量 x1,y1,w1,h1,x2,y2,w2,h2 )。然而,如果我们继续这样做,我们会得到以下(相当令人失望)的结果:
两个边界框似乎都在矩形的中间。发生了什么事?想象以下情况:我们在上面图中最左边的图像上训练我们的网络。假设左矩形的期望包围盒在目标向量中的位置 1(x1,y1,w1,h1 ),右矩形的期望包围盒在向量中的位置 2(x2,y2,w2,h2 )。显然,我们的优化器将改变网络的参数,使得第一个预测器向左移动,第二个预测器向右移动。现在想象一下,稍后我们遇到了一个类似的图像,但是这次目标向量中的位置被交换了(即左矩形在位置 2,右矩形在位置 1)。现在,我们的优化器将把预测器 1 拉到右边,把预测器 2 拉到左边——与前面的更新步骤正好相反!实际上,预测的边界框位于中心。由于我们有一个巨大的数据集(40k 图像),将会有很多这样的“副本”。
解决方案是在训练期间将每个预测的边界框“分配”给一个矩形。然后,预测器可以学习专攻矩形的某些位置和/或形状。为了做到这一点,我们在每个时期之后处理目标向量:对于每个训练图像,我们计算预测和目标之间的均方误差 A)对于目标向量中边界框的当前顺序(即 x1,y1,w1,h1,x2,y2,w2,h2 ),以及 B)如果目标向量中的边界框被翻转(即 x2,y2,w2,h2,x1,y1,w1,h1 )。如果 A 的 MSE 低于 B,我们保持目标向量不变;如果 B 的 MSE 低于 A,我们翻转向量。我在这里实现了这个算法。下面是翻转过程的可视化:
上图中的每一行都是来自训练集的样本。从左到右是训练过程的时期。黑色表示目标向量在此时期后翻转,白色表示没有翻转。你可以很好地看到,大多数翻转发生在训练的开始,当预测者还没有专门化的时候。
如果我们在启用翻转的情况下训练我们的网络,我们会得到以下结果(同样是在保留的测试图像上):
总体而言,该网络在训练数据上实现了 0.5 的平均 IOU(我没有计算测试数据集的 IOU,但应该非常相似)。不像单个矩形那样完美,但是相当不错(特别是考虑到它是一个如此简单的网络)。请注意,最左边的图像与之前图中的图像相同(没有翻转的图像),您可以清楚地看到预测器已经学会了专门处理矩形。
最后,关于翻转算法还有两点需要注意:首先,上面介绍的方法当然只对两个矩形有效。然而,通过查看预测器和矩形的所有可能组合,您可以很容易地将其扩展到多个矩形(我将在下面更详细地解释这一点)。其次,您不必使用均方差来决定目标是否应该翻转——您也可以使用 IOU 甚至边界框之间的距离。在我的实验中,所有三个指标导致了非常相似的结果,所以我决定坚持使用 MSE,因为大多数人应该对它很熟悉。
分类对象
到目前为止,探测物体已经做得很好了,但是我们当然也想知道物体是什么。因此,我们将添加三角形并分类对象是矩形还是三角形。酷的是,我们不需要任何额外的算法或工作流程。我们将使用与上面完全相同的网络,并且只将每个边界框的一个值添加到目标向量:如果对象是矩形,则为 0,如果对象是三角形,则为 1(即,二进制分类;这里的代号是。
下面是结果(我把图片尺寸增加到 16x16,这样小三角形更容易识别):
红色边界框表示网络预测了矩形,黄色表示预测了三角形。样本已经表明分类工作得相当好,而且我们确实获得了几乎完美的分类准确度。
把它们放在一起:形状、颜色和卷积神经网络
好了,一切都正常了,现在让我们来玩一玩:我们将把这个方法应用到一些更“真实”的场景中——这意味着:不同的颜色,更多的形状,一次多个物体。为了引导图像,我使用了 pycairo 库,它可以将 RGB 图像和简单的形状写入 numpy 数组。我也对网络本身做了一些修改,但让我们先来看看结果:
如你所见,边界框并不完美,但大多数时候它们都在正确的位置。测试数据集上的平均 IOU 在 0.4 左右,对于一次识别三个对象来说还不错。预测的形状和颜色(写在边界框上面)非常完美(测试准确率为 95 %)。显然,网络已经真正学会了将预测器分配给不同的对象(正如我们用上面介绍的翻转技巧所瞄准的)。
与上面的简单实验相比,我做了三处修改:
1)我使用了卷积神经网络(CNN)而不是前馈网络。CNN 用可学习的“过滤器”扫描图像,并在每一层提取越来越多的抽象特征。例如,早期层中的过滤器可以检测边缘或颜色梯度,而后期层可以记录复杂的形状。我不会在这里讨论技术细节,但你可以在斯坦福大学 CS231n 班的讲座或迈克尔·尼尔森的书的这一章中找到精彩的介绍。对于上面显示的结果,我训练了一个有四个卷积层和两个池层的网络大约 30-40 分钟。更深/更优化/更长时间训练的网络可能会得到更好的结果。
2)我没有使用单个(二进制)值进行分类,而是使用 one-hot vectors(处处为 0,类的索引处为 1)。具体来说,我对每个对象使用一个向量来分类形状(矩形、三角形或圆形),一个向量来分类颜色(红色、绿色或蓝色)。请注意,我在输入图像中添加了一些随机的颜色变化,看看网络是否能够处理这种情况。总而言之,图像的目标向量由每个对象的 10 个值组成(4 个用于边界框,3 个用于形状分类,3 个用于颜色分类)。
3)我修改了翻转算法来处理多个边界框(如上所述)。在每个时期之后,该算法计算一个预测的和一个预期的边界框的所有组合的均方误差。然后,取这些值中的最小值,将相应的预测和预期边界框相互赋值,从尚未赋值的框中取出下一个最小值,依此类推。
你可以在这个笔记本里找到最终代码。
现实世界的物体
识别形状是一个很酷很简单的例子,但显然这不是你想在现实世界中做的事情(不幸的是,自然界中没有那么多抽象的 2D 形状)。此外,我们的算法只能预测每幅图像的固定数量的包围盒。然而,在现实世界中,你有各种各样的场景:一条小岔路上可能没有汽车,但只要你在高速公路上行驶,你就必须同时识别数百辆汽车。
尽管这似乎是一个小问题,但实际上很难解决——如果算法不知道有多少个对象,它应该如何决定什么是对象,什么是背景?想象你自己从近处看一棵树:即使你只看到一堆树叶和树枝,你仍然可以清楚地说这都是一个物体,因为你明白树是什么。如果树叶散落在地板上,你会很容易发现它们是单独的物体。不幸的是,神经网络不太理解什么是树,所以这对它们来说是一个相当大的挑战。
在对可变数量的对象进行对象检测的许多算法中(例如over feet或R-CNN;看一下这个讲座的概况),我只想重点介绍一个,因为它和我们上面用的方法很像:它叫YOLO(YouOonlyLookOnce)。与旧的方法相比,它只需通过一个神经网络就可以检测图像中的对象。简而言之,它将图像划分为一个网格,为每个网格单元预测两个边界框(即,与我们上面所做的完全相同),然后尝试在整个图像中找到最佳边界框。因为 YOLO 只需要通过一个网络,它的速度非常快,甚至可以处理视频。下面是一个演示,你可以在这里看到更多的例子。
如果你想了解我的工作,请在 Twitter 上关注我( @jrieke )!你也可以在我的网站上看看其他的项目。
带有语音反馈的物体检测— YOLO v3 + gTTS
帮助盲人听到他们看不见的东西。
期末考试终于结束了!!!我被计算机视觉中的物体检测的想法迷住了,并想开始一个关于它的项目。我意识到,我们或许可以通过图像到文本和文本到语音的转换来帮助盲人“看”得更好,而不需要任何复杂的硬件。
要完全理解整个流程中的每一个环节是非常困难的,但是我已经尽我所能去理解这个任务。
目标检测
是计算机视觉的一个领域,它检测图像/视频中语义对象的实例(在我们的例子中,通过在它们周围创建边界框)。然后,我们可以将注释文本转换成语音响应,并给出对象在人/摄像机视野中的基本位置。
非常高层次的概述
- **训练数据:**用上下文中的公共对象 (COCO)数据集训练模型。你可以在链接中浏览他们标记的图片,这很酷。
- 模型:这里的模型是你只看一次 (YOLO)算法,它通过一种极其复杂的卷积神经网络架构的变体运行,称为暗网。尽管我们使用的是一个更加增强和复杂的 YOLO v3 模型,我还是会解释最初的 YOLO 算法。另外,python cv2 包有一个从 yolov3.cfg 文件中的配置设置 Darknet 的方法。
这一次我更感兴趣的是让一些东西尽快工作,所以我将使用一个预先训练好的模型。这意味着可可已经被其他人在 YOLO v3 上训练过,并且我们已经获得了存储在 200+mb 文件中的权重。
如果你不确定什么是权重,就把它想象成在线性回归中寻找最佳拟合线。我们需要找到 y=mx+c 中 m 和 c 的正确值,使我们的线使所有点之间的误差最小。现在,在我们更复杂的预测任务中,当我们将图像输入复杂的网络时,我们有数百万个 x。这些 x 每个都有一个 m,这些是存储在 yolov3.weights 文件中的预测重量。这些 m s 已经被不断地重新调整以最小化一些功能损失。
3.**输入数据:**我们将使用我们的网络摄像头以每秒 30 帧的速度向这个经过训练的模型提供图像,我们可以将其设置为每隔一帧处理一次,以加快速度。
- API: 每一帧中检测到的物体的类别预测将是一个字符串,例如“猫”。我们还将获得图像中对象的坐标,并将位置“上”/“中”/“下”&“左”/“中”/“右”附加到类预测“猫”上。然后,我们可以使用 gTTS 包将文本描述发送到 Google 文本到语音转换 API。
5.**输出:**我们还将获得在我们的帧中检测到的每个对象的边界框的坐标,将这些框覆盖在检测到的对象上,并将帧流作为视频回放返回。我们还将计划在每秒的第一帧(而不是 30 fps)获得语音反馈,例如“左下角的猫”,这意味着在我的相机视图的左下角检测到一只猫。
理解 YOLO 算法
以前,基于分类的模型用于使用定位、基于区域的分类或诸如滑动窗口之类的东西来检测对象。只有图像的高得分区域被认为是检测,并且它们可能非常耗时。
All that work just for 1 frame.
相反,YOLO 是基于回归的。我们在算法**(只看一次图像的像素)、、的一次运行中快速预测整个图像的类别和边界框,以便图像中的全局上下文通知、**预测。
训练时间
Object classes in coco.names file are indexed.
c 代表我们试图标记的对象的类索引。一个运动球意味着 C=33。训练已经在 COCO 上完成了。
Values in pixels, measured from (0,0) as top-left. Example of how the images are labeled to train the model.
在训练期间,我们必须以这种格式C bx by bw bh
为图像中的每个对象手动标记以下 5 个值。我们还将通过将 4 个 b 值表示为 W & H (1280 x 720 px)的一部分,将每个 b 值归一化到 0–1 之间。
假设我们在框架中标记了两个对象——运动球和我自己。这由张量表示:向量的一般形式,将在训练期间输入到模型中。
[33, 0.21, 0.58, 0.23, 0.42] - sports ball
[1, 0.67, 0.5, 0.5, 0.9] - myself
预测/检测时间
现在,我们在预测时间将 1280 x 720 帧从我们的相机输入到 YOLO。YOLO 会自动将其大小调整为 416 x 234,并通过用 0 填充超出部分来适应流行的标准大小的 416 x 416 网络。YOLO 将每幅图像分成 S×S 个单元,每个单元的大小为 32×32(缩减系数=32)。这就产生了 416/32 = 13 x 13 个单元。
Using 8x8 cells for illustration. Dark-green box is the cell which contains the center of the object.
边界框中有 5 个值— (bx,by,bw,bh,BC)
如果对象的中心(红点)落入网格单元,则只有该网格单元(深绿色单元)负责检测该对象。每个边界框有 5 个值。前 4 个值 bx,by,bw,bh 代表盒子的位置。
- Normalized using the coordinates of the top-left corner of the cell which contains the object’s center. 2) using the dimensions of the entire image.
第 5 个值是 BC :盒子置信度得分。
BC = Pr(存在于框中的对象)* IOU ( 并集上的交集)。
这衡量了盒子中包含一个任意类的物体的可能性以及预测的准确性。如果在那个盒子里不存在任何物体,那么 BC=0,我们希望 BC=1 来预测地面实况。
Fairly high IOU
在每个网格单元中预测有 B 个包围盒
YOLO v3 makes B=3 bounding boxes in each cell to predict that one object in the cell.
在每个网格单元中也有 C 个条件类概率
当我们使用 COCO 时,每个单元格有 80 个条件类概率— Pr(Class i | Object)。假定在单元中有一个对象,则预测的对象属于 I 类的概率。
1 person 0.01
2 bicycle 0.004
.
.
33 sports ball 0.9
.
.
80 toothbrush 0.02
在我们上面的例子中,类别 33 具有最高的概率,并且它将被用作我们对该对象是一个运动球的预测。
综上所述
有 S×S 个单元,并且在这些单元的每一个中有 2 样东西:1) B 个边界框,每个边界框有 5 个值(bx,by,bw,bh,BC),2) C 个条件类概率。预测被编码为一个 S x S x (5 * B + C)张量。
非最大抑制
对于唯一用于预测对象的网格单元,实际上有 B 个重复检测(深绿色框)。NMS 抑制了具有低盒置信度分数的检测:BC,以便当只有一个运动球时,我们不会最终预测到 3 个运动球。NMS 的实现可以是:
- 从具有最高 BC 的边界框开始。
- 移除与其重叠超过给定阈值量= 0.5 的任何剩余边界框。
- 转到步骤 1,直到不再有边界框。
损失函数
虽然我们已经有了我们的预测,但我们想了解权重是如何调整的,以使我们在训练期间的损失函数最小化。这个函数看起来很复杂,但分解起来却非常直观。
- 地面实况框与预测边界框之间的差异。
- 物体在盒子中的 100%置信度与盒子置信度之间的差异。
- C 实际类别概率(0,…,1,…,0)与 C 预测类别概率(0.01,…,0.8,…,0.02)之间的差异
Basically uses sum of squared-differences for each component. Most symbols are pretty self-explanatory.
参数λcoord 通常=5,以增加定位损失的权重,使其更重要。
参数λnoobj 通常=0.5,以降低置信度损失的权重,因为不包含对象的盒子具有置信度得分 BC=0。这使得模型更稳定,更容易收敛。
语音反馈
我们可以使用相对于 W & H 的 bx & by 来确定检测到的物体的位置,并通过这个简单的命令将其作为文本字符串发送给 gTTS。
tts = gTTS("mid left sports ball, lang=’en’)tts.save(‘tts.mp3’)
我还使用了 pydub 和 ffmpeg 来操作生成的音频文件。
演示
我不能实时返回帧,因为当它处理每 30 帧时,会使视频播放看起来非常不稳定。我还研究了多线程技术,理论上讲,每隔 30 帧就应该创建一个进程来处理视频,另一个进程用于视频播放。
然而,我只能对我的网络摄像头上实时检测到的物体进行口头描述,这更重要,因为盲人无论如何都看不到边界框。对于下面的视频,我在传递它之前记录了自己,以创建边界框并生成口头响应。
在那里,YOLO v3 的可可随着 gTTS,做它的魔术!
我很享受这个学习、实践、然后分享的过程。我认为“从应用中学习”在分享方面更上一层楼。将复杂的问题分解成简单的问题,用外行人的语言理解和解释困难的概念,这是我想进一步磨练的技能。更多即将推出!
请在 LinkedIn 或通过 jasonyip184@gmail.com 与我进一步讨论!
参考文献
[## 基于 OpenCV - PyImageSearch 的 YOLO 目标检测
在本教程中,您将学习如何使用 YOLO 对象检测器来检测图像和视频流中的对象…
www.pyimagesearch.com](https://www.pyimagesearch.com/2018/11/12/yolo-object-detection-with-opencv/) [## 了解 YOLO
这篇文章解释了 YOLO 对象检测体系结构,从某人的角度谁想要实现…
hackernoon.com](https://hackernoon.com/understanding-yolo-f5a74bbc7967) [## 使用 YOLO、YOLOv2 和现在的 YOLOv3 进行实时物体检测
你只看一次(YOLO)是一个目标为实时处理的对象检测系统。我们将介绍 YOLO…
medium.com](https://medium.com/@jonathan_hui/real-time-object-detection-with-yolo-yolov2-28b1b93e2088)
过食中的物体定位
目标定位的任务是预测图像中的目标及其边界。目标定位和目标检测之间的区别是微妙的。简单地说,目标定位旨在定位图像中的主要(或最可见)目标,而目标检测则试图找出所有目标及其边界。
Citation needed.
AlexNet 应该是第一个用来做物体定位或检测的神经网络。由于 Alexnet 的论文没有提到实现, Overfeat (2013) 是第一个发表的基于神经网络的目标定位架构。基本思想如下图所示。
Object Localization Architecture
如果去掉边界回归器,这将是一个典型的图像分类架构。实际上,Overfeat 首先训练一个图像分类器。然后确定特征层并训练边界回归器。这再简单不过了。
乍一看,不同的类应该有不同的边界回归量,因为不同的对象往往有不同的方法来定义它们的边界。然而,在本文的实验中,类之间共享的回归器优于 1000 个不同的回归器(因为 ImageNet 有 1000 个类)。是因为数据稀缺吗?我们能直接训练回归变量来预测边界而不需要对象的类别吗?培训结束我会更新答案:-)。
Overfeat 中一个有趣的贡献是多尺度分类,它利用卷积神经网络的空间特征来减少计算。
多尺度分类
如在其他实验中所示,我们可以通过简单地裁剪多个图像补片并在测试阶段根据补片的预测投票决定最终预测来提高图像分类的准确性。显然,我们可以将这种方法用于目标定位问题中的图像分类器。假设我们有一个 8×8 的图像或特征图,我们采用 6×6 的随机裁剪来训练我们的图像分类器。在预测阶段,我们随机裁剪几个 6×6 的小块,并从这些小块的预测中选出最终的预测。下图显示了两种作物(蓝色和绿色)。重叠区域是黄色的,而红色的 3x3 补丁是应用于重叠作物的滤镜之一。
Redundant Compution in CNN
如果我们将两种作物一个接一个地输入分类器,我们将在红色区域应用 3×3 滤镜两次。计算是多余的,因为滤波器和图像中的位置是相同的。Overfeat 提出了一个巧妙的方法来消除这种冗余。
假设我们有一个大小为 18x18 的要素地图或图像,我们希望获得大小为 12x12 的裁剪,然后应用卷积和池化操作。卷积运算的滤波器是 3×3,没有重叠,因此原始映射将缩小到 6×6。然后我们应用 2x2 非重叠池,大小将变成 3x3。作物(0,0,12,12)变成(0,0,2,2)在最终的特征图中,作物(6,0,18,12)变成(1,0,3,2),作物(0,6,12,18)变成(0,1,2,3),作物(6,6,18,18)变成(1,1,3,3)。我们可以看到,我们可以在原始地图上应用一次操作,得到四种作物的特征地图。最终特征图(0,0,2,2)和(1,1,3,3)的初始裁剪如下图所示。
Apply convolutional and pooling operations for patches at the same time.
因此,我们可以对初始特征地图或图像应用非重叠卷积和汇集操作,以获得其裁剪结果。这里的好处是避免了我们之前谈到的冗余计算。这里的架构包括非重叠、非重叠过滤器和非重叠池。
如果避免了冗余计算,我们可以用不同大小的裁剪来训练不同的分类器,以集成结果。本文称之为多尺度分类。
如果我们有多个分类器,每个分类器都预测预测对象的一个框,哪个框是最准确的?Overfeat 将重叠较大且相互靠近的盒子保留下来,将两个相距较远的盒子的坐标进行平均,如下图所示。这种方式有助于移除其他对象的框而不是主对象。然后使用检测器的分类分数挑选出最终的盒子。
The box with dotted borders has a better chance
过量进食检测
过量饮食中的目标检测属于图像分类领域。唯一的区别是,你需要一些负样本来使分类器能够预测物体之外的背景。显然,多作物和多尺度分类有助于提高准确性和性能。
观察不是干预
偶然的因果推断
以及为什么条件概率是不够的
这是因果推理和数据科学系列文章的第三篇。前一个是“用因果图!”下一个是“解决辛普森悖论”。
在因果推断中,我们感兴趣的是测量变量 A(比如某种特定疾病的治疗方法)对另一个变量 B(比如康复的概率)的影响,这种影响通常来自观察数据。这意味着我们感兴趣的是测量 A =治疗与 A =未治疗病例之间恢复概率的差异。
在数据科学和机器学习中,我们习惯于使用条件概率,这似乎对这个目的很有用。但是,我们会用一个简单的例子看到,光有条件是不够的。
什么是条件反射
以值 X=x 为条件意味着,在 X 取的所有可能值中,我们选择值 x. 的特定样本,例如,如果我们有数据
选择 X=1 将导致
药店示例
想象一下下面的情况。我们去药店,因为我们感冒了。他们有两种不同的药物:药物 1 和药物 2。药物 1 更受欢迎,所以我们首先要求它:他们有 50%的时间,所以我们服用它,我们恢复。在另外 50%的病例中,90%的情况下他们有一种更贵的药物 2,我们买了它,也康复了。但是在剩下的 10%里,他们两种都用完了,所以我们保持冷静。
Drugstore selling diagram
如果实验室停止生产药物 2 怎么办?我们康复的可能性有多大?答案似乎很清楚:50%的病例我们无法恢复。
让我们看看,如果我们尝试用直接条件概率来回答这个问题,会发生什么。如果我们收集前面的信息,我们得到药店销售表。
Drugstore selling table
现在,在没有药物 2 的情况下,治愈的概率是多少?为此,我们需要选择对应于药物 2 =否的样本
No Drug 2 table
并计算恢复的概率
p(恢复中|药物 2 =否)= 50 /( 50 + 5) ~ 91%
这是一个完全不同的结果!
发生了什么事?!
我们可以使用因果图来模拟数据生成过程。
Data generation graph
这张图表反映了我们的观察数据。买药 2 看之前有没有买过药 1,恢复看买过哪些药。该过程产生的数据在上面的药店销售表中获得。
但是,我们关于缺少药物 2 的问题涉及不同的数据生成过程。其中药物 2 不再依赖于药物 1,因为药物 2 总是缺失。
Interventional graph
这个图被称为干预图,它模拟了如果没有药物 2 会发生什么。如果我们可以从这个图中采样数据,我们将获得介入数据表
Interventional data table
我们可以在新的概率分布 P _ intervened 下直接计算
p _ 干预(恢复|药物 2 =否)= 50 /( 50 + 50)= 50%
这是预期的结果。为什么直接条件概率不奏效?因为它们回答了关于由数据生成图生成的数据的问题。在某些情况下是可以的,但在这种情况下,这是不够的。
这个玩具练习是一个简单的例子,用来理解在一般情况下这种类型的分析所附带的问题。这里我们知道数据是如何产生的(因为我们做到了)。然而,获得介入数据表不会如此简单。简单的解决方法是,回到现实,停用药物 2 一段时间,然后测量有多少人康复。当然,在许多情况下,这将会产生很大的不良后果。
因果推理的一个主要问题是,我们是否可以仅从收集的观察数据中从介入图中导出数据,而不必去现实中做实验。意思是,在只有历史数据的介入图中,我们能得到恢复的概率吗?在下面的帖子中,我们将解释如何用经典的辛普森悖论得到这样的结果。
明显的动态规划
结合动态规划和机器学习
Photo by Tatiana Rodriguez on Unsplash
这个世界上很多问题都是高效算法解决不了的。我的意思是没有比暴力更快的算法了。即使我们使用蛮力,对于很多问题我们也没有足够的时间来解决。因此,我们使用试探法来解决这类问题。试探法是寻找近似的解决方案。这些并不总是最好的解决方案,但仍然比随机的要好。
在开始我自己的探索之前,让我们看一个我提到的这种复杂问题的具体例子。
旅行推销员问题
旅行推销员问题(TSP)是一个很好的例子,因为每个人都能理解基本的问题集。想象一下,一名销售人员接受任务,向几个城市的潜在客户介绍一种特定产品。由于时间和资源的稀缺,销售人员必须以最优的顺序从一个城市到另一个城市,以便使用最短的路线。
为了找到最短的路径,销售人员必须计算所有可能解决方案的总距离。让我们假设有两个城市要去。这很简单,因为只有两种组合可以比较:
2 possibilities to travel to the customers from the orange head quarter
如果我们现在添加一个城市,我们会发现可能性会增加不止一个:
2 possibilities to travel to the customers from the orange head quarter
此外,第四个城市会将可能性空间增加 4 倍。每种可能性都会有 4 种额外的组合。你可以把这个想象成你想把新城放在四个箭头中的一个上。所以你有 6 乘 4 的可能性。这种增长是阶乘的。如果有 n 个城市,我们有 n 个 T2!可能性。因此,如果有 10 个城市:10 个,销售人员会计算很多来找到最佳解决方案!= 3.628.800 种可能性!
这种比较所有可能性的强力“算法”时间效率不高,但它是目前为止找到最优解的最好算法。但是,对于路由程序或其他具有阶乘复杂性的应用程序来说,这不是一个选项。
动态规划求解 TSP
使用强力算法时,组合的某些部分会被计算多次。动态编程解决了这个问题,“记住”已经计算过的行程,以找到比暴力更快的解决方法。缺点是动态规划是一种只能找到近似解的启发式方法。考虑到使用这种方法节省的时间,一个近似值就足够了。
在 TSP 的情况下,想象一个代表计划旅行的所有选项的决策树是有用的:
One track from orange to orange is one of the 6 possibilities when visiting 3 cities.
动态规划(DP)的概念是从橙色的叶子开始,然后回到单个橙色的根。而向上 DP 增加节点之间的距离并记住它们。一旦到达一个有多条出路的节点(如橙色根或第二行中的节点),DP 就比较输出分支的距离,只记住较小的一条。
E. g., we start with the distance of 1<>2. Add the distance of 2<>3 and the distance of 3<>4. Then we start with the distance of 5<>6, add the distance of 6<>7 and the distance of 7<>4. At 4 we have to compare the distances 1<>2<>3<>4 and 5<>6<>7<>4 to know which is smaller. The smaller one will then be used to continue going up.
这个概念也可以表述为递归函数:
r 是取一组未去过的城市 S 的递归函数。 r 返回 S 中每个城市 j 的一个元素的集合的最小值,即 i 和 j 之间的距离加上城市 j 经过未访问城市(不含当前城市 i )到目的地的最佳距离。
明显的改进
动态编程是愚蠢的。它的唯一规则是比较每一个可能的组合,每一个…甚至一个被认为是:
Very long route far from being optimal is also considered using DP
很明显,这种结合是无效的。但是算法不能考虑这样的事情。人类的直觉和视觉聚类使我们能够在寻找明显无效的组合时执行节拍 DP 算法。为了向更直观、更明显的方向改进 DP,我采用了数据挖掘的方法。
16 randomly distributed points
首先,我们取 16 个随机分布的点。乍一看,人眼可以立即将这些点连接起来,从而可以创建接近最优的解决方案。让我们以两对直接相邻的点为例。它们可能会相互连接。不幸的是,一个简单的 DP 算法将非常绝望,并试图将它们分开。
Clustered by KMeans
现在,让我们通过用 KMeans 算法对这些点进行聚类来给算法一点直观的感觉。在图中,我们看到 4 个集群。我们总共拿了 16 分。在选择一个聚类数之前,我将总数除以 4,以创建平均 4 个元素的小聚类。4 个元素有可能 4 个!= 24 种组合。这么小的一套,足够快 DP 就能解决。图中的这 4 个聚类类似于真人进行的直观聚类。
The salesperson’s start and end position illustrated as the red point
现在让我们也给销售人员一个随机的位置。红点是现在销售人员的位置。这个位置是整体的起点和终点。
Solving TSP with Dynamic Programming on the clusters only
因为我们现在有了起点和集群,所以我们能够执行一轮 DP。这一轮将从销售人员的位置开始,并通过所有聚类找到近似最短的路线。每个群集的位置由群集到其质心的最近点定义。这一轮 DP 给了我们顶级订单。
Closest connections between the successive clusters
下一步是找到连续聚类之间最近的点。因为我们已经发现了集群的顺序,所以我们知道哪个集群继承了另一个集群。因此,我们可以找到每个聚类对中彼此距离最近的两个点。这使得算法能够定义将在每个单个集群内发生的 DP 过程的起点和终点。
显而易见的动态规划的最后一部分是在每个单个簇中寻找最近的轨道。起点和终点已在之前的步骤中定义。一旦这样做了,我们就有了一个很好的近似最优解。
Final approximation to an optimal solution
当然,有些连接本可以做得更好。但是,如果您将执行该算法所花费的时间与经典的动态编程方法进行比较,您会发现我的方法所花费的时间只有几毫秒,而我在执行简单的动态编程方法 5 分钟后就停止了我的计算机。
在顶层,我们将所有点分成 4 个块。如果你总共有 16 个,顶级也只是一个 4 号的 DP。对于更大的尺寸,我们可以在不同的级别上执行该算法。
结论
提出的方法表明,动态规划不仅比较接近的可能解决方案,而且比较无意义的组合。最后,结果只是基于另一种启发,并不能保证是最好的解决方案。但是,它可以显著加快运行时间。
带有 Akka、Tesseract 和 JavaCV 的 OCR
我最近有一个用例,需要从 PDF 文档中提取姓名和日期。我认为,利用 google 的 tesseract 来执行基本的 OCR,构建一个快速的程序是非常容易的。只需几行代码,您就可以让 node-tesseract 在图像上运行 OCR。但是,如果图像是倾斜的、有噪声的或者其中有一堆图像,那么来自 tesseract 的文本结果将变得不可用。
Tesseract 文档列出了一系列预处理图像以提高 OCR 质量的方法:
- 重新缩放
- 二值化
- 噪声消除
- 旋转(去歪斜)
- 边界移除
从图像中提取文本需要很多步骤。我仍然需要执行日期提取和命名实体提取。问题是我不熟悉这些预处理和提取技术。所以我认为构建一个能够拥有可插拔架构的系统是一个好主意——我可以在学习如何实现它们时添加步骤。如果图像可以通过这些不同的转换阶段流动不是很好吗?😉
Akka Stream
旅程
让我们构建一个 REST 服务器,它接受图片作为上传,其中各个端点将返回各种结果。Tess4j 库有许多方便的方法,其中一些我们将用于图像去倾斜和二值化。我们将使用 JavaCV,一个 OpenCV 包装器,用于图像去噪和一般增强。
我们最终将用OpenNLP和Natty以及使用拼写检查器 增强 OCR 输出——第 2 部分 。
我拍了一本书的一页。这将作为系统的输入。注意图片的微小角度。
input.jpg
必需的软件库
让我们创建一个特征来保存宇宙魔方;我们稍后将能够混合这个。
现在,我们将使用 Akka Http 创建我们的基础应用程序,它将绑定到端口 8080。我们创建了一个 rest 端点,它将图像读入内存,并且不做任何处理。该端点最终将返回预处理的图像。
正如我们所看到的,我们的图像是类型BufferedImage
的,我们可以使用 Tess4j 的助手方法来创建一个二进制图像。我们将创建一个 BufferedImage 流,它将帮助器函数映射到传入的 BufferedImages。二值化会将图像转换为黑白。这对于文本上有阴影的图像来说效果不好,但是我会在后面详细说明。
然后,我们可以再次使用 Tess4j 来消除图像的倾斜。让我们再创建两个流:一个用最小去歪斜角阈值去歪斜一个BufferedImage
,另一个从一个BufferedImage
获取字节,这样我们就可以将字节发送回客户端。
现在,我们可以将上述所有流程结合起来,更新我们的服务器。我们将利用内存中的映像制作一个Source
,将流链接在一起,并将其传递给 Akka 的complete()
方法。
对我们的服务器运行一个简单的 curl 将会返回我们预处理过的图像。
curl -X POST -F 'fileUpload=@/Users/duanebester/Desktop/blog/input.jpg' 'http://localhost:8080/image/process' --output output.png
这是我们的二进制,去歪斜的图像:
厉害吧!?现在我们已经有了流畅的一切,我们可以简单地添加更多的片段来进一步提升我们的形象。此时,我们可以将图像传递给 tesseract,并让它执行 OCR 以给出一个字符串。然而,我觉得 OpenCV 中有太多的图像处理魔法,我们应该使用。
JavaCV 和 OpenCV
JavaCV 和 OpenCV 使用一个称为 Mat 的对象来执行它们的图像处理。面临的挑战是将 Java BufferedImage
转换成 JavaCV Mat
,然后再转换回来,下面是实现这一点的流程:
我们现在可以流一个BufferedImage ~> Mat ~> BufferedImage
😎
OpenCV 有fastnlmeansdexing和 detailEnhance 方法,我们可以在Mat
中使用它们——所以让我们将这些方法包装在Flow[Mat]
中
我们现在可以
- 创建二进制文件
BufferedImage
- 将其转换为
Mat
并增强 - 将其转换回一个
BufferedImage
- 消除
BufferedImage
的偏斜,然后将其发送回客户端
A smoother & enhanced image
我们可以在这里添加缩放,这样我们就可以发送一个更小的图像,基本上是裁剪上面图像中的文本,以便 tesseract 进行处理,但还没有到那一步😅
最后一个部分是对BufferedImage
执行 OCR,并将结果字符串发送回客户端。我们创建一个将返回一个String
的Flow[BufferedImage]
——我们还更新了我们的 web 服务器以添加这些额外的流。
当我们运行新的 curl 来获得 JSON 响应时:
curl -X POST -F 'fileUpload=@/Users/duanebester/Desktop/blog/input.jpg' 'http://localhost:8080/image/ocr'
我们得到我们的文本结果:
CHAPTER 1
THE COMPOUND EFFECT IN ACTION
You know that expression, ”Slow and steady Wins the
race”? Ever heard the story of the tortoise and the hare?
Ladies and gentlemen, I’m the tortoise. Give me enough
time, and I will beat Virtually anybody, anytime, in any
competition. Why? Not because I’m the best or the smartest
or the fastest. I’ll win because of the positive habits I’ve
developed, and because of the consistency I use in applying
those habits. I’m the world’s biggest believer in consistency.
I’m living proof that it’s the ultimate key to success, yet it’s
one of the biggest pitfalls for people struggling to achieve.
Most people don’t know how to sustain it. I do. I have my
father to thank for that. In essence, he was my first coach
for igniting the power of the Compound Effect.
My parents divorced when I was eighteen **mohths 01d**,
and my dad raised me as a single father. He **wasn t** exactly
页面朝着图片的底部变得波浪状,宇宙魔方认错了个月大的,忘记了中的撇号不是。尽管如此,我们在上述转换中实现了 99.67%的准确率!
正如你所看到的,有了这个系统,添加我们需要的部件非常容易。我们可以考虑获取字符串结果,并将其传递给更多的阶段,这些阶段可以执行某些拼写检查和名称/日期提取。
感谢并继续 Part 2 !
~杜安
十月版:课文理解
9 篇必读文章
如何开始使用 NLP
由梅勒妮·托西克 — 3 分钟阅读。
我在某处读到过,如果你不得不回答同一个问题两次,把它变成一篇博客文章可能是个好主意。为了遵守这条规则,也为了给我未来的自己节省一些时间,现在我对这个问题的标准答案是:我的背景是科学,我对学习 NLP 感兴趣。
非 NLP 数据和研究人员的词向量
通过康纳麦当劳 — 8 分钟阅读。
单词向量代表了在提高我们分析单词、句子和文档之间关系的能力方面的一个重大飞跃。
word 2 vec 的非自然语言处理应用
通过 Kwyk — 6 分钟读取。
当使用机器学习解决问题时,拥有正确的数据至关重要。不幸的是,原始数据通常是“不干净的”和非结构化的。自然语言处理 ( NLP ) 从业者对这个问题很熟悉,因为他们所有的数据都是文本。
用于自然语言推理的卷积注意力模型
通过Marek galo VI—5 分钟阅读。
在这篇文章中,我想向你展示一个我在 Quora 问题配对竞赛中使用的模型。首先,我将描述一个用于自然语言推理的可分解注意力模型(帕里克等人,2016 ),然后用卷积层对其进行扩展,以提高损失和分类精度。
机器学习,NLP:使用 scikit-learn、python 和 NLTK 的文本分类。
由贾韦德谢赫 — 7 分钟读取。
文档/文本分类是监督的机器学习(ML)中重要而典型的任务之一。为文档分配类别,文档可以是网页、图书馆书籍、媒体文章、图库等。有许多应用,例如垃圾邮件过滤、电子邮件路由、情感分析等。
一个数据科学练习:根据就职演说,特朗普与其他总统有多相似?
由布莱恩·雷 — 4 分钟读完。
这是基于谷歌团队编写的一些 NLP(自然语言处理) Doc2Vec 算法的运行结果。(浅层,两层神经网络)。
这首诗是什么时候写的?我的电脑可以告诉你
由查姆格鲁克 — 6 分钟读完。
我最近的项目真的很令人兴奋。我热爱诗歌已经有一段时间了,所以我选择它作为我第一次涉足自然语言处理(NLP)的主要领域。
使用预先训练的 word2vec 进行迷因搜索
通过 Eyyüb Sari — 6 分钟读取。
模因抵得上千言万语。它们是一种文化。我和我的朋友过去常常用 Giphy 在 Messenger 上发送很多这样的消息。
Scikit-了解亚马逊美食评论的文本分析
由苏珊李 — 7 分钟读完。
我们知道亚马逊产品评论对商家很重要,因为这些评论对我们如何做出购买决定有着巨大的影响。
十月版:无监督学习
8 篇必读文章
无监督学习由数据科学家和其他数据从业者使用,在这个机器学习算法家族中,没有已知的输出或标签来指示学习算法。在聚类中使用了不同类型的无监督学习,例如 K-Means 聚类、文本挖掘和维数减少,例如在预处理阶段使用的主成分分析,以转换用于监督学习机器学习建模的数据集。
最近,航空公司可以使用聚类算法来分析客户反馈调查,保险公司已经审查了他们的客户投诉登记册,选举 Twitter feeds 已经分组在一起,以监控全天的关键讨论主题,分析新闻文档的语料库,并进行主题建模以提取关键主题。
聚类根据相似性将数据划分为不同的组。算法的类型是多种多样的,包括基于距离连接对象的分层聚类和将聚类表示为单个均值向量的 K 均值聚类。
使用无监督学习的挑战是确定它是否“表现良好”,因为输出的标签是未知的。无监督学习的好处包括能够在探索性数据分析阶段对数据进行预处理,以便对训练和测试数据进行缩放。因此,转换后的数据允许数据科学家在监督学习(如岭回归)之前,使用主成分分析来可视化数据的方向并减少维度或特征的数量。
我们希望你会喜欢并在这个月学到一些新的东西,因为我们通过编辑从《走向数据科学》中精心挑选的内容来探索无监督学习。
Wendy Wong ,TDS 编辑。
用 Python 进行无监督学习
由维哈尔鞍马 — 7 分钟阅读。
无监督学习是一类机器学习技术,用于发现数据中的模式。提供给无监督算法的数据没有标记,这意味着只提供输入变量(X ),没有相应的输出变量。在无监督学习中,算法自己去发现数据中有趣的结构。
使用无监督学习来计划去巴黎的假期:地理位置聚类
通过 Hamza Bendemra — 6 分钟阅读
因为我自己也去过巴黎几次,我想我可以在其他方面有所帮助,比如为旅游景点列表做贡献。在列出所有的景点之后,我创建了一个谷歌地图,每个位置都有一个图钉。
现实生活中的 K-Means:聚类锻炼时段
By 卡罗莱纳便当 — 6 分钟阅读
K-means 聚类是一种非常流行的无监督学习算法。在这篇文章中,我想提供一些关于它的背景知识,并展示我们如何在真实生活中使用它。
我们编织了一张多么解开的网:VAE 的表征学习
由科迪·玛丽·怀尔德 — 15 分钟阅读
无监督学习的一个常见策略是生成模型,其思想是:你应该给模型一个从给定分布中产生样本的任务,因为在该任务中表现良好需要模型隐式地学习该分布。
对抗性自动编码器的向导指南
通过 Naresh Nagabushan — 9 分钟读取
我们知道,卷积神经网络(CNN)或在某些情况下密集的全连接层(MLP——一些人喜欢称之为多层感知器)可以用来执行图像识别。但是,CNN(或 MLP)不能单独用来执行像从图像中分离内容和风格这样的任务…
在 SELU 自动编码器(不是另一个 MNIST)上高斯混合模型的无监督学习
由gona lo Abreu—5 分钟读取
大多数聚类方法都受到维数灾难的困扰。这样,为了执行无监督学习,降维方法是必要的。
使用数据、聚类和可视化发现我的 Spotify 音乐的相似之处
由胡安·德·迪奥斯·桑多斯 — 16 分钟阅读
音乐品味是一个人非常独特、奇特和有特色的品质。在现存的数以百万计的歌曲和声音中,我认为许多人决定发展对一种特定风格、流派或音乐“子集”的喜爱并非偶然。
自然语言处理从业者指南
由迪潘詹(DJ)萨卡尔 — 31 分钟读取
非结构化数据,尤其是文本、图像和视频包含了丰富的信息。然而,由于处理和分析这些数据的固有复杂性,人们通常不会花费额外的时间和精力从结构化数据集冒险出来分析这些非结构化数据源,这可能是一座潜在的金矿。
A 型数据科学家的颂歌
分解他们提供的影响,以及为什么下一代不关心
神话中的独角兽
你现在可能已经听说过难以捉摸的科学独角兽 da了。如果你还没有,独角兽是在数据科学领域及其周围掌握了几种跨学科技能的专业人士。他们有你关于数据分析、机器学习、产品指标、大数据、实验、深度学习、商业敏锐度、领域知识等问题的所有答案。
这一罕见壮举的更好的可视化可以在下面的的研究中看到,调查了 400 多名数据专家,他们对不同区域的舒适度进行了调查,这些区域可以被归类为真正的独角兽。
Source: Business Over Broadway
正如你可能想象的那样,找到一个在这些方面都擅长的人肯定不容易;这几乎是不可能的。由于领先公司中的这种认识,我们开始看到在更广泛的数据科学领域中形成了专门的角色。
这些专业化包括机器学习工程师、数据工程师、数据分析师、产品科学家、核心数据科学家、数据研究员、定量分析师等职位,以及其他已经与更知名的数据科学家一起成为常见固定职位的角色。
Source: Mindful Machines
正如您在上面所看到的,这些角色之间总会有一些重叠。这通常取决于每家公司、他们的数据生态系统以及他们的未来目标。信不信由你,事情不会就此停止。我们可以进一步分解它。
A 型与 B 型
数据科学界许多备受尊敬的人士尝试对不同类型的数据科学家进行分类。然而,没有人比潘多拉公司的前研究主管迈克尔·霍彻斯特博士更有效了,他在 Quora 上给出了以下答案:
**A 型数据科学家:A 是做分析的。**这种类型主要与理解数据或以相当静态的方式处理数据有关。A 型数据科学家非常类似于统计学家(也可能是一名统计学家),但他们知道统计学课程中没有教授的所有数据处理的实际细节:数据清理、处理非常大的数据集的方法、可视化、特定领域的深入知识、写好数据等等。
B 型数据科学家:B 代表建筑。B 型数据科学家与 A 型共享一些统计背景,但他们也是非常强的编码员,可能是训练有素的软件工程师。B 型数据科学家主要对“在生产中”使用数据感兴趣他们建立与用户互动的模型,通常提供推荐(产品、你可能认识的人、广告、电影、搜索结果)。
这些描述主要适用于在行业中使用数据科学,但我发现它们在我的经验中非常准确。同样值得注意的是,这些分类不是确定的,当然也不是一成不变的。你可能拥有两种类型的混合技能,这没什么不好。事实上,如果做得正确,它实际上可以带来独特的、无价的技能组合,有助于创造性和有效的解决方案。
下一代
如果你在最近的新闻中看到数据科学,无论是《T4》《纽约时报》的一篇特写还是 TechCrunch 的一篇文章,都有可能关注机器学习和人工智能的影响。
这是有充分理由的。人工智能和机器学习的发展将继续对我们所有人的生活产生越来越深远的影响。这种现象以这样或那样的方式影响着地球上的每个人,大量的媒体报道反映了这一点。考虑到这一点,让我们来探讨一个该领域的任何领导者都应该牢记的重要问题:
这对下一代数据科学家意味着什么?
如果您还记得我们对数据科学家的深入分类,这些令人兴奋的新技能非常符合类型 B 的描述,重点是在生产中处理数据时构建和部署模型。
很明显,像机器学习这样的数据技能目前被更多的炒作和吸引力所包围。出于这个原因,有抱负的数据科学家正在进入这个领域,他们的目光瞄准了这个基于 ML 的特殊技能集。
我的意思是,谁不想建立让你预测未来的机器学习模型?谁不对模仿人脑的推荐系统和神经网络着迷呢?
Source: Machine Learning Mastery
对这些技能的需求肯定是存在的,正如大量数据驱动的教育倡议和目前快速增长的人工智能和人工智能工程师库所证实的那样。
但是,这种心态有点短视。尽管标题和流行语暗示,大多数问题都不能用机器学习来解决。
我想利用这篇文章的剩余部分来论证与经常被忽视和低估的A 型数据科学家相关的技能和行动所提供的价值。
我为什么要关心 A 型数据科学家?很高兴你问了…
他们回答困难的问题
A 型数据科学家从数据中提取信息,以探索和回答通常由领域专家、商业领袖或管理层提出的复杂问题。这看起来并不那么迷人,数据科学也是如此——事实并非如此。您几乎总是需要处理和清理一些数据。
然而,一旦你过了这个阶段,事情就会很快变得有趣起来。对于提出的问题,很少有直接的答案。你必须有创造力,想出一条看似无限的路线来往下走。
“批判性思维技能将黑客与真正的科学家区分开来”——杰克·波威
这是这个职业给许多人带来的后果。然而,我不敢苟同。分析和解决问题的无限方法在很大程度上使得数据科学对如此庞大的人群如此具有挑战性和趣味性。
他们让复杂变得简单
可以说,数据科学家可能拥有的最重要也是最容易被忽视的技能是简单而彻底的沟通。解构复杂的解决方案并将其打包,以便业务领导、产品经理或用户能够理解,这不是一个小任务。
“数字本身无法说明问题。我们为他们说话。在我们要求更多的数据之前,我们需要对自己提出更高的要求。”——Nate Silver
我们表达数字的方式可以有很大的不同;这些包括演示技巧、数据故事、数据可视化、商业洞察力和技术写作。能够决定使用这些工具中的哪一个,并以一种有效的方式这样做并不容易,但这非常令人满意。
他们始终推动影响
很自然,你的结果取决于他们的影响力。A 型数据科学家通常会有机会比他们的B 型同行在日常工作中产生更多影响。你不用花时间在特性工程和迭代模型上,而是探索直接影响业务或产品决策的问题。
“没有任何伟大的营销决策是基于定性数据做出的.”—约翰·斯卡利
对于A 型数据科学家来说,增值的转变也要快得多。您将会得到一致的工作反馈,因此,您将有机会作为一名数据科学家快速成长。
强行推销
这篇文章的重点不是阻止任何人专注于开发机器学习工具包来构建强大的模型。就我个人而言,我每天都花时间来发展这些技能。我还认为,在生产中使用数据是一个非常有用的工具,可以以独特的方式扩展您的项目并影响业务。
简而言之,B 型数据科学无疑也有它的优势。每种技能组合处理生态系统中非常不同的部分。这两种类型都生活在更大的、快速发展的数据科学城市的不同社区。
然而,我相信,由于围绕机器学习和人工智能的炒作,目前绝大多数即将到来的数据人才都被吸引到 B 型工作。出于这个原因,我担心与A 类数据科学相关的有效技能,主要是处理分析和交流的技能,会被忽视。
虽然分析和交流可能不像机器学习那样性感,但现实是它们在行业中提供了最一致的影响。
在一个数据是新石油的世界里,利用分析来解决问题是一件非常有力量的事情。当然,你有时会被卡住。这就是努力工作的好处。总有另一个挑战需要解决。另一个需要解决的问题。另一个要回答的问题。
对于那些问题,我们有A 型数据科学家。
感谢阅读!如果你喜欢这篇文章,请继续向鼓掌按钮展示你的爱。如果你对未来的更多帖子感兴趣,请确保关注我并订阅下面的我的简讯以接收任何新内容。更多关于我和我在做什么,请查看我的网站。
禁忌、邻居和优化
改善您的路线
“A mailman sitting in a mail truck sorting mail parked outside of a house in Tulsa” by Pope Moysuh on Unsplash
假设你经营一个快递车队。每天,您必须通过将包裹分配到配送货车来安排包裹递送,确保它们按时送达,确保您不会让任何货车超载,确保工作在司机之间平均分配,确保司机不会超过他们的合同和法律约束期,确保您最大限度地减少燃料消耗……根据您的特定业务,这个清单还可以继续下去。GOGOVAN 的 Kamil Bujel 曾在另一篇文章中描述过这种特殊情况。
他们通过使用现成的优化包来解决这个问题,以帮助他们解决手动调度车辆的日常繁重工作。Kamil 在他的文章中详细描述了这个过程,以及他们试图让算法在合理的时间和内存范围内工作所经历的麻烦。但是为什么优化解决方案会有这样的表现呢?为什么会消耗这么多内存?这样,优化解决方案就像一个黑匣子,它的用户很少或根本不知道里面可能会发生什么。
如果我们能看到这些优化算法中的一个会怎么样?为了吐出一个“优化”的解决方案,他们在引擎盖下表演了什么样的魔术?我决定在 Kamil 自己的文章之后写这篇文章。碰巧的是,在其他事情中,我一直在为我自己的公司开发一个这样的路线优化算法,这篇文章是我通过实现一个特定类型的优化算法所学到的东西的一个简短的精华。
离散优化
优化是一个误称,因为我们很少找到最好的解决方案。这个领域的所有研究,从臭名昭著的旅行推销员问题(TSP)开始,会告诉你最优解只能在玩具问题中找到。真正的问题,有数百辆车和交货地点,实在是太大了,无法在有用的时间内完全搜索,所以我们必须用一些聪明的方法。此外,我在这里讨论的优化类型是离散型的。如果你熟悉连续优化,那么你可以利用梯度,以便沿着最陡的路径下降到全局最小值。离散优化就没有这种运气了。向组合中添加另一辆货车,或删除一个交货,或在货车之间移动一个交货会产生什么结果?你必须尝试这个选项,评估结果,然后决定怎么做。这基本上是我们如何在精神上做这种类型的优化,也许使用几个显而易见的规则,如地理分组交付。
我已经提到了一些没有很好定义的术语。我提到了一个最小值。但是最少什么?我们是否希望最小化车辆、距离、时间和燃料消耗?这个问题很容易回答:我们希望最小化日常运营成本。但是这个成本怎么算呢?好奇的读者,请继续读下去。
路线优化
路线优化是如何工作的?计算我们必须服务的工作的最优车辆分配需要什么?如何计算时间和顺序,以便我们最大限度地降低运营成本,同时保持高客户满意度和低司机流失率?我们从哪里开始?我们如何结束?
这篇文章将告诉你这个问题的一个可能的解决方案,一个臭名昭著的旅行推销员问题(TSP)的扩展,使用一些具有异国情调的名字的扩展。在这里,我将解释一个解决这个问题的实现,通过解决一个真实的发行公司的需求,像 GOGOVAN 。如果你还没有这样做,请阅读 Kamil 的文章,以获得一个这样的公司如何运作,以及他们的优化挑战是什么。
我不是使用现成的解决方案,而是在概念上开发一种方法,基于禁忌搜索、局部搜索和可变邻域搜索来解决相同的问题。让我们继续学习这些概念。
在快递这一行,你每天都要处理大量相对较小和较轻的包裹。交货是在具有给定货物容量的类似货车中进行的,通常以重量、体积、单位或这三者的任意组合来衡量。计算车辆载货量很重要,因为这是这个问题的一个硬限制,也就是说,出于安全和法律原因,你不能让货车超载。如果一辆或多辆货车装载的货物超过允许的数量,您就无法设计出解决包裹配送问题的方案。这不是一个可行的方案可行的方案。当我谈到可行的解决方案时,我指的是不违反像这样的硬性限制的解决方案。请注意,一个可行的解决方案可能会违反软限制,例如当货车计划晚点到达给定的客户时。在这种情况下,这种解决方案(通过应用迟到成本惩罚)会比所有货车都准时交付的另一种方案更昂贵。请注意,选择什么是硬限制或软限制完全由你决定,我只是用我以前用过的限制来说明这个概念。
在这种类型的交付场景中,所有车辆每天一次被装载到一个地方,即中央仓库(我从跟踪我的网上购买推测是在清晨)。优化算法的目的是通过确保满足交付时间,同时保持最低的运营成本,来计划所有的日常交付。
如果这个优化过程是一个烹饪食谱,那么我们需要关心的配料是什么?我们有客户、送货、货车、司机、道路、交通和运营成本。让我们对其中的每一项进行建模,以便了解我们需要的信息类型。
客户
客户可以很容易地被建模为简单的地理位置,即他们的纬度和经度。地理配准客户是一个重要的步骤,因为我们需要推导出运营地图中任意两个位置之间的行程持续时间和距离。为了计算这些,必须将所有客户位置转换为地理坐标,以便距离和时间计算方法能够正常工作。如果这些客户有特定的交付时间窗口,那么这些也可以考虑并记录下来。如果这样做,还要考虑打破这些时间窗口是硬限制还是软限制。请记住,硬限制会使解决方案无效,而软限制只会增加解决方案的成本。当我们考虑成本最小化时,会有更多的讨论。
交付
交付是一个简单的陈述,一辆货车必须访问一个客户位置,并在那里花费给定的时间交付给定货物尺寸(重量、体积、单位)的包裹。这意味着单次交付必须被视为从车辆到达交付地点的行程,加上执行交付所需的时间。优化程序将试图在时间和货车中调整交货,以便以低成本产生一个高效的解决方案。
车辆
除了每辆货车的唯一标识符(如牌照)之外,我们还需要每辆货车的最大载货量记录。将交货分配给给定的货车时,我们从可用的车辆货物中扣除交货货物尺寸,剩余值必须为正数。否则,我们会超载的。
除了这些数据,我们还必须记录每辆货车的任何相关运营成本,如租金、每公里成本或其他可用于优化程序最小化的成本。
我还要假设每辆车都有自己的司机,所以司机不是稀缺资源。然而,我们需要考虑的是任何合同安排,比如每天最长工作时间,或者公司工作时间。使用这种简化,这些限制可以应用于货车本身,我们不担心司机作为一个优化实体。
道路和交通状况
道路网络和交通阻抗是强加于模型的外部条件,必须予以考虑。在这里,我们有一系列的可能性,从最昂贵和最复杂的(从 Google 或 Here 等专业提供商处获取数据)到最便宜和不太精确的(使用测地线测量值结合距离因子计算所有距离),以及用于计算行程持续时间的平均速度。如果您选择第一种方式,流量也是一种选择,既可以作为实时反馈,也可以作为给定时间间隔内的典型阻抗。无论如何,你必须能够建立任意两点之间的距离和持续时间对的矩阵,因为这是优化算法的主要材料。
成本
我一直提到运营成本,因为这将有助于衡量优化器生成的解决方案的质量。为了做到这一点,我们必须创建一个成本函数,将前面所有的成分转换成同一个指标:经济成本。使用每公里成本率将距离转换为成本。使用罚金将延误转化为成本。使用货车的每日折扣率或租赁率将车辆使用率转换为成本。您可以将这些成本视为真实的分类账成本和/或您对优化流程的个人偏好。例如,如果您不关心要使用的货车数量,您可以将它们的单个成本设置为零。另一方面,如果您想要最小化货车的数量,请指定每辆车的使用成本。因此,优化器会倾向于使用较少的 van 的解决方案。距离也是如此。请注意,优化器在决定最佳解决方案时,只会查看这个成本函数的输出,,其他什么都不会做。这就是为什么所有的重要变量都必须转换成一个成本,并包含在这个成本函数中。
优化过程
既然所有的配料都收集好了,我们可以开始做饭了。
我将使用术语“解决方案”来表示一个可行的配置,它只是车辆的集合,每辆车包含一个有序的计划交付的集合。这些计划交付包括关于开始和结束时间以及它们的地理路线的信息。
A toy solution with three vans and six deliveries
对于每个解决方案,可以通过成本函数计算相关成本。优化器将尽力最小化该成本,,即,在给定所有限制和计算时间的情况下,找到具有最小可能成本的解决方案。
初始解
我们需要做的第一件事是创建最初的解决方案。就像匆忙地把你孩子的所有玩具放进一个盒子里,让盖子关上,我们将使用任何必要的试探法来创造一个这样的可行的解决方案。请注意,这将是一个成本高昂的糟糕解决方案。但这是可行的。这是我们的起点,我们现在可以开始改进了。
改进循环
改进初始解决方案需要一个非常简单的概念:对初始解决方案做一个小的扰动(确保我们仍然得到一个可行的解决方案),然后评估它的成本。但是什么是扰动呢?它可以简单到改变一辆货车的交货顺序,或者将一批货物从一辆车转移到另一辆车上。它可以是简单的,也可以是复杂的。在某种意义上,这是一个邻域并且在其中的搜索是一个局部搜索。
Perturbing a solution by moving a delivery
请注意,可以将邻域视为执行单一类型扰动的算法。在图片的例子中,它的工作方式是将一批货物从一辆货车转移到另一辆货车上。还要注意,货车内的交货顺序也很重要,因为它决定了交货的顺序,进而决定了要走的路线。这对距离成本有明显的影响。
正如我之前提到的,不可能预先知道给定的扰动是否会降低成本。与连续优化相反,我们不能计算成本函数的梯度,并跟随它们下降到(希望是)全局最小值——我们必须做出改变并评估其价值。它降低了成本,增加了成本还是保持不变?我们该怎么办呢?如果它降低了成本,我们可以采用它作为我们的下一个最佳解决方案,即现任解决方案。现任解决方案是目前为止最好的解决方案,成本最低,是您在优化过程结束时将使用的解决方案。
但是如果我们的扰动增加了求解成本呢?我们是不是放弃这个解决方案,尝试另一个方案,直到我们获得更低的成本?还是我们采用了更差的解决方案,希望它会带来更好的解决方案?如果你从高空滑下,这就像爬上附近的土堆,希望另一边有一个更陡的斜坡。
从我的经验来看,你可以两者都做,但在不同的情况下。第一种方法是所谓的贪婪搜索,当不同的可能解决方案的数量——状态空间——非常大时,这种方法似乎效果最好。在这些场景中,可能的解决方案数量如此之大,以至于你几乎总是可以指望一条下降的路径。对于较小的状态空间,情况并非如此。在这里,经验告诉我允许成本增加,以便优化器能够找到附近更深的成本谷,在那里它可以寻找更好的解决方案。
现在我们可以返回,用我们更新的解运行循环,产生另一个扰动,看看会发生什么。这是一个决定我们是坚持使用同一个小区还是应该使用另一个小区的好时机。这个决定可能非常重要,尤其是当其中一个邻域似乎停留在局部最小值上,无法产生更好的解决方案时。决定何时改变邻域以及改变到哪个邻域的方法本质上是启发式的。简而言之,这就是可变邻域搜索(VNS)。
这是严格的禁忌……
这个计划还有最后一个要素:我们必须像迷宫中的阿里阿德涅一样,标出我们要走的路。每个生成的解决方案都必须保留在一个列表中以备将来使用,以防止优化器再次探索它。因此它的名字叫做:禁忌列表。每当优化器生成一个新的解决方案时,它必须查看禁忌列表,并检查该解决方案是否已经生成(或被访问过)。如果是这样,它应该尝试另一个,可能是第二好的。
停止准则
那么我们什么时候停止?正如我之前所说的,几乎不可能知道你找到了可能的最佳解决方案,所以必须有一个预设的标准来停止改进循环并报告现有的解决方案。在这里,我把它留给你的想象力。我的不是很牵强,所以我用了一个严格的时间标准。在运行优化过程之前,我指定了我愿意等待“优化”解决方案的时间。仅此而已。
或者,您可以计算流程已经计算的循环次数,并在 N 次无改进循环后停止。
结束语
我希望现在这样更有意义。毕竟,这些都是简单的概念,有着花哨的名字,围绕着现代技术的计算能力。但是我在这里仅仅触及了表面。还有更多细节等待着您去探索,尤其是当您开始使用并行化的强大功能时。没有剧透给你,继续探索这个迷人的世界离散优化!
推荐阅读
哦,我的天啊!
最近看了 90 年代的经典电视节目《老友记》之后,我认为“哦,我的上帝”这句话说得太离谱了——现在我有数据可以证明这一点。
“‘哦,我的上帝!’常用作感叹词,强调惊讶、愤怒或震惊。"
— Quora
汇编数据
利用《老友记》电视节目的 抄本 ,我搜索了全部 236 集的对话,以确定每个角色说“哦,我的上帝”的频率。
包括什么?
必须说出“哦”、“我的”和“上帝”这三个词(按此顺序)才能包含在计数中。允许字符暂停或向短语添加额外的单词。以下是一些可接受的例子:
不包括什么?
其他提到上帝,但不符合上述要求的短语将不会被计算在内。下面列出了一些例子:
Season 3, Episode 5: Sorry Ross — Mouthing the words “Oh my God” will not be tallied.
结果呢
《老友记》在 NBC 电视台成功播出了 10 季(1992-2003)。在此期间,这句话“哦,我的上帝”被说了 1069 次*。下面我们来看看详细的结果:
第九季以 126 分代表了“天啊”狂潮的巅峰。
一些粉丝可能会认为扮演贾尼斯的女演员玛姬·惠勒会是我们的“哦,我的上帝”冠军(因为这是她的标志性对白)。
Maggie Wheeler portrayed Janice in 19 episodes of Friends.
然而,惠勒女士只在《老友记》的 19 集中出现过,她根本没有机会对抗我们过于戏剧化的主角。
莫妮卡和瑞秋占了“哦,我的上帝”话语总数的近 50%。
罗斯在大结局时非常激动,他说了 9 次“哦,我的上帝”。
有趣的发现
- 《老友记》一集的平均时长是 20-22 分钟。因此,“哦,我的上帝”大约每 5 分钟说一次!
- 只有 8 集“我的天啊”是不是说的。
- 该系列的大结局一集包含了在一集里最多提及的“哦,我的上帝”,共有 23 次。公平地说,这一集被认为是两集。
- 在第十季中,莫妮卡拥有单季 38 次“哦,我的上帝”惊呼的记录。
- 瑞秋是《哦,我的上帝》中被提及次数最多的角色,共有 269 次。在 10 季中的 6 季里,瑞秋是说“哦,我的上帝”最多的人。她也是在 10 集的单集中被提及次数最多的角色。👇
Season 2, Episode 4: Rachel encounters a pigeon and shouts “Oh my God” (at least) 10 times.
重要比较
好吧,那么这些年轻的、令人难以置信的朋友们说了 1050 多次“哦,我的上帝”——是不是很多?让我们比较一下“哦,我的上帝”和《老友记》中其他一些流行的美国英语单词/短语。
A search of the Friends transcripts indicates that “Oh my God” was said much more frequently than these other common words, phrases, and Friends-specific catch phrases.
“表达‘哦,我的上帝!’…[是]20 世纪 80 年代圣费尔南多“山谷语”流行文化兴起的一部分。"
— Quora
因为“哦,我的上帝”这一表达方式在 20 世纪末变得更加流行,也许它也经常出现在那个时代其他流行的情景喜剧中?
没有。《老友记》似乎自成一类。
The estimated average amount of times “Oh my God” is spoken per script in popular ’90s sitcoms.**
结论
“哦,我的上帝”似乎经常出现在《老友记》中,对此我很恼火,于是我在网上搜索了一下,看看是否有傻瓜统计过这个短语在节目中出现了多少次。当搜索没有返回确定的答案时,我意识到我可能就是那个傻瓜!完成任务后,我开始在指标中寻找更深层次的意义。
自从《老友记》第一集播出以来,文本中提到“哦,我的上帝”的次数增加了两倍,这是巧合吗?
Google Ngram measures the frequency of an phrase in text sources printed between 1500 and 2008.
许多人认为说“哦,我的上帝”违反了第十条戒律并且轻视了上帝的名字。《老友记》是否对保守价值观的急剧转变负有部分责任?
1951: Married couple Lucy and Ricky sleep in separate beds (left). 1996: Roommates Monica and Rachel argue over who will use the last condom (right) to engage in premarital sex. An argument that is ultimately settled with a game of Rock-Paper-Scissors.
《老友记》是否描绘了一种过于随意和进步的不切实际的生活方式?从而导致近年来美国的钟摆向相反的方向摆动?
🤔我认为这些问题最好改天在另一篇文章中回答,可能由比我聪明得多的博客作者来回答。
*数据假设记录完整准确。我尽了最大努力获得准确的人工计数。
- *估计基于对每部情景喜剧一季的分析。《弗雷泽》(第二季)、《宋飞正传》(第四季)和《保姆》(第二季)。季节是随机选择的,但为了确保可比的样本量,精选了 20 多集。
好的,Alexa…你是怎么工作的?
“我有许多由许多人制造的组件。”—亚马逊回声
“我可以帮你做很多事情。例如,你可以说这样的话……要查看更多示例,请查看 Google Home 应用程序。”—谷歌主页
这不是我想要的答案。
好的,杰瑞,声控扬声器是如何工作的?
我最近偶然发现了 YouTube 上风险投资家 a16z ( 安德里森·霍洛维茨)的频道,并立即被他们的视频内容吸引住了,尤其是他们的动画短片系列。在我的最爱中,普通合伙人维贾伊·潘德、本尼迪克特·埃文斯和克里斯·迪克森分别将机器学习、S 曲线和创新者困境的复杂概念,分解成易于消化、易于理解的 5 分钟视频。
受到他们例子的启发,我决定创作自己的动画短片,尽可能清晰简洁地总结我的热情和研究领域——语音计算。是动画 TL;我写的文章的博士,如果你愿意的话。利用类似的手绘视觉效果和彩色动画,我想创造一个简短的抓住本质
- 为什么语音是下一个大的平台转移
- 以语音为中心的设备如何工作
- 我们如何衡量音频传感器的质量,以及如何增强方向性
- 亚马逊 Echo 和谷歌 Home 中已经包含的定向麦克风还有待改进
语音计算已经在我们中间了。事实上,百度首席科学家吴恩达预测,到 2020 年,50%的搜索将基于语音或图像。同样,Juniper Research 的一份报告发现,到同一年,语音智能扬声器将进入 55%的美国家庭。随着我们一点点接近那个未来,我很高兴看到初创公司继续 1)为亚马逊 Echo 和谷歌 Home 生态系统开发服务,2)寻找在多个行业使用语音的新机会,以及 3)建立支持语音的基础设施——为日益增长的语音技术热潮提供支持。
如果您喜欢该视频,请点赞、评论并分享。我很想听听你对你希望我深入研究的其他领域的看法。
此外,我强烈推荐去看看并订阅 a16z 的 YouTube 频道。除了短片之外,它还提供了很棒的内容,如他们一年一度的 a16z 峰会的视频记录和 Frank Chen 对所有前沿技术的特殊走查。
好的谷歌:如何进行语音识别?
语音识别是检测口语单词的任务。有许多技术可以进行语音识别。在这篇文章中,我们将介绍语音识别所需的一些背景知识,并使用一种基本技术来构建一个语音识别模型。该代码可在 GitHub 上获得。对于这篇文章中提到的技术,检查这个 Jupyter 笔记本。
“turned-on charcoal Google Home Mini and smartphone” by Bence ▲ Boros on Unsplash
音频处理的一些背景知识
让我们后退一步,理解音频到底是什么。我们都在电脑/手机上听音乐。通常,它们是 mp3 格式的。但是. mp3 文件并不是真正的音频。这是一种在我们的计算机中表现音频的方式。我们不会直接打开. mp3 文件并阅读它们(就像我们阅读一样。记事本中的 txt 文件)。我们使用应用程序打开那些. mp3 文件。这些应用程序知道什么是. mp3 文件以及如何播放它们。这些 mp3 文件编码(代表)音频。
音频被表示为波。通常,这些波有两个轴。x 轴表示时间,y 轴表示振幅。所以在每一个时刻 t,,我们都有一个振幅值。
Sine wave — A simple audio wave (Source)
你可以在这里听一个简单的正弦波。太好了!现在我们只需要弄清楚如何在我们的代码中使用这些音频文件来执行识别。
使用音频文件
我们将使用波形音频文件格式或。wav 文件。那么我们该如何解读这些?wav 文件?输入 librosa——一个允许我们阅读的 python 包。wav 文件。看完这些我们得到了什么。wav 文件?我们得到了大量的数字。这是我读了一个 1 秒长的音频文件后得到的输出。
数组([ 0.0007143,0.00551732,0.01469251,…, -0.00261393,-0.00326245,-0.00220675],dtype=float32)
这些数字是什么意思?记得我告诉过你,音频被表示为具有两个轴的波。这些值代表该波的 y 轴,也称为振幅。那么 x 轴 aka 时间是怎么表示的呢?这就是数组的长度!所以对于 1 秒的音频,长度应该是 1000(1000 毫秒)。但是这个数组的长度实际上是 22050。这是哪里来的?
采样率
考虑一个 5 秒钟的音频剪辑。如果它是模拟的,那么它在每一瞬间都有一些振幅值,也就是每纳秒,或者每皮秒都有一些值。因此,考虑一个 5 秒钟的音频剪辑,它对每一皮秒都有一定的价值。那些是 5e+12 或500000000000值。想象一下储存在电脑上。在 C 语言中,存储一个浮点值需要 4 个字节。所以是 5e+12 * 4 字节。仅 5 秒钟的音频片段就需要大约 18tb 的数据!
Analog vs Digital Audio Signal (Source)
我们不想仅仅为了存储一个 5 秒钟的音频片段而使用 18tb。所以我们把它转换成离散形式。为了将其转换为离散形式,我们在每个时间步长记录样本(也称为振幅值)。因此,对于 5 秒钟的音频,我们可以每 1 秒钟记录一次样本。那只是 5 个值(样本)!这被称为采样率。
Sampling Rate (Source)
形式上,采样率是每秒收集的样本数。这些收集的样本在时间上以相等的间隔隔开。对于上面的例子,采样率是每秒 1 个样本。你可能已经注意到有很多信息丢失。这是从连续(模拟)转换到离散(数字)的一个折衷。采样率应尽可能高,以减少信息损失。
那么为什么我们得到了长度为 22050 的数组呢?如果没有指定,Librosa 使用默认的采样率 22050。你可能会奇怪,为什么是 22050?这是人类听觉范围的上限。人类可以听到 20 赫兹到 20 千赫的频率。那 20 千赫就是 22050。更常见的采样速率是 44100,即 44.1KHz。
另外,请注意,我们得到的是 1D 数组,而不是 2D 数组。这是因为。我使用的 wav 文件是单声道音频,而不是立体声。有什么区别?单声道音频只有一个声道,而立体声有两个或更多声道。什么是频道?简单来说,就是音频的来源。假设您使用一个麦克风来录制您的两个朋友之间的对话。在理想情况下,麦克风只录下你朋友的声音,不录下任何其他背景噪音。您录制的音频有两个声道,因为有两个信号源,即您的两个朋友。现在,如果背景中有狗叫声,音频将有 3 个通道,3 个来源是你的朋友和狗。
在音频处理中使用之前,我们通常会将立体声音频转换为单声道音频。再次,天秤座帮助我们做到这一点。我们只是在加载时传递参数 mono=True 。wav 文件,它可以为我们将任何立体声音频转换成单声道。
音频识别功能
我们可以使用上述时域信号作为特征。但是它仍然需要大量的计算空间,因为采样率应该相当高。表示这些音频信号的另一种方式是在频域中。我们使用傅立叶变换。简而言之,傅立叶变换是一种工具,可以将时域信号转换到频域。频域中的信号需要少得多的存储计算空间。来自维基百科,
在数学中,傅立叶级数是一种将函数表示为简单正弦波之和的方法。更正式地说,它将任何周期函数或周期信号分解成一组(可能无限)简单振荡函数的和,即正弦和余弦
简单来说,任何音频信号都可以表示为正弦波和余弦波之和。
A Time Domain Signal represented as the sum of 3 sine waves. (Source)
在上图中,时域信号表示为 3 个正弦波之和。这如何减少存储空间?考虑正弦波是如何表示的。
The mathematical representation of sine wave. (Source)
由于信号表示为 3 个正弦波,我们只需要 3 个值来表示信号。
梅尔频率倒谱系数
我们的声音依赖于我们声道的形状,包括舌头、牙齿等。如果我们可以准确地确定这个形状,我们就可以识别正在说的单词/字符。MFCC 是声音的短期功率谱的代表,简单来说,它代表声道的形状。你可以在这里阅读更多关于 MFCC的信息。
光谱图
频谱图是表示音频信号的另一种方式。光谱图以二维形式传达三维信息(2D 光谱图)。x 轴是时间,y 轴是频率。特定时间特定频率的振幅表示为该点的颜色强度。
Waveform and corresponding Spectrogram for a spoken word “yes”. (Source)
方法概述
为了。wav 文件,我使用了 Kaggle 竞赛的训练数据子集- Tensorflow 语音识别挑战赛。Google Colaboratory 用于训练。它提供 12 小时的免费 GPU 使用。它不是很快,但对这个项目很好。
音频文件以 16000 的采样率进行采样。频谱图用于语音命令识别。我写了一个小脚本来转换。wav 文件转换成光谱图。光谱图图像被输入到卷积神经网络。迁移学习在 Resnet34 上完成,resnet 34 在 ImageNet 上训练。PyTorch 用于编码这个项目。
重启随机梯度下降(SGDR)
SGDR 使用余弦退火作为学习速率退火技术来训练模型。学习率在梯度下降的每次迭代(非历元)时降低,并且在一个循环完成后,学习率被重置,即设置为初始学习率。这有助于实现更好的泛化。
其思想是,如果模型处于局部最小值,其中参数的微小变化会极大地改变损失,那么它不是一个好的局部最小值。通过重置学习率,我们允许模型在搜索空间中找到更好的局部最小值。
SGDR for 3 cycles
在上图中,一个循环由 100 次迭代组成。学习率在每个周期后重置。在每一次迭代中,我们逐渐降低学习率,这使我们能够陷入局部最小值。然后,通过在一个周期结束时重置学习率,我们检查局部最小值是好是坏。如果它是好的,那么在下一个周期结束时,模型将进入相同的局部最小值。但是如果它是坏的,那么模型将收敛到不同的局部最小值。我们甚至可以改变周期的长度。这允许模型深入到局部最小值,从而减少损失。
快照集成
这是一种和 SGDR 一起使用的技术。集成的基本思想是为一个特定的任务训练一个以上的模型,并平均出它们的预测值。大多数模型对相同的输入给出不同的预测。所以如果一个模型给出了错误的预测,另一个模型给出了正确的预测。
Snapshot Ensembling (https://arxiv.org/abs/1704.00109)
在 SGDR,我们借助自行车进行组装。基本上,每个局部最小值具有不同的损失值,并对数据给出不同的预测。在做 SGDR 时,我们从一个局部最小值跳到另一个局部最小值,最终找到最优最小值。但是,来自其他局部最小值的预测也是有用的。因此,我们在每个周期结束时检查模型参数。在进行预测时,我们将输入数据提供给每个模型,并对它们的预测进行平均。
调整设置以减少培训时间
培训是在 Google Colab 上进行的。它提供了一个 Tesla K80 GPU,非常适合这个任务。在该 GPU 上,梯度下降的一次迭代大约需要 1.5-2 秒。但是当训练结束后,一个时期的训练需要大约 80 分钟!这是因为,默认情况下,PyTorch 数据加载器中不能使用超过 1 个 workers。如果您尝试,PyTorch 会抛出一个错误,突然中断训练。
但是为什么要 80 分钟呢?这是因为准备下一批的任务是在 CPU 上完成的,而只有梯度下降和权重更新是在 GPU 上完成的。当权重更新完成后,GPU 空闲,等待下一批。所以在这种情况下,CPU 大部分时间是忙的,GPU 是闲的。
当我们在数据加载器中指定 num_workers 参数时,PyTorch 使用多重处理来并行生成批处理。这消除了瓶颈,并确保 GPU 得到适当利用。
我们如何在 Google Colab 上做到这一点?Google Colab 基于 Linux 系统。并且大多数 Linux 系统都有一个名为 /dev/shm 的临时分区。该分区被进程用作共享内存。它是一个虚拟内存,这意味着它不驻留在硬盘上,而是驻留在内存上。PyTorch 使用这个分区为 GPU 放置批处理。
默认情况下,Google Colab 为这个分区分配 64 MB 的大小。这个规模对于使用足够数量的工人来说是非常小的。这意味着如果我们尝试使用 num_workers,在训练期间的某个时候,这个分区将溢出,PyTorch 将抛出一个错误。解决方案是增加这个分区的大小。增加大小后,我们可以使用许多工作线程来加载数据。但是我们应该使用多少 num_workers 呢?
似乎使用尽可能多的 num_workers 是好的。我用不同大小的/dev/shm 和不同的 num_workers 做了不少实验。这是结果。
看起来使用 64 名工人不是最好的选择。为什么我们会得到这些结果?当我们在数据加载器中为 num_workers 指定一个值时,在开始训练之前,PyTorch 会尝试用批处理填充这些数量的 workers。因此,当我们指定 num_workers=64 时,PyTorch 用批处理填充 64 个工作线程。仅这个过程就需要 2.5-3 分钟。这些是我们的模型所要求的。然后,该模型根据这些批次更新权重,并等待下一组批次。这个过程只需要大约 3-5 秒钟。与此同时,CPU 正在进行下一组批处理。在 Google Colab 中,只有一个 CPU。所以在更新权重之后,GPU 再次空闲等待 CPU。同样,大约需要等待 2 分钟。这个过程还在继续。这就是为什么在使用大量工人时,培训需要大约 10 分钟。
因此,在选择工人数量时,需要权衡模型更新权重所需的时间和 CPU 生成下一批所需的时间。我们必须通过考虑这些时间来选择工人数量。通过选择 8 名工人,,我们能够减少 96%的培训时间。你可以在这个 Jupyter 笔记本里查看这个调整。
结果
经过这些麻烦之后,我终于能够训练我的模型了。该模型达到了 90.4%的准确率。这个结果可以通过不同的技术来改进。其中一些是:
- 数据扩充 —我没有在我的数据中使用任何数据扩充。音频数据有许多数据增强,如时移、速度调整等。你可以在这里找到更多关于数据扩充的信息。
- 结合梅尔光谱图+ MFCC —当前模型仅基于光谱图给出预测。CNN 进行特征提取,分类器(全连接层)从 CNN 的输出特征中寻找最佳超平面。除了这些特征,我们还可以给分类器 MFCC 系数。这将增加一些特征,但 MFCC 会给分类器提供音频文件的额外信息。这将有助于提高精确度。需要适当的调整以避免过度拟合。
- 使用不同类型的网络——正如我们在音频数据中看到的,它有一个时间维度。对于这种情况,我们可以使用 RNNs。事实上,对于音频识别任务,有结合 CNN 和 RNN 的方法,其产生比仅使用 CNN 更好的结果。
目前就这些。如果你喜欢这个帖子,请分享给你的朋友并留下掌声:)如果你想联系我,请在 LinkedIn 上联系我,或者在 Twitter 上关注我。敬请关注更多内容。
橄榄油是橄榄做的,婴儿油是给婴儿做的[论文摘要]
本文总结了一种新颖的技术,用于自然语言处理中的一项非常复杂的任务,即名词复合分类。
论文题目
橄榄油是由橄榄制成的,婴儿油是为婴儿制造的:用神经模型中的释义解释名词复合词——Vered shw artz 和 Chris Waterson
基本概述
这篇论文解决了一个重要的自然语言处理任务——自动解释名词复合成分之间的关系。
动机
考虑下面的名词复合词例子: 橄榄油 和 婴儿油 。可以观察到, 【橄榄油】 中的 【橄榄】 一词描述的是来源关系, 【婴儿油】 中的 【婴儿】 一词描述的是目的关系。换句话说,就婴儿在现实世界中所代表的意义而言,他们永远不应该被放在与橄榄相同的环境中。这种区别很重要,因为它可以用于需要复杂文本理解能力的各种应用程序。
例子例子例子
想象一下,你问谷歌搜索橄榄油是由什么组成的。如果谷歌搜索是聪明的,它应该回应“橄榄”。现在想象一下,你问谷歌婴儿油是由什么组成的。绝对不是婴儿!答案应该是油的其他成分或者油的主要成分。这是一个非常重要的区别!这是一项具有挑战性的任务,因为这两种油的含义都不容易解释给定其组成单词的含义。
你能想出更多的例子吗?试一试,你就会明白为什么 NLP 研究的这个领域很重要。作为一名 NLP 研究人员,我甚至可以看到这对于消除情感短语之间的歧义是多么有用。(在另一篇文章中有更多关于这方面的内容。)
文献综述
两种非常常见的方法被用来解决这个问题: 释义 和 名词复合表示 。第一种方法映射成分之间的关系,后一种方法利用单个成分的分布表示。(不要慌,我一会儿解释他们的意思。)
最近的一项工作(马頔,2016) 表明,成分嵌入可以有效地表示名词性复合词(以下简称 NCs)。这种方法有效的主要原因在于一种被称为词汇记忆的现象。
贡献
本文提出了一种结合路径嵌入(代表名词短语之间的关系)和分布信息(直接从单词嵌入中获得)的神经释义方法来执行名词短语分类任务。作者还对避免词汇记忆的设置进行了实验,以表明他们的方法更加稳健,他们的结果与这一现象无关。
型号
作者使用 HypeNET 来学习连接语料库中成分实例的联合出现的模式。这些也被称为路径嵌入。
结合三种模型进行 NCs 关系分类:基于路径的、集成的和集成的-NC 。每个模型递增地添加新的特征(在这种情况下是不同的分布式输入),这实质上向整个输入向量添加了更多上下文化的信息。在下图中可以更清楚地看到这一过程:
路径嵌入(图中紫色部分)是用一个普通的 LSTM 学习的,输入向量表示下列向量的连接:引理、词性标签、依存标签和方向向量。(详见论文)。NC 标签(关系)通过 LSTM 的输出使用远程监控方法获得。
评价
从 Tratz (2011) 获得的两个数据集用于评估提出的神经释义模型。提出了几个比较模型,包括几个基线模型和从以前的工作和最新方法中采用的重新训练模型。(有关实验设置的更多详细信息,请参见论文)。
表 1 显示,在大多数情况下,集成模型( Int 和 Int-NC )在使用不同的数据拆分策略方面优于所有其他模型(显示在拆分列中)。从 Int 模型和 Int-NC 模型获得的结果之间几乎没有差别,表明 NC 嵌入对分类任务没有太大贡献。
分析
对随机分裂策略进行了进一步的分析,以分析不同模型的结果的变化。在表 3 中,您可以观察到产生合理性能的一些关系(例如,度量和个人头衔)
作者还发现复杂关系表现不佳,如 NC 的词汇化,“*肥皂剧”*和 NC 的目标,“恢复计划”。(见文中更有趣的例子)。
下面的表 4 提供了从测试集获得的 NC 嵌入的例子(左)和嵌入中最相似 NC 的例子(右)。作者观察到只有 27.61%的 NCs 与具有相同标签的 NCs 非常相似。他们将这种行为归因于不一致的注释,而不是嵌入的质量。
我的 进一步的想法和结论
- 可视化 NC 向量嵌入,以观察可能具有相似属性的关系簇和模式。
- 更仔细地研究词汇记忆现象,本文使用整个模型中基于路径的部分来帮助*【轻微】*解决这个问题。
- 总体而言,性能得到了提高,但在数据质量和建模方面仍有很大的改进空间。
- NC 嵌入对当前模型没有帮助,因此它在不改变模型整体结构的情况下提供了一个可行的未来研究方向。
资源
使用 Python 的 Pandas 和 SeaBorn 从 Kaggle 数据集提取洞察
Data Science is the science of patterns. Source: Pixabay
好奇心和直觉是数据科学家最有力的工具。第三个可能是熊猫。
在我的上一篇文章中,我向你展示了如何了解一个数据集有多完整,如何绘制一些变量,以及如何观察一段时间内的趋势和倾向。
为此,我们在 Jupyter 笔记本上使用 Python 的熊猫框架进行数据分析和处理,使用 Seaborn 框架进行可视化。
在上一篇文章中,就像在这篇文章中一样,我们使用了 Kaggle 的 120 年奥运会数据集,并观察了女性随时间的参与情况、运动员的体重和身高分布以及其他变量,但没有使用关于每位运动员参加哪项运动的数据。
这一次,我们将关注数据集的 Sport 列,并获得一些关于它的见解。
我能想到的几个问题是:
- 什么运动适合胖人?高个子呢?
- 哪些运动比较新,哪些比较老?有什么运动实际上失去了奥运会的青睐,不再被玩了吗?
- 有没有一些运动总是相同的队伍赢?最多样化的运动呢,获胜者来自许多不同的地方?
和以前一样,我们将使用这个 Github 项目进行分析,您可以派生它并添加您自己的分析和见解。让我们开始吧!
体重和身高
对于我们的第一个分析,我们将看看哪些运动有最重和最高的运动员,哪些运动有最轻或最矮的运动员。
正如我们在上一篇文章中看到的,身高和体重在很大程度上取决于性别,我们对男运动员的数据比对女运动员的多。因此,我们将对男性进行分析,但同样的代码只需切换“性别”过滤器就可以对两者进行分析。
如你所见,如果我按运动项目分组,我可以得到每个运动项目的运动员的最小、最大和平均体重和身高。
然后,我查看了前 5 项最重的运动,发现如下(以千克为单位):
Sport min max average
Tug-Of-War 75.0 118.0 95.61
Basketball 59.0 156.0 91.68
Rugby Sevens 65.0 113.0 91.00
Bobsleigh 55.0 145.0 90.38
Beach Volleyball 62.0 110.0 89.51
不算太意外吧?拔河练习者,篮球运动员,橄榄球运动员都很重。有趣的是,篮球和橄榄球运动员的体重差异很大,从 59 公斤到 156 公斤不等,而大多数拔河运动员都超过 80 公斤。
然后我画出了每项运动的平均体重,发现它呈正态分布:
sns.distplot(sport_weight_height_metrics.Weight.dropna()['mean'])
身高具有类似的正态分布,但其方差要小得多,高度集中于平均值:
接下来,我开始用有序散点图绘制所有单个平均值,看看是否有异常值。
事实上,“最重”的运动相对于图表的其他部分来说是非常异常的,同样的情况也发生在“最轻”的运动上。如果我们观察身高,尽管方差明显较小,但该图揭示了“异常值”和接近平均值的人之间更大的差异,强调了大多数人并没有真正偏离它很多的事实。
对于最轻的运动,可以使用之前生成的变量 plot_data 获得结果。
结果(忽略最重的,因为我们已经看到了)如下:
lightest:
Gymnastics: 63.3436047592
Ski Jumping: 65.2458805355
Boxing: 65.2962797951
Trampolining: 65.8378378378
Nordic Combined: 66.9095595127
所以体操运动员,即使是男运动员,也是迄今为止最轻的选手!紧随其后的是跳台滑雪、拳击(这让我有点吃惊)和蹦床,这实际上很有意义。
如果我们转而寻找最高和最矮的运动员,结果就没那么令人惊讶了。我想我们都期望同样的运动会出现在顶部,不出所料,它确实出现了。至少我们现在可以说这不是一个刻板印象。
shortest (cm):
Gymnastics: 167.644438396
Weightlifting: 169.153061224
Trampolining: 171.368421053
Diving: 171.555352242
Wrestling: 172.870686236 tallest (cm):
Rowing: 186.882697947
Handball: 188.778373113
Volleyball: 193.265659955
Beach Volleyball: 193.290909091
Basketball: 194.872623574
所以我们看到体操练习者很轻,而且很矮。但是这些排名中的一些项目并没有出现在重量级项目中。我想知道每项运动的“体格”(体重/身高)如何?
该图看起来非常线性,直到我们到达最大离群值所在的顶部:
Build (Weight/Height) distribution of Olympics’ athletes
以下是建造最少和最多的体育项目:
**Smallest Build** (Kg/centimeters)
Alpine Skiing 0.441989
Archery 0.431801
Art Competitions 0.430488
Athletics 0.410746
Badminton 0.413997
**Heaviest Build**
Tug-Of-War 0.523977
Rugby Sevens 0.497754
Bobsleigh 0.496656
Weightlifting 0.474433
Handball 0.473507
所以橄榄球和拔河仍然是最重要的运动,这次高山滑雪是最不重要的,射箭和艺术比赛(我刚刚知道这是奥运会项目,需要进一步研究)紧随其后。
运动随时间推移
现在我们已经用这三列做了所有我能想到的有趣的事情,我想开始看看时间变量。具体是哪一年。我想看看奥运会是否引入了新的运动项目,什么时候引入的。但也不赞成使用。
这段代码通常在我们需要查看某件事情第一次发生的任何时候都很有用,尤其是当我们想要查看变量的异常增长时。
图表向我们展示了每年有多少项运动首次出现在奥运会上。或者,换句话说,每年有多少运动被引进:
因此,尽管许多运动在 1910 年以前就有了,而且大部分是在 1920 年以前引进的,但也有许多相对较新的引进。查看数据,我看到 1936 年引入了许多新运动,之后它们总是以小规模(少于五个运动)引入。【1936 年至 1960 年间没有任何新的运动项目,冬季两项被引入,然后他们很有规律地增加新项目:
Sport introduced
Biathlon 1960
Luge 1964
Volleyball 1964
Judo 1964
Table Tennis 1988
Baseball 1992
Short Track Speed Skating 1992
Badminton 1992
Freestyle Skiing 1992
Beach Volleyball 1996
Snowboarding 1998
Taekwondo 2000
Trampolining 2000
Triathlon 2000
Rugby Sevens 2016
对被否决的运动的类似分析(其中 max year 不是最近的)显示了这些运动的列表,其中大多数我从未听说过(尽管这绝不是一项运动是否受欢迎的好指标!)
Basque Pelota 1900
Croquet 1900
Cricket 1900
Roque 1904
Jeu De Paume 1908
Racquets 1908
Motorboating 1908
Lacrosse 1908
Tug-Of-War 1920
Rugby 1924
Military Ski Patrol 1924
Polo 1936
Aeronautics 1936
Alpinism 1936
Art Competitions 1948
我们看到艺术比赛在 1948 年被取消,马球从 1936 年起就没有在奥运会上出现过,航空学也是如此。如果有人知道航空学到底是什么,请让我知道,我在想象飞机上的人,但不知道竞争会是什么样的。也许是飞机比赛?让我们把那些拿回来!
各位,今天就到这里吧!我希望你喜欢这篇教程,也许你会在下次家庭聚餐时提出一个新的有趣的事实。
像往常一样,随意从这个分析中分叉代码,添加自己的见解。作为跟进,我正在考虑训练一个小型机器学习模型,根据运动、体重和身高栏预测运动员的性别,告诉我你会使用什么模型!如果你觉得这篇文章中的任何内容没有得到恰当的解释,或者仅仅是错误的,也请告诉我,因为我也在从中学习!
关注我,获取更多数据分析文章、Python 教程和其他任何与数据相关的东西!如果你喜欢这篇文章,请在 twitter 上与你的数据朋友分享。
最初发表于www . dataden . tech。
关于敏捷、特雷罗和思想的“干燥”
Photo by Tracey Hocking on Unsplash
在我开始创建自己的预测分析产品的科技创业公司之前,我曾在咖啡馆、酒吧和餐馆做全职工作。科技初创企业的场景和热情好客相去甚远。但我最近的转变,从初创企业到收缩的数据科学角色,揭示了一些更令人震惊的对比。餐馆和公司都喜欢在真正“干净”的环境中工作。但在企业界,这种清洁实际上窒息了那些从事真正有创意和复杂项目的人,比如数据科学,而初创企业似乎在这方面蓬勃发展。
清洁与干燥的区别
在酒店业,你的工作是为人们创造一个享受食物和饮料的环境。卫生很重要。经理们的永恒妙语是“如果你有时间学习,你就有时间打扫”。让东西看起来非常干净,(桌子、餐具、玻璃杯、地板等)理所当然地占据了大量的注意力。
最近转向合同工,为一般的大公司客户管理数据科学项目,让我看到了另一种洁癖。一眼望去,大公司工作的数字空间和程序闪闪发光。光泽出现在每个方面,从完美的电子邮件签名,程序文档的完美模板,如“解决方案范围定义声明”,带有品牌页眉和页脚,文档元数据,归属所有者的超链接字段,目录号,截止日期等。在他们的文件共享系统中,目录中预装了一些文件夹,这些文件夹描述了项目每个可能阶段的所有可以想象的文件类型。但还是没有一个明显符合你现在要上传的文件。你必须点击几十个可能的目录和子目录(大部分都是空的),才能找到一个既能找到又不会玷污系统完美状态的地方。
过了一段时间,我才停止责备自己,我在初创公司使用的工作流程是多么没有条理,看起来是多么“混乱”。就像一个优秀的服务人员一样,我的第一反应是认为清洁是一种普遍的美德。但是项目进行了几个月后,我意识到实际上清洁文化可能是完成真正好的工作的大部分困难的一部分,如果不是原因的话。
公司,尤其是他们的 IT、数据或创新部门,没有生产食品的工作。他们的工作是产生想法,并从中获取价值。有时是通过提供新的商品和服务,有时是通过提高现有流程的效率,有时是进入新的市场,或者更好地满足现有市场的需求。有没有可能创意需要在一个不像准备和提供食物和饮料的地方那么优雅的地方准备和提供?
简单的回答是肯定的。最好的想法来自原始的创意汤,它看起来并不纯粹。说好的想法是从一个乱七八糟的地方诞生的,这是在说真话。他们的品质最初并不明显,但经过大量的工作和精心的提炼和展示,他们变得如此。
酒店业也有相似之处。事实上,在所有最好的厨房和酒吧里都有很多乱七八糟的东西。然而,脏乱的部分总是发生在旨在控制和管理脏乱的阶段和系统中,因此最终产品最终完美呈现给顾客,并且始终保持良好的卫生。
反思我最近所看到的,我开始认为,企业对结构和秩序的痴迷实际上可能是扼杀大量好想法的原因。他们不知道如何在一件东西还处于不整洁的状态时就让它存在。模板、网关、标准和检查点系统有效地组成了一个自动免疫系统,旨在消除任何可能不健康的东西。问题是,它还扼杀了可能带来伟大新想法的创造性过程,并且在面对复杂项目时遇到了巨大的阻力,在这些项目中,下一步并不总是显而易见和常规的,包括数据科学。
这听起来像是不可避免的紧张。大公司抵制怪异、不干净或奇怪的想法,因为它们可能不卫生,并威胁整个系统的健康。小型初创企业孕育着各种古怪的想法。但是他们也经常死去,因为这些想法并不完全是好的,好的部分没有成功。
大型、笨重的组织有希望找到一种方法来平衡对强大而严格的卫生系统的需求,同时为做创新或挑战性的事情所需的杂乱无章的流程留出足够的创造性空间吗?我想是的,因为卫生不仅仅是清洁。
在酒店业,老手们都知道清洁与保持卫生同等重要,如果不是更重要的话。干燥。事实证明,不管一件东西有多干净,如果它是湿的,甚至是微湿的,并且允许它长时间保持这种状态,它不可避免地会产生某种可见的霉菌,或者有气味的臭味,并且必须重新清洁或处理掉。保持东西干净很容易。更微妙和普遍的敌人是持久的水分。就像那块被潮湿地折叠起来放在抽屉里的抛光布,或者是台面上的一个小扭结,它可以防止水溅出来。大量的卫生危害实际上与非常干净的东西有关。它们还没干。
我认为这是一个不言而喻的事实,即在许多大公司中管理程序和项目的闪闪发光、格式良好的文件。它们很干净,但不是干的。最近(一个客户)鼓励我将他们的一个项目启动文档中的一些文本复制到我正在做的一个报告中。但是我发现很难做到。章节标题(完美的项目符号)没有真正的意义。真正复杂的话题或问题被一笔带过。定义或列表通常是部分冗余的,相互矛盾的,或者没有定义最重要的东西。我有一个清晰的印象,那就是我正在读的东西是某人脑海中浮现的第一件东西,它可以被格式化以满足所有被认为是官方文件的“干净”标准。其实并不坏。这只是…嗯,这就是我们的工作,并没有激发信心。这让我想起了上周末放在架子后面的一品脱啤酒,湿湿的,从那以后就再也没用过了。完全干净,但里面仍然有一层凝结的雾气,还有一股淡淡的霉味,会破坏你对啤酒的渴望。
我认为,大公司实际上可以调整他们的流程来培养新的创意,并承担现有模板无法依赖的复杂流程。但是他们必须调整心态。对“清洁”的关注必须大幅转向“干燥”。你需要释放出许多仍然很乱、湿淋淋的想法,在它们被清理干净之前,把它们放在一个可以“晾干”的地方。
我说的干涸,是指他们需要得到持续的曝光或任何形式的曝光(批评、评论、也许是一个赞、投票、甚至表情符号、任何东西、任何东西),在他们打算适应任何形式的规定结构或通过任何验收标准之前。这就是 Trello、Slack 或其他现代协作和消息工具开始发挥作用的地方。在他们看起来准备好成为人们期待的特定事物之前,他们创造了一点空间来把事情公开。它们提供了创造、协调和容纳创造性混乱的空间。
人们尝试了几种方法,但都失败了
传阅稿
我怀疑,当带有标记的草案文件在被采纳前通过电子邮件传阅时,企业可能会为自己的透明和合作而沾沾自喜。这是一种高尚的努力,但完全是可悲的,就像一个酒保用擦桌子湿了的抹布擦酒类。是的,我知道你在努力打扫,但其实……(重重的叹了口气)。
一旦某样东西成了“草稿”,你就已经明确宣布了它应该是什么样的,并且有效地接受了所有的标准,即“最终”版本是必要的和充分的。你需要在那个阶段之前很久就开始表达你的想法。被认为是“干净”的东西并不意味着它是“好”的。大多数情况下,草稿会选择前者,这意味着后者。在你修改格式、调整措辞等之前,很久就要理清想法的好与坏,以及它们可能如何混合、融合或改编。
此外,如果你让一个人自己完成草稿,你现在已经让他们的自我和可用性在草稿中得到内在的提升。像‘不,我认为这是完全错误的角度,也许我们应该试试……’这样的评论再也不会出现了。被当成人身攻击的风险太大了,更不用说,这意味着所有的努力都白费了。
最后,很有可能分发列表太小了。如果它是一封电子邮件,它只发送给那些被认为需要或需要批准或输入的人,并且只由那些有足够时间阅读的人阅读。这两个群体的交集通常几乎不包含任何人。
召集会议
这很容易是项目管理和领导类型最常见的下意识反应,无论何时复杂性或混乱超过了他们最初的指示。一旦人们开始指出一些可能需要解决的紧张关系或问题,并且没有明显的答案,领导者会非常自豪地召集会议。能够利用人们的日记显然是对他们资历的一种安慰性的确认,这可能不是通过任何技术力量获得的。他们解决问题的妙招是把所有其他有能力和知识解决这个问题的人聚集在一个房间里,激励他们去解决这个问题。
总的来说,我还是喜欢开会。让人们交谈,尤其是面对面的交谈,在很多方面都有好处。但是对于困难的问题,这往往是不够的。会议的失败在于人们对会议的期望,一旦会议结束,我们就会有一个计划,知道该做什么。
难题的麻烦在于,包括像数据科学这样具有技术挑战性的问题,人们头脑中准备在会议上脱口而出的观点和知识通常不足以解决问题。你不能只是在房间里走来走去,获得每个人的观点,然后让正确的道路出现。
这并不意味着你抓错了人。对于真正复杂或技术性的项目,即使是非常有能力的人,即使是他们领域的专家,也不知道所有的事情。他们可能知道去哪里找,这就足够了,前提是你不要让他们在会议上当着同事的面当场给出一个即时的答案,而这个答案是你为接下来的几周设定路线的依据。
在数据科学会议上,经常会出现这样的情况,即最佳答案是什么,就像这样,我应该去调查一下。这可能包括去和其他一些人讨论,我们认为这些人对于会议的主要焦点来说是不必要的。或者,敏锐的技术人员会说‘等一下,我马上就有’,然后迅速搜索 google、Github、Stack-overflow 或其他地方以获得快速答案。也许这需要他们两分钟,但这仍然足以打破会议的流程,当答案到来时,每个人都在聊别的事情。
另一个常见的是,答案已经存在,并且“准备好”讨论。但这是一个列表。房间里的一个人已经仔细考虑过的清单,可能会引起另一个人的强烈兴趣,但每个人都不想(或不能)完成实际的项目。在会议真正开始之前,两人必须就此达成某种结论,把它分开,选出前三名,或者类似的事情。
因此,一个过早召开的会议的典型标志是一个结果,看起来像一个奇怪的杂七杂八的待办事项列表,一些技术,一些管理,要找出的事情,其他利益相关者要交谈,一个小团队处理一些事情并汇报的小型子会议…换句话说,所有应该提前完成的事情,都被推迟完成了。
为了避免这种令人不满意的结果,一位意志坚定的经理将犯下最大的错误,并在会议进行期间,在其他所有人都在场的情况下,开始记录结果/结论。这是一种极具破坏性的领导风格。这相当于要求房间里的每个人通过沉默来表示同意。这是锁定一个非常湿的、草率的想法的终极方法,并把它固定下来,这样它就永远不会被挑战。在那些关键的要点被写下来的时候,四处弥漫着一种意味深长的沉默,这是其他人的尴尬,他们要么脱口而出自己对提案的平庸有多么不满,要么在句号出现和下一个话题开始之前,被无法准确说出问题所在或提出更好的替代方案的挫败感所压倒。好的领导者应该给他们的员工时间来表达他们最聪明、最有建设性的异议。
预定一个‘单口相声’
再说一次,原则上我喜欢单口相声,但是它们的真正目的被那些试图弥补会议不足的项目经理们滥用了。这很快就变成了‘鉴于我留给你们的目标是多么模糊,我想每天都和你们大家检查一下,督促你们确保你们仍然朝着我认为正确的方向前进’。是啊,当然。请到其他地方“清除阻挡者”。
单口相声应该只出现在 sprint 团队,而不是 scrum 团队。客户,甚至是项目经理和其他股东,都不应该被邀请。这是关于那些在战壕中工作的人,他们每天一次从自己的屏幕上抬起头来,看看其他人过得怎么样。有机会把他们的作品放在更大的画面中,在他们可以的地方提供帮助或建议,也许调整团队内的优先次序,以帮助更快地达到相同的固定目标。
你绝不会希望非技术股东接近这些会议。他们不能帮助解决技术人员实际面临的任何问题。他们能做的就是改变范围。他们通过改变目标来“帮助”。那一点帮助都没有。一旦开发人员或数据科学家团队被告知,每天都是一个机会,可以少做一些他们计划做的事情,而是做一些不同的事情,那么生产力就会开始下降。提供无限的移动目标的机会是对未能首先找到目标位置的最糟糕的补偿。
敏捷的数据科学诀窍:在冲刺之间放慢速度
对于任何在解决方案中工作的项目,我都是敏捷的大力提倡者——对于成功的定义来说,空间太大或太复杂,以至于无法预先很好地定义。软件开发和数据科学是两个很有资格的学科。实际上,我认为数据科学更需要它,正是因为它主要涉及科学(发现关于外部现实的未知),而软件仍然有重要的工程成分(将新事物带入现实)。
我承认我从未接受过任何正式的培训,但是我读过一些关于敏捷方法的文献。我推荐阅读由 Ken Schwaber 和 Jeff Sutherland 撰写的 Scrum 指南,作为一个主要框架的相当确定的起点。我发现这份文档非常简洁地说明了要做什么,但在解释为什么每一步都很重要方面却很糟糕。因此,它给人的感觉相当枯燥和教条,人们可能会试图只松散地应用某些部分,但一点点经验通常会证明,几乎所有元素背后都有一个重要的原因。
但只有一点我想认真对待。也许这只是数据科学中的一个问题,但是我从来没有发现“在前一个冲刺结束后,一个新的冲刺立即开始”(强调是附加的)这个想法是实际的或者完全可以实现的。**
我怀疑这可能是因为大部分数据科学项目实际上是一系列实验。你不能构建一个特性,然后转移到下一个。你正试图证伪一个假设,证明或否定某件事,或者更有可能确定一些概率上的自信,而你却没有能力做到这两者。下一个逻辑实验可能会完全不同,这取决于上一个实验的结果。
所以我的直觉(我不是软件开发人员,所以这只是直觉)是,在数据科学中,我们有更少的、概念性的产品积压,而不是我们希望看到的所有功能和特性的丰富、扩展的列表。(我们称之为项目积压,因为有时“产品”不是自然的终点)。这个项目有一个广泛的目标,但是接下来的逻辑步骤是什么,或者这个目标是否仍然是可实现的,或者是否如我们所希望的那样是可实现的,很少会在一个 sprint 之前就清楚了,并且通常即使是上一个 sprint 的结果也需要在下一个 sprint 开始成形之前进行一点消化。
如果这听起来很极端,我认为有必要强调一下,现实生活中的数据科学项目实际上与 Kaggle 竞赛完全不同。Kaggle 竞赛通常在一开始就有两个完美定义的东西:数据和标签。现实世界的数据科学项目,尤其是咨询/承包项目,通常两者都没有。他们通常从一种模糊的业务目标开始,如“节省运营成本”,或“更好地满足客户需求”,以及可用数据的手写描述。有时你听说所有的数据都准备好了,但是一旦你开始使用它,你就会发现所有的迹象,你收到的摘录实际上只是所有数据的一小部分。
我越来越相信敏捷工作流程中最有价值的部分是发生在冲刺阶段的部分。弄清楚下一步该做什么实际上是最难的,也是最重要的部分。
我已经采纳了一个普遍的规则,即冲刺评审可以而且应该在冲刺结束后立即进行,而冲刺计划应该是紧接在冲刺之前的会议。但是那两个会议应该永远不要在同一天。如果是的话,至少根据我的经验,你会遇到我前面提到的所有问题。你将被迫去处理那些首先浮现在脑海中的想法。没有人会有时间和空间尽可能地提出最好的批评或反建议。本质上,当你开始工作时,你将确保你关于下一步该做什么的想法是完全错误的。最轻微的不完美,看似良性的假设或简化,将随着 Sprint 的进行而恶化和变异,直到它们对 Sprint,甚至整个项目真正有害。
创建一个垂直或倾斜的表面
让想法得到适当的暴露和通风,直到坚实的想法出现的方法是让所有可能的想法以它们最辉煌的潮湿,凌乱,邋遢的状态,到我倾向于称之为某种“垂直表面”,或者至少是“倾斜表面”上。什么是“垂直表面”,这是最后一个酒店类比。
几乎在任何餐馆或酒店的任何酒吧下面,你都会发现一些看起来相当恶心的表面。冰箱的侧面,或者支撑架子的腿的背面,将会用啤酒和拖把水的飞溅来装饰,用咖啡渣或石灰木髓或其他东西来覆盖。但是,尽管它看起来并不吸引人,但它没有气味,也不会造成任何伤害。除了飞溅发生的几秒钟,表面一直保持完全干燥,因为多余的液体流到地板上,其余时间,一堆冰箱和啤酒冷却器的热旋转空气保持完全干燥。虽然表面仍然应该定期清洁,在最好的场地,足够的干燥实际上确保了即使是明显恶心的脏乱也不会导致任何真正危险的事情发生。
我认为这个概念有数字上的对等物。在社交媒体的各种订阅源或论坛上的帖子中,这些平台能够很容易地保持最受欢迎或最受关注的内容——在顶部附近浮动的项目,最不相关的项目很快就会消失。我认为创造一个“垂直”或至少“倾斜”的表面是创造空间的一个重要创新,在这个空间里,想法可以在混乱中形成和出现,而没有肮脏的东西也在混乱中产生危险的风险。
我目前的想法是,在一个数据科学项目中,Scrum 团队中的每个人(尤其是产品负责人)都应该在 Sprint 评审后尽快将他们关于下一步的所有想法放到某种垂直的平面上。一个松弛频道可能是好的,但目前我正在尝试与特雷罗。它没有自然地体现提要的倾斜/排序特性,但是我通过使用几个不同的列表复制了这种效果,适当地命名,这样一个可以是“头脑风暴”,另一个是“草稿待办事项”,等等。这个想法只是为人们创造一个空间,让他们可以毫无拘束地把所有想法放在桌面上,包括问题、异议、未知、对未来疯狂的渴望等等。然后,他们可以慢慢地形成清晰、明确的计划或清单,每个人都可以边看边评论。
老实说,我正在努力。尤其是公司客户,他们似乎有种麻痹的恐惧,害怕写下任何在某种程度上没有“完成”或“正确”的东西。它认为这就是文化。在会议上,未完成的事情可以自由表达。但是你写下的东西呢??!天哪,在你仔细检查草稿十几遍并和你的上级确认之前,不要把这个放在心上。
这是一种愚蠢的文化,必然会阻碍任何真正优秀或复杂的东西的发展,在这种情况下,你可能需要许多其他真正聪明的人坐下来思考一些事情,然后他们才能发现缺陷,或者提出改进建议。但我是一个乐观主义者,并希望像 Trello 和 Slack 这样的东西是有用的工具,可以创造空间,让人们更多地用语言表达,但用书面形式表达。
我正在取得一些成功。在两天的过程中,我从一些客户端利益相关者那里获得了一些关于 Trello 的有意义的参与,包括一个以前从未使用过 Trello 的人。客户写下了他对 sprint 的期望的精彩描述。他写的时候,它完全没有定义,完全不可能执行,但它很好地描述了他希望看到的,并允许我充实所有的不确定性和中间步骤,这将是实现目标所必需的。我张贴了一个分类变量的直方图,一位主题专家说它将包含感兴趣事件的重要标志,以突出与该列中其他类似命名的标签的混淆。他核实了他的消息来源,并通过在图表下方发表评论来回复我进行澄清。完美。
我越来越相信,花几天时间在 Trello 或其他工具上研究出所有你能想到的东西,是有效的冲刺规划会议的必要前提。你应该为每个人都真正可能关心的话题预留见面时间,并且能够做出贡献。比如阐明意图、关于替代方向或权衡的重大决策。目的是让每个人都有最后一次机会表达自己的担忧,或者听取相关人员的意见,从而建立整个团队对计划的信任和信心。
如果你还在讨论事实、技术细节、填充列表、写下要点,那么你就是在浪费宝贵的会议时间。预计人们会脱离,一些超负荷的领导者不得不人为地将事情处理成一个可定义的结果,你甚至会在开始之前就让自己陷入一场失败的冲刺。在你把人们召集到一起之前,一个可行的计划的所有要素都应该已经摆在桌面上了。
所以我的建议是在冲刺之间花点时间。会议是好的,但还不够。想法需要一段时间来暴露,虽然仍然是一片混乱,以便干了一点。我认为在 Trello 或 Slack 上工作一两天提供了这种时间,以及一种合适的“倾斜”表面,这种表面可以比我认为过去可能做到的更好。固体的东西会粘在一起,而不干净的东西会流下来,变干,变得无害。当你的想法干了,那么你就可以把它们弄干净,为接下来的冲刺产生一个优秀的计划。