!!!DOGS VS CATS 图像分类器!!!
建立一个最先进的图像分类器
几个月来我一直在浏览 fast.ai。我不得不承认在这个过程中我学到了很多东西和很棒的技术。我会确保更新我博客中的所有内容。感谢和 瑞秋·托马斯 为 AI 民主化所做的努力。感谢牛逼的 fast.ai 社区的所有快速帮助。
下图描绘了我到目前为止的旅程,这使它成为一个有趣的旅程。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- IMDB 电影数据集上的自然语言处理情感分析
- 电影推荐系统的基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- 检测图像中最大物体的 ML 模型 Part-2
所以,振作起来,专注于 Fastai 课程的第一部分第二课。
狗 VS 猫分类器:
这篇博文讨论了狗和猫的分类模型。这是杰瑞米·霍华德在 FastAI 课程第一部分第二课中讲授的。
导入将在此模型中使用的如下所有库。
!pip install fastai==0.7.0
!pip install torchtext==0.2.3!pip3 install http://download.pytorch.org/whl/cu80/torch-0.3.0.post4-cp36-cp36m-linux_x86_64.whl
!pip3 install torchvisionimport fastai
from matplotlib import pyplot as plt# Put these at the top of every notebook, to get automatic reloading # and inline plotting
%reload_ext autoreload
%autoreload 2
%matplotlib inline# This file contains all the main external libs we'll use
# from fastai.imports import *from fastai.transforms import *
from fastai.conv_learner import *
from fastai.model import *
from fastai.dataset import *
from fastai.sgdr import *
from fastai.plots import *
使用以下命令检查 GPU 是否已启用:-
上述命令的输出应该返回 True。
在深入研究之前,我想提几个可能有用 Linux 命令。
使用前缀为“!”的命令马克。
!ls
是一个列出当前目录中文件的命令。!pwd
代表打印工作目录。将打印工作目录的路径!cd
代表变更目录。
以上三个命令有助于在目录间导航。
使用以下命令下载了狗和猫的图像。
<< !wget http://files.fast.ai/data/dogscats.zip>>
文件夹的结构应该如下所示
设置存储数据的路径
PATH = "data/dogscats/"
sz=224
使用以下命令检查文件是否已经下载
****
上面的f ’
代表 f 弦。这是一种在 Python 中格式化字符串的新方法。想了解更多关于 f 弦的信息,请点击 realpython.com 的链接。
分类任务将利用预训练模型。预训练模型是已经由其他人对类似类型的数据进行了训练的模型。因此,不是从头开始训练模型,而是使用已经在 ImageNet 上训练过的模型。ImageNet 是由 120 万幅图像和 1000 个类组成的数据集。ResNet34
是将要使用的模型版本。这是一种特殊类型的卷积神经网络。ResNet34
获得 2015 年 ImageNet 大赛冠军。ResNet 的细节将在即将发布的博文中讨论。
下面几行代码显示了如何使用 fastai 训练模型。
使用的架构resnet34
已经保存在 arch 变量中。数据保存在数据变量中,因为它在前面指定的路径中查找数据。tfms
是数据扩充的一部分,稍后将详细讨论。
pre-trained
方法从 arch 模型(resnet34
)创建新的神经网络。拟合方法使用学习率和指定的时期数来训练模型。并且已经获得了0.9895
的精度。
梯度下降
我来解释一下上面的图像。最初选择的参数是随机的。此时的损失很大。高损失表明在训练期间,“结果/预测值”和“目标值/标签”之间的差异更大。因此,应该遵循一种方法,使用这种方法应该使这种差异最小。收敛或达到局部最小值意味着此时损失最小,因此结果和目标值/标签之间的差异最小。这个过程被称为梯度下降。****
学习率:-
上述拟合函数中的学习率(LR)** 是最重要的参数之一,应仔细选择,以使模型快速有效地达到最优解。基本上说的是如何快速到达函数中的最优点。如果 LR 很低,则过程很慢,如果 LR 太高,则很有可能超过最小值。因此,必须仔细选择 LR,以确保收敛(达到局部最小值)以有效的方式发生。下图描述了上述概念。**
如何选择最佳学习率?
!!!别担心,杰瑞米·霍华德会支持你的。杰里米提到了一个很好的方法来计算学习率,它被称为
学习率查找器。
请检查下面的代码。
****
使用lr_find()
可以获得最佳学习率。如学习率与迭代图所示,LR 在每次小批量后增加,并呈指数增加。在第二个图中,即损耗对学习率,观察到损耗随着学习率的增加而减少一段时间,当学习率为 0.1 时,损耗处于最小值,之后它开始再次上升(这意味着 LR 如此之高,以至于它已经超过最小值,损耗变得更糟)。
选择最佳学习率,步骤如下:-
- 确定上面损失与学习率图表中的最低点(即 0.1)
- 后退 1 级(即 0.01),选择该值作为学习率。
后退 1 级背后的概念:-
虽然在这一点上损失最小,但是在这一点上选择的学习速率太高,并且继续使用这一学习速率将不会收敛。请查看下图进行解释。
注意:- 学习率查找器是最重要的超参数之一,如果调整/选择得当,将会产生最佳效果。
改进模型
改进模型的一个方法是给它更多的数据。因此,我们使用数据增强。等等,但是 为什么要数据增强?
我们的模型通常有几百万个参数,当训练更多的数时,有很大的可能性,它可能开始过度拟合。过度拟合意味着模型过度学习训练数据集中图像的特定细节,并且它可能无法在验证数据集或测试数据集上很好地概括。换句话说,当验证数据集的精度小于训练数据集的精度时(或者在训练数据集上计算的损失远小于在验证数据集上计算的损失),就发生了过拟合。因此过度拟合可以通过向模型提供更多数据来避免,因此使用数据扩充。
注意:- 数据增强并不是创造新的数据,而是让卷积神经网络从一个非常不同的角度学习如何识别狗或猫。
对于数据扩充,我们在tfms_from_model()
函数中将transforms_side_on
传递给aug_tfms
。transforms_side_on
通过水平翻转将给出不同版本的图像。它让神经网络看到图像,就好像它是从侧面角度拍摄的一样,少量旋转它们,稍微改变它们的对比度、亮度,稍微放大一点,移动一点。这些变化可以在下图中看到。
要进行数据扩充,请编写以下代码
tfms = tfms_from_model(resnet34, sz, aug_tfms=transforms_side_on, max_zoom=1.1)
data = ImageClassifierData.from_paths(PATH, tfms=tfms)
虽然为数据扩充创造了空间,但是数据扩充不起作用,因为它最初被设置为precompute=True .
让我详细解释以下代码及其与上述语句的关系:-
data = ImageClassifierData.from_paths(PATH, tfms=tfms)
learn = ConvLearner.pretrained(arch, data, precompute=True)
learn.fit(1e-2, 1)
当使用ConvLearner.pretrained(…)
声明架构时,预计算被设置为真,这表示实现来自预训练网络的激活。预训练网络是已经学会识别某些事物的网络。对于我们的狗与猫的研究,使用的预训练网络已经学会了对 ImageNet 数据集中 120 万张图像的 1000 个类别进行分类。因此,采取倒数第二层(因为这是一层,有所有必要的信息来计算出图像是什么),并保存这些激活。为每个图像保存这些激活,这些被称为预计算激活。现在,当创建新的分类器时,利用这些预先计算的激活,并基于这些激活快速训练模型。因此要实现这个 set precompute=True。
注意:- 当**precompute=True**
时,数据扩充不起作用,因为它当前使用的是特定版本的扩充 cat,或者换句话说,即使每次显示的是不同版本的 cat,特定版本 cat 的激活已经预先计算好了。第一次运行时,预计算激活需要一两分钟。
当使用预计算激活训练时,精确度是98.8%
:-
要进行数据扩充,设置**precompute=False**
并检查准确性。在下面的代码中**cycle_len**
是一个重要的参数,将在本文后面详细讨论。
精确度增加了一点到99.1%
,好消息是,它没有过度拟合,训练损失进一步减少。为了进一步改进模型,让我们关注:-
SGDR(重启随机梯度下降)
SGDR 说,当我们越来越接近最小值时,让我们降低学习率。随着我们的训练(即更多的迭代次数)降低学习率的想法被称为学习率退火。有步进式和余弦退火。在这个过程中,杰瑞米·霍华德使用余弦退火。
****
在余弦退火中,当不在最小值附近时,我们使用较高的学习率进行训练。当接近局部最小值时,切换到较低的学习速率,并在此基础上进行几次迭代。
上图显示了一个简单的损失函数。实际上,数据集是在一个非常高维的空间中表示的,有许多相当平坦的点,这些点不是局部极小值。假设我们的表面看起来像下面的图表
从 1 号红点开始,达到了 2 号红点所示的全局最小值,但是这里不能很好地概括。如果使用这种解决方案,在稍微不同的数据集的情况下,它不会导致好的结果。另一方面,红点 3 将在稍微不同的数据集的情况下很好地概括。我们的标准学习率退火方法将下降到一个点,在高维度中有很大的机会陷入尖峰区域,在那里它不会更好地概括,因此不是一个好的解决方案。相反,可以部署一个学习速率调度器**,它将重置并执行余弦退火,然后再次跳转,这样它将从点 2 跳转到点 3,以此类推,直到它到达一个泛化能力非常好的点。**
每次学习率被重置,它将再次增加学习率,这将导致离开表面的讨厌的尖峰部分,并最终跳到一个漂亮光滑的碗,这将更好地概括。
上述过程被称为 SGDR (重启随机梯度下降)。这个 SGDR 最好的部分是一旦达到一个“像表面一样光滑的曲线”,它就不会再开始了。它实际上是在空间的这个好地方逗留,然后不断变得更善于找到合理的好位置。请检查下图。
使用 SGDR 和学习率查找器会给我们更好的结果。从学习率搜索器中,试着视觉上找到一个好的学习率,否则在 SGDR 它不会跳到一个平滑的表面上。借助**cycle_len**
参数重置学习率。这基本上意味着在每 1 个时期后重置学习率。下图显示了重置是如何发生的
注意:- 学习率的重置发生在每一个时期之后,因为cycle_len=1
和学习率在每一个小批量之后保持变化。y 轴是学习率,其中 0.010 是我们从学习率查找器获得的学习率。所以 SGDR 会在 0 到 0.010 之间调整学习率。
建议在中间步骤继续保存模型。为此,请使用以下命令:-
learn.save('224_lastlayer')
learn.load('224_lastlayer')
该模型保存在 dogscats 文件夹下的 models 文件夹中,如下所示
所有预计算的激活都保存在tmp
文件夹中。因此,如果出现奇怪的错误,可能是由于半完成预计算激活或其他方式,继续删除tmp
文件夹,并检查错误是否已经消失。这是快速开关它的方法。
注意:- 预计算激活不需要任何培训。这些是预训练模型用我们下载的重量创建的。
我们还能做些什么来让模型变得更好?
到目前为止,预训练激活已经下载并直接使用。CNN 内核中预先训练的激活或预先计算的权重保持不变(即,尚未进行预先计算的权重的重新训练)。预先训练的模型已经知道如何在早期阶段找到边缘、曲线、梯度,然后找到重复的模式,最终找到主要特征。到目前为止,只有新的层被添加到顶部,模型学会了如何混合和匹配预先训练的功能。如果在 Imagenet 上训练的模型被扩展到诸如“卫星图像分类”的情况,其中特征完全不同,则需要重新训练大多数层,因为特征完全不同。因此,需要探索一个新概念,命名为:-
微调和差分学习率
要学习一套不同的功能或告诉学习者卷积滤波器需要改变,只需**unfreeze**
所有层。冻结的层是其权重没有被训练或更新的层。
**!!!好吧好吧艾尔莎,我会让它去解冻层!!!😍 😍
解冻图层将使图层权重对训练或更新开放。但是与后面的层相比,最初的层需要很少或任何训练。这普遍适用,因为初始层的工作是学习边缘和曲线,而后面的层学习重要的特征。因此,对于不同的层集合,学习速率被设置为不同的。这个概念被称为差异学习率。****
learn.unfreeze()
lr=np.array([1e-4,1e-3,1e-2])
进行必要的更改后,按如下所示训练模型。
前面讨论了cycle_len=1
和number_of_cycles=3
参数。再次提醒一下,cycle_len=1
是历元的数量,number_of_cycles=3
表示学习者将做 3 个周期,每个周期 1 个历元。现在一个新的参数被引入,命名为cycle_mult=2
。此cycle_mult
参数在每次循环后乘以每次循环的长度。这里的倍增因子是 2。于是(1+2*1 +2*2 )epoch
= 7 epoch
。也就是说,如果周期长度太短,它开始下降,找到一个合理的好点,然后弹出,再次下降,弹出。它实际上从来没有找到一个好点,这既是一个很好的最小值,也是一个很好的概括。这是一个机会的问题。它没有探索表面。所以要探索地表更要设定cycle_mult=2
。现在,图表看起来更具探索性
据观察,到目前为止,精度已经提高到99.0%
,损耗也大幅降低。还有最后一个方法可以让模型变得更好。它被称为
测试时间增加(TTA)
在验证/测试数据集上,所有输入都必须是正方形。这有助于 GPU 快速处理。如果验证数据集中的输入图像具有不同的维度,则处理速度不会很快。为了保持一致,在中间画出正方形。如下例所示:-
如果上面的图片在中间是方形的,模型将很难预测它是狗还是猫,因为它是唯一进入验证数据集的身体。为此(测试时间增加)使用了 TTA。它将随机进行四次数据增强,以及未经增强的原始中心裁剪图像。然后取所有这些图像上所有预测的平均值。这是我们最后的预测。
注:- 仅适用于测试和验证数据集。
如上所示,应用 TTA 后的精度为99.35%
。
为了得到我们的分类器的概要,画一个混淆矩阵。混淆矩阵用于分类,以了解有多少预测正确或不正确,如下图所示。
混淆矩阵的解释:-
混淆矩阵说明了我们的分类器有多好。如上所述,深蓝色区域已经被正确分类。996 张猫图片已被分类为猫,993 张狗图片已被正确分类为狗。7 张狗图片被归类为猫,4 张猫图片被归类为狗。因此,我们的分类器做得非常好。
希望这篇文章对你有所帮助。在我未来的博客文章中,我们将深入探讨。因为涵盖了很多重要的概念,你现在可能会有这种感觉。
!!坚持住,更多有趣的东西即将到来。直到那时再见😉!!
附注——如果你有兴趣,请在这里 查看代码 。
甲乙丙 - 一直在鼓掌。 👏 👏👏👏👏😃😃😃😃😃😃😃😃😃👏 👏👏👏👏 👏**
编辑 1:-TFW·杰瑞米·霍华德同意你的帖子。😃😃😃😃😃😃
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 利用神经网络进行时间序列分析
- 对 IMDB 电影数据集的 NLP 情感分析
- 电影推荐系统的基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- ML 模型检测图像中最大的物体 Part-2
“犬种图像分类”
建立一个最先进的图像分类器。
欢迎来到第二集的第二部分,我们将讨论狗的品种分类问题。我们有 120 种狗的图片需要分类。在我们开始之前,我想感谢和 雷切尔·托马斯 为民主化人工智能所做的努力。感谢牛逼的 fast.ai 社区和Sam Charringtonfor the onlineTWiML&AI x fast . AI 学习小组会议 。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分:- 狗和猫的图像分类
- 犬种图像分类
- 多标签图像分类
- 利用神经网络进行时间序列分析
- IMDB 电影数据集上的 NLP 情感分析
- 电影推荐系统的基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- 检测图像中最大物体的 ML 模型 Part-2
没看过前一集的,请点击这里查看第 2.1 集。为了节省您的时间,我将在这里快速浏览最后一集。下面是我们构建一个最先进的分类器的步骤
- 启用数据扩充并设置
PRECOMPUTE = TRUE.
- 使用
lr_find()
找到损失仍在明显改善的最高学习率 - 从预先计算的几个时期的激活中训练最后一层。
- 用
CYCLE_LEN=1
训练数据增强的最后一层(即PRECOMPUTE=FALSE
)2-3 个历元。 - 解冻所有层。
- 将前几层设置为比下几层更低的学习速率,并对其进行训练。
- 再次使用
lr_find()
。 - 用
cycle_mult=2
训练全网,直到过拟合。
所以在这篇博文中,我们将讨论狗的品种识别。到这个 kaggle 数据集的链接出现在这里。主要目的是对 120 个品种的狗图像进行分类。
1。下载数据并导入包。
所以要开始,我们必须下载数据。为了轻松获得这些数据,我们将使用 kaggle api。要了解更多关于这个 API 的信息,请点击查看。但是底线是
- 安装 kaggle api
- 导入它
- 并用它将数据下载到你想要的路径。下面的快照中已经执行了提到的步骤。
Downloading data done right
接下来,让我们导入所有必需的包:-
[glob](https://www.npmjs.com/package/glob)
包将使用 shell 使用的模式匹配文件。在下面的代码中,我们可以看到 glob 有助于获取上述路径中的所有文件。在下面的要点中从第 7 行开始提到了输出。
2。检查 GPU 可用性并解压缩下载的文件
要确保 GPU 对您可用,请运行以下命令。这些应该返回 true。
Cuda done right
下载完所有文件后,下面的代码有助于解压这些文件。
unzipppp
3。使用熊猫熟悉数据
import PANDAS as 🐼
现在让我们检查数据。拉开 train and test zip files
的拉链后,我们会知道它有 120 种狗的图片。Sample_submission.csv
files 告诉我们竞赛在提交过程中期望的文件内容。让我们看看labels.csv
文件的内容。
它包含狗的所有图像的image_id
和狗所属的breed or labels
。labels.csv
为训练和测试数据集中的图像提供品种。这种变通方法使生活变得更加轻松。
让我们检查一下一个特定品种有多少只狗。
上面的输出显示了 120 种狗的品种,并以降序显示了对应于每种狗的图像数量。对不起,我不能在一张快照中容纳所有的品种。
通常,我们有一个训练、验证和测试数据集。我们在训练数据集上训练我们的模型,同时在验证数据集上预测它。这涉及到参数调整,以提高验证数据集的准确性。最后,当我们确信我们的模型是好的,我们用它来预测未知的数据集,即测试数据集。这个过程有助于防止过度拟合。
vaidation dataset done right
上面的第一行设置了 label.csv 文件的路径。第 2 行打开文件并计算数据集除标题之外的行数,因此减 1。这为我们提供了 csv 文件中的行数或图像数。第 3 行中的get_cv_idxs(n)
将随机返回 20%的数据,用作验证数据集**。这将返回我们将用作验证数据集的文件的索引。让我们交叉核对这一个。**
!!!似乎是合法的!!!验证数据集的大小实际上是总数据集大小的 20%。
现在,我们将使用预先训练好的resnext_101_64
架构来构建我们的模型。
当我写这篇博客的时候,fastai 库中没有预训练的resnext_101_64
架构的权重,所以我们必须将其下载到这个位置'/usr/local/lib/python3.6/dist-packages/fastai/weights'
,然后运行我们的模型,否则它会抛出一个错误消息weights not found
。按照下面代码中解释的步骤进行操作。
获得预训练模型权重的步骤
- 使用中提到的链接(第 3 行)将预训练模型下载到任何位置。
- 将其移动到上述位置。(第 20 行)
- 将上述位置作为您的当前目录。(第 23 行)
- 并解压文件。(第 27 行)
- 回到你存放数据的地方。(第 41 行)
resnext101 weights
注意:- 将来,如果发生新的 fastai 代码更新,可能会考虑上述步骤,因此该步骤可能是可选的。
在继续下一步之前,决定图像的大小、使用的架构以及要考虑的批量大小。
4。按照 FASTAI 格式设置数据
为了按照 fastai 格式设置数据,我们编写以下代码。请注意,之前我们曾经为狗与猫分类器做了ImageClassfierData.from_paths()
,因为我们在单独的文件夹中指定了数据。在这种情况下,文件夹的名称就是标签的名称。
但是在这里,我们将数据(图像)呈现在 train 和 test 文件夹中,文件名汇总在labels.csv
文件中。labels.csv 文件包含训练和测试数据集中每个图像的标签/品种,因此我们选择如下所示的ImageClassfierData.from_csv(...)
。
参数 **ImageClassfierData.from_csv(...)**
为:
PATH
是数据的根路径(用于存储训练模型、预计算值等)。还包含所有的数据。'train'
—包含训练数据的文件夹。labels.csv
文件中有不同狗狗图片的标签。val_idxs
有验证数据。它指示已经放入验证数据集中的 labels.csv 中的索引号。test_name='test'
是test
数据集。- 文件名实际上在末尾有一个
.jpg
,在labels.csv
文件中没有提到,因此我们有suffix=’.jpg’
。这将把.jpg
添加到文件名的末尾。 tfms
是我们要申请的数据增强的转换。
上面已经创建了数据对象。使用data
对象,我们可以检查train_ds
(训练数据集)。要知道使用数据对象还能访问什么,写data.
并按 tab 键。将出现一个下拉菜单,显示data
对象的属性。下面提到的fnames
告诉我们训练数据集中存在的文件名。
让我们检查图像是否位于正确的位置:-
图像的输出如下所示。正如我们所看到的,狗的图像占据了大部分的画面,因此不用担心变换(tfms
)阶段的裁剪或缩放技术。
下面的第 6 行将文件名映射到文件的大小,并将其存储在size_d
中。size_d
是一个字典,其中键是文件名,值是每个文件的维度。第 8 行有zip(*)
命令,帮助解压行和列,并保存在row_sz
和col_sz
中。
图像的大小是:-
检查下面 1 号线train dataset
和test dataset
以及 5 号线number of data classes/dog breeds
和what are the first five breed of dogs
的尺寸。
在进一步讨论之前,让我们检查一下我们正在建模的数据的维度。这只是为了检查的目的。因此:-
在上面的直方图中,我们可以看到,我们有 5000 个尺寸约为 500 像素的图像,很少有图像大于 1000 像素。在下面的直方图中,我们只检查尺寸低于 1000 像素的图像。它还显示了有多少特定尺寸的图像。
5。建立一个最先进的分类器。
等待结束了。最终呈现在你面前的是最先进的分类器。
对于最先进的分类器,需要遵循几个步骤。它们如下:
5.1)启用数据扩充并设置 PRECOMPUTE =TRUE。
出于一致性目的,让我们调整数据的大小。get_data()
有正常的几行代码。第一个是Setup data augmentation
,另一个是Format your data
,我们把 image_size 和 batch_size 传递给这个函数。当我们开始处理新的数据集时,如果我们先处理小图像,那么一切都会变得非常快。因此我们从尺寸sz=224 and bs=64
开始。之后我们可以增加尺寸。如果在增加大小时我们看到Cuda Out of Memory error
,重启内核,将批处理大小设置为较小的值,然后再次运行。
现在让我们用 precompute=True 设置神经网络:-
当使用ConvLearner.pretrained(…)
声明架构时,预计算被设置为 True,这表示它实现了来自预训练网络的激活。预训练网络是已经学会识别某些事物的网络。对于我们的狗品种识别案例研究,使用的预训练网络(RESNEXT101_64
)已经学会对 ImageNet 数据集中 120 万张图像的 1000 个类别进行分类。因此,采取倒数第二层(因为这是一层,有所有必要的信息来计算出图像是什么),并保存这些激活。卷积神经网络有称为“激活”的东西激活是丰富的功能。激活是一个数字,表示“这个特性在这个地方,具有这个置信度(概率)”。为每个图像保存这些激活,这些被称为预计算激活。现在,当创建新的分类器时,利用这些预先计算的激活,并基于这些激活快速训练模型。因此要实现这个设置precompute=True
。
预训练方法从arch
模型中创建我们的新神经网络。同时,它做如下两件事:-
- 它所做的是,它保留除最后一层之外的所有层(最后一层是输出层,在 Imagenet 的情况下,它给出 1000 个类别内的概率)。
- 最后一层被添加的几个层所取代,这些层以输出层结束,输出层给出了所有 120 种犬种的概率。
所以最初一切都是frozen
和precompute=True
,因此我们所学的都是我们添加的图层。与precompute=True
一样,
数据增强没有做任何事情,因为我们每次都显示完全相同的激活。precompute=True
所做的是预先计算图像有多少看起来像激活的东西。Precomputed activations
是我们不打算训练的每个冻结层中使用的激活函数的输出。这有助于我们在最后加速新添加的完全连接层的训练。我们只预计算网络倒数第二层的激活。在所有层上执行都是存储密集型的。
5.2)使用
**lr_find()**
找到损失仍在明显改善的最高学习率
以下命令有助于找到最佳学习率。
该命令产生如下图所示的图形,该图显示了学习率随着迭代次数的增加而增加的事实。
该命令绘制了损耗与学习率的关系,给出的结果表明,随着学习率的增加,损耗达到最小值,然后出现一个点,在该点之后,损耗超过最小值,因此损耗变得更大。因此,我们必须选择一个与最小损失相对应的学习率。但是此时的学习率已经太高了,所以我们从学习率表上的最小损失点后退一步,选择它作为最佳学习率。这里是0.01
。
5.3) 从几个时期的预计算激活中训练最后一层。
这里,我们选择最佳学习率(0.01
)并训练 NN 的最后一层(因为预计算=真且第一层被冻结),即它们的权重将被更新,以最小化模型的损失。使用这种技术,我们达到了92%
的精度。但是有一点点过度拟合,因为我们的验证损失大于训练损失。为了避免这种情况,我们引入了Dropout
、Data Augmentation
和training on larger images
。
5.4) 在 CYCLE_LEN=1 的 2-3 个历元内,训练最后一层的数据扩充。
- 辍学
ps
是漏失参数。它指的是随机丢弃 50%的神经元。这有助于神经网络防止过度学习,从而防止过度拟合。正如我们可以看到的,此时我们的精度已经下降到了91.6%
,但好消息是我们的验证损失小于训练损失,这是一个明确的迹象,表明我们没有过度拟合。
- 数据扩充
为了进一步改进模型,我们需要更多的数据,因此通过设置learn.precompute=False
打开数据扩充。通过设置precompute=False,
,我们仍然只训练我们在最后添加的层,因为它被冻结了,但是数据增加现在正在工作,因为它实际上从头开始经历和重新计算所有的激活。cycle_len 的概念在上一集已经详细讨论过了。
后数据增加我们看到92.17%
的精确度增加,没有任何过度拟合。
注意:- An epoch
是一次通过数据,a cycle
是一个周期中出现的时期数。所以这里 cycle 基本上和 epoch 是一样的。
- 在较大的图像上训练是防止过度拟合的最好方法。
现在我们看到了拟合不足的情况,因为验证损失比训练损失低得多。我们的主要目标应该是使 val_loss 和 trn_loss 尽可能接近,同时注意精度。
Cycle_len=1
可能太短了。让我们设置cycle_mult=2
以找到更好的参数。这将有助于防止不合身。当我们拟合不足时,这意味着cycle_len=1
太短(在它有机会放大并选择最佳参数之前,学习率被重置)。cycle_mult
的概念已经在这里详细讨论过。
让我们为更多的时代训练它。
!!!但是等等!!!
如果您仔细观察输出,我们的 val_loss 仍然略高于 trn_loss。这是否意味着它的过度拟合,对我们的神经网络有害。让我们来听听专家的意见,看看为什么一点点过度拟合是好的。查看下面的链接。
** [## 确定你什么时候过度适应,什么时候不适应,什么时候刚刚好?
过拟合 if:训练损失>验证损失恰到好处 if 训练损失~验证损失问题:我们应该如何…
forums.fast.ai](http://forums.fast.ai/t/determining-when-you-are-overfitting-underfitting-or-just-right/7732/5?u=ashis)
除此之外,这个数据集类似于 ImageNet 数据集。所以训练卷积层帮助不大。因此,我们不打算解冻所有的层。最后,我们正在做TTA
( 测试时间增加)并得到预测概率。
在最后一步,我们计算精度和损失。很高兴看到我们的模型在测试数据集上获得了93.3%
的准确性,这简直是令人兴奋的。
这就是我们如何得到最先进的结果,我的朋友。
附:随着我继续学习其他课程,这篇博文将会更新和改进。如果你对源代码感兴趣,请点击 查看 。
甲乙丙 - 一直在鼓掌。👏 👏👏👏👏😃😃😃😃😃😃😃😃😃👏 👏👏👏👏 👏
感谢大卫·罗宾逊的激励😃😃😃😃😃😃
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 利用神经网络进行时间序列分析
- IMDB 电影数据集上的 NLP 情感分析
- 电影推荐系统的基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- 检测图像中最大物体的 ML 模型 Part-2
如果您有任何问题,请随时联系 fast.ai 论坛或 Twitter:@ ashiskumarpanda**
“多标签图像分类的一个例子”
建立一个最先进的多标签图像分类器。
欢迎来到第三集 Fastdotai ,在这里我们将接手多标签分类的案例。在我们开始之前,我想感谢 【杰瑞米·霍华德】 和 雷切尔·托马斯 为民主化人工智能所做的努力。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- IMDB 电影数据集上的自然语言处理情感分析
- 电影推荐系统的基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- ML 模型检测图像中最大的物体 Part-2
今天我们将处理多标签分类,这里我们有多个标签作为目标变量。在深入多标签分类之前,我们先了解:-
CNN(卷积神经网络)是如何工作的?
CNN 架构有不同的部分。让我们详细地讨论它们,之后,我们将把它们结合起来,详细地讨论 CNN 的架构。所以让我们从输入开始,也就是图像
- 图像:-
最初,我们有一个图像。图像实际上是一个数字网格。看起来像这张图片
This is how a gray-scale image representing # 7 looks like . The pixel values has been standardized between 0 and 1.
2。内核/过滤器:-
在图像的顶部,我们有一个内核。在这种情况下,核/过滤器是 3d 张量的 3×3 切片,有助于我们执行卷积。
这个 3 乘 3 切片内核在图像上滑动,并产生特征图。
3.激活:-
特征图由激活组成。激活是一个数字,计算方法如下
- 取相同维度的输入切片。
- 确保您的内核与输入片段的维度相同。
- 将步骤 1 中得到的输入与步骤 2 中得到的内核进行逐元素相乘
- 然后总结一下。
- 它产生一个数字,比如“N”。
- 在此基础上应用 ReLu(校正线性单位)激活功能。基本上 ReLu 就是
max(0,N).
的意思 - 我们得到的数字被称为“激活”。
4.张量:-
假设我们的网络经过了训练,在训练结束时,它已经创建了一个卷积滤波器,其核值已经学会识别垂直和水平边缘。Pytorch 不会将这些过滤器值保存为两个不同的 9 位数组。它将值存储为张量。张量是一个高维数组。张量有一个额外的轴,可以帮助我们把这些过滤器堆叠在一起。
5。隐藏层:-
除了输入层和输出层之外的所有层都称为隐藏层。构成激活图的层就是这样一个隐藏层。它一般被命名为 Conv1 和 Conv2 和是核卷积的结果。
然后我们得到了一个非重叠的 2 乘 2 最大池。它通过高度和宽度将分辨率减半。一般命名为 Maxpool 。
除此之外,我们还有密集层/全连接层。对于 max-pool 层中出现的每一个激活,我们创建一个权重,对应于被称为**的全连接层。**然后对每一个权重的每一次激活做一个和积。这将产生一个单一的数字。
使用额外全连接层的缺点 :-这会导致过度拟合,也会降低处理速度。
注意:-内核的尺寸和图像/激活图的切片的尺寸应该总是相同的。对于多通道输入,创建多通道内核。这有助于更高维的线性组合。
内核值是如何更新的?
基本上,我们从一些随机核值开始,然后在训练期间使用随机梯度下降来更新核值,以便使核中的值有意义。以这种方式,在几个时期之后,我们到达初始层内核正在检测边缘、角的位置,并且随后更高层内核正在学习识别更重要的特征。
我对使用 KERAS 对 MNIST 数据集进行分类的简单 CNN 的看法
代表代码的简图(概括地说是 CNN)
CNN in detail
所以我们从(28,28,1)输入图像开始。
- 我们使用过滤器/内核来减少或增加激活图的深度/宽度,并减少激活图的高度和宽度。当我们用 32 个维数为(5,5)的核卷积维数为(28,28,1)的输入图像时,我们得到(24,24,32)的输出。
- 使用{(n-f+1),(n-f+1),(#Kernels)}计算输出维度,其中
- n=图像尺寸
- f =内核维数
- #内核数=内核数
- 所以我们得到{(28–3+1),(28–3+1),(#Kernels)}=(24,24,32)
**3。**我们在深度学习中使用非线性函数/ReLU 激活函数。但是为什么呢?看看下面这个 Quora 帖子。
回答(第 1 题,共 9 题):“为什么使用非线性激活函数?”在没有非线性激活函数的情况下,神经网络…
www.quora.com](https://www.quora.com/Why-does-deep-learning-architectures-only-use-the-non-linear-activation-function-in-the-hidden-layers)
**4。**发帖称,我们使用最大池将内核的高度和宽度减少了 2 倍。
- 因此,激活图(24,24,32)减少到(12,12,32)。
**5。**这个(12,12,32)激活图与 32 个维数为(3,3)的核以及现在的输出维数按照公式{(n-f+1),(n-f+1),(#核)} = {(12–3+1),(12–3+1),32}=(10,10,32)进行卷积。
6。这个(10,10,32)激活图与 10 个具有维度(10,10)的核进行卷积,现在输出维度按照公式
{(n-f+1),(n-f+1),(# Kernels)} = {(10–10+1),(10–10+1),10}=(1,1,10)。
**7。**最后,我们已经达到了激活的(1,1,10)维。这是倒数第二层。它吐出 10 个随机数。
**8。**然后我们在此基础上使用 softmax 激活将数字转换成概率。
9。soft max Activation返回范围从(0,1,2,3,…9)的 10 个数字的概率值,并且它还倾向于特别强烈地拾取一个事物。Softmax 只出现在最后一层。这些将是我们的预测值。因为这些是概率值,所以结果是 1。我们将把这些预测值与我们的目标值进行比较。请检查上述附加代码(keras.ipynb)的第 9 行,以了解目标值如何保存在一个热编码表单中。数字 5 表示如下。
10。之后,我们将使用损失函数尽量减少 10 个预测值和 10 个目标值之间的损失。为了计算损失函数,我们使用梯度下降的概念。使用梯度下降保持更新参数/内核值。
11。最后,考虑最小损耗点对应的参数。并且在对测试数据集进行预测期间使用这些参数/核值。这是单一标签分类的概念,如狗对猫或狗的品种分类。现在我们来看一个多标签分类的案例。
多标签分类的最好例子是 kaggle 竞赛星球:从太空了解亚马逊。所以让我们分两步来做。
1。 下载数据,导入所需的包。
使用以下命令下载数据
! pip install kaggle
import kaggle
! kaggle competitions download -c planet-understanding-the-amazon-from-space
!pip install fastai==0.7.0
!pip install torchtext==0.2.3!pip3 install http://download.pytorch.org/whl/cu80/torch-0.3.0.post4-cp36-cp36m-linux_x86_64.whl
!pip3 install torchvision
导入包并检查目录中是否存在这些文件
train_v2.csv
file 具有训练数据集中存在的文件的名称以及对应于它们的labels
。
2。 用熊猫熟悉数据
单标签和多标签分类的区别
在单一标签分类中,图像是猫或狗,如下图所示
让我们检查多标签分类:-
正如我们可以看到的输出,在多标签分类的情况下,图像被分为两部分
- 天气——资料中提到的天气有很多种。从中我们可以看到上面快照中的霾和晴。
- 要素—上图中的要素列表为主要、农业、水。
原生代表原生雨林。
农业代表用于农业用地的空地。
水代表河流或湖泊。
基本上,在多标签分类中,每个图像属于一个或多个类别。在上面的例子中,第一幅图像属于两类:霾和原生雨林。第二幅图像属于 4 类:初级、清晰、农业和水。Softmax 不是一个很好的分类这些图像的激活函数,因为它倾向于将一个图像分为一个类别,而不是多个类别。因此,Softmax 适用于单标签分类,不适用于多标签分类。
Fastai 在 **train_v2.csv**
文件中查找标签,如果发现任何样品有一个以上的标签,它会自动切换到多标签模式。
如第 2.2 集所述,我们创建了一个占训练数据集 20%的验证数据集。下述命令用于创建验证数据集:-
3。 获取 FASTAI 格式的数据
这些步骤与我们在前两集所做的相同。get_data(sz)
有两行代码:-
-
tfms_from_model 有助于数据扩充。
aug_tfms=transforms_up_down
表示垂直翻转图像。它实际上做的不止这些。正方形图像实际上有 8 种可能的对称性,这意味着它可以旋转 0、90、180、270 度,并且可以翻转其中的每一种。这是我们对正方形对称性所能做的一切的完整列举。它被称为dihedral
集团。这段代码将完成完整的 8 组翻转,即dihedral
组旋转和翻转加上小的 10 度旋转,一点缩放,一点对比度和亮度调整。要了解更多信息,请查看fastai
文件夹中的transforms.py
文件。下面附上了transforms.py
中执行二面角旋转的片段。请检查我们在transforms.py
文件中应用的其他转换。 -
参数
**ImageClassfierData.from_csv(...)**
为:
它有助于按照 fastai 格式读取文件。
PATH
是数据的根路径(用于存储训练模型、预计算值等)。还包含所有的数据。'train'
—包含训练数据的文件夹。labels.csv
文件有行星图像的标签。val_idxs
有验证数据。它指示已经放入验证数据集中的 labels.csv 中的索引号。test_name='test'
是test
数据集。- 文件名实际上在末尾有一个
.jpg
,在labels.csv
文件中没有提到,因此我们有suffix=’.jpg’
。这将把.jpg
添加到文件名的末尾。 tfms
是我们要申请的数据增强的转换。bs
= 64 张图像的批量大小。
py torch 中数据加载器与数据集的概念:-
我们在之前的剧集中遇到的数据集将返回单个图像,而数据加载器将返回一小批图像。我们只能得到下一个小批量。为了将数据加载器转换成迭代器,我们使用了一个标准的 python 函数 iter。那是一个迭代器。要获取下一个迷你批次,请将 iter 传递给 next。它将返回下一批图像和标签。下文对此进行了描述
x,y = next(iter(data.val_dl))
y
上述命令是一个验证集数据加载器,将返回一个图像和标签的小批量。y
标签给出了下面的输出
正如我们所看到的,在这 64 个样品的小批量中有 17 个标签。在上面的get_data(bs)
函数中已经明确提到了bs=64
。要理解这些热编码标签的含义,请查看下面的代码
list(zip(data.classes, y[0]))
data.classes 具有实际的标签名称,而y[0]
给出了特定样本所属的所有标签的名称。如上所示,输出表示第一幅图像具有标签农业、清洁、初级和水。标签的一个热编码表示已经在下面的图像中被表示。标签的一次性编码由 Pytorch 框架在内部处理。
Data Representation
这个标签的热编码表示是实际值。神经网络提取 17 个这样的值(在这种情况下),这些值被称为预测值。我们使用损失函数和梯度下降的概念来最小化实际和预测值之间的误差。
在某些情况下,图像不是那么清晰。在这种情况下,为了掌握图像的所有特征,可以使用 1.5/1.6/1.7 的倍增系数来增加图像的亮度,如下所示。
使用这些行星数据的最大好处是它与 ImageNet 不同。在现实世界中处理数据时,我们没有类似于 ImageNet 数据集的数据。
这里,我们首先将数据大小调整为(64,64)而不是原始大小(256,256)。我们不会在狗与猫分类的情况下开始这么小,因为预训练的 resnet 网络开始时几乎完美,所以如果我们将所有东西的大小调整为(64,64)并重新训练权重,它将破坏先前预训练为好的权重。大多数 ImageNet 模型是在(224,224)或(299,299)之上训练的。我们开始这么小的主要原因是 ImageNet 图像与这个星球竞赛数据集不相似。已经在 ImageNet 数据集上训练的 Resnet 网络的主要收获是可以检测边缘、拐角、纹理和重复图案的初始层。
它是这样工作的
获取所需大小的数据,即(64,64)。
sz=64
data = get_data(sz)
data = data.resize(int(sz*1.3), '/tmp')
4。 设置神经网络,寻找最佳学习率
from planet import f2metrics=[f2]
f_model = resnet34learn = ConvLearner.pretrained(f_model, data, metrics=metrics)
f2 指标将在这篇博文的后面讨论。此外,在这个模型中,由于没有提到precompute=True
,因此默认情况下它采用precompute=False
。要了解这一点,点击shift+Tab
,它将显示所有参数及其默认值。在这个时间点当precompute=False
,
- 我们的数据扩充是在的**。**
- 倒数第二层之前的所有层都被冻结。
- 在倒数第二层之后,我们将额外完全连接的 层附加到最后,然后我们就有了最终输出。
现在,让我们来看看最好的学习率发现者。
lrf=learn.lr_find()
learn.sched.plot()
正如我们在损失 对学习率的图表中看到的,最佳学习率可以接近 0.2。怎么会?
- 如前所述,y 轴上的损失在 0.2 处最小,对应的学习率在 x 轴上是 10⁰ =1。
- 正如前面讨论的,我们可以在损失最小的点之前获得最佳学习率,因此是 0.2。
现在使用最好的学习率0.2
,让我们训练我们的模型,如下面的代码所示。
5。 从几个时期的预计算激活中训练最后一层。
lr = 0.2
learn.fit(lr, 3, cycle_len=1, cycle_mult=2)
Cycle_len
和Cycle_mult
的概念在第 2.1 集中已经详细讨论过了。到目前为止,我们只训练我们最后连接的额外的完整层。
训练所有的层直到最后,
- 为层的子集设置不同的学习率。
- 解冻冻结层。
- 开始训练所有层。
要学习一组不同的特征或告诉学习者需要改变卷积滤波器,只需**unfreeze**
所有层。冻结的层是其权重没有被训练或更新的层。要了解解冻和冻结图层的工作原理,请查看第 2.1 集。由于行星竞赛中的图像不同于 ImageNet 数据集:-
- 所以学习率高。
- 而且前面几层比后面几层需要学的更多。
6。解冻层并训练所有层。
lrs = np.array([lr/9,lr/3,lr])
learn.unfreeze()
learn.fit(lrs, 3, cycle_len=1, cycle_mult=2)
下面我们可以看到,在每一个周期后,损失大幅下降。
learn.save(f’{sz}’)
learn.sched.plot_loss()
7。 改进我们的模型,防止过度拟合:-
从现在开始,我们将把图像尺寸增加到(128,128)并进一步增加到(256,256)以便
- 减少过度拟合。
- 减小 trn_loss 和 val_loss 之间的间隙。
- 训练神经网络的早期层(通过解冻它们),因为预训练的权重来自 ImageNet 模型,该模型与行星竞争数据集没有太多相似之处。
sz=128
learn.set_data(get_data(sz))
learn.freeze()
learn.fit(lr, 3, cycle_len=1, cycle_mult=2)
learn.unfreeze()
learn.fit(lrs, 3, cycle_len=1, cycle_mult=2)
learn.save(f'{sz}')
sz=256
learn.set_data(get_data(sz))
learn.freeze()
learn.fit(lr, 3, cycle_len=1, cycle_mult=2)
learn.unfreeze()
learn.fit(lrs, 3, cycle_len=1, cycle_mult=2)
learn.save(f'{sz}')
最后我们做一个 TTA( 测试时间扩增 )来得到。
multi_preds, y = learn.TTA()
preds = np.mean(multi_preds, 0)
f2(preds,y)
Accuracy
瞧,我们得到一个 ***93.6%***
的准确度,这对于多标签分类来说太好了。
如果你陪我到这一步,给自己一个击掌。
??????????有问题的,请举手??????????
??? ???
Qs 1:-下面的命令中 **data.resize()**
是做什么的?
data = data.resize(int(sz*1.3), '/tmp')
如果初始输入是(1000,1000 ),那么读取该 jpeg 并将其大小调整为(64,64)比训练 convnet 每批所花费的时间要多。resize 的作用是,它表示不会使用任何大于 sz*1.3 的图像。所以仔细检查并创建新的size=sz*1.3
的 jpegs。这一步不是必需的,但它加快了进程。
问题 2:-为什么行星卫星图像竞赛中这里使用的度量是 **f2**
而不是精度?
有很多方法可以将我们在狗和猫的分类中看到的混淆矩阵转化为准确度分数。那些是
- 精确
- 回忆
- f-β
根据这个竞赛标准,准确性是根据 f-Beta 分数来判断的。在 f-Beta 评分中,Beta 表示你对假阴性和假阳性的权重是多少?在 f-β中,β值是 2。当我们建立神经网络时,我们将它作为一个metrics
来传递。查看下面的代码。
from planet import f2metrics=[f2]
f_model = resnet34learn = ConvLearner.pretrained(f_model, data, metrics=metrics)
Qs 3:-多标签和单标签分类的区别?
单标签分类问题的输出激活函数是 Softmax。但是如果我们必须预测特定图像中的多个标签,如下文最后一列所示
那么 Softmax 是一个可怕的选择,因为它有强烈选择特定标签的倾向。对于多标签分类问题,我们使用的激活函数是 **Sigmoid。**fastai 库如果观察到多标签分类问题,会自动切换到 Sigmoid。Sigmoid 公式是 ex/(1+ex)。Sigmoid 图看起来像:-
基本上,Sigmoid 图表示的是,如果激活小于 0.5,则 Sigmoid 将返回低概率值,如果激活大于 0.5,则 Sigmoid 将返回高概率值。多件事怎么可能有高概率。
问题 4:-蛋鸡训练如何进行?
这些层次非常重要,但其中预先训练的权重并不重要。所以最想训练的是后面几层。早期的层已经接近我们想要的,即检测边缘和角落。
因此,在狗与猫的情况下,当我们从预训练的模型创建模型时,它会返回一个模型,其中所有卷积层都被冻结,一些随机设置的完全连接层被添加到末端并被解冻。所以当我们说 fit 的时候,首先,它在最后训练随机初始化的全连接层。如果某样东西真的很接近 Imagenet 数据集,那往往就是我们需要的。因为早期的层已经善于发现边缘、梯度、重复图案等。然后,当我们解冻时,我们将早期层的学习速率设置得非常低,因为我们不想对它们进行太多的更改。
而在卫星数据中,早期的层似乎比后期的层更好,但我们仍然需要对它们进行相当大的改变,这就是为什么我们的学习速率比最终的学习速率小 9 倍,而不是像前一种情况那样小 1000 倍。
问题 5:-为什么我们不能直接从解冻所有层开始?
我们可以做到,但是需要更多的时间。首先,通过解冻最终层并保持初始层冻结,我们正在训练最终层学习更重要的功能。卷积层包含预先训练的权重,因此它们不是随机的。对于那些接近 ImageNet 的东西,它们真的很好,但是如果它们不接近 ImageNet,它们总比没有好。我们所有的 FC 层都是完全随机的,因此你总是想通过先训练它们来使完全连接的层比随机层更好,因为否则如果你直接去解冻,那么我们将在早期层权重仍然随机时摆弄早期层权重。
需要记住的几点是
- 训练就是更新核值的权重和 FC 层的权重。根据权重和先前层激活输出来计算激活。
**learn.summary()**
命令用来可视化模型。
如果你喜欢,那么ABC*(永远被击节 )。 👏 👏👏👏👏😃😃😃😃😃😃😃😃😃👏 👏👏👏👏👏* )
如果您有任何问题,请随时在 fast.ai 论坛或 Twitter 上联系: @ashiskumarpanda
附:随着我继续学习其他课程,这篇博文将会更新和改进。如果你对源代码感兴趣,可以在这里查看。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分:- 狗和猫的图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- 对 IMDB 电影数据集的 NLP 情感分析
- 电影推荐系统基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- 检测图像中最大物体的 ML 模型 Part-2
编辑 1:-TFW·杰瑞米·霍华德同意你的帖子。💖💖 🙌🙌🙌 💖💖。
“使用神经网络进行时间序列分析”
使用神经网络建立一个先进的时间序列预测模型。
欢迎来到第四集 Fastdotai ,在这里我们将处理结构化和时间序列数据。在我们开始之前,我想感谢 【杰瑞米·霍华德】 和 雷切尔·托马斯 为民主化人工智能所做的努力。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分:- 狗和猫的图像分类
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 利用神经网络进行时间序列分析
- 对 IMDB 电影数据集的 NLP 情感分析
- 电影推荐系统的基础
- 从无到有的协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- ML 模型检测图像中最大的物体 Part-1
- 检测图像中最大物体的 ML 模型 Part-2
我们将讨论的笔记本是郭/伯克哈恩的[ 分类变量的实体嵌入 ]中详述的罗斯曼卡格尔竞赛第三名结果的实现。代码已经在 kaggle 内核的帮助下执行。所以会有一些额外的东西被写出来,这样代码就可以在 kaggle 上流畅地运行。如果您在任何其他云 GPU 平台上运行代码,这些额外的代码行可能是不必要的。我会在这篇博文的最后附上 kaggle 内核链接。
正如上面的代码片段所述,我们将拥有更多的数据集,这将有助于我们丰富特性,从而帮助我们获得更好的准确性。构成特征空间的这些数据集如下所述。
特征空间涉及:
- train:包含每天的商店信息,跟踪销售、顾客、当天是否是假日等信息。
- 商店:商店列表。商店的一般信息,包括竞争情况等。
- store_states:商店到所在德国州的映射。
- googletrend:某些 google 关键字随时间的变化趋势,用户发现这些关键字与给定的数据有很好的相关性。
- 天气:每个州的天气情况。
- 测试:与培训表相同,没有销售和客户。
让我们将这些数据文件名保存在如下所示的特定列表中:-
我们可以使用head()
快速浏览每个表格的内容:
数据清理/特征工程:-
在下面的代码片段中,我们将进行数据清理:-
在继续之前,让我们看一下googletrends
数据,因为接下来我们将对此进行特性工程。
让我们看一看特征工程后的googletrend
。检查新列Date ,State
和对State
列所做的更改。
以下步骤对特征工程非常重要:-
正如我们在下面的快照中所看到的,我们已经向googletrends
添加了更多的列,这些列是使用上面的命令从Date
列形成的。
在上面的代码片段中,joined
是我们的训练数据,joined_test
是我们的测试数据。众所周知,一幅画胜过 1000 句话。让我描述一下我们如何通过合并多个表得到训练数据— joined
和测试数据— joined_test
的流程图。以下快照与joined
和joined_test
相同。
删除额外变量前后的比较
正如我们在下面的代码中看到的,我们将填充训练数据— joined
和测试数据— joined_test
中出现的缺失值。
输出如下所示:-
在下面的代码中,我们替换了离群值并做了更多的功能工程。
促销日期的相同功能工程。
让我们关注一下持续时间:-
这篇文章你已经看了一半了。干得好。继续走。从这里开始会很有趣。
现在,让我们关注分类变量和连续变量。
Categorical vs Continuous
决定哪个变量是分类变量还是连续变量?
在上面的代码中,我们已经分离了将被视为连续和分类的列。但是怎么做呢?这个需要详细解释。
因此,根据列/变量的基数可以说该列/变量是连续的或分类的。基数被定义为一个类别中级别的数量。例如,基数表示一周的天数=7
- 无论哪个变量已经以分类形式出现在数据中,都将是模型中的分类变量。
- 对于连续变量,我们必须检查它们的基数。如果它们的基数(不同级别的数量)太高,它将是连续的,否则它将被转换成分类变量。
- 连续变量应该具有连续平滑的函数。例如,年份虽然是一个连续变量,但没有很多不同的级别,因此最好将其作为一个分类变量。在这种情况下,连续的是类型为
floating point
或数据类型为int
的那些。 - 我们可以绑定一个连续变量,然后将其转换为分类变量。有时候宁滨会很有帮助。
哪些变量是分类变量,哪些是连续变量,这是我们必须做出的建模决策之一。
在这个时间点上,我们的数据看起来像这样。它有一些连续的,一些布尔的,一些分类的等等。
在上面的代码中,Fastai 有一个名为 process _ data frame(proc _ df)的函数。
- 它从数据帧**‘joined _ samp’中取出因变量,即‘Sales’**,并将其存储在单独的变量
**y**
中。 - 除了因变量’ Sales '之外的其余数据帧保存在
**df**
中。 - nas :返回它创建了哪个 nas 的字典,以及相关的中位数。
- 映射器:一个数据帧映射器,存储相应连续变量的平均值和标准偏差,然后用于测试期间的缩放。
- 它还处理缺失值,因此分类变量中的缺失值变为 0,其他类别变为 1,2,3,4,依此类推。
- 对于连续变量,它用中值替换缺失值,并创建一个新的布尔列,表示是否缺失。
现在输出 df 的所有变量都是连续的。分类列由等价的连续值表示。查看“年份”和“产品组合”栏在此之前和之后的变化。
这样,所有的列都是连续的。
- 连续的列保持不变。它们被改成了
float32
,因为这是 pytorch 接受的标准数字数据类型。 - 分类列被转换成等效的连续类型。
验证数据集
根据 Kaggle,我们在 Rossman 数据中的问题陈述是预测接下来两周的销售。由于它是一个时间序列数据,我们的验证数据集不是随机的。相反,它是我们实际应用中的最新数据。
深度学习从这里开始。
-
根据罗斯曼数据竞赛的 Kaggle 规则,我们将在 RMSPE(均方根百分比误差)的基础上进行评估。
-
RMSPE 将是度量而不是准确性,因此我们在下面的代码中对此进行了公式化:-
-
让我们创建我们的模型数据对象:-
-
早些时候是
ImageClassifierData
,因为那时我们正在处理图像。现在在这种情况下,当我们处理纵列表格数据时,它是ColumnarModelData
。 -
我们有了
from_data_frame
,而不是from_Paths
。 -
PATH
—存储模型文件的位置。 -
val_idx
—要放入验证数据集中的行的索引列表。 -
df
—数据框。 -
y1
—由因变量组成。 -
cat_flds
—将所有列视为分类变量,因为此时所有列都转换为数值。 -
bs
—批量大小。
对分类变量应用嵌入:
上面的代码所做的是,它遍历每个分类变量(cat_vars)
并打印出它所拥有的不同级别或类别的数量。上面代码中带有类别的+1
是为缺失值保留的。基本上,它打印每个变量的基数和变量名。
我们用每个变量的基数来决定它的嵌入矩阵应该有多大。
在上面的代码中,我们遵循一条经验法则,即嵌入大小是cardinality size//2
,但不大于 50。
嵌入矩阵如何工作?
- 当我们创建这些矩阵时,它有随机数。因此,我们将它们放入神经网络,并不断更新它们的值,以减少损失函数。这些嵌入矩阵可以与一组权重相比较,这些权重以减少损失的方式自我更新。这样,我们从这些权重的随机值到有意义的更新值。
- 客观地说,嵌入矩阵的值可以在 0 和该类别的最大层数之间。然后我们可以索引那个矩阵,找到一个特定的行,我们把它附加到所有的连续变量上,之后的一切都和之前一样。
嵌入矩阵的图示:-
将神经网络应用于连续变量:-
上图显示了神经网络如何处理连续变量。查看矩阵乘法如何工作并产生相应的输出。这是一个 2 隐层神经网络。假设有 20 列作为输入,并且我们已经设计了神经网络,使得第一隐藏层具有 100 个隐藏单元,第二隐藏层具有 50 个隐藏单元。因此,我们的输入[1,20]乘以维度为[20,100]的权重矩阵将得到[1,100]。然后,我们将 ReLU 应用于这个[1,100]维度值,这导致[1,100]的激活。然后,这个[1,100]维激活乘以[100,50]维的权重,这导致具有[1,50]维的激活。这个[1,50]激活然后乘以维度[50,1]的权重,这导致 1 输出。我们在最后一层应用 Softmax 来得到最终的输出。
- 注意:- 不要将 ReLU 放在最后一层,因为 Softmax 需要负值来创建更低的概率。ReLU 函数去掉了负值。在罗斯曼销售数据的情况下,我们试图预测销售,因此我们最终不需要 Softmax。
让我们创建我们的学习者。这就是我们如何建立我们的神经网络。
best lr = 1e-3
get_learner()
中使用的参数。
emb_s
—对每个分类变量使用此嵌入矩阵。len(df.columns)-len(cat_vars)
—表示连续变量的数量。0.04
—一开始就辍学。1
—最后一个线性层的输出。[1000,500]
—第一和第二线性层的激活次数。[0.001,0.01]
—用于第一和第二线性层的漏失。y_range=y_range
—前面已经介绍过了。tmp_name=f”{PATH_WRITE}tmp”
—(可选)仅在 kaggle 内核中使用。models_name=f”{PATH_WRITE}models”
—(可选)仅在 kaggle 内核中使用。
???有什么问题吗???
!!! Question Time !!!
Qs 1 :-星期嵌入中的四个值表示什么?
最初,我们从一些随机的四个值开始。它的功能与砝码相同。所以我们在最小化损失的同时更新这些值。当损失被最小化时,我们将以一些更新的四个值结束。此时,我们会发现这些特定的参数是人类可以解释的,而且非常有趣。
Qs 2 :-除了随机初始化,还有什么方法初始化嵌入矩阵?
如果罗斯曼有一个预先训练好的奶酪销售嵌入矩阵,我们可以用它来预测酒的销售。instacart 和 pinterest 正在使用这种技术。他们有产品和商店的嵌入矩阵,在组织内共享,这样人们就不必培训新的产品和商店。
Qs 3 :-使用嵌入矩阵比一键编码有什么优势?
以周日的一个热门编码向量为例:-
[1 0 0 0 0 0 0]
Sunday 的独热编码表示法的问题是它表示一个浮点数。它只代表一件事。更多的是线性行为。
有了嵌入,星期天就是一个四维空间的概念。更新这些值后我们得到的是丰富的语义概念。例如,如果结果是周末与工作日相比具有不同的行为,那么我们看到在这个嵌入矩阵中周六和周日的某个值会更高。通过拥有这些高维向量,我们给神经网络一个机会来学习这些潜在的丰富表示。正是这种丰富的表现让它能够学习如此有趣的关系。这种表示嵌入的思想被称为“分布式表示”。神经网络具有有时难以解释的高维表示。矩阵中的这些数字不一定只有一个意思。它可以随着上下文改变它的意思,因为它经历了丰富的非线性函数。
虽然一个热门的编码在一周的几天中有更多的维度,但它并不是有意义的高维。嵌入矩阵的使用有助于减小尺寸,并更恰当地表示变量。
问题 3:-嵌入适合某种类型的变量吗?
当我们遇到分类变量时,我们使用嵌入的概念。但是对于高基数的变量就不行了。
问题 4:add_datepart()
如何影响季节性?
fastai 库有一个add_datepart()
函数,它接受一个数据帧及其表示日期的列。它可以选择删除日期列,而不是返回许多表示该日期有用信息的列。例如用dayOfWeek
、 MonthOfYear
、 Year
、Month
、 Week
、 Day
等代替Date
等。所以daysOFWeek
现在可以用一个【8,4】嵌入矩阵来表示。从概念上讲,这允许模型挑选一些有趣的特征和模式。
- 假设,有一个 7 天周期的东西,它在周一上涨,周四下跌,只有在柏林,它可以完全提取该模式,因为它有所有需要的信息。这是处理时间序列模型的好方法。我们只需要确保我们的时间序列模型中的周期指标或周期性应该以列的形式存在。
使用以下命令培养学习者并获得最佳的学习速度。
正如我们所看到的,最好的学习率在 10^-3.的某个地方所以我们将继续用 lr=10^-3.训练我们的神经网络
m.fit(lr, 3, metrics=[exp_rmspe])
[ 0\. 0.02479 0.02205 0.19309]
[ 1\. 0.02044 0.01751 0.18301]
[ 2\. 0.01598 0.01571 0.17248]m.fit(lr, 5, metrics=[exp_rmspe], cycle_len=1)
[ 0\. 0.01258 0.01278 0.16 ]
[ 1\. 0.01147 0.01214 0.15758]
[ 2\. 0.01157 0.01157 0.15585]
[ 3\. 0.00984 0.01124 0.15251]
[ 4\. 0.00946 0.01094 0.15197]m.fit(lr, 2, metrics=[exp_rmspe], cycle_len=4)
[ 0\. 0.01179 0.01242 0.15512]
[ 1\. 0.00921 0.01098 0.15003]
[ 2\. 0.00771 0.01031 0.14431]
[ 3\. 0.00632 0.01016 0.14358]
[ 4\. 0.01003 0.01305 0.16574]
[ 5\. 0.00827 0.01087 0.14937]
[ 6\. 0.00628 0.01025 0.14506]
[ 7\. 0.0053 0.01 0.14449]
注意:- 从梯度推进切换到深度学习是好的,因为它需要更少的特征工程,并且它是需要更少维护的更简单的模型。这是使用深度学习方法的最大好处之一。使用这种方法,我们可以得到很好的结果,但工作量要少得多。
总结:-
第一步:- 列出分类变量名和连续变量名,放入数据框。
步骤 2:- 创建一个我们希望包含在验证集中的 row_indexes 列表。
步骤 3:- 创建柱状模型数据对象。
步骤 4:- 创建一个我们希望嵌入矩阵有多大的列表。
步骤 5:- 调用 get_learner 并使用确切的参数开始。
第六步:- 调用 m.fit()
!!!恭喜你在 fast.ai 上又学完了一课。干得好。!!!
如果你喜欢,那么ABC*(*永远被击节 。👏 👏👏👏👏😃😃😃😃😃😃😃😃😃👏 👏👏👏👏👏 )
如果您有任何问题,请随时在 fast.ai 论坛或 Twitter 上联系: @ashiskumarpanda
注:随着我继续学习其他课程,这篇博文将会更新和改进。更多有趣的东西,可以随时查看我的Github账号。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- IMDB 电影数据集上的 NLP-情感分析
- 电影推荐系统基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- 检测图像中最大物体的 ML 模型 Part-2
编辑 1:-TFW·杰瑞米·霍华德同意你的帖子。💖💖 🙌🙌🙌 💖💖。
“电影推荐系统”
欢迎来到第五集 Fastdotai ,在这里我们将处理电影推荐系统。在我们开始之前,我想感谢 【杰瑞米·霍华德】 和 雷切尔·托马斯 为民主化人工智能所做的努力。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- IMDB 电影数据集上的自然语言处理情感分析
- 电影推荐系统的基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- ML 模型检测图像中最大的物体 Part-2
拿一份爆米花,我们开始吧。
首先,让我们导入所有需要的包。
%reload_ext autoreload
%autoreload 2
%matplotlib inlinefrom fastai.learner import *
from fastai.column_data import *
设置路径的位置
- 输入数据被存储。
- 将存储临时文件。(可选-在 kaggle 内核中使用)
- 模型重量将被存储。(可选-在 kaggle 内核中使用)
path='../input/'
tmp_path='/kaggle/working/tmp/'
models_path='/kaggle/working/models/'
- 数据的读取。
ratings = pd.read_csv(path+'ratings.csv')
ratings.head()
# This contains the userid , the movie that the userid watched , the time that movie has been watched , the ratings that has provided by the user .
movies = pd.read_csv(path+'movies.csv')
movies.head()
# This table is just for information purpose and not intended for # modelling purpose
创建热门电影和用户 ID 的交叉表:-
g=ratings.groupby('userId')['rating'].count()
topUsers=g.sort_values(ascending=False)[:15]
# Users who have given most number of ratings to the movies are # considered as top Users.g=ratings.groupby('movieId')['rating'].count()
topMovies=g.sort_values(ascending=False)[:15]
# Movies that have got most number of ratings are topMovies .top_r = ratings.join(topUsers, rsuffix='_r', how='inner', on='userId')
top_r = top_r.join(topMovies, rsuffix='_r', how='inner', on='movieId')
pd.crosstab(top_r.userId, top_r.movieId, top_r.rating, aggfunc=np.sum)
因此,我们将通过三种方式来处理电影推荐。
- 矩阵分解。
- 从无到有的协同过滤。
- 神经网络方法。
首先,我们将深入研究矩阵分解方法:-
- 矩阵分解:-
左侧方框中的表格显示了实际评级。这是我们的实际数据。
让我详细讨论一下右表是如何组成的,左表和右表是什么关系。
- 制作预测收视率表(右表)
- 右边的表以用户 id (users)为行,以电影 id (movies)为列。电影 id 和用户 id 用嵌入矩阵来描述。还记得我们在上一篇博文中讨论的嵌入矩阵吗?正如我们所知,嵌入矩阵是由嵌入向量组成的,在开始时,它们只是随机数。在上图中用紫色表示。
- 例如,用户 Id 14 由四个随机数表示。类似地,电影 Id 27 由 4 个随机数表示。这些数字乘积的总和产生了预测的等级。每个嵌入向量在开始时被随机初始化。换句话说,每个预测的评级是两个嵌入向量的矩阵乘积。
- 我们的目标函数是最小化预测评级和实际评级之间的 RMSE。如果我们看到下面的公式
- SUMXMY2 函数计算数组中相应项之间的差的平方和,并返回结果的总和。为了分解公式,它取预测值和实际值之间的 MSE(均方误差),然后求和,得出一个数字。然后将该数字除以评级数量的计数。然后我们取这个数的平方根。在上图中,这个数字用蓝色表示。这就是我们要最小化的目标函数。
???有什么问题吗???
这些嵌入向量是什么意思?
- 最初这些都是随机的,但是经过训练后,就开始有意义了。几个时期后,检查这些额定值。这些值会不断自我更新。因此,在几个时期之后,这些预测的额定值将接近实际额定值。据此,这些嵌入向量会自我调整。例如对于电影 Id 27(指环王):-由如下所示的 4 个数字组成的嵌入向量
- 假设每个单元格表示(%科幻,%基于 CGI,%对话驱动,%现代,%喜剧)。它表示电影的类型。
- 类似地,在用户 Id 嵌入向量的情况下,每个数字表示用户 Id 14 有多喜欢科幻电影、现代 CGI 电影、对话驱动电影等等。
- 我们将在后面讨论偏见。
注意:-这里我们没有任何非线性激活函数或任何类型的隐藏层。因此,它会被认为是浅薄学习的一个例子。
Qs:-协同过滤与概率矩阵分解有何相同之处?
这里我们得到的预测结果是两个不同向量的叉积。问题是,我们没有关于每个用户或电影的适当信息,所以我们假设这是理解系统的合理方式,并使用 SGD 来找到将工作的优化数字。
Qs:-如何决定这些嵌入向量的长度?
我们应该选择一个嵌入维数,它足以代表手头问题的真正复杂性。同时,它不应该太大,否则会有太多的参数,运行时间太长,或者即使进行正则化也会产生过度拟合的结果。
Qs:-负数在嵌入向量中表示什么?
电影 id 为负数表示特定电影不属于该特定类型。在用户 ID 为负数的情况下,表示特定用户不喜欢该特定类型的电影。
问:-当我们有一部新电影或新用户时会发生什么?
如果我们使用网飞作为新用户,它总是问我们喜欢什么电影。并且它重新训练它的模型以便给出好的推荐。
- 协同过滤的时间到了:-
协同过滤推荐系统方法是用户和项目的概念。假设有一个用户 Id -14 喜欢电影 Id- 24,那么协同过滤方法说,哪个其他用户喜欢那个电影- 24,那个用户 ID-14 也喜欢。然后,它浏览与用户 Id-14 有相同偏好的其他用户的电影列表,并将这些电影推荐给用户 Id-14。
所以它有两个部分:-
- 用户 Id 和电影 Id
- 评级值(因变量)
val_idxs = get_cv_idxs(len(ratings))
wd=2e-4 # L2 Regularization , helps in preventing overfitting
n_factors = 50 # Embedding dimensionalitiescf = CollabFilterDataset.from_csv(path, 'ratings.csv', 'userId', 'movieId', 'rating')
# 1\. path - where the file is stored.
# 2\. 'ratings.csv' - The excel file which contains the data to be read.
# 3\. 'userId' - What should be the rows .
# 4\. 'movieId' - What should be the columns .
# 5\. 'rating' - Values for predictions. learn = cf.get_learner(n_factors, val_idxs, 64, opt_fn=optim.Adam, tmp_name=tmp_path, models_name=models_path)# Finally, we train our model
learn.fit(1e-2, 2, wds=wd, cycle_len=1, cycle_mult=2)
math.sqrt(0.766)
# 0.8752142594816426
# Let's compare to some benchmarks. Here's [some benchmarks](https://www.librec.net/release/v1.3/example.html) on the same # dataset for the popular Librec system for collaborative filtering. They # show best results based on [RMSE](http://www.statisticshowto.com/rmse/) of 0.91\. We'll need to take the square # root of our loss, since we use plain MSE.preds = learn.predict()
我们来分析一下结果:
movie_names = movies.set_index('movieId')['title'].to_dict()
# Contains movieid and their title in form of dictionaries
g=ratings.groupby('movieId')['rating'].count()
# Which movie got how many ratings
topMovies=g.sort_values(ascending=False).index.values[:3000]
# Take the movieid of 3000 movies which has got most number of ratings.
topMovieIdx = np.array([cf.item2idx[o] for o in topMovies])
# Replace the movieid with contigious ids.
# Check out our model below. It has 50 embedding vectors for each of movies and users . And a bias for each movie and each user.
# First, we'll look at the movie bias term. Here, our input is the movie # id (a single id), and the output is the movie bias (a single float). movie_bias = to_np(m.ib(V(topMovieIdx)))
- 代码
to_np(m.ib(V(topMovieIdx)))
将在遍历嵌入层中的每个 MovieIds 并返回其偏差后给出一个变量。 m.ib
指项目/电影的嵌入层,即偏置层。我们知道有 9066 部电影和与之相关的偏见。m.ib
将返回该图层的值。- 模型/层需要变量来跟踪梯度,因此有了
V(…)
。 - 使用
to_np()
将张量转换成数值。 - 为了推理的目的,将模型从 GPU 移动到 CPU,使用
m.cpu()
。并使用m.cuda()
将其移动到 GPU。
movie_ratings = [(b[0], movie_names[i]) for i,b in zip(topMovies,movie_bias)]
# A list comprehension where movie_bias is stored in b and topMovies in # movie_names. Check out the below output which returns a list of tuples # having movies and its bias .
根据电影的倾向性对电影进行排序(即使用 lambda 函数对每个元组的第 0 个元素进行排序)。在检查中我们发现,偏见表明电影的质量。好电影有正面偏见,烂片有负面偏见。这就是如何解释偏见术语。
sorted(movie_ratings, key=lambda o: o[0], reverse=True)[:15]
# Sort the movies by its bias (i.e the 0th element of each tuple by using # lambda function). Reverse=True means in descending order of Bias # values.
让我们来解释嵌入向量:-
movie_emb = to_np(m.i(V(topMovieIdx)))
# m.i(...) for item embeddings.movie_emb.shape
# Because it's hard to interpret 50 embeddings, we use [PCA](https://plot.ly/ipython-notebooks/principal-component-analysis/) to simplify # them down to just 3 vectors.from sklearn.decomposition import PCA
pca = PCA(n_components=3)
movie_pca = pca.fit(movie_emb.T).components_
movie_pca.shape
fac0 = movie_pca[0]
movie_comp = [(f, movie_names[i]) for f,i in zip(fac0, topMovies)]
# Here's the 1st component. It seems to be 'easy watching' vs 'serious'.# Its upto us to decide what does these Embeddings mean . Check the output belowsorted(movie_comp, key=itemgetter(0), reverse=True)[:10]
# Lets interpret the 2nd component
fac1 = movie_pca[1]
movie_comp = [(f, movie_names[i]) for f,i in zip(fac1, topMovies)]
# It seems to be 'CGI' vs 'dialog driven'.
sorted(movie_comp, key=itemgetter(0), reverse=True)[:10]
这就是我们如何分析一个电影推荐系统。评价标准是最小化 RMSE。早先的误差基准是 0.91 。使用 fastai,我们得到 0.87。
因此,这种模式表现良好。
在下一部分,我们将从头开始讨论协同过滤。
如果你喜欢,那么ABC*(永远被击节 。 👏 👏👏👏👏😃😃😃😃😃😃😃😃😃👏 👏👏👏👏👏* )
如果您有任何问题,请随时联系 fast.ai 论坛或 Twitter:@ ashiskumarpanda
注:随着我继续学习其他课程,这篇博文将会更新和改进。更多有趣的东西,可以随时查看我的Github账号。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- 对 IMDB 电影数据集的 NLP 情感分析
- 电影推荐系统的基础
- 从无到有的协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- 检测图像中最大物体的 ML 模型 Part-2
编辑 1:-TFW·杰瑞米·霍华德同意你的帖子。💖💖 🙌🙌🙌 💖💖。
“从零开始的协作过滤”
从头开始构建电影推荐的协同过滤
欢迎来到第五集 Fastdotai 的第二部分,我们将从零开始讲述协同过滤——一种广泛应用于推荐系统的技术。在我们开始之前,我想感谢 【杰瑞米·霍华德】 和 雷切尔·托马斯 为民主化人工智能所做的努力。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- IMDB 电影数据集上的自然语言处理情感分析
- 电影推荐系统的基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- 检测图像中最大物体的 ML 模型 Part-2
网飞背后的原因和寒意。
首先,让我们导入所有需要的包。
%reload_ext autoreload
%autoreload 2
%matplotlib inlinefrom fastai.learner import *
from fastai.column_data import *
设置路径的位置
- 输入数据被存储。
- 将存储临时文件。(可选-在 kaggle 内核中使用)
- 模型重量将被存储。(可选-在 kaggle 内核中使用)
path='../input/'
tmp_path='/kaggle/working/tmp/'
models_path='/kaggle/working/models/'
- 数据的读取。
ratings = pd.read_csv(path+'ratings.csv')
ratings.head()
# This contains the userid , the movie that the userid watched , the time that movie has been watched , the ratings that has provided by the user .
movies = pd.read_csv(path+'movies.csv')
movies.head()
# This table is just for information purpose and not intended for # modelling purpose
u_uniq = ratings.userId.unique()
user2idx = {o:i for i,o in enumerate(u_uniq)}
# Take every unique user id and map it to a contiguous user .
ratings.userId = ratings.userId.apply(lambda x: user2idx[x])
# Replace that userid with contiguous number.# Similarly, we do it for the movies.
m_uniq = ratings.movieId.unique()
movie2idx = {o:i for i,o in enumerate(m_uniq)}
ratings.movieId = ratings.movieId.apply(lambda x: movie2idx[x])
将 movieId 和 userId 转换成连续的整数有助于我们决定嵌入矩阵。这些 userId 和 movieID 的值在开始时不连续。它可能从 100 万开始,并且不会是连续的。因此,如果我们使用这些值来决定我们的嵌入矩阵,那么嵌入矩阵的大小将会太大,这可能会导致缓慢的处理或过拟合。
class EmbeddingDot(nn.Module):
def __init__(self, n_users, n_movies):
super().__init__()
self.u = nn.Embedding(n_users, n_factors)
self.m = nn.Embedding(n_movies, n_factors)
self.u.weight.data.uniform_(0,0.05)
self.m.weight.data.uniform_(0,0.05)
def forward(self, cats, conts):
users,movies = cats[:,0],cats[:,1]
u,m = self.u(users),self.m(movies)
return (u*m).sum(1).view(-1, 1)model = EmbeddingDot(n_users, n_movies).cuda() # Class Instantiation
上述代码中涉及到 OOPs 的概念。所以我来详细解释一下。
self
是一个参考变量,当对象(即模型)被创建时,存储该对象。def __init__(self, n_users, n_movies):
是一个神奇的功能。每当为该类创建对象时,都会自动调用它。这种类型的函数被称为构造函数。model = EmbeddingDot(n_users, n_movies).cuda()
。这里创建了对象。随着它的创建,构造函数被自动调用。- 但是物体是什么?一个对象(即模型)是一个具有一些属性和行为的实体。
- 这些行为是嵌入的形状和值,如下所示。
self.u = nn.Embedding(n_users, n_factors) # User Embeddings
self.m = nn.Embedding(n_movies, n_factors) # Movie Embeddings
self.u.weight.data.uniform_(0,0.05) # Values for User Embeddings
self.m.weight.data.uniform_(0,0.05) # Values for Movie Embeddings
- 为了获得这些嵌入的值,我们使用了从
nn.Module
继承而来的nn.Embedding
,使用了 OOP 的Inheritance
概念,使用了下面这行代码:-super().__init__()
。 self.u
设置为嵌入类的实例。它有一个包含实际嵌入矩阵的.weight
属性。嵌入矩阵是一个变量。变量和张量一样,它会自动微分。- 要访问张量使用,
self.u.weight.data
属性。 self.u.weight.data.uniform_
:-末尾的下划线符号表示它是一个就地操作。self.u.weight.data.uniform_
表示这个张量的适当大小的均匀随机数,不返回它,而是在适当的位置填充矩阵。- 当我们稍后进行拟合时,前进功能开始起作用。但是,让我们来详细了解一下当调用 forward 函数时会发生什么。
def forward(self, cats, conts):
users,movies = cats[:,0],cats[:,1]
u,m = self.u(users),self.m(movies)
return (u*m).sum(1).view(-1, 1)
users,movies = cats[:,0],cats[:,1]
:-抓取用户和电影的迷你批次。u,m = self.u(users),self.m(movies)
:-对于小批量的用户和电影,使用self.u(users),self.m(movies)
查找用户和电影的嵌入矩阵。- 在得到用户和电影的嵌入后,我们将这两者进行叉积,得到一个数字,这就是预测的收视率。
x = ratings.drop(['rating', 'timestamp'],axis=1)
# The x contain movies and users from the dataframe. Independent # variables.y = ratings['rating'].astype(np.float32)
# The y contains the dependent Variable i.e the ratings.data = ColumnarModelData.from_data_frame(path, val_idxs, x, y, ['userId', 'movieId'], 64)1# path :- path of the file.
2# val_idxs :- Validation data
3# x, y :- Described above as independent and dependent variable.
4# ['userId', 'movieId'] :- List of categorical variables.
5# 64 :- batch size.wd=1e-5 # Regularization parameter
opt = optim.SGD(model.parameters(), 1e-1, weight_decay=wd, momentum=0.9)
# Optimizer to be used to update the weights or model.parameters().
# model.parameters() is derived from nn.Module which gives list of all # the weights that are needed to be updated and hence passed to optimizer # along with learning rate, weight decay and momentum.
为了拟合我们的数据,也就是为了训练,早先我们使用了learner
,它是 fast.ai 的一部分,但是现在我们将使用 PyTorch 功能。当执行下面的fit
命令时,检查 fastai 文件夹中的model.py
文件,以了解 fit 命令的底层。基本上它做的是:-
- 通过调用正向函数
def forward(self, cats, conts):
进行正向传递 - 以及更新嵌入的反向传递,这是 PyTorch 的功能。
fit(model, data, 3, opt, F.mse_loss)
这里我们不会得到 SGDR 的功能,因此手动重置学习率,并检查损失。
set_lrs(opt, 0.01)
fit(model, data, 3, opt, F.mse_loss)
虽然我们的模型表现良好,但由于我们没有正确实施 SGDR,因此我们的损失比以前更高。
如何进一步完善模型??
现在我们将考虑偏见。会有一些用户非常热情,平均来说会给所有的电影更高的评价。因此,我们将为电影和用户添加一个常量。这个常数被称为偏差。
min_rating,max_rating = ratings.rating.min(),ratings.rating.max()
min_rating,max_ratingdef get_emb(ni,nf):
# Input is #User,#Factors i.e Embedding Dimensionality
e = nn.Embedding(ni, nf) # Creation of Embedding matrix
e.weight.data.uniform_(-0.01,0.01)
# Fill it with randomly initialized values between (-0.01,0.01)
return eclass EmbeddingDotBias(nn.Module):
def __init__(self, n_users, n_movies):
super().__init__()
# Creating an embedding for User (self.u) , Movies (self.m),
# User bias (self.ub), Movie bias (self.mb) by calling get_emb().(self.u, self.m, self.ub, self.mb) = [get_emb(*o) for o in [
(n_users, n_factors), (n_movies, n_factors), (n_users,1), (n_movies,1)
]]
def forward(self, cats, conts):
users,movies = cats[:,0],cats[:,1]
um = (self.u(users)* self.m(movies)).sum(1)
res = um + self.ub(users).squeeze() + self.mb(movies).squeeze()
# Add in user bias and movie bias. Using .squeeze() does a broadcasting. res = F.sigmoid(res) * (max_rating-min_rating) + min_rating
# This is gonna squish the value between 1 and 5 . What it does is if its # a good movie then it will get a really high number else a low number.
# F.sigmoid(res) is gonna squish it between 0 and 1. return res.view(-1, 1)wd=2e-4
model = EmbeddingDotBias(cf.n_users, cf.n_items).cuda()
opt = optim.SGD(model.parameters(), 1e-1, weight_decay=wd, momentum=0.9)
fit(model, data, 3, opt, F.mse_loss)
set_lrs(opt, 1e-2)
fit(model, data, 3, opt, F.mse_loss)
最后,我们达到了 0.8 的损失,这相当不错。
如果你喜欢,那么ABC*(永远被击节 。 👏 👏👏👏👏😃😃😃😃😃😃😃😃😃👏 👏👏👏👏👏* )
如果您有任何问题,请随时联系 fast.ai 论坛或 Twitter:@ ashiskumarpanda
注:随着我继续学习其他课程,这篇博文将会更新和改进。更多有趣的东西,可以随时查看我的Github账号。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分:- 狗与猫的图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- 对 IMDB 电影数据集的 NLP 情感分析
- 电影推荐系统的基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- ML 模型检测图像中最大的物体 Part-1
- ML 模型检测图像中最大的物体 Part-2
编辑 1:-TFW·杰瑞米·霍华德同意你的帖子。💖💖 🙌🙌🙌 💖💖。
“使用神经网络的协同过滤”
利用神经网络构建电影推荐的协同过滤。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分
- 狗 Vs 猫图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- 对 IMDB 电影数据集的 NLP 情感分析
- 电影推荐系统的基础
- 从零开始协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- ML 模型检测图像中最大的物体 Part-1
- ML 模型检测图像中最大的物体 Part-2
欢迎来到第五集 Fastdotai 的第三部分,在这里我们将讨论使用神经网络的协同过滤——一种在推荐系统中广泛使用的技术。在我们开始之前,我想感谢 【杰瑞米·霍华德】 和 雷切尔·托马斯 为民主化人工智能所做的努力。
做好准备,因为表演时间到了。
首先,让我们导入所有需要的包。
%reload_ext autoreload
%autoreload 2
%matplotlib inlinefrom fastai.learner import *
from fastai.column_data import *
设置路径的位置
- 输入数据被存储。
- 将存储临时文件。(可选-在 kaggle 内核中使用)
- 模型重量将被存储。(可选-在 kaggle 内核中使用)
path='../input/'
tmp_path='/kaggle/working/tmp/'
models_path='/kaggle/working/models/'
- 数据的读取。
ratings = pd.read_csv(path+'ratings.csv')
ratings.head()
# This contains the userid , the movie that the userid watched , the time that movie has been watched , the ratings that has provided by the user .
movies = pd.read_csv(path+'movies.csv')
movies.head()
# This table is just for information purpose and not intended for # modelling purpose
u_uniq = ratings.userId.unique()
user2idx = {o:i for i,o in enumerate(u_uniq)}
# Take every unique user id and map it to a contiguous user .
ratings.userId = ratings.userId.apply(lambda x: user2idx[x])
# Replace that userid with contiguous number.# Similarly, we do it for the movies.
m_uniq = ratings.movieId.unique()
movie2idx = {o:i for i,o in enumerate(m_uniq)}
ratings.movieId = ratings.movieId.apply(lambda x: movie2idx[x])
在我们之前的方法中,我们采用了一个电影嵌入和一个用户嵌入,并做了一个叉积来产生一个数字,这就是我们的预测评级。
同样的事情可以通过神经网络方法来完成。在神经网络方法中,我们将采用两种嵌入方式,将它们连接起来,并将其输入到神经网络中,以产生一个单一的数字,即评级。
流程图如下所示
步骤 1:- 从特定用户的用户嵌入矩阵中选取嵌入向量,并从特定电影的电影嵌入矩阵中选取嵌入向量。
第二步:- 连接两个向量。对所有的电影和用户做同样的事情,这是我们想要的。这将导致一个嵌入矩阵,其中每一行由电影和用户嵌入向量的连接组成。行数将与用户数和电影组合数相同。而列是由因子的个数决定的。与我们之前讨论的嵌入维度相同。所以我们现在拥有的维度是 (#(用户+电影)组合,#因素)
步骤 3 :- 把它喂给第一个线性层,线性层的维度是(#因子,10)。输出将是(#(用户+电影)组合,10)。
步骤 4:- 使其通过具有 ReLU 激活的第二线性层,其维度为(10,1)。输出将是(#(用户+电影)组合,1)。
第五步:- 这是我们想要的输出。之前我们为每个用户和电影做的是,我们做了他们嵌入的叉积,这给了我们一个单一的数字,即预测评级。在这里,我们使用神经网络来获得这个单一的数字,即预测评级。
步骤 6:- 然后,我们将尝试最小化预测评级和实际评级之间的损失,并进而更新模型参数(嵌入值)。这样我们可以使我们的预测更加准确。
让我们检查一下动手部分。
val_idxs = get_cv_idxs(len(ratings))
n_factors = 10min_rating,max_rating = ratings.rating.min(),ratings.rating.max()
min_rating,max_ratingclass EmbeddingNet(nn.Module):
def __init__(self, n_users, n_movies, nh=10, p1=0.05, p2=0.5):
super().__init__()
(self.u, self.m) = [get_emb(*o) for o in [
(n_users, n_factors), (n_movies, n_factors)]]
**# Getting the Embedding matrix for users and movies check out the output # below to know the Embedding dimensionality of User and Movies.** self.lin1 = nn.Linear(n_factors*2, nh)
**# The 1st Linear Layer dimensions is (100,10).** self.lin2 = nn.Linear(nh, 1)**# The 2nd Linear Layer dimensions is (10,1).**
self.drop1 = nn.Dropout(p1)
self.drop2 = nn.Dropout(p2)
**# Some drop-outs introduced in both the layer.** def forward(self, cats, conts):
users,movies = cats[:,0],cats[:,1]
x = self.drop1(torch.cat([self.u(users),self.m(movies)], dim=1))
x = self.drop2(F.relu(self.lin1(x)))
return F.sigmoid(self.lin2(x)) * (max_rating-min_rating+1) + min_rating-0.5wd=1e-5
model = EmbeddingNet(n_users, n_movies).cuda()
opt = optim.Adam(model.parameters(), 1e-3, weight_decay=wd)model
让我们训练我们的模型。
fit(model, data, 3, opt, F.mse_loss)
最后,我们优化了损失函数,得到了 0.78 的损失,这比我们之前在 5.1 和 5.2 中讨论的方法要好得多。
如果您对代码感兴趣,请查看我的 Github repositori es。
如果你喜欢,那么ABC*(永远被击节 。 👏 👏👏👏👏😃😃😃😃😃😃😃😃😃👏 👏👏👏👏👏* )
如果您有任何问题,请随时联系 fast.ai 论坛或 Twitter:@ ashiskumarpanda
注:随着我继续学习其他课程,这篇博文将会更新和改进。更多有趣的东西,可以随时结账我的Github账号。
为了充分利用这个博客系列,请按照以下顺序随意探索这个系列的第一部分:- 狗和猫的图像分类
- 犬种图像分类
- 多标签图像分类
- 使用神经网络的时间序列分析
- 对 IMDB 电影数据集的 NLP 情感分析
- 电影推荐系统的基础
- 从无到有的协同过滤
- 使用神经网络的协同过滤
- 像尼采一样写哲学
- 不同神经网络在 Cifar-10 数据集上的性能
- 检测图像中最大物体的 ML 模型 Part-1
- 检测图像中最大物体的 ML 模型 Part-2
编辑 1:-TFW·杰瑞米·霍华德同意你的帖子。💖💖 🙌🙌🙌 💖💖。
fast.ai:生活中最好的东西总是免费的
[Image[1] (Image courtesy: https://pixabay.com)]
“与朋友促膝谈心,回忆往事;忙碌一天后,在舒适的床上美美地睡上一觉;与家人共度美好时光;为你真正相信并且一直想帮助的事业做志愿者;看着那个人的眼睛,让他/她感觉到他/她对你来说是多么的特别……”这些都是我们生活中最美好的事情。有很多这样的情况确实有助于让我们发挥出最好的一面。如果你仔细观察这些事情,你会非常惊讶地发现,我们生活中所有这些美好的时刻都有一个共同的特点。是啊!如题,“人生最美好的东西,永远是免费的”。
保持冷静!这篇文章不是关于我们生活的哲学方面:d .在这篇文章中,我将对一个 100%免费的学习平台发表我的意见(是的!这是一个金矿)在这里你可以"做和学习"深度学习。是啊!边做边学。请不要离开我,我会解释你需要知道的关于这个学习平台的每一分钟的信息。让我们开始行动吧,😄
我一直想学习数据科学和数据工程。我是计算机科学出身,接触过“模式识别”、“数据挖掘和数据仓库”、“分布式系统”、“高性能计算”,我意识到这是一个把所有的点连接起来的问题。所以我开始认真“开始做”数据科学和数据工程。最终我降落在“卡格尔”上。我开始向同龄人学习,这给了我很大的推动。每当我试图开始一个新的问题时,我都不得不在以前的项目上来来回回(这完全没问题,😄)。我从“探索性数据分析”[1][2]开始,逐步学习建立模型和做“严肃的事情”。此时,我正在做“Python”和“R”之间的成本效益分析,我想到了坚持使用“Python”。
Python 是众多入门方式之一。我最初想同时掌握 Python 和 R,然后在阅读了一些 Reddit 和 Quora 帖子后,我得出一个结论,目前,我打算坚持使用 Python。主要原因是,Python 更像是工程师的选择,而 R 是统计学家的选择。
Slow & Steady [Image[2] (Image courtesy:http://cathjayasuriya.blogspot.sg/2011/02/learning-from-ants.html)]
一开始,这是一个缓慢但稳定的旅程。要做“严肃的事情”,我知道我必须伸出手指“努力工作”。“努力工作”意味着拓宽我对“数据科学”主题的理解(我总是试图在“数据科学”和“数据工程”之间取得平衡,因为我个人更喜欢全方位的工作)。
正是在这一点上,我意识到加深对神经网络理解的重要性。探索又开始了。我遇到了几个主要的领先在线课程,杰弗里·辛顿教授的用于机器学习的神经网络、吴恩达教授的深度学习专业化以及 Udacity 的人工智能——深度学习纳米学位。这些无疑是在神经网络中掌握和超越的最佳资源。你可以免费学习所有这些材料(如果你想获得证书,那么只有你需要付费)。尽管这些资源是许多人追随的最好和最流行的方法,我仍然继续寻找我的问题的正确答案。然后就碰到了“ Udemy ”平台。在彻底复习了 Udemy 课程后,我选择了“深度学习 A-Z:动手操作人工神经网络”,因为这门课程直接跳到了实现,而没有深入数学。这个课程是 10 美元,我不介意花这么多钱来学习一个能给我很大帮助的材料。如果你想探索神经网络背后的深层概念和数学,你需要阅读额外的材料(本课程的讲师提供了这些材料的链接)。我对正确答案、学习神经网络的正确平台的追求仍然存在。那些日子里,我花了大量时间在 Reddit 和 Quora 上衡量每个用户的观点。
它发生在:D
我记不清这个故事了。我坚信,经过一番努力,我找到的学习平台是满足我需求的正确答案。
fast.ai
我来自计算机科学背景,并在行业和计算机科学研究领域工作了 2 年多,我相信对我来说,学习“神经网络”必须是一种不同的方法,而不是先学习理论,然后实施,然后在 Kaggle 竞争,这是一种口语方法。“ fast.ai 提供了一种通过直接编码和实现真实的 Kaggle 比赛来掌握深度学习的实用方法。然后慢慢地,它对“神经网络”的基本概念,如何将这些概念应用到现实世界的场景中,以及它们(神经网络)的局限性建立了坚实的理解。这门课真正让我着迷的是,这门课的老师分享了他们自己的经历,这些经历帮助我把我前面提到的点联系起来。
让我简单介绍一下这门课的老师。
“fast.ai”的创始人是“杰瑞米·霍华德”——旧金山大学的研究科学家(贪婪的凯格勒(# 1));以及“瑞秋·托马斯”——她被福布斯选为“推进人工智能研究的 20 位杰出女性”之一。我鼓励你看看“fast.ai/about”来获得更多关于这两个不可思议的角色的信息。这两个美丽的灵魂使这门课程对所有人完全免费,❤
Jeremy Howard and Rachel Thomas [Image[3] (Image courtesy: http://www.fast.ai/)]
让我带你浏览一下 via " fast.ai 提供的课程
程序员实用深度学习,第 1 部分
对于任何具有计算机科学(或其他相关学科)背景的人来说,这是开始神经网络之旅的正确起点。在这个初级课程中,你将进行真正的 Kaggle 比赛。开发环境是 Amazon Web Services (AWS)或 Paperspace。在 7 个视频结束时,您将对“如何使用深度学习方法处理研究问题”有一个透彻的理解。每周投资 6-10 个小时来理解内容将是你作为深度学习实践者在未来职业生涯中所做的早期投资。每个视频最多 2 小时,看的时候最好反复看同样的内容,直到你掌握了基本原理。它的回报更高。我仍在学习这门课程,我将简要回顾一下到目前为止我所学的内容。
程序员的前沿深度学习,第二部分
这是第一部分“程序员实用深度学习,第一部分”的继续。我还没有开始这个课程,所以让我来分享一下第 2 部分的内容。
程序员的前沿深度学习,第 2 部分,在这里你将了解深度学习的最新发展,如何阅读和实现新的学术论文,以及如何解决具有挑战性的端到端问题,如自然语言翻译(摘自http://course.fast.ai/lessons/lessons.html)
相当令人兴奋,对吧,😄,我热切地期待着在我完成第一部分后,马上“开始做”这一部分。
也许你会认为这门课只是深度学习。保持冷静!!!。Jeremy 和 Rachel 都是带着让每个人都可以使用深度学习的愿景开始“fast.ai”的。当我参加“ fast.ai forums ”的时候,我注意到这两个美丽的灵魂发布了一个关于机器学习的课程。
又一次请客!提前获得机器学习介绍视频
这是“ fast.ai ”提供的第三个课程。我希望我在机器学习生涯的早期就发现了这一点。在本课程中,Jeremy 和 Rachel 讨论了如何通过 Kaggle 竞赛掌握将机器学习概念应用于现实世界问题的技能。我开始跟踪这些材料,以便进一步加深我对机器学习的理解,将机器学习应用于现实世界的问题。
好了,现在让我跟随“ fast.ai ”分享一些我的经验。我就不深入了。既然现在你知道了这个" fast.ai "平台的价值,我鼓励你去体验这个平台。一言以蔽之,我要通过这个平台来反映我到目前为止学到的东西(我从开始的地方走了多远:P)。
狗 vs 猫
Dogs vs Cats[Image[4] (Image courtesy: https://pixabay.com/)]
“狗 vs 猫”是在 Kaggle 举办的一场比赛,这是“程序员实用深度学习,第 1 部分”试图通过最先进的方法找到解决方案的第一个任务。这个比赛是关于将图像分为两类,“猫”和“狗”。最初,我们得到了相应标记的训练数据集。我们的任务是使用这些训练数据集开发一个分类模型。最后,开发的模型需要正确分类未标记的测试数据集。好吧,这听起来很简单。但是当你“开始做”这项任务时,你会遇到大量以前从未遇到过的新事物。
以下是我在完成这个比赛后学到的东西:
- 为深度学习设置 AWS 这可能一开始听起来很奇怪。但我认为,对于当时像我这样的初学者来说,这听起来可能并不奇怪。为了训练和开发深度学习模型,你需要有很高的计算能力。我之前确实尝试过几个小规模的深度学习任务。但是我没有迁移到云基础架构的要求。为深度学习设置 AWS 给了我关于 AWS 基础设施的大量实践经验。我了解了“ t2.xlarge ”实例和“ p2.xlarge ”实例。在 AWS IAM 中设置角色,创建 AWS 用户,将策略应用于用户, EC2 实例, S3 桶,一个认证者应用登录时的安全 root 帐户, VPC , Dynamo DB 以及更多++的应用(后四个是我通过简单地摆弄 AWS 管理控制台学会的)。
- 在本地机器中配置 AWS,并使用别名通过命令行别名启动、停止、获取实例 id 。
- 使用 tmux 进行多任务处理(以前没有使用过 tmux:(😛)
- VGG16 模型和 ImageNet 竞赛——vgg 16 模型是使用各种标记图像的预训练模型。用于训练模型 VGG16 的这些图像的主要特征是,这些图像在图像本身上清晰可见。我的意思是,在训练图像中,除了一个可见的图像,没有其他对象可见。让我说得更清楚些。在图像的左侧,我们可以清楚地看到图像中的狗,而在右侧,我们可以看到两只狗,但这些狗不是景点的中心。VGG16 模型已经使用类似于左手侧的图像进行了训练。你可以参考伊曼吉内特【3】【4】了解更多细节。
Dogs vs Dog image with other objects[Image[5] (Image courtesy: Google Images)]
- 将相同的技术应用于其他图像分类任务——您只需构建相同的文件夹结构。
- 理解和应用 VGG16 模型
我认为这足以让你明白为什么这个课程是“最好的”。本课程和本课程的第二部分现在已经发展到一个更复杂的层次。在最新的系列中,杰瑞米·霍华德使用“fastai”库作为所有项目的基础库。这一次(截至 2018 年),云基础设施来自 Paperspace 。
现在,让我向您介绍一下我在完成“机器学习入门”视频系列的第一项任务后获得的一些关键学习成果。
推土机蓝皮书
Blue Book for Bulldozers [Image[6] (Image courtesy: https://pixabay.com/)]
这是杰里米在“机器学习导论”系列中讨论的第一个 Kaggle 项目。这个项目的目标是预测“销售价格”,这是一个连续的价值因变量。这个项目有多年来收集的数据。任务中使用的算法是“随机森林”。Jeremy 直截了当地指出“随机森林”如何用于开发一个成功的预测模型。在做模型的时候和模型建立之后,他会更深入,覆盖广度和深度。
我鼓励你遵循这些令人敬畏的免费材料。你会发现这些非常有用。成为高度参与的社区论坛的一部分。我保证你会从同龄人那里学到很多特别的内容。我通过这篇文章的最终目的是让你们了解这个令人敬畏的平台“ fast.ai ”。这就是为什么我在阐述这个平台的价值时只考虑了两个场景。我坚信我成功地以有效的方式向你们传达了这一信息。
接下第一项任务后,我想强调以下几点:
- 首先,我学到了很多关于 Jupyter Notebook 的东西——主要是在笔记本上浏览功能实现和文档,快捷键,调试++
- “日期”特征的值——“日期”可以由“年-月-日”格式或“年-月-日-时-分-秒”格式组成。在任何时间序列问题中,仔细检查“日期”参数是极其重要的。从“日期”我们可以派生出“一年中的星期”,“日期的星期”和许多其他功能。这些功能将有助于更广泛地了解我们的数据。我们都知道特征工程是机器学习中必不可少的一部分。如果你在“fast.ai”平台上看了这个视频,你会对特征工程感到惊讶和信服。
- 将“字符串变量”转换为分类变量的过程和重要性,以及一旦完成分类,Python 库的内部工作如何将数值分配给变量。
- 处理缺失值(数值和分类)
- 以保存在 RAM 中的格式保存数据——这种方法有助于快速检索项目
- 改进随机森林回归方程的方法
简而言之,这就是我完成第一个任务后学到的东西。
就此,我想以向你表示衷心的感谢来结束这篇文章。让我知道你对这篇文章的想法和评论。我很欣赏你的反馈。如果你觉得这篇文章很有收获,请在 Faceboook、Twitter、Google+和其他社交媒体平台上与你的朋友分享。请随意给我一拍、二拍、三拍或者热烈的掌声来激励我。这肯定会帮助我保持势头。
就像我在这篇文章的标题中提到的:
生活中最好的东西总是免费的!!!
【1】https://www . ka ggle . com/omarelgabry/a-journey-through-titanic
【2】https://www . ka ggle . com/MRIs dal/exploring-survival-on-the-titanic
【3】http://www.image-net.org/
【4】http://image-net.org/explore
Fast.ai:实用深度学习的 TOC 第 1 部分
如果 USF 数据学院的证书和来自 Fast.ai 的 MOOC 是一本书,这将是它的目录
我目前正在将我对深度学习的兴趣和迷恋转化为职业的旅程中。作为一名软件工程出身的人,我比其他非博士/硕士稍微领先一点,但也不算多。
你可以在 Medium 上的 这里阅读我的辞职和职业转型帖子 ,以及在 LinkedIn 上的 更新评论版本 。
写博客是我旅程的一个重要部分,尤其是记录我实际学到了什么。不仅仅是为了此刻的自己,也是为了任何一个跟随类似脚步的人。所以这篇文章是写给那些对 Fast.ai 和 USF 数据学院深度学习项目感兴趣的人。
这篇帖子的部分灵感也来自一条推文,暗示出色的工作 雷切尔·托马斯 和 杰瑞米·霍华德 正在做的事情被简化了。
瑞秋回应的第 10 部分(11 部分全部看完,太棒了!):
第一部分
第 1 章:图像识别
- 设置您自己的 AWS 实例
- 深度学习简介以及它为什么有用
- 深度学习的 7 行代码
- 分解 VGG16
- 进入一个 Kaggle 竞争:放置前 50%的狗对猫 redux
**第二章:**CNN
- 狗对猫 Redux:国家的最先进的模式解释
- 预训练网络与随机权重
- 微调的方式和原因
- 稠密层、随机梯度下降和激活函数
第三章: 了解上下拟合
- CNN 在工作:从点积到转换,再回到传播
- 处理过度装配和装配不足
- CNN 正则化技术
- 半监督学习、伪标记和知识蒸馏
- Excel 中的卷积和 SGD
第四章: 协同过滤、嵌入和更多
- Excel 中的嵌入
- 推荐系统和协同过滤
- 潜在因素
- 建立更多模型
**第五章:**NLPs 和 RNNs 介绍
- Keras 功能 API
- 多尺寸 CNN
- 情绪分析
- NLP 迁移学习
- 将神经网络可视化为计算图
- RNNs 简介
第六章: 从零开始的 RNNs、嵌入和 Theano API
- 在 Excel 中嵌入 rnn
- 用 Keras 从头开始构建 RNN 模型
- 用 ano API 构建 rnn
第 7 章: CNN 架构、包围盒和多输入
- ResNet 和 Inception CNNs 概述
- 数据泄露
- CNN:如何处理多重输入、输出和包围盒
- 全卷积网络
摘要
这个程序的第一部分已经涵盖了很多内容。对于每个“章节”,都有一个 2 小时的视频、附带的 Jupyter 笔记本、笔记/维基(主要由学生编写/更新)、Jeremy 建议的阅读材料(博客、论文等)、作业(没有标记,但建议练习)以及现场和在线学生令人惊叹的活跃论坛。
教学风格是“自上而下”的方法,你可以在这里阅读更多关于的内容。个人觉得很棒!同样,我不需要知道汇编/机器码来编写 Python,我也不需要知道每个数学公式的复杂性来利用深度学习技术。
但是不要弄错了,如果你喜欢的话,有数学、公式、复杂的概念要理解,还有枯燥的学术论文要读。正是这种不同的/更好的方法吸引了许多人。就像任何在线或大学的课程或项目一样,你在事情上付出的努力。
对我来说,我已经成功地完成了第一部分,感觉比一个月前聪明多了。我不是深度学习方面的专家(目前还不是!)但因为 Fast.ai,我肯定比我的许多同事拥有更多的知识和实践经验。
现在,我正在努力完成第 2 部分,希望在 4 周内,你可以准备好我的后续文章。
思想?关于该计划的问题?欢迎在下面的评论区提出你的问题。
你将从 fast.ai (V2)第 1 课中学到什么
fast.ai 是一个学习深度学习(DL)的在线平台。它有 14 节课,分为两部分,每部分 7 节课。第 1 部分主要涵盖与 DL(深度学习)在各个领域的应用相关的主题,以及如何为自己的项目构建这些模型。另一方面,第 2 部分让您深入了解数据科学的当前研究,这推动了前沿技术的发展。版本 2 (v2)是 fast.ai 的 2018 版本。
与其他大多数在线课程不同,fast.ai 采用自上而下的方式教授 DL。这意味着 fast.ai 不是专注于每个算法背后的理论,而是提供如何构建和使用 DL 模型的实践经验。在使用这些模型时,你将在需要时学习必要的主题。
这个博客为那些已经看过第一课视频的人做了一个总结,如果你还没有看过的话,它也是一个帮助你做好准备的来源。我试着把事情分解成小模块,这样每一段都谈论一个特定的主题。
如果你已经熟悉了 DL 和机器学习(ML)的基础,你可以直接跳到第一课总结。但是如果你是这个领域的新手,那么前几段是为你准备的。作为一名数据科学新手,有一些事情你必须知道。
最重要的是,的参数。参数是模型的全部。人们经常谈论参数或权重(两者都一样),下面是它们的意思。假设我们有已经分成两类的数据。模型的工作是将每个数据点分类到其各自的箱中。“参数”是那些决定哪个点将进入哪个类的值。
损失函数是你应该知道的下一件重要的事情。损失函数的作用类似于参数的质量检查。如果参数是对每个数据点进行分类的值,那么损失函数给我们关于参数对于给定数据有多好的信息。
所以训练一个模型无非是找到损失最小的正确参数。我们随机选取一组参数,并在每次迭代后更新这些参数,以获得最小损失。梯度下降用于决定哪个方向带我们到达最小值。
打个比方,如果你在山顶的车里,目的是往下开,梯度下降就是你的车行驶的方向。说到开车下坡,有一件事是我们在开车下坡时都会做的。或者说,我们必须这样做。那会是什么?大胆猜测一下。明白了吗?是啊!我们使用刹车。没有一个理智的人会在没有摩擦力的帮助下疯狂地开车。(除了刹车失灵)。当使用梯度下降更新参数时,我们应用一种特殊的刹车,通常称为学习率。
学习率提供了从随机参数到最新模型的平滑过渡。将学习率设置得太高就像加速汽车下坡。更别说到达山脚,加速度会让你偏离道路。学习率太高,不会收敛到最小损失。损失随着高学习率而增加,并且模型将停止学习。
如果学习率太小,就像过度使用刹车。模型肯定会达到最小值。但这需要很长时间。我们不能无限期地训练一个模型。所以设定正确的学习速度总是非常重要的。
最后,**参数初始化。**我们总是采用一组随机数作为参数,并使用梯度下降进行更新。初始化的经验法则:对称不起作用。我们的大脑都一样。我们对初始化的第一个想法非常简单。“为什么不能用全零?”没有。那不行。
最好的初始化方法是从高斯分布中抽取随机数。这仅仅意味着用随机数乘以 sqrt{2/n}。n 是所有层的参数总数。
话虽如此,让我们进入本博客的主题——fastai 第一课概要。
第 1 课总结:
第一课就像是每门课程教材的典型的第一章。
第一章:引言。
是啊!我说的是那一章,通常是你从那本书里读到的最后一章。(我也这么做。击掌!)嗯,fast.ai 的第一课就是那个入门章节。
第一课的要点可以大致分为四类。
- 通用深度学习简介
- 每个 fast.ai 视频的内容(前 7 个)
- 设置虚拟机
- 关于代码、构建代码的语言以及其他细节
1。深度学习概述:
深度学习相对于机器学习算法的优势在于,ML 需要大量的特征工程。ML 也有各种算法可供选择,对于每个数据集,我们应该检查哪一个效果最好。DL 通过使用深度神经网络(DNN) (因此得名深度学习)让生活变得更容易
神经网络(NN)看起来像这样。
©http://www.extremetech.com/wp-content/uploads/2015/07/NeuralNetwork.png
另一方面,DNN(深度神经网络)看起来像这样。
©https://qph.ec.quoracdn.net/main-qimg-7c35987ad55173b3b76214b9112830ff
不要担心它看起来有多复杂。只是欣赏美丽的图案。
深度学习有三重优势。无限灵活,通用参数拟合,快速&可扩展。
给定任何数据,神经网络理论上应该能够近似拟合它,只要我们给它 足够的参数。 这就是所谓的普适逼近定理。但是这在真实的数据集中是失败的,因为我们使用的数据有很多噪音。出于这个原因,我们通过层层叠加来使用深层网络。它非常有效。因此,灵活性—检查
DNN(深度神经网络)的目标是将参数尽可能完美地拟合到手头的数据。所以随机寻找最佳参数是行不通的。获得良好参数的更好方法是沿着损耗最小的方向。而梯度下降给出这个方向。给定任何问题,(负)梯度下降将指向最小损失。因此,所有目的参数拟合—检查
尽管深度神经网络需要相当长的时间来训练,但是预测时间是最小的。GPU 在过去十年中发挥了重要作用,减少了训练或预测所需的时间。
©https://www.karlrupp.net/2013/06/cpu-gpu-and-mic-hardware-characteristics-over-time/
几乎所有为深度学习研究而构建的语言,如 TensorFlow、Theano、PyTorch 等,都使用这些 GPU。快速&可扩展—检查
卷积神经网络(CNN)就是这样一类深度学习算法。在 fast.ai 的前几次讲座中,我们将在 CNN 工作。CNN 致力于一个叫做卷积的概念(很明显!!).卷积是一种数学方法,它整合两个函数,观察当一个函数发生变化时,另一个函数如何变化。
2.fast.ai '课程结构:
第一课——简介(无聊?我知道。但是继续读。有些事情你可能会感兴趣。)
**第 2 课—不同数据集上的图像分类器。**考虑各种数据集,学习 DL 中不同的技术,对图像进行分类。
**第 3 课——预测分析。**从结构化数据中,我们将尝试预测销售或天气,或者检测帐户和其他酷应用程序中的欺诈行为。
第 4 课—自然语言处理。(NLP)理解给定文本数据中存在的内容。或者对文本属于哪个上下文进行分类。像这样的问题将在第四课中讨论。
**第五课——协同过滤和推荐系统。**这将是一堂非常有趣的课(也是我个人最喜欢的),我们将讨论如何根据之前的观看列表推荐一部电影或一本书。网飞、Prime Video 或其他类似网站使用推荐系统。
**第 6 课——文本生成。**想一个算法,它能为你的剧本提供莎士比亚风格的对话。在本课中,您将学习如何做到这一点
第 7 课—图像分割。在最后一课中,你将学习如何训练一个模型在给定的图片中找到一只猫或一只狗。fast.ai 的第一部分到此结束。
3.设置虚拟机:
我们已经讨论过深度学习如何使用 GPU 来处理复杂的任务。但并不是每个人都有一台笔记本电脑或一台配有良好 GPU 的台式机。而且买一个 GPU 好的系统是很大的投资。为了克服这一点,人们开始使用虚拟机。这些服务器向公众开放,每月收取象征性的费用。
已经设置了 fastai 的一些虚拟机包括:
- Crestle :使用方便。可以在 CPU 和 GPU 之间切换,降低整体成本。
- Paperspace :更便宜更快。
除了这两家之外,还有其他虚拟机提供商
- 谷歌云平台:给你 300 美元积分,一年免费订阅。太好了。但是你需要在用完那 300 美元的积分后付款。
- 亚马逊网络服务:有很多变体可供选择。其中一些非常便宜,而且几乎免费。AWS 还有一年免费层。
- Google Colab:我的最爱。为什么这么问?完全免费。有什么条件?每次你向谷歌申请服务器时,它都会给你一个有限的时间来访问其中的一个。之后连接终止,刷新,访问权授予另一个用户。所以如果你超过了时间限制,那么你必须从头开始。
我可以详细说明如何设置这些虚拟机,但这将使我们偏离主题。在第 1 课中,Jeremy 在前 12 分钟介绍了这一点,您可以轻松设置 Crestle 或 Paperspace,没有任何问题。
如果您在设置任何其他虚拟机时遇到问题,请使用 Google Colab。所有你需要的 Colab 是一个工作的谷歌帐户。打开 Colab 笔记本后,在工具栏中进入*运行时>改变运行时类型>硬件加速器> GPU。*你可以走了。
关于代码的其他详细信息:
法斯泰图书馆。 fastai 是由杰瑞米·霍华德和瑞秋·托马斯创建的开源库。它基于 PyTorch 构建,使用 python 3.6。(当心!一些代码对你来说可能看起来很新,因为它没有运行在 python 3.5 上)要使用这个库,在你的终端中,
git 克隆https://github.com/fastai/fastai>CD fastai>conda env 更新。
lr _ find()函数。设置正确的学习速率对于学习正确的参数至关重要。在 fastai 库中,lr_find()函数以非常小的学习速率开始,并且在每次迭代后加倍。经过几千次迭代后,损失开始增加,此时 lr_find()停止,我们可以绘制损失与学习速率的关系。
损失急剧下降的区域是最佳学习率。在这种情况下,它在 1e-2 左右。
fast.ai V2 L1 的总结到此结束。正如我在开头所说的,fastai 的基本概念是在需要的时候学习必要的东西。我尊重他们的想法,所以我对每一个概念都做了大致的介绍,而没有深入到它们的细微差别。一旦你理解了神经网络是如何工作的,我可以用数学给你一个更好的描述。已经在路上了。
如果我错过了什么或者你想知道更多,请在评论中提出。我总是乐于接受积极的批评和讨论。
快乐学习。干杯!
是的。如果你喜欢这个博客,别忘了鼓掌…
使用位置敏感散列的快速近似重复图像搜索
一个快速的 5 部分教程,讲述深度学习如何与高效的近似最近邻查询相结合,用于在庞大的集合中执行快速语义相似性搜索。
第 1 部分:为什么最近邻查询如此重要
如果你在机器学习方面受过一些教育,最近邻居这个名字可能会让你想起 k-nearest neighbors 算法。这是一个非常简单的算法,看起来实际上没有“学习”:kNN 规则只是通过训练集中 k 个最近邻中的多数标签对每个未标记的例子进行分类。
k-NN algorithm: with k=3, the green example is labeled as red; with k=5, it is labeled as blue
这似乎是一个非常天真,甚至“愚蠢”的分类规则。是吗?这取决于你用什么作为你的距离度量,也就是:你如何选择来度量例子之间的相似性。是的,天真的选择——在“原始”特征中使用简单的欧几里德距离——通常在实际应用中导致非常差的结果。例如,这里有两个例子(图像),它们的像素值在欧几里德距离上很接近;但是有争议的是,仅仅因为左边的图像是右边图像的邻居,就把它归类为花是疯狂的。
Euclidean distance in pixel space = visual/syntactic/low-level similarity
但是,事实证明,将 kNN 规则与距离度量的适当选择结合起来实际上是非常强大的。“度量学习”领域表明,当在使用 kNN 规则之前应用机器学习来学习度量时,结果可以显著提高。
我们当前的“深度学习时代”的伟大之处在于有大量可用的预训练网络。这些网络解决了某些分类任务(预测图像类别,或单词周围的文本),但有趣的是,它们在这些任务上的成功并不多,但实际上它们为我们提供了极其有用的副产品:密集向量表示,简单的欧几里德距离实际上对应于高级的“语义”相似度。
Euclidean distance in deep embedding space = semantic similarity
关键是,对于许多任务(即通用图像和文本),我们已经有了一个很好的距离度量,所以现在我们实际上可以使用简单的 kNN 规则。我在过去已经谈过很多次这一点——例如,在以前的一篇文章中,我试图使用这样的搜索来验证这样的说法,即生成模型真的在学习底层分布,而不仅仅是记忆训练集中的例子。
这就给我们留下了实际寻找最近邻居的任务(我称之为 NN 查询)。这个问题——现在几乎是任何 ML 管道中的一个构建模块——已经得到了很多关注,无论是在 CS 理论文献中,还是从需要高度优化生产环境解决方案的公司那里。这里,社区再次受益,因为这个领域的几个大玩家实际上已经开源了他们的解决方案。这些工具使用精心制作的数据结构和优化的计算(例如在 GPU 上)来有效地实现 NN 查询。我最喜欢的两个是 Facbook 的 FAISS 和 Spotify 的asury。这篇文章希望能让你了解这些库“幕后”发生的事情。
当我们谈论最近邻查询时,第一个区别是在精确和近似解之间。
精确算法需要返回数据集中给定查询点的 k 个最近邻。这里,简单的解决方案是简单地将查询元素与数据集中的每个元素进行比较,并选择具有最短距离的 k。该算法取 O(dN),其中 N 是数据集的大小,d 是实例的维度。乍一看,这似乎很令人满意,但是仔细想想:1)这只是针对一个查询!2)虽然 d 是固定的,但它通常可能非常大,最重要的是 3)在“大数据”范式中,当数据集可能非常大时,数据集大小的线性不再令人满意(即使你是谷歌或脸书!).其他精确查询的方法使用树结构,可以获得更好的平均复杂度,但是它们最坏的情况复杂度仍然接近 n 中的线性复杂度。
近似算法留有一定余地。有几个不同的公式,但主要思想是它们只需要返回实例,这些实例到查询点的距离是真正最近邻居的距离的几乎(其中‘几乎’是算法的近似因子)。允许近似解打开了随机化算法的大门,它可以在次线性时间内执行 ANN(近似 NN)查询。
第 3 部分:位置敏感哈希
一般来说,实现次线性时间算法的一个常见的基本构件是散列函数。散列函数是将输入映射到固定大小(通常是较低维度)的数据的任何函数。最著名的例子是校验和散列,你可能只是从网上下载文件时遇到过。他们背后的想法是生成一个“指纹”——也就是说,一个特定的数据块有希望是唯一的一些数字——可以用来验证数据在从一个地方转移到另一个地方时没有被破坏或篡改。
checksum hash: good for exact duplicate detetction
这些散列函数的设计只有一个目的。这意味着它们实际上对输入数据的微小变化非常敏感;即使一个比特发生了变化,也会完全改变哈希值。虽然这确实是我们对精确重复检测所需要的(例如,当两个文件确实相同时进行标记),但它实际上与我们对近似重复检测所需要的正好相反。
这正是位置敏感哈希(LSH)试图解决的问题。顾名思义,LSH 依赖于数据的空间性;特别是在高维度上相似的数据 项,会有更大的几率收到相同的 hash 值。这是目标;有许多算法可以构造具有这种特性的散列函数。我将描述一种方法,这种方法非常简单,并展示了随机投影令人难以置信的惊人力量(另一个例子,参见美丽的约翰逊-林登斯特劳斯引理)。
基本思想是我们使用以下过程生成大小为 k 的散列(或签名):我们生成 k 个随机超平面;项目 x 的哈希值的第 I 个坐标是二进制的:当且仅当 x 在第 I 个超平面之上时,它等于 1。
the hash value of the orange dot is 101, because it: 1) above the purple hyperplane; 2) below the blue hyperplane; 3) above the yellow hyperplane
整个算法只是重复这个过程 L 次:
an LSH algorithm using random projections with parameters k and L
让我们了解一下如何使用 LSH 来执行人工神经网络查询。直觉如下:如果相似的项目具有(很有可能)相似的散列,那么给定一个查询项目,我们可以用只与具有相似散列的项目进行比较来替换对数据集中所有项目的“原始”比较(在普通的行话中,我们称之为“落在相同桶中”的项目)。这里我们看到,我们愿意满足于精度的事实正是允许次线性时间的原因。
因为在桶内我们计算精确的比较,所以 FP 概率(即,说一个项目是 NN,而它实际上不是)是零,所以算法总是具有完美的精度;然而,我们将只返回那个桶中的项目,所以如果真正的 NN 最初没有被散列到桶中,我们就没有办法返回它。这意味着在 LSH 的背景下,当我们谈论准确性时,我们实际上是指回忆。
形式上,使用 LSH 的 ANN 查询按如下方式执行:1)找到查询项的“桶”(哈希值)2)与桶中的每个其他项进行比较。
我们来分析一下这个算法的计算复杂度。会很快很容易的,我保证!
阶段 1)费用丹麦;阶段 2)成本 N/2^k 预期 ( 因为在数据集中有 n 个点,在我们的分区空间中有 2^k 区域)。由于整个过程重复 l 次,总成本平均为 LDK+LDN/2^k.。当 k 和 l 约为 logN 时,我们得到所需的 O(logN)。
第 4 部分:LSH 超参数,或精度-时间权衡
我们已经看到了 LSH 的基本算法。它有两个参数,k(每个哈希的大小)和 L(哈希表的数量)—k,L 值的不同设置对应于不同的 LSH 配置,每个配置都有自己的时间复杂性和准确性。
正式分析这些有点棘手,需要更多的数学知识,但一般来说是这样的:
通过仔细设置这些参数,你可以得到一个任意精确的系统(不管你对“近似重复”的定义是什么),但是其中的一些会以很大的 L 为代价,即很大的计算成本。
一般来说,根据经验解决这种权衡的一个好方法是在一个明确定义的任务上量化它们,你可以用最少的手工劳动来设计。在这种情况下,我使用的是 Caltech101 数据集(没错,是旧的;是的,在 ImageNet 之前就有图像数据集了!),带有 101 个简单物体的图像。作为我的 LSH 方案的输入,我使用了 4096 维的特征向量,这些特征向量是通过将每个图像经过预先训练的 VGG 网络而获得的。为了简单起见,我假设来自同一类别的其他图像是特征空间中的真实 NN。
Caltech101
有了“基本事实”,我们可以尝试不同的超参数组合,并测量它们的准确性(召回)和运行时间。绘制结果可以很好地权衡精度和时间:
我们清楚地看到更好的召回是以更长的运行时间为代价的。请注意,实际结果取决于任务:一般来说,您认为“接近”的项目越相似(在高维度中),任务就越容易。高效地找到远处的邻居是一项艰巨的任务,当心!
第 5 部分:为一个示例应用程序将所有这些放在一起
我想把这个管道拼凑成一个个人项目,更有效地浏览我的个人照片集。旅行归来,我经常会从几个设备上拍下照片,其中许多照片非常相似——我对风景的欣赏通常会给我留下几十张几乎相同的照片。语义相似到救援!以下是一些结果。
每行代表一个查询;左边是查询图像,右边是散列到同一个桶的图像,它们的实际距离用绿色表示。很酷的东西!
***总结(TL;*博士)。
我们回顾了两个非常有用的想法:
- 位置敏感哈希(LSH)是一个有用的工具,用于执行近似最近邻查询,即使对于非常大的数据集也能很好地扩展。
- 深度学习的时代为我们提供了免费的图像、文本和音频的“现成”表示,其中相似向量(在简单、欧几里德、距离上)是语义相似*(图像的 VGG 特征向量,文本的 Word2Vec)。*
最后,我们看到了这两种想法的结合——即,不在原始数据(图像、文本)上而是在深层表示上应用 LSH——如何用于在庞大的集合中执行快速相似性搜索。
噪声文本的快速分词
TL;速度三角形定位法(dead reckoning)
更快用三角矩阵代替动态规划分词。集成的拼写纠正允许嘈杂的输入文本。GitHub 上的 C#源代码。
对于西方人来说,单词之间用空格分隔似乎是显而易见的,而在汉语、日语、朝鲜语(CJK 语言)、泰语和爪哇语中,单词之间是没有空格的。
甚至古典希腊语和晚期古典拉丁语都没有这些空格。这被称为continua脚本。
似乎我们还没有失去我们的能力:我们可以很容易地破译
quickbrownfoxjumpsoverthelazydog
如同
敏捷的棕色狐狸跳过懒惰的狗
我们的大脑以某种方式直觉地和无意识地做到这一点。我们的阅读速度稍微慢了一点,这是因为我们的大脑需要处理所有的背景信息。如果我们尝试以编程的方式来做,我们将会看到它到底有多少。
为什么?
但是,如果人们无论如何都能阅读未分段的文本,我们为什么要以编程方式实现分词呢?
对于单词间没有空格的 CJK 语言来说 *,*就更明显了。
像谷歌或百度这样的网络搜索引擎必须以一种允许高效快速检索的方式对文本进行索引。那些网络搜索引擎是基于倒排索引的。在抓取每个单词的过程中,会创建一个单独的链接列表。每个列表都包含指向出现该特定单词的所有网页的链接。
如果我们搜索一个单词,那么列表中包含的所有链接都是有效的搜索结果。如果我们对两个单词进行布尔搜索(AND ),那么这两个列表相交,并且只有包含在两个列表中的链接作为结果返回。
拼写纠正允许纠正拼错的单词。这是通过在字典中查找可能拼错的单词来完成的。如果找到该单词,则该单词被认为是正确的。如果没有找到该单词,那么字典中最接近候选的那些单词(根据编辑距离度量,如 Damerau-Levenshtein )被呈现为拼写纠正建议。当然,计算每个字典条目的编辑距离的简单方法是非常低效的。符号拼写是一个快得多的算法。但无论如何,前提条件是首先识别单词边界,以便首先为拼写校正算法提供输入。
机器翻译,语言理解,S 感知分析等很多信息处理任务也是基于单词的。
但是对于单词之间已经有空格的语言,我们为什么还需要分词呢?嗯,即使在那些通常有空格的语言中,有时也会缺少空格!应用领域多得惊人:
- 规范化书写可变的英语复合名词:例如,ice box = ice-box = icebox 猪圈=猪圈=猪圈)进行搜索&索引。
- **复合词分词:**原词和拆分词部分都应编入索引。
- 打字错误可能导致空格丢失。
- 转换错误:在转换过程中,word 之间的一些空格可能会丢失,例如,通过删除换行符而不是用空格替换它们。
- OCR 错误:原始文档或手写文本的质量较差,可能会导致无法正确识别单词之间的所有空格。
- **传输错误:**在噪声信道上传输期间,可能会丢失空格或引入拼写错误。
- 关键字提取从 URL 地址、域名、表格列描述或无空格书写的编程变量。
- 对于密码分析,可能需要从密码中提取术语。
- 语音识别,如果在口语中不能正确识别单词之间的空格。
- 自动编程变量 。
但是,除了自然语言之外,单词分割也可能是令人感兴趣的,例如,将 DNA 序列分割成单词 (PDF)。
分段变体生成
一个字符串可以用几种方式来划分。每个不同的分割变体被称为一个组合**。存在多少种不同的成分?**
- 在长度为 n 的字符串中,潜在字边界的数量是n’= n-1**(在字符串的每个字符之间)。**
- 这些位置中的每一个实际上都可以用作字边界,也可以不用作字边界。我们可以认为这是一个二进制形式的数字,其中每一位都可以设置或不设置。
- 在二进制数字系统中,一个 n 位数可以代表 x=2^n 数。因此,分割变体的数量也是x=2^n’(n’潜在单词边界的数量)
- 每个长度为 n 的字符串可以被分割成个 2^n−1** 个可能的个组合。**
必须根据两个标准评估钻柱的成分:
- 作文是否是有效的分词,即由真实的单词组成(我们将学习如何处理未知单词)。
- 对于特定的输入字符串,哪个有效的单词分段(可能存在几个)具有最高的概率,并且将被选为最终结果。
递归方法
最简单的方法是生成所有可能的变体,将字符串分割成子字符串(候选单词),并在字典中查找这些候选单词。所有子字符串都是有效单词的那些分段变量将作为结果返回。
以下递归算法枚举所有合成:
对于“ isit ”作为输入,它将生成所有 8 个可能的组合:
i s i t
i s it
i si t
**i sit**
is i t
**is it**
isi t
isit
两个作文由真正的英语单词组成,并且将是有效的分段建议。在分段变量选择部分,我们将学习如何确定两个变量中哪一个更有可能。
但是有一个问题。长度为 n 的每一串可以被分割成 2^n−1 可能的成分。这是巨大的!
朴素的算法是指数和不会缩放更长的字符串!
例如,我们的字符串quickbrownfoxjumpsoverthelazydog的长度为 35。这导致产生超过170 亿个切分变体,它们的所有单词都要在字典中进行验证,最后,这些变体按概率进行排序。
我们通常没有那么多时间和计算能力。我们需要想出更聪明、更有效的方法。
局部最优的增量计算
我们不需要为了找到最好的而生成所有的作文!
在朴素算法中,生成分割变量的整个树。对于重复子串**,也重复生成分段。并且仅在最后,所有生成的完整分割被比较以找到最佳分割。**
但是每个特定的子串我们只需要分割一次**。我们只为每个子串计算一次最佳部分分割,并在整个输入串的增量分割期间重用它。**
局部最优的选择基于假设连续的部分分割是独立的。****
只计算一次每个子串的最佳分段并重用它节省了生成和存储重复模式所需的大量时间和内存**。**
下一节将介绍两种不同的方法来实现这一点。
动态规划方法
改进算法的一种方法是使用动态编程:
这是一种解决复杂问题的方法,将复杂问题分解成一系列更简单的子问题,每个子问题只解决一次,然后存储它们的解。下一次出现相同的子问题时,不用重新计算它的解,只需查找先前计算的解,从而节省计算时间。每个子问题解都以某种方式被索引,通常基于其输入参数的值,以便于查找。将子问题的解存储起来而不是重新计算的技术叫做“ 记忆化 ”。【来源:维基百科】
每次在我们的程序进行递归调用来分割剩余的字符串之前,我们都要检查这个精确的子串以前是否被分割过。如果是这样,我们只需消除递归调用,并从缓存中检索该子串的最佳分割结果(在特定子串第一次被分割时存储在缓存中)。
这种技术已经被多次用于分词:
- 彼得·诺维格的分词 Python 代码详见本书 自然语言语料库数据 章节【优美数据
- grant Jenkspython _ word segment。
- 杰昆分词
由于我在网上找不到 C#端口,下面是我对动态编程方法的实现:
WordSegmentationDP source code
三角矩阵方法
****动态规划方法使用递归和字典来记忆剩余子串的最佳分段。
****三角矩阵方法使用嵌套循环和循环数组来存储前缀子串的最佳分段。
生成长度递增的部件的三角形矩阵,组织成圆形阵列。此允许恒定的 O(1)内存消耗**(与动态编程的线性 O(n)相比),因为一旦不再需要中间分段变量,它们就会被覆盖。不是存储完整的分段串,而是仅使用潜在空间位置的位向量。这减少了存储分段变量的内存消耗**(1 位而不是 1 字符)并且垃圾收集友好。****
Triangular Matrix algorithm
以及三角矩阵方法的 C#实现:
WordSegmentationTM source code
动态规划与三角矩阵
那么,这两种方法的相同点和不同点是什么呢?
- 两种算法提供相同的结果**。**
- 两者具有相同的线性计算复杂度 O(n)。
- 两者都存储特定子串的最佳分段变量,因此只需计算一次。
- DP 连续计算特定剩余子串的所有分段变量。最好的变体是存储在缓存字典(哈希表)中的**。为了访问特定余数的分割结果,子串被用作关键字。**
- TM 在内部循环的特定位置计算特定前缀子串** 非连续的分段变量。最好的变体是存储在数组中的**。为了访问特定前缀子串的分割结果,循环位置被用作索引**。**
- TM 有一个常量内存消耗** (数组大小= O(1)= maxSegmentationWordLength),而 DP 有一个线性内存消耗 (缓存字典条目数= O(n) =输入文本长度)。**
- 此外,即使对于相同数量的条目,数组(MT)的内存消耗也低于字典(DP)的内存消耗。
- 此外,TM 仅存储潜在空间位置的位向量,而 DP 存储完整的分段串。这进一步减少了存储分段变量的内存消耗(1 位而不是 1 字符)并且垃圾收集友好。****
- 通过索引(MT)访问数组的比通过键(DP)访问缓存字典的更快。
- 两者的词频词典的查找号码类似于**。**
- 迭代通常比递归快,并防止可能的递归限制(超过最大递归深度/堆栈溢出)。
在我的基准测试中,三角矩阵方法比动态编程方法快 2 倍。它有更低的内存消耗,更好的可伸缩性,并且是 GC 友好的。****
最初我认为这两种方法完全不同。 但在比较了它们的特点后,我认为三角矩阵方法是 只是一种特殊形式的动态编程 ,它使用一个 数组代替字典 进行记忆,使用 循环代替递归 并增量优化 前缀字符串而不是
最大字长
候选单词是从最大长度的字符串中生成的。Norvig 将最大单词长度任意选择为 20。由于最长的单词是语言相关的(中文最多 6 个字符),最好从字典中存在的最长单词中导出。虽然这是试探性的,但是不太可能存在大于字典中包含的最长单词的有效真实单词。它还可以防止查找我们已经知道不在字典中的单词,并创建包含这些不存在的单词的组合。这将确保最大的分割速度。
计算的复杂性
动态规划和三角矩阵方法都有一个线性运行时间 O(n)** 来寻找最佳组合。**
文本长度 n 和运行时间的确切关系是 O(n*Min(n,最大字典字长)/ 2) 。
分段变量选择
不过,将字符串拆分成单词可能有几种有效的方法:
isit 可能是 i sit 或者是**it**
词频(或单词出现概率)用于确定最可能的分段变量。
单词 出现概率 P =字数 C /语料库规模 N
语料库大小 N 是用于生成频率词典的文本语料库中的总字数。只有当字典是完整的,n 才等于频率字典中所有计数 c 的和,但如果字典被截断或过滤,n 就不等于。
朴素贝叶斯规则
我们假设两个单词的单词概率是独立的。因此,单词组合的朴素贝叶斯概率是两个单词概率的乘积:
*P(AB)=P(A)P(B)
使用双词概率代替单字概率可以进一步提高切分质量。
对数标度
我们不是计算概率的乘积**,而是计算概率对数的**和。因为单词的概率是关于 10^-10 的,所以许多这样的小数字的乘积可能超过(下溢)浮点数的范围并变成零。****
log(P(AB))= log(P(A))+log(P(B))
已知单词
为了计算单词出现的概率,我们可以使用不同的方法:
- 通过统计大型文本语料库中的单词来创建我们自己的词频词典。如果字典来源于与你要处理的文档相似的语料库,那么相似词出现概率分布将确保最优结果**。**
- 使用包含字数的现有频率词典,例如 Google Books Ngram 数据。缺点是 Google Books Ngram 数据不仅包含有效单词,还包含拼写错误和其他片段。虽然许多拼写错误由于概率低,无论如何都不会有影响,但这并不总是有保证的。例如,常用词的频繁拼写错误可以战胜真正的稀有词。
- 词典质量对于分段质量至关重要。为了实现这一点,两个数据源可以通过交集来组合:巨大的 Google Books Ngram 数据提供了有代表性的词频**(但是包含许多有拼写错误的条目),甚至对于罕见的单词和SCOWL——面向拼写检查器的单词列表,其确保了真实的英语词汇(但是不包含在相同编辑距离内对建议进行排序所需的词频)。**
我已经决定使用变体 3,即真正的英语单词词典与来自 Google Books Ngram 语料库的词频的交集,因为即使对于罕见的单词也有相关的词频。但是与变体 1 相比的缺点是谷歌语料库来源于不同世纪的书籍**。随着时间的推移,语言的使用已经发生了变化,语言的使用在不同的领域也有所不同(如医学、法律、散文、新闻、科学)。**
未知单词
我们不能完全依赖字典。没有一本字典是完整的。有生僻词、新词、外来词、人名、品牌名、产品名、缩略语、非正式用词、俚语、拼写错误。即使对于字典中不包含的单词,我们也希望分词算法选择最可能的分词变体。
因此,我们必须估计一个词出现的概率,以未知的词。我们拥有的甚至是未知单词的信息就是它们的长度。
乔治·金斯利·齐夫观察到单词的长度和它们的频率成反比。经常使用的词,如“the”,往往很短(Zipf g . The psycho biology of Language)。Zipf 用“最小努力原则”(Zipf g . Human Behavior and the Principle of less Effort)对此进行了解释。
Peter Norvig 在《自然语言语料库数据》第 224 页中提出了以下计算未知单词概率的公式:
近似词出现概率 P=10 / (N * 10^word 长度 l)
我们必须意识到,这是一个包含启发式参数的原始估计值**,可能需要针对除英语之外的**语言进行调整。关于单词长度和词频关系的更多信息可以在 Miller,Newmann,Friedmann 的书面英语的长度-频率统计和 Strauss,Grzybek,Altmann 的 **【单词长度和词频】**中的不同语言方面找到。****
当然,我们可以想到更复杂的概率计算,例如,通过使用马尔可夫链或已知前缀和后缀来估计特定子串成为真正单词的概率。这将使正确分割连续的未知单词成为可能。
语言
分词算法本身是语言独立的**。但是词频词典是特定于语言的。为了对以某种语言编写的文本进行分词,需要该语言的频率词典。 Google Books n-gram 数据包括许多语言的词频。**
此外,如上所述,根据未知单词的长度来估计未知单词的概率的公式包含启发式参数,必须针对每种语言单独调整这些参数,以获得最佳分割结果。
分词和拼写纠正
如上所述,存在几种分词解决方案。
符号拼写。分词结合了分词和拼写纠正**。**
在切分过程中,会生成许多潜在的候选单词,所有候选单词都需要进行拼写检查,并对候选建议进行排序。
这只有通过利用 SymSpell 的极限查找速度才是可行的:
通过最大编辑距离的一个参数,我们可以控制允许多少拼写纠正。在 maxEditDistance=0 的情况下,我们有没有拼写校正的纯单词分割。在 maxEditDistance=2 的情况下,如果字典中的所有单词都在一个 Damerau-Levenshtein 编辑距离≤2 的范围内,我们就认为它们是子字符串的有效候选词。
更高的最大编辑距离允许校正更多的错误**,但是以假阳性校正和更低的分割性能为代价。实际的权衡取决于投入材料的质量。它可以使有错误的输入变得可读,但也可能给原本完美的输入带来错误。**
例 1
input: isit
Norvig segment: is it -> no spelling correction
WordSegmentation ed=0: is it -> no spelling correction
**WordSegmentation ed=1: visit -> spelling correction** LookupCompound ed=0: i sit -> no spelling correction
**LookupCompound ed=1: visit** -**> spelling correction**
例 2
input: independend
Norvig segment: in depend end -> no spelling correction
WordSegmentation ed=0: in depend end -> no spelling correction
**WordSegmentation ed=1: independent -> spelling correction** LookupCompound ed=0: independend -> no spelling correction
**LookupCompound ed=1: independent -> spelling correction**
例 3
input: whocouqdn’tread
Norvig segment: who couqdn’t read -> no spelling correction
WordSegmentation ed=0: who co uqdn’t read -> no spelling correction
**WordSegmentation ed=1: who couldn’t read -> segmentation+correction** LookupCompound ed=0: whocouqdn’tread -> more than 1 space/token
LookupCompound ed=1: whocouqdn’tread -> more than 1 space/token
*为了使 SymSpell 的算法具有可比性。分词和 Norvig 的分词相同 频词典 一直在使用。
单词分段与查找复合
SymSpell 拼写纠正和模糊搜索库附带一个方法lookup compound。它支持多单词输入字符串的复合感知自动拼写纠正,有三种情况:
- 在正确的单词中错误地插入空格导致了两个不正确的术语
- 错误地省略了两个正确单词之间的空格,导致了一个不正确的组合术语
- 有/无拼写错误的多个输入术语
拆分错误、连接错误、替换错误、换位错误、删除错误和插入错误可以混合在同一个单词中。
那么,符号之间有什么区别呢。单词切分和符号拼写。LookupCompound** ,和什么相似?**
- ****两个都可以在多词输入字符串中插入和删除空格,以及纠正拼写错误。
- LookupCompound 可以只在令牌中插入一个空格(由现有空格分隔的字符串片段)。它用于单词分段文本的拼写纠正,但可以修复偶尔丢失的空格。因为每个标记只有一个空格,所以要生成和评估的变量较少。因此,它更快,并且校正的质量通常更好。
- 分词可以在一个令牌中插入任意多的空格。因此,它也适用于没有任何空间的长字符串。缺点是速度和校正质量较慢,因为存在更多的潜在变量,需要生成、评估和从中选择。
应用
CJK 语言文本或嘈杂文本的分词是搜索引擎和搜索即服务搜索 API 的文本处理管道的一部分,在这里你必须每秒索引数千个文档。在分词甚至不是主要处理任务,而只是文本预处理中许多组件之一的情况下,您需要最快的分词算法。
源代码
分词 无拼写纠正 :
worsegmentationtm和worsegmentationdp并在 GitHub 上发布为开源在 MIT 许可下。****
分词 同 拼写更正:
WordSegmentation和lookup compound是 SymSpell 库的一部分,在 GitHub 上发布为开源在 MIT 许可下。****