训练朴素贝叶斯模型以识别电子邮件或文档的作者
“brown track and field” by Adi Goldstein on Unsplash
在这个例子中,我们使用由两个不同的人写的一组电子邮件或文档。目的是训练一个朴素贝叶斯模型,使其能够根据文档/电子邮件中使用的单词来预测是谁写的文档/电子邮件
包含本例中使用的文件的 Github 存储库可以在这里找到。文件nb_email_author.py
包含加载数据、训练模型以及查找训练和测试集预测得分的脚本。
在这里,我们解释脚本的主要部分和结果。
加载数据
脚本的第一部分加载数据。这里唯一的特殊性是‘pickle’用于反序列化原始数据文件(关于 pickle 和序列化/反序列化的更多信息,请看这个链接)。
加载两个文件,一个包含电子邮件或文档,另一个只包含电子邮件的作者。一旦我们反序列化并加载文件,我们就有两个数组(列表),一个名为words
,一个名为authors
,大小都是 17,578。words
中的每个元素都是包含电子邮件或文档的单个字符串。“authors”中的每个元素不是 0 就是 1。
像往常一样,我们使用 Scikit-learn 方法sklearn.model_selection.train_test_split
将数据分成训练集和测试集。
*from* sklearn.model_selection *import* train_test_splitfeatures_train, features_test, labels_train, labels_test = train_test_split(words, authors, *test_size*=0.1, *random_state*=10)
文本矢量化
在机器学习中处理文本时,将文本转换成易于分析和量化的数据是很常见的。
对于这一点,最常用的技术是 tf-idf 简称“词频-逆文档频”,基本反映了一个词在集合或语料库(我们的一组邮件或文档)中对一个文档(邮件)有多重要。
tf-idf 是一个统计量,随着一个单词在文档中出现的次数而增加,由语料库中包含该单词的文档数量来惩罚( Wikipedia )。
幸运的是,Scikit-learn 有一个方法可以做到这一点(sklearn.feature_extraction.text.TfidfVectorizer
)。见文档此处。
因此,我们以如下方式将此方法应用于我们的数据:
*from* sklearn.feature_extraction.text *import* TfidfVectorizervectorizer = TfidfVectorizer(*sublinear_tf*=True, *max_df*=0.5, *stop_words*='english')features_train = vectorizer.fit_transform(features_train)
features_test = vectorizer.transform(features_test)
TfidfVectorizer
设置矢量器。这里我们将sublinear_tf
改为 true,用 1 + log(tf) 代替 tf 。这解决了“一个术语在一个文档中出现二十次”不代表“一次出现的重要性的二十倍”(链接)的问题。因此降低了高频词的重要性(注意 1+log(1) = 1 ,而 1+log(20) = 2.3 )。
此外,stop_words
被设置为“英语”,因此在这种情况下,诸如“和”、“the”、“him”之类的停用词将被忽略,而max_df=0.5
意味着我们将忽略文档频率高于 0.5 的术语(即,出现该术语的文档的比例)。
接下来,我们对训练集和测试集的特征(在我们的例子中是术语或单词)进行拟合和转换。注意,对于训练集,我们使用fit_transform
,对于测试集,我们只使用transform
。
这是有意义的,因为我们希望模型通过训练集学习词汇和文档频率,然后将训练特征转换为术语-文档矩阵。对于测试集,我们只想使用学习到的文档频率(idf)和词汇将其转换为术语-文档矩阵。
让我们用一个简化的例子来看看这个是什么样子的:
假设我们有以下训练语料库,同样,每个条目代表一个文档/电子邮件:
corpus = [
"This is my first email.",
"I'm trying to learn machine learning.",
"This is the second email",
"Learning is fun"
]
现在,让我们来适应和改造它:
vectorizer = TfidfVectorizer()X = vectorizer.fit_transform(corpus)
print(X.__str__)*# <4x13 sparse matrix of type ‘<class ‘numpy.float64’>’ with 18 stored elements in Compressed Sparse Row format>*
fit_transform
返回一个稀疏矩阵:
print(X)*# (0, 10) 0.41263976171812644
# (0, 3) 0.3340674500232949
# (0, 7) 0.5233812152405496
# (0, 1) 0.5233812152405496
# (0, 0) 0.41263976171812644
# (1, 12) 0.4651619335222394
# (1, 11) 0.4651619335222394
# (1, 4) 0.4651619335222394
# (1, 6) 0.4651619335222394
# (1, 5) 0.3667390112974172
# (2, 10) 0.41263976171812644
# (2, 3) 0.3340674500232949
# (2, 0) 0.41263976171812644
# (2, 9) 0.5233812152405496
# (2, 8) 0.5233812152405496
# (3, 3) 0.4480997313625986
# (3, 5) 0.5534923152870045
# (3, 2) 0.7020348194149619*
如果我们将X
转换成一个 2D 数组,它看起来像这样(总共有 13 列,每一列代表一个单词/术语,为了简洁起见,奇数列被省略):
vocabulary = vectorizer.get_feature_names()pd.DataFrame(*data*=X.toarray(), *columns*=vocabulary).iloc[:,0::2]
TFIDF Matrix (Training Set)
print(vocabulary)*# [‘email’, ‘first’, ‘fun’, ‘is’, ‘learn’, ‘learning’, ‘machine’, ‘my’, ‘second’, ‘the’, ‘this’, ‘to’, ‘trying’]*
现在让我们假设我们有下面的“测试”文档:
test = [“I’m also trying to learn python”]
让我们转换一下,看看它:
X_test = vectorizer.transform(test)pd.DataFrame(*data*=X_test.toarray(), *columns*=vocabulary).iloc[:, 0::2]
TFIDF Matrix (Test Set)
就这样,这就是文本或文档如何被矢量化以供进一步分析的过程。
选择一组较小的特征
虽然选择一个较小的特征集并不是绝对必要的,但用太多的单词或特征来训练模型可能在计算上具有挑战性。
在本例中,我们使用 Scikit-learn 的SelectPercentile
来选择得分最高的特性(文档):
*from* sklearn.feature_selection *import* SelectPercentile, f_classifselector = SelectPercentile(f_classif, *percentile*=10)
selector.fit(features_train, labels_train)features_train = selector.transform(features_train).toarray()
features_test = selector.transform(features_test).toarray()
选择器使用f_classif
作为得分函数,计算样本的方差分析 F 值。基本上,我们选择具有最大 F 值的术语(即,在不同类别或作者中,频率均值最有可能不同的术语或单词)。这是常见的,以便选择跨类的最佳区别特征(在最初的 38,209 个单词中,我们最终得到 3,821 个)。
训练一个朴素贝叶斯模型
对于这个例子,我们使用高斯朴素贝叶斯(NB)实现(Scikit-learn 文档这里)。在以后的文章中,我们将详细讨论朴素贝叶斯背后的理论。
目前,值得一提的是,NB 是基于应用贝叶斯规则来计算一组单词(文档/电子邮件)由某人或某个类编写的概率或可能性(例如 P(“Chris”| "learn “、” machine “、” trying ",……))。
然而,没有所谓的朴素贝叶斯法则。“天真”一词的出现是由于假设特征彼此独立(条件独立),这意味着,对于我们的电子邮件分析,我们假设单词在句子中的位置是完全随机的(即,“am”或“robot”同样可能跟在单词“I”后面,这当然不是真的)。
NB 带 Scikit-learn
一般来说,用 Scikit-learn 训练机器学习模型很简单,通常遵循相同的模式:
- 初始化类模型的实例,
- 拟合训练数据,
- 预测测试数据(我们在这里省略了这一点),
- 计算训练集和测试集分数。
*from* sklearn.naive_bayes *import* GaussianNB
*from* time *import* timet0 = time()
model = GaussianNB()
model.fit(features_train, labels_train)print(f”\nTraining time: {round(time()-t0, 3)}s”)t0 = time()
score_train = model.score(features_train, labels_train)
print(f”Prediction time (train): {round(time()-t0, 3)}s”)t0 = time()
score_test = model.score(features_test, labels_test)
print(f”Prediction time (test): {round(time()-t0, 3)}s”)print(“\nTrain set score:”, score_train)
print(“Test set score:”, score_test)
结果如下:
>>> Training time: 1.601s
>>> Prediction time (train): 1.787s
>>> Prediction time (test): 0.151s
>>> Train set score: 0.9785082174462706
>>> Test set score: 0.9783845278725825
还不错!
用 Python 中的 OpenCV 训练神经网络检测手势
我如何用一个网络摄像头和一个梦想构建了类似微软 Kinect 的功能。
Gesture → Prediction → Action
您可以在这里 找到 Github 项目资源库中的 代码,或者在这里 查看 最终演示幻灯片。
灵感
想象一下,你正在为心爱的人举办生日聚会。每个人都玩得很开心,音乐在播放,派对很吵。突然,该吃生日蛋糕了!使用 Alexa 太大声了,而不是寻找你的手机或遥控器,如果你在谈话中简单地举起一只手,你的智能家居设备会识别这个手势,并关闭音乐,会怎么样?用同样的手势,你可以调暗灯光——正好可以看到生日蜡烛照亮生日男孩或女孩的脸。那不是很神奇吗?
背景
我对手势检测很好奇很久了。我记得当第一台微软 Kinect 问世时——我玩游戏、用手一挥就能控制屏幕,玩得非常开心。随着时间的推移,谷歌 Home 和亚马逊 Alexa 等设备的发布,手势检测似乎不再受到关注,而是转向了语音。尽管如此,我还是想知道,既然像脸书门户网站和亚马逊 Echo Show 这样的视频设备正在出现,它是否有可能经历一次复兴。考虑到这一点,我想看看是否有可能建立一个神经网络,它可以实时识别我的手势,并操作我的智能家居设备!
数据,和我早期的模型
我对这个想法很兴奋,并很快付诸实施,就像我从大炮中被射出来一样。我开始在Kaggle.com上使用手势识别数据库,并探索这些数据。它由 20,000 个带标签的手势组成,如下图所示。
Odd images, but labeled and plentiful.
当我读入图像时,我遇到的第一个问题是我的图像是黑白的。这意味着 NumPy 阵列只有一个通道,而不是三个通道(即,每个阵列的形状是(224,224,1))。因此,我无法将这些图像用于 VGG-16 预训练模型,因为该模型需要 RGB 3 通道图像。这是通过在图像列表上使用 np.stack,X_data:
一旦我克服了这个障碍,我就开始建立一个模型,使用一个训练测试分割,这个分割完全展示了 10 个人中的 2 个人的照片。在重新运行基于 VGG-16 架构构建的模型后,我的模型总体上获得了 0.74 的 F1 分数。这已经很不错了,平均来说,随机猜测 10 个类别的准确率只有 10%。
然而,训练模型从同质数据集中识别图像是一回事。训练它实时识别以前从未见过的图像是另一个问题。我试着调整照片的光线,使用深色背景——模仿模特训练过的照片。
我还尝试了图像增强——翻转、倾斜、旋转等等。虽然这些图像比以前做得更好,但我仍然有不可预测的——在我看来是不可接受的——结果。我有一种挥之不去的感觉,我需要重新思考这个问题,并想出一个创造性的方法来使这个项目工作。
要点:在尽可能接近它在现实世界中可能看到的图像上训练你的模型。
重新思考这个问题
我决定转向尝试新的东西。在我看来,训练数据的奇怪外观和我的模型在现实生活中可能看到的图像之间存在明显的脱节。我决定尝试建立自己的数据集。
我一直在使用 OpenCV,一个开源的计算机视觉库,我需要一个工程师的解决方案,从屏幕上抓取图像,然后调整图像的大小,并将其转换为我的模型可以理解的 NumPy 数组。我用来转换数据的方法如下:
简而言之,一旦你启动并运行相机,你就可以抓取帧,变换它,并从你的模型中得到一个预测:
让网络摄像头和我的模型之间的管道连接是一个巨大的成功。我开始思考什么是适合我的模型的理想图像。一个明显的障碍是很难将感兴趣的区域(在我们的例子中是一只手)从背景中分离出来。
提取手势
我采用的方法是任何玩过 Photoshop 的人都熟悉的——背景减除法。这是一件美好的事情!从本质上说,如果你在你的手放进去之前拍摄一张场景的照片,你可以创建一个“遮罩”,它将删除新图像中除了你的手以外的所有东西。
Background masking and binary image thresholding.
一旦我从我的图像中减去背景,我就使用二进制阈值来使目标手势完全为白色,而背景完全为黑色。我选择这种方法有两个原因:它使手的轮廓清晰明了,并且它使模型更容易在不同肤色的用户中推广。这就产生了我最终用来训练我的模型的“剪影”般的照片。
构建新数据集
既然我可以在图像中准确地检测到我的手,我决定尝试一些新的东西。我的旧模型没有很好地概括,我的最终目标是建立一个可以实时识别我的手势的模型——所以我决定建立自己的数据集!
我选择关注 5 个手势:
我有策略地选择了 4 个手势,它们也包含在 Kaggle 的数据集中,这样我可以在以后对照这些图像交叉验证我的模型。我还添加了和平手势,尽管这个手势在 Kaggle 数据集中没有类似的。
在这里,我通过设置我的网络摄像头来构建数据集,并在 OpenCV 中创建一个 click binding 来捕获和保存具有唯一文件名的图像。我试图改变框架中手势的位置和大小,这样我的模型会更健壮。很快,我就建立了一个包含 550 张剪影图片的数据集。是的,你没看错——我拍摄了 2700 多张照片。
培训新模型
然后我用 Keras & TensorFlow 构建了一个卷积神经网络。我从优秀的 VGG-16 预训练模型开始,并添加了 4 个密集层以及顶部的辍学层。
然后,我采取了不同寻常的步骤,选择在我之前尝试过的原始 Kaggle 数据集上交叉验证我的模型。这一点很关键——如果我的新模型不能推广到以前没有训练过的其他人的手的图像,那么它并不比我的原始模型好。
为了做到这一点,我对每个 Kaggle 图像应用了与应用于我的训练数据相同的变换——背景减除和二进制阈值处理。这给了他们一个我的模型所熟悉的相似的“外观”。
L, Okay, and Palm gestures from Kaggle data set after transformation.
结果
模特的表现超出了我的预期。它对测试集中的几乎每个手势都进行了正确的分类,最终得到了 98%的 F1 分数,以及 98%的精确度和准确度分数。这是个好消息!
然而,任何经验丰富的研究人员都知道,一个在实验室表现良好但在现实生活中表现不佳的模型价值不大。在我最初的模型上经历了同样的失败后,我谨慎乐观地认为这个模型将在实时手势上表现良好。
智能家居集成
在测试我的模型之前,我想添加另一个扭曲。我一直是一个智能家居爱好者,我的愿景一直是只用我的手势来控制我的 Sonos 和飞利浦 Hue 灯。为了方便地访问飞利浦 Hue 和 Sonos APIs,我分别使用了 phue 和 SoCo 库。它们使用起来都非常简单,如下所示:
使用 SoCo 通过 web API 控制 Sonos 可以说更加容易:
然后,我为不同的手势创建了绑定,以便用我的智能家居设备做不同的事情:
当我最终实时测试我的模型时,我对结果非常满意。我的模型在大部分时间里准确地预测了我的手势,我能够用这些手势来控制灯光和音乐。观看下面的视频进行演示:
我希望你喜欢这个结果!感谢阅读。你可以在推特上找到我,这里是 T1,在 T2 的领英上找到我,这里是 T3。最近,我一直在为 Databricks 写内容,用简单的术语解释复杂的主题,就像这个页面解释数据湖。最后,我定期给数据博客投稿。向前向上!
训练随机森林以识别恶性乳腺癌肿瘤
在 Sklearn Python 库中,有一组可以导入的示例数据集。在这些数据集中,有一个二元分类乳腺癌数据集,是从威斯康星州的观察中提取的。我选择为一个个人项目研究这个数据集,因为它提出了一个我认为有影响力和有趣的主题(也是练习我在数据科学方面的技能的好方法)——我的目标是训练一个分类模型来识别恶性乳腺癌肿瘤,准确率为> 95% 。数据集可以按如下方式导入:
Importing the Data Set
构建用于比较的基线模型
在对数据集进行任何分析之前,通常最好建立一个基线分类模型,该模型可以用作基准来决定机器学习模型是否有效。为了建立这个基线模型,我观察了数据集中“恶性”(标记为 1)和“良性”(标记为 0)观察值的分布。根据这些分类类别中哪一个更有可能(或发生率更高),我预测每个观察结果都属于更有可能的类别。下图显示了两个目标类别的分布情况:
Distribution of the Output Variable
从该图可以看出,大约有 350 个“恶性”观察值和大约 220 个“良性”观察值。因此,如果每个观察结果都被预测为恶性,就会创建一个大约 61%准确的模型**——这个简单的模型将被用作未来比较的基准。**
数据清理和预处理
在定义了简单的基线模型之后,我执行了一些快速的数据清理和观察,例如检查空值**,查看数据集中每个特性的数据类型,以及查看集合中观察值的总数。在这种情况下,因为数据来自 Sklearn python 库中维护的示例集,所以不需要做太多的数据清理工作。如果数据集存储在 pandas 数据框中,可以使用以下命令检查每一列中 null 值的总数:**
Checking for Null Values with Pandas
在这种情况下,在数据集中不存在空值,因此不需要替换/清除数据中的空值。此外,当检查每一列的数据类型时(使用熊猫数据框的“dtypes”属性),发现所有数据都是类型“float 64”。因此,因为所有的特征都已经是数字的,所以不必进行数据清理来创建可以直接输入到机器学习模型中的特征。这个预处理阶段唯一有趣的发现是数据集只包含 569 个观察值。这是用于训练机器学习模型的非常少量的数据,并且可能在未来产生问题(即,模型的过度拟合或缺乏准确性),因此在选择使用随机森林对数据进行分类时,这一点得到了充分的考虑(随机森林对过度拟合有很强的抵抗力,在此阅读更多关于它们的信息)。
探索性数据分析(EDA)
为了更好地理解数据集以及哪些特征可能对机器学习模型有用,进行了简单的数据分析和可视化。对数据集进行的第一个查询是可视化数据集中所有不同特征的相关性矩阵(在熊猫数据帧上使用“corr”方法计算相关性)。该关联图揭示了哪些特征为问题提供了新信息,哪些特征与集合中的其他特征相似。相关矩阵被绘制为热图,这使得数据集中各要素之间的相关性变得易于查看。看起来如下:
Correlation Heat Map for the Breast Cancer Data Set
在这种情况下,具有白色的特征对彼此高度相关,因此呈现出与问题相似的信息。例如,特征对(0,2)、(0,3)和(2,3)都高度相关。后来,当为机器学习模型选择特征时,考虑了这种高相关性,并且消除了与其他特征具有非常高相关性(> 98%)的特征。
除了可视化相关性,还对数据集中的每个特征进行了单变量分析和可视化。更具体地说,创建了特征值及其相关分类的散点图和每个目标类别的平均特征量图。单独查看每个特征的分布会使更好地理解每个目标类别之间哪些特征具有明显/可见的差异,从而揭示哪些特征在创建分类模型时会有用。这些可视化的一些结果如下:
Univariate Visualization Ex. 1
在这种情况下,特征 5 显示了两个目标分类类别之间值的明显差异,其中分类为“良性”(0)的观察值似乎比分类为“恶性”(1)的观察值更高。因此,该可视化暗示特征 5 可能是包括在最终分类模型中的有用特征。****
Univariate Visualization Ex. 2
在上面的可视化中,特征 7 似乎在两个目标类别之间具有相似的特征——散点图上 1 和 0 大致相似的位置以及相似的平均特征值。因此,这种可视化暗示了特征 7 在确定准确分类时对我们的模型可能不是那么有用。****
当决定在训练机器学习模型中使用哪个特征时,在两个目标分类类别之间表现出显著特征差异的特征被保留,而没有表现出这种差异的特征被去除。一旦排除了这些特性,就创建了一个聚合可视化(使用 seaborn python 库中的 “pairplot” 方法)来查看集合中最有趣的特性的整体属性。结果如下:
Pair Plot of Selected Features
上面的图由每个观察值的分类值着色。对于配对图中的每个特征,可以注意到,在大多数情况下,可以注意到两个目标分类类别之间的值的差异。
特征工程/选择
在数据集上执行简单的 EDA 之后,哪些特征将对机器学习模型有用变得非常清楚。因此,在选择/创建特征时没有做太多额外的工作。尝试用于自动特征选择的一些方法包括:
- 使用 Sklearn 创建多项式和交互式特征。
- 运行简单的随机森林,并根据要素对模型的重要性选择要素。
- 消除与集合中其他特征高度相关的特征。
创建多项式要素并没有提高随机森林模型的性能(精度实际上降低了)。然而,使用随机森林的“feature_importances_”属性过滤特征非常有用,并最终提高了最终模型的准确性。为了创建这样的过滤器,在现有特征集(不包括多项式特征)上训练默认随机森林,并且通过参考训练的随机森林的“feature_importances_”属性来确定每个特征的重要性。为重要性低的特征设置阈值,重要性低于重要性阈值的所有特征都从数据集中删除**。测试了几个重要性阈值,以确定哪一个性能最好,结果如下:**
Feature Filtering on Different Importance Thresholds
从上面的报告中可以看出,最佳过滤阈值是 0.008,准确率为 95.5%(高于我最初的目标!).在特征工程的最后一步之后,工作开始建立最终模型。
构建随机森林模型
对于这个实验,使用 Sklearn 随机森林分类器对数据进行分类。可以使用以下代码导入该模型并使其适合一组观察值:
Example of Constructing a Random Forest Classifier
上面的代码从 Sklearn 库中导入随机森林,用 50 棵树的大小实例化它( n_estimators 是将被构造来形成随机森林对象的决策树的数量),并使随机森林适合一组测试数据。在这个实验中,使用 Sklearn.model_selection 中的 “train_test_split” 方法将数据分成训练集和测试集,该方法根据所需的比率将数据分成训练组和测试组。当随机森林使用分区的训练和测试数据进行训练时,结果如下:
Random Forest Accuracy
从上面可以看出,50 棵决策树的随机森林在数据集上获得了 95.77% 的准确率!这超过了该实验最初设定的 95%的准确率目标。然而,在实验结束之前,对随机森林的不同数量的估计量进行了测试,以查看模型是否可以变得更加精确。此外,最高性能随机森林的精度和召回被观察以获得关于模型的整体质量的另一个度量。****
测试不同的随机森林大小
选择了 25、50、75、100、125 和 150 的随机森林大小,并测试了每个模型的准确性,以确定哪种大小的随机森林最有效。结果如下:
Accuracy with Different Forest Sizes
在上面的报告中,可以看到最准确的森林大小是 125,准确率为 96.7%!这样的准确率远远高于 95%的最初目标,因此该模型被选为表现最好的**,然后观察该模型的精确度和召回率以评估其整体质量。**
精确度和召回率
因为原始数据集有些不平衡(目标分类类别不是均匀分布的),除了准确性之外,对我的模型的质量进行度量是一种很好的做法——具有不平衡目标变量分布的模型可能会获得较高的准确性,但实际上并没有很好地拟合数据。因此,决定观察每个目标分类类别的模型的精度和召回**。如果你对这些术语不熟悉,我推荐你阅读这篇文章来更好地理解它们。与准确度一样,精确度和召回率也是评估机器学习模型有效性的一个指标。使用以下代码可以观察随机森林模型的精度和召回率:**
Code for Finding Precision and Recall
使用上述代码,评估了 125 估计量随机森林模型的精度和召回率,以获得以下结果:
Precision/Recall Score
该模型平均获得了 99%的精确度和99%的召回率,这是一个非常好的分数(1.0 是这两个分数的最高分)。观察到这一指标后,很明显随机森林分类模型与数据吻合得很好,准确率超过 96%,精确度/召回分数为 99% 。
结论
在这篇文章中,我使用 Sklearn 乳腺癌数据集建立了一个随机森林分类模型,将乳腺癌肿瘤分为“恶性”或“良性”。我最初的目标是获得一个至少 95%准确的模型。在对简单的 EDA 进行预成型以确定数据集中最重要的特征,分析各种选定特征的特征重要性,并测试不同大小的随机森林后,我得到了一个最终的模型,其准确率为 96.7% !
如果你想看看这个项目的源代码,你可以看看为它创建的 GitHub 库 !如果你有任何问题或者想关注我未来的帖子,请随时评论这篇帖子或者通过 LinkedIn 与我联系。 非常感谢您的阅读!
训练一个代理来打败网格世界
什么是网格世界?网格世界是一个大小为(Ny,Nx)的 2D 矩形网格,代理从一个网格方块开始,并试图移动到位于其他地方的另一个网格方块。这种环境是应用强化学习算法来发现网格上的代理的最佳路径和策略的自然环境,以便以最少的移动次数到达他们期望的目标网格方格。就我个人而言,我一直认为解决网格世界是开始学习强化学习的一个很好的方式,因为它直观的几何图形和它与许多现实世界应用的相关性。
在我们的网格世界实现中,我们从左上角的网格角(0,0)开始代理,目标是以最少的步数(Ny + Nx 步)到达右下角的网格角(Ny-1,Nx-1)。代理只允许在上、下、左、右方向移动 1 个方格的动作。
为了打败这个游戏,我们使用了一个策略上的蒙特卡罗平均奖励抽样的强化学习算法,以及带有一个ε贪婪代理的在网格世界环境中导航。在这个实现中使用了奖励、状态-动作值和策略的表格形式(在这里适用于小网格尺寸),上面的大部分理论可以在萨顿&巴尔托的“强化学习”教科书中找到。这个算法的 Python 代码实现可以在我的 Github 中找到:
https://github . com/ankonzoid/learning x/tree/master/classical _ RL/grid world
通过运行我们的代码,可以找到最佳策略的示例代码输出:
Final policy:
[[2 1 1 2 2 2 2]
[2 2 1 1 2 1 2]
[1 2 1 1 2 2 2]
[2 1 1 2 1 1 2]
[1 1 2 2 2 1 2]
[1 1 1 1 1 2 2]
[1 1 1 1 1 1 3]]
action['up'] = 0
action['right'] = 1
action['down'] = 2
action['left'] = 3
注意,在这种情况下不存在唯一的最优策略!只要最终训练的策略中的所有动作是“向下”或“向右”移动,那么我们将知道我们处于(非唯一的)最优策略。
在本文的剩余部分,我们将在代码中简要介绍代理和环境的组成。
更多我关于深度学习和强化学习的博客、教程、项目,请查看我的 中 和我的 Github 。
我们的 Python 代码中使用的方法的演练
我发现通过定义 4 个不同的对象类,我们可以使代码在概念上更容易理解。具体来说,这些类是:
(1)环境
(2)智能体
(3)大脑(智能体)
(4)记忆(智能体)
训练周期包括让代理通过采取行动、收集相应的奖励以及将其状态转换到其他状态来与环境进行交互。基于大脑通过处理存储在存储器中的事件的过去状态和动作历史而进行的操作,可以完成代理如何建立其未来决策。正是这种大脑和记忆的结合,提供了对什么样的状态和行动序列可以导致对代理人的高和低长期回报的评估。
问题 1: 我们如何设置环境?
我们定义了一个 2D 网格,并开始定义代理在每个网格方格*上允许的动作,即代理可以在中间方格的所有 4 个方向上移动,在网格边缘的 3 个方向上移动,在网格角落的 2 个方向上移动。*我们还将智能体的起始状态定义为坐标(0,0)对应网格的左上角,将(Ny-1,Nx-1)定义为网格右下角的终止状态。至于对代理人的奖励,我们对到达期望的目标方格给予 R=+100 的奖励,以及 R=-0.1 的奖励,以激励代理人减少过多的移动次数来达到目标。
问题 2:我们如何设置代理?
我们在这里为代理选择一个ε贪婪策略,这意味着对于每个动作决策,代理尝试完全随机动作的概率为ε(不需要代理大脑),否则它将贪婪地选择一个动作*,即 argmax{action} Q(state,action)* (需要代理大脑)。
问题 3:我们如何设置大脑?
我们初始化一个列表状态-动作值函数 Q(s,a ),它将被迭代更新以帮助代理的开发机制。回想一下,Q(s,a)表示对状态“s”应用动作“a ”,然后对剩余的状态转换遵循最优策略所收集的预期长期贴现或未贴现回报。
特别是对于我们的网格世界示例代码,我们使用一种奖励平均抽样技术作为我们的 Q(s,a)更新方法,这是一种计算 Q(s,a)的简单方法,作为当(s,a)被代理体验时收集的平均总奖励(更多细节请参考萨顿&巴尔托)。Q(s,a)更新发生在每一集之后,其中我们获取从该集收集的总报酬,并且准确地更新代理在该集期间经历的(s,a)状态-动作对的 Q(s,a)值;正是记忆储存了这些信息,供大脑处理。
问题 4:我们如何设置内存?
记忆的目的是通过记录一个情节中发生的状态、动作和奖励来帮助大脑进行计算。因此,这就像在训练期间和之后反复更新我们的计数器一样简单。
训练和可视化单词向量
用数据做酷事!
在本教程中,我想展示如何在 tensorflow 中实现 skip gram 模型,为您正在处理的任何文本生成单词向量,然后使用 tensorboard 将它们可视化。我发现这个练习非常有用,有助于我理解 skip gram 模型是如何工作的,以及在你将它们用于 CNN 或 RNNs 之前,感受一下这些向量捕捉到的关于你的文本的关系。
我在 text8 数据集上训练了一个 skip gram 模型,该数据集是英文维基百科文章的集合。我用 Tensorboard 来可视化嵌入。Tensorboard 通过使用 PCA 选择 3 个主轴来投影数据,可以让您看到整个单词云。超级爽!你可以输入任何单词,它会显示它的邻居。你也可以分离出最接近它的 101 个点。
参见下面的剪辑。
你可以在我的 Github repo 上找到完整的代码。
为了可视化训练,我还查看了与一组随机单词最接近的预测单词。在第一次迭代中,最接近的预测字看起来非常任意,这是有意义的,因为所有的字向量都是随机初始化的
**Nearest to cost:** sensationalism, adversity, ldp, durians, hennepin, expound, skylark, wolfowitz,
**Nearest to engine:** vdash, alloys, fsb, seafaring, tundra, frot, arsenic, invalidate,
**Nearest to construction:** dolphins, camels, quantifier, hellenes, accents, contemporary, colm, cyprian,
**Nearest to http:** internally, chaffee, avoid, oilers, mystic, chappell, vascones, cruciger,
训练结束时,该模型在寻找单词之间的关系方面变得更好。
**Nearest to cost:** expense, expensive, purchase, technologies, inconsistent, part, dollars, commercial,
**Nearest to engine:** engines, combustion, piston, stroke, exhaust, cylinder, jet, thrust,
**Nearest to construction:** completed, constructed, bridge, tourism, built, materials, building, designed,
**Nearest to http:** www, htm, com, edu, html, org, php, ac,
Word2Vec 和 Skip Gram 型号
创建单词向量是这样的过程,即获取大量文本并为每个单词创建向量,使得在语料库中共享共同上下文的单词在向量空间中彼此非常接近。
这些单词向量可以非常好地捕捉单词之间的上下文关系(例如,黑色、白色和红色的向量会很接近),并且我们使用这些向量代替原始单词来执行 NLP 任务(如文本分类或新文本生成)会获得更好的性能。
生成这些词向量有两种主要的模型——连续词袋(CBOW)和跳格模型。CBOW 模型试图预测给定上下文单词的中心单词,而 skip gram 模型试图预测给定中心单词的上下文单词。一个简单的例子是:
CBOW:猫吃了 _____。填空,在这种情况下,是“食物”。
跳过-gram: ___ ___ __ 食物。完成单词的上下文。在这种情况下,是“猫吃了”
如果你对这两种方法的更详细的比较感兴趣,那么请看这个链接。
各种各样的论文已经发现 Skip gram 模型可以产生更好的单词向量,所以我一直致力于实现它
在 Tensorflow 中实现 Skip Gram 模型
这里我将列出构建模型的主要步骤。请看我的 Github 上的详细实现
- 预处理数据
我们首先清理我们的数据。删除所有标点符号、数字,将文本拆分成单个单词。因为程序处理整数比处理单词好得多,所以我们通过创建一个 vocab to int 字典将每个单词映射到一个 int。代码如下。
counts = collections.Counter(words)
vocab = sorted(counts, key=counts.get, reverse=True)
vocab_to_int = {word: ii for ii, word in enumerate(vocab, 0)}
2.二次抽样
经常出现的单词,如“the”、“of”和“for ”,不会为附近的单词提供太多的上下文信息。如果我们丢弃其中一些,我们可以从数据中去除一些噪声,反过来得到更快的训练和更好的表示。这个过程被米科洛夫称为子采样。对于训练集中的每个单词,我们将根据其频率的倒数给出的概率将其丢弃。
3.创建输入和目标
skip gram 的输入是每个单词(编码为 int ),目标是该窗口周围的单词。Mikolov 等人发现,如果这个窗口的大小是可变的,并且更靠近中心单词的单词被更频繁地采样,那么性能会更好。
“由于距离较远的单词通常比距离较近的单词与当前单词的关系更小,因此我们在训练示例中通过从这些单词中抽取较少的样本来降低距离较远的单词的权重……如果我们选择窗口大小=5,则对于每个训练单词,我们将在 1 和窗口大小之间随机选择一个数字 R,然后使用当前单词的历史中的 R 个单词和未来中的 R 个单词作为正确的标签。”
R = np.random.randint(1, window_size+1)
start = idx — R if (idx — R) > 0 else 0
stop = idx + R
target_words = set(words[start:idx] + words[idx+1:stop+1])
4.构建模型
从 Chris McCormick 的博客中,我们可以看到我们将要建立的网络的大致结构。
我们将把像“蚂蚁”这样的输入单词表示为一个热向量。这个向量将有 10,000 个分量(我们词汇表中的每个单词一个分量),我们将在对应于单词“ants”的位置放置一个“1”,在所有其他位置放置 0。
网络的输出是一个单一的向量(也有 10,000 个分量),它包含我们词汇表中的每个单词,随机选择的邻近单词是该词汇表单词的概率。
在训练结束时,隐藏层将具有训练过的单词向量。隐藏层的大小对应于我们的向量的维数。在上面的例子中,每个单词都有一个长度为 300 的向量。
您可能已经注意到,skip-gram 神经网络包含大量的权重……对于我们有 300 个特征和 10,000 个单词的 vocab 的示例,隐藏层和输出层各有 3M 个权重!在大型数据集上进行这种训练是不允许的,因此 word2vec 的作者引入了一些调整来使训练可行。你可以在链接中了解更多信息。 Github 上的代码实现这些来加速训练。
5.使用 Tensorboard 可视化
您可以使用 Tensorboard 中的嵌入投影仪来可视化嵌入。为此,您需要做几件事:
- 在培训结束时,将您的模型保存在检查点目录中
- 创建一个 metadata.tsv 文件,将每个 int 映射回 word,以便 Tensorboard 显示单词而不是 int。将这个 tsv 文件保存在同一个检查点目录中
- 运行以下代码:
from tensorflow.contrib.tensorboard.plugins import projector
summary_writer = tf.summary.FileWriter(‘checkpoints’, sess.graph)
config = projector.ProjectorConfig()
embedding_conf = config.embeddings.add()
# embedding_conf.tensor_name = ‘embedding:0’
embedding_conf.metadata_path = os.path.join(‘checkpoints’, ‘metadata.tsv’)
projector.visualize_embeddings(summary_writer, config)
- 通过将 tensorboard 指向检查点目录来打开它
就是这样!
给我一个❤️,如果你喜欢这个职位:)希望你拉代码,并尝试自己。如果你对这个话题有其他想法,请在这篇文章上发表评论,或者给我发邮件,地址是 priya.toronto3@gmail.com
其他著述:http://deeplearninganalytics.org/blog
PS:我有自己的深度学习咨询公司,喜欢研究有趣的问题。我已经帮助几家初创公司部署了基于人工智能的创新解决方案。请到 http://deeplearninganalytics.org/来看看我们。
如果你有一个我们可以合作的项目,请通过我的网站或 priya.toronto3@gmail.com 联系我
参考文献:
- Udacity 深度学习纳米度
训练深度神经网络
深度学习配件
深度神经网络是计算机视觉和语音识别领域的关键突破。在过去的十年里,深度网络使机器能够识别图像、语音,甚至以人类几乎不可能的精度玩游戏。为了达到高水平的准确性,需要大量的数据和计算能力来训练这些网络。然而,尽管涉及到计算的复杂性,我们可以遵循某些准则来减少训练的时间和提高模型的准确性。在本文中,我们将介绍其中的一些技术。
数据预处理
数据预处理的重要性只能通过这样一个事实来强调,即您的神经网络仅与用于训练它的输入数据一样好。如果重要的数据输入丢失,神经网络可能无法达到所需的精确度。另一方面,如果数据没有被预先处理,它会影响网络的准确性和性能。
均值减法(零居中)
这是从每个数据点中减去平均值使其以零为中心的过程。考虑神经元(单元)输入全为正或全为负的情况。在这种情况下,反向传播期间计算的梯度将是正的或负的(与输入的符号相同)。因此参数更新只限于特定方向,这反过来会使收敛效率低下。
Mean subtraction (Zero centering the data)
数据正常化
归一化是指将数据归一化,使其在所有维度上具有相同的尺度。通常的方法是将每个维度的数据除以其标准偏差。然而,只有当你有理由相信不同的输入特征具有不同的尺度,但它们对学习算法具有同等的重要性时,这才有意义。
Normalization of data across both dimensions
参数初始化
深度神经网络对数百万或数十亿的参数并不陌生。这些参数的初始化方式可以决定我们的学习算法收敛的速度以及最终的精确度。最直接的方法是将它们全部初始化为零。然而,如果我们将层的权重初始化为全零,则对于层中的每个单元,计算的梯度将是相同的,因此对于所有单元,权重的更新将是相同的。因此,该层与单个逻辑回归单元一样好。
当然,我们可以通过用一些小随机数初始化权重来做得更好。不是吗?好吧,让我们用一个 10 层深度神经网络来分析这个假设的有效性,每个神经网络由 500 个单元组成,并使用双曲正切激活函数。【在继续下一步之前,请注意 tanh 激活】。
Tanh activation function
左边是 tanh 激活函数的图。随着我们继续进行,有几个要点需要记住:-
- 该激活以零为中心。
- 输入为大正数或大负数时饱和。
首先,我们从具有零均值和 1 e-2 标准偏差的标准高斯初始化所有权重。
**W = 0.01 * np.random.randn(fan_in, fan_out)**
不幸的是,这仅适用于小型网络。为了了解它对更深层次的网络造成了什么问题,用不同的参数生成了图。随着我们深入网络,这些图描绘了每一层的平均值、标准偏差和激活度。
Mean, standard deviation and activation across layers
注意,平均值总是在零附近,这很明显,因为我们使用的是以零为中心的非线性。然而,随着我们深入网络,标准差逐渐缩小,直到它崩溃为零。这也是显而易见的,因为我们在每一层用非常小的权重乘以输入。因此,计算的梯度也将非常小,因此对权重的更新将可以忽略。
嗯不太好!!!接下来让我们尝试用非常大的数字初始化权重。为此,让我们从均值和标准差为零的标准高斯样本中抽取权重作为 1.0 (而不是 0.01 )。
**W = 1.0 * np.random.randn(fan_in, fan_out)**
下图显示了所有层的平均值、标准偏差和激活度。
Mean, standard deviation and activation across layers
请注意,每一层的激活要么接近 1,要么接近-1,因为我们将输入乘以非常大的权重,然后将其馈送到 tanh 非线性(挤压到+1 到-1 的范围)。因此,当 tanh 在这些区域饱和时,计算的梯度也将非常接近于零(导数为零)。最后,对重量的更新也几乎可以忽略不计。
实际上, Xavier 初始化用于初始化所有层的权重。Xavier 初始化背后的动机是以这样一种方式初始化权重,使得它们不会在 tanh 激活的饱和状态中结束,即使用不太小也不太大的值进行初始化。为了实现这一点,我们在从标准高斯随机采样的同时,根据输入的数量进行缩放。
**W = 1.0 * np.random.randn(fan_in, fan_out) / np.sqrt(fan_in)**
然而,这在假设 tanh 用于激活的情况下工作得很好。如果有其他激活功能,例如 ReLu,这肯定会中断。毫无疑问,正确的初始化仍然是一个活跃的研究领域。
批量标准化
这与我们到目前为止所讨论的内容有些关联。请记住,我们在将输入输入到我们的网络之前对其进行了标准化。这样做的一个原因是考虑到网络中由协方差偏移引起的不稳定性。
它解释了为什么即使在学习了从一些输入到输出的映射之后,我们还需要重新训练学习算法,以便在输入的数据分布改变的情况下学习从相同的输入到输出的映射。
然而,这个问题并没有在这里得到解决,因为数据分布在更深的层中也可能发生变化。每一层的激活会导致不同的数据分布。因此,为了增加深度神经网络的稳定性,我们需要通过减去平均值并除以标准偏差来标准化每一层的数据*。有一篇文章对此进行了深入的解释。*
正规化
训练深度神经网络最常见的问题之一是*过拟合。*当你的网络在训练数据上表现出色,但在测试数据上表现不佳时,你就会意识到过度拟合。这是因为我们的学习算法试图拟合输入中的每个数据点,即使它们代表一些随机采样的噪声,如下图所示。
正则化通过惩罚网络的权重来帮助避免过度拟合。为了进一步解释,考虑为神经网络上的分类任务定义的损失函数如下:
Loss function
**J(theta) - Overall objective function to minimize.
n - Number of training samples.
y(i) - Actual label for ith training sample.
y_hat(i) - Predicted label for ith training sample.
Loss - Cross entropy loss.
Theta - Weights of neural network.
Lambda - Regularization parameter.**
请注意,正则化参数 (lambda)如何用于控制权重对最终目标函数的影响。因此,在λ取非常大的值的情况下,网络的权重应该接近于零,以便最小化目标函数。但是,当我们让权重崩溃为零时,我们会抵消层中许多单元的影响,因此网络并不比具有几个逻辑回归单元的单个线性分类器好。出乎意料的是,这将把我们扔进所谓的欠拟合状态,这并不比过拟合好多少。显然,我们必须非常小心地选择λ的值,以便最终我们的模型落入平衡类别(图中的第三个图)。
辍学正规化
除了我们所讨论的,还有一种更强大的技术来减少深度神经网络中的过拟合,称为退出正则化。
关键思想是在训练网络时随机丢弃单元,以便我们在每次迭代中使用更小的神经网络。丢弃一个单元等同于在向前传播或向后传播期间忽略那些单元。在某种意义上,这阻止了网络适应一些特定的特征集。
在每次迭代中,我们会从网络中随机删除一些单元。因此,我们强迫每个单位不要依赖(不要给高权重)前一层的任何特定单位,因为它们中的任何一个都可能随机爆炸。这种分散权重的方式最终会缩小单个单元级别的权重,类似于我们在 L 2 正则化中所讨论的。
大部分内容可以归功于
[## 斯坦福大学 CS231n:用于视觉识别的卷积神经网络
计算机视觉在我们的社会中已经变得无处不在,在搜索、图像理解、应用程序、地图绘制…
cs231n.stanford.edu](http://cs231n.stanford.edu/)
请通过您的评论让我知道文章中需要的任何修改/改进。
使用谷歌合作实验室训练甘斯!
在我们开始之前,我只想让读者明白,这篇文章旨在做两件事:
- Google Colab 入门(及其免费的 K80 GPUs😛)
- 训练一个生成性的对抗网络(即使你是深度学习的新手或不熟悉,也没关系,只要享受输出就好了……哦,孩子😈)
现在,你已经知道的是什么,让我们直接进入主题:
什么是谷歌联合实验室?
如果你的电脑中没有足够好的 GPU 或 CPU,那么现在合作实验室是你最好的选择。
Colaboratory 是 Google 的免费 Jupyter 笔记本环境,不需要设置,完全在云中运行。通常缩写为“ *Colab”,*这是目前可用的最佳选择。它完全免费使用,并且已经安装了许多 Python 库和包。它还在笔记本本身提供了一个终端接口,你可以通过 pip 安装任何其他的库。
Colab 由强大的 K80 GPUs 支持,也支持本地运行时。这使得它比 Paperspace 或 AWS 等任何其他云平台都更好。
所以现在就去拿你的 Google Colab 笔记本吧!😸
编辑描述
colab.research.google.com](https://colab.research.google.com/)
什么是‘生成性对抗网络’?
生成对抗网络(GANs)是深度学习中的下一个大事件。顾名思义,GAN 是各种深度学习模型的组合( s ),这些深度学习模型试图相互竞争,以满足任何深度学习项目中最基本的需求: 生成 更多数据以在上训练😛。
在这里,我们将训练一个由两个模型组成的 GAN:
- 发电机。(它将试图从现有数据中生成伪造数据,并最终试图欺骗侦探,使其相信这是真实数据)
- 鉴别器。(这将是我们的侦探😃试图找出生成器生成的伪造数据)
这两个模型相互竞争,将会给我们最好的可能的 新的 和 看不到的 数据。
如果您对深度学习更感兴趣,并且需要关于什么是 GAN 的更多细节,您可以稍后关注这篇文章:
从无到有创造一些东西是最伟大的感觉之一,…简直是天堂。
medium.com](https://medium.com/@jonathan_hui/gan-whats-generative-adversarial-networks-and-its-application-f39ed278ef09)
我们自己培养一个甘吧!
从现在开始,我们的讨论将遵循我的 Colab 笔记本的内容,您可以在这里找到:
编辑描述
colab.research.google.com](https://colab.research.google.com/github/rajaswa/Google_Collaboratory_Projects/blob/master/Digit_Generation_by_GAN.ipynb)
这个笔记本已经实现了所有代码,并且已经运行过一次。您可以使用自己的笔记本从头开始,也可以一步一步地运行笔记本中的单元。
#第一步:
Google Colab 没有这个项目的一些依赖项。所以我们将使用 colab 中的终端接口通过 pip 安装它们。(运行前三个单元格)
Installing Pytorch, torchvision and tensorboardX via pip (run first three cells to install them)
只是为了确保您确实从 Colab 获得了 GPU 支持,运行笔记本中的最后一个单元格(上面写着: *torch.cuda.is_available。*如果它返回一个 假 值,那么从顶部菜单改变运行时设置
#第二步:
接下来,让我们导入所有需要的库并创建一个 logger 类,它将帮助我们监控我们的训练进度。(这并不重要,如果您没有完全理解 logger 类中正在做什么也没关系)
#第三步:
我们将在这里使用的数据集是 MNIST 手写数字图像数据集。因此,让我们创建数据集类,下载数据集并初始化数据加载器,数据加载器将迭代地向模型提供数据。
#第四步:
现在,让我们创建生成器和鉴别器模型。这些将是 3 层深度神经网络,在每个隐藏层中具有顺序->线性->泄漏 ReLU 函数。
#第五步:
接下来,让我们创建噪声采样器(我们将馈送给生成器),初始化优化器,初始化损失函数(我们使用 BCE 损失进行生成器和鉴别器之间的最小-最大对抗游戏)。我们还将定义一些函数,这些函数将在以后帮助我们定位或标记真假图像。
然后,让我们为生成器和鉴别器模型定义训练函数。
#第六步:
最后,让我们交叉手指,开始训练吧!😃
注意:众所周知,Colab 在 PIL 模块方面存在一些问题。如果出现任何与 PIL 相关的错误,只需重启内核,并使用顶部菜单中的运行时选项重新运行所有单元。
在这里,我们应该在 Colab 上训练 200 个纪元,大约需要 1.5-2 小时。笔记本已经训练了 139 个纪元,我们可以清楚地看到它在短短的 139 个纪元中提供了什么输出。你可以前进,训练它完成 200 个历元,以得到完美书写的数字。
#输出:
最初,输出几乎都是有噪声的图像,但是几个时期之后,你会看到模型开始学习手写数字的模式:(从左到右,学习的进度)
那么,我们实际上取得了什么呢?
到目前为止,我们已经看到了如何轻松地使用 Google Colaboratory,以及如何使用 Colaboratory 的 GPU 支持来实现基本的 GAN。我希望这个小项目已经让你有足够的信心在 Colab 笔记本上编写代码、安装外部库、下载数据等。
几个小时的训练有什么结果?
正如我们可以在训练单元的输出中看到的,通过训练这个 GAN,我们得到了全新的手写图像。这里要注意的最重要的一点是,这些新形成的图像是 而不是从实际数据集中复制的 (正如我们的侦探,鉴别者所确保的)。
相反,它们是由生成器模型生成的原始图像。所以,这些是我们甘培训前从未见过的新图像。😏**
所有这些与人工智能有一点点联系吗?无论如何,生成模型有什么特别之处吗?
为了通俗地提出这一点,让我们通过一个例子来看这个……
既然我们在这里使用了手写数字数据,让我们考虑这样一种情况:你希望你的人工智能尽可能有效地读取、识别和正确分类人类手写数字。为了实现这一点,你需要你的模型事先查看尽可能多的手写数字,也就是尽可能多的不同书写风格的手写数字。那么,你想如何获得更多的这些原始手写数字图像呢?是通过一个人一个人地跑,让他们都写下所有的数字,最终手动收集成千上万的图像还是通过让 GAN 在几个小时内为你生成原始图像?😏**
你可以想象,这是一个非常简单的例子,有一个深度学习的数据集😛对于庞大而复杂的数据,生成模型的优势被进一步放大。
在 GAN 开发的最初几年,我们取得了令人瞩目的进展。再也没有邮票大小的面部照片了…
medium.com](https://medium.com/@jonathan_hui/gan-some-cool-applications-of-gans-4c9ecca35900)*
我希望这对你来说是一次有趣的经历。如果你还没有开始深度学习,我相信这本书已经让你渴望并有动力开始你的人工智能之旅,如果你还没有使用 Google Colab,我相信你现在会自信地开始使用它!😃
干杯!
快乐编码!
如果你觉得这很有趣,你可以联系我,在这里找到我在 Github 上的其他作品。
你可以在 LinkedIn 这里和我联系。
使用 CPU 上的自定义图像训练初始状态
使用 Tensorflow 使用您自己的图像进行训练
在我之前的帖子中,我们看到了如何在 CPU 上使用 Python API 使用 TensorFlow 进行图像识别,而无需任何培训。我们使用的是 Inception-v3 模型,它已经被谷歌在 1000 个类上训练过,但是如果我们想用我们自己的图像做同样的事情呢。我们将使用迁移学习,这将帮助我们重新培训已经培训过的 Inception-v3 模型的最后一层,从头开始添加新的类别。在笔记本电脑上大约需要 30 分钟,没有任何 GPU。要了解更多信息,请参考这个链接或者那些只想要 linux 命令的人去他的链接。
我们将在 tensorflow 托管的免费下载的花卉数据上训练模型。在我们开始之前,让我们在我的 CPU 上对一个随机的蒲公英图像做一个测试。
结果是…
我们将使用 Python 3 和 TensorFlow 1.4
如果您的 tensorflow 不是最新的,请使用以下命令进行更新。
pip install --upgrade tensorflow
数据集的训练可以仅通过如下 4 个步骤来完成:
1.下载面向诗人的张量流-2
先新建一个文件夹 *Flowers_Tensorflow。*现在在这里打开命令提示符并键入…
git clone https://github.com/googlecodelabs/tensorflow-for-poets-2
这将从 you Flower_Tensorflow 文件夹中的 tensorflow 存储库中下载“tensor flow-for-poets-2”文件夹。
这个文件夹包含脚本、tf_folder 等文件。
2.下载数据集
去这个链接下载花数据。然后从文件夹中提取“flower_photos”文件夹。tgz 文件,并将其粘贴到 tf_files 文件夹中。这个文件夹包含 5 类雏菊,蒲公英,玫瑰,向日葵,郁金香和一个 LICENSE.txt 文件。
3.重新训练模型
在“tensorflow-for-poets-2”文件夹中打开命令提示符,然后键入
*python scripts/retrain.py --output_graph=tf_files/retrained_graph.pb --output_labels=tf_files/retrained_labels.txt --image_dir=tf_files/flower_photos*
注意:这是一行。只需从上面复制完整的东西,并粘贴到命令提示符。
按回车键后,程序将开始创建。C:/tmp/through/roses 等中的 txt 文件。它将产生大约 7300 个瓶颈。txt 文件,看起来像这样。
在这之后,它将开始训练并完成大约 4000 步,就像这样…
当您的计算机正在对新的花卉数据集进行训练时,让我分解命令并解释我们刚刚做了什么…
整个命令可以分为 4 个部分
调用/运行 retrain.py 脚本。
*python scripts/retrain.py*
在 tf_files 文件夹下新建一个图形文件(训练完成后)。
*--output_graph=tf_files/retrained_graph.pb*
在 tf_files 文件夹下新建一个标签文件(训练完成后)。**
*--output_labels=tf_files/retrained_labels.txt*
指向花卉数据集目录。
*--image_dir=tf_files/flower_photos*
注意:您可以在上面的命令中添加/更改参数
更改除 Inception-v3 之外的型号 Mobilenet 型号
***--architecture mobilenet_1.0_224***
张量板
***--summaries_dir=tf_files/training_summaries/${write the architecture here}***
改变瓶颈目录
***--bottleneck_dir=tf_files/bottlenecks***
改变训练步骤
***--how_many_training_steps=500***
4.测试新训练的模型
要测试该模型,只需下载任何图像并粘贴到“tensorflow-for-poets-2”中,然后键入(其中image.png是文件的名称)。**
***python scripts/label_image.py --image image.png***
但是您可能会得到一个错误。
要解决此错误,请打开脚本文件夹中的 label_image.py 文件。
转到第 74 行并更改数值或转到此链接。
改变:
***input_height = 224
input_width = 224
input_mean = 128
input_std = 128
input_layer = "input"***
收件人:
***input_height = 299
input_width = 299
input_mean = 0
input_std = 255
input_layer = "Mul"***
现在,我们已经作出了改变,让我们这样做在其他花卉。
菊花
玫瑰
向日葵
郁金香
好了,让我们停止吧。找了这么多花我都想吐了…
如果你想在移动平台上对一个视频直播进行同样的实验。
在 Android 和 iOS 上
towardsdatascience.com](/tensorflow-on-mobile-tutorial-1-744703297267)
但是先鼓掌这个!!!***
我已经尽力让文章尽可能准确易懂。有什么意见,建议或者有什么问题,写在评论里吧。
关注我中、脸书、推特、 LinkedIn 、 Google+ 、 Quora 看类似帖子。
鼓掌吧!分享一下!跟我来。
乐意帮忙。荣誉………
你会喜欢的以前的故事:
3. TensorFlow 图像识别 Python API 教程 CPU 上
免费在线训练机器学习模型(GPU,TPU 启用)!!!
在大数据集上训练机器学习和深度学习模型所需的计算能力,一直是机器学习爱好者的巨大障碍。但是有了运行在云上的 jupyter notebook,任何有学习热情的人都可以训练并取得很好的成绩。
在这篇文章中,我将提供关于各种服务的信息,这些服务为我们训练模型提供了计算能力。
- Google Colab
- 凯格尔内核
- 关于 GCP 的朱庇特笔记本
- 亚马逊 SageMaker
- Azure 笔记本
1)Google Colab
Colaboratory 是谷歌的一个研究项目,旨在帮助传播机器学习教育和研究。Colaboratory (colab)提供免费的 Jupyter 笔记本环境,不需要设置,完全在云中运行。它预装了大多数机器学习库,它是一个完美的地方,你可以即插即用,尝试那些不存在依赖性和计算问题的东西。
笔记本连接到你的 google drive,所以你可以随时访问它,也可以从 github 上传或下载笔记本。
GPU 和 TPU 使能
首先,你需要为笔记本电脑启用 GPU 或 TPU。
导航至编辑→笔记本设置,并从硬件加速器下拉列表中选择 TPU。
用于检查 TPU 是否已启用的代码
import os
import pprint
import tensorflow as tfif ‘COLAB_TPU_ADDR’ not in os.environ:
print(‘ERROR: Not connected to a TPU runtime; please see the first cell in this notebook for instructions!’)
else:
tpu_address = ‘grpc://’ + os.environ[‘COLAB_TPU_ADDR’]
print (‘TPU address is’, tpu_address)with tf.Session(tpu_address) as session:
devices = session.list_devices()
print(‘TPU devices:’)
pprint.pprint(devices)
安装库
Colab 安装了大多数 ml 库,但是您也可以轻松地添加没有预安装的库。
Colab 支持pip
和apt
包管理器。
!pip install torch
apt 命令
!apt-get install graphviz -y
这两个命令在 colab 中都有效,别忘了还有**!**(感叹句)在命令之前。
上传数据集
有许多方法可以将数据集上传到笔记本
- 用户可以从本地机器上传文件。
- 从 google drive 上传文件
- 人们也可以直接从 kaggle 上传数据集
从本地上传的代码
from google.colab import files
uploaded = files.upload()
您可以浏览并选择文件。
从 google drive 上传文件
PyDrive 库用于从 google drive 上传文件
!pip install -U -q PyDrivefrom pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials# 1\. Authenticate and create the PyDrive client.
auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)# PyDrive reference:
# [https://gsuitedevs.github.io/PyDrive/docs/build/html/index.html](https://gsuitedevs.github.io/PyDrive/docs/build/html/index.html)# 2\. Create & upload a file text file.
uploaded = drive.CreateFile({'title': 'Sample upload.txt'})
uploaded.SetContentString('Sample upload file content')
uploaded.Upload()
print('Uploaded file with ID {}'.format(uploaded.get('id')))# 3\. Load a file by ID and print its contents.
downloaded = drive.CreateFile({'id': uploaded.get('id')})
print('Downloaded content "{}"'.format(downloaded.GetContentString()))
你可以得到你想要上传的文件的 id,并使用上面的代码。
获取更多资源从谷歌服务上传文件。
从 kaggle 上传数据集
我们需要安装 kaggle api 并添加认证 json 文件,可以从 kaggle 网站下载(API_TOKEN)。
!pip install kaggle
通过从本地机器上传文件,将 json 文件上传到笔记本。
创建一个/。kaggle 目录
!mkdir -p ~/.kaggle
将 json 文件复制到 kaggle 目录
更改文件权限
!cp kaggle.json ~/.kaggle/
!chmod 600 ~/.kaggle/kaggle.json
现在,您可以使用命令从 kaggle 下载任何数据集
kaggle datasets download -d lazyjustin/pubgplayerstats
现在你可以使用下面的方法从 kaggle 下载比赛数据,但是你必须参加比赛。
!kaggle competitions download -c tgs-salt-identification-challenge
在这里你可以在线培训和运行 fashion_mnist,没有任何依赖性。
对于每个对机器学习感兴趣的人来说,Colab 是一个很棒的工具,所有使用 colab 的教育资源和代码片段都在官方网站上提供,并附有笔记本示例。
2)Kaggle 核
Kaggle Kernels 是一个云计算环境,支持可重复的协作分析。
人们可以在 kaggle 内核中运行 Python 和 R 代码
Kaggle 内核运行在远程计算环境中。他们提供所需的硬件。
在撰写本文时,每个内核编辑会话都提供有以下资源:
CPU 规格
4 个 CPU 内核
17gb 内存
6 小时执行时间
5gb 自动节省的磁盘空间(/kaggle/working)
16gb 的临时暂存磁盘空间(外部/ka ggle/工作)
GPU 规格
2 个 CPU 内核
14 千兆字节内存
运行中的内核
一旦我们在kaggle.com创建了一个账户,我们就可以选择一个数据集来玩,只需点击几下鼠标,就可以运行一个新的内核。
点击创建新内核
你将拥有 jupyter 笔记本。底部是您可以使用的控制台,右侧是各种选项,如
版本
当你提交和运行一个内核时,你在一个独立于你的交互会话的会话中从上到下执行内核。一旦完成,您将生成一个新的内核版本。内核版本是您工作的快照,包括您编译的代码、日志文件、输出文件、数据源等等。内核的最新版本是在内核查看器中显示给用户的。
数据环境
当您为数据集创建内核时,数据集将被预加载到笔记本的输入目录中
../input/
您也可以点击添加数据源,添加其他数据集
设置
**分享:**你可以把你的内核私有,也可以把它公开,让别人可以学习你的内核。
添加 GPU: 你可以在你的内核中添加单个 NVIDIA Tesla K80。与本地机器或您自己的虚拟机相比,使用内核的一个主要好处是内核环境已经预先配置了 GPU 就绪的软件和软件包,这可能非常耗时,而且设置起来令人沮丧。要添加 GPU,请从内核编辑器导航到“设置”窗格,然后单击“启用 GPU”选项。
自定义包:内核有默认的包,如果你需要任何其他的包,可以通过以下方式轻松添加
- 只要输入库名,kaggle 就会为你下载。
- 输入用户名/回购名称
这两种方法都能很好地添加定制包。
Kaggle 是一个完美的平台,既可以提供数据,也可以通过计算来处理提供的大量数据。它还举办各种比赛,人们可以尝试提高自己的技能。
更多关于 kaggle link 的资源请点击这里。如果你是 kaggle 的新手,你绝对应该尝试一下泰坦尼克号数据集它有很棒的教程。
其他关于 kaggle、colab 和机器学习的资源关注 Siraj Raval 和Yufeng。
由于我无法在这篇文章中涵盖在线培训 ml 模型的所有服务,这篇文章将有第 2 部分。
学习和练习机器学习所需的所有资源都是开源的,可以在线获得。从计算、数据集、算法到各种高质量的在线免费教程,你需要的只是一个互联网连接和学习的热情。
感谢你一直读到最后,我希望这篇文章会有用,因为它解决了那些开始走向机器学习和数据科学的人所面临的主要问题。如果你喜欢这篇文章,请让我知道,为文章鼓掌。欢迎查询,您可以关注我在maithreyan surya中的帖子,也可以在这里给我发邮件。
有效使用 Colab 的视频简介:https://www.youtube.com/playlist?list = pl 9 a 4 goxnjut 3 qyy 56 ay 6 q 9 z B2 nm 4c Q3 tu
机器学习有潜力改变世界,你也一样。
培训 MXNet 第 4 部分:分布式培训
在第 3 部分中,我们使用了 CIFAR-10 数据集,并学习了如何调整优化参数。我们最终使用一个 g2.8xlarge 实例的所有 4 个 GPU 训练了一个 110 层的 ResNext 模型……这花了大约 12 个小时。
在本文中,我将向您展示如何使用多个实例来显著加快训练速度。系好安全带。
Training CIFAR-10 on 4 instances and 32 GPUs. Read on!
创建主节点
我们将使用运行深度学习 AMI 、 Ubuntu edition 的 p2.8xlarge 实例。然而,您可以很容易地用任何类型的 EC2 实例或者甚至在您办公桌下运行的一堆 PC 上复制这一点:)
让我们开始吧。我们将按照我们喜欢的方式配置主节点,然后我们将克隆它以向我们的 MXNet 集群添加更多实例。第一步是转到 EC2 控制台的市场部分,找到深度学习 AMI。
然后,选择您想要使用的实例类型。请注意实例成本:一个 p2.8xlarge 每小时的成本是 7.20 美元。不要担心,您实际上可以使用任何实例类型,因为 MXNet 能够使用实例的 CPU 或 GPU。很明显,GPU 实例会比 t2.micros 快很多:)
再点击几下就完成了。只需确保 SSH 端口是打开的,并且您已经为实例创建了一个新的密钥对(姑且称之为 ec2 )。几分钟后,您可以使用 ubuntu 用户(不是 ec2-user )进入主节点。
在 MXNET 中启用分布式培训
默认情况下,在源代码发行版中没有启用分布式培训,这意味着我们可能必须从源代码中重新构建 MXNet。如果您的构建已经包括分布式培训,您可以跳过这一部分。
深度学习 AMI 包括 MXNet 源代码:我们只需将它们变成我们自己的,并刷新到最新的稳定版本( 0.9.5 在撰写本文时)。
然后,我们需要配置我们的构建选项。最后一个实际上实现了分布式训练。
现在我们可以构建和安装库了。不需要添加依赖项,因为它们已经包含在 AMI 中了。我在 32 个内核上运行并行 make,因为这是 p2.8xlarge 所拥有的。
一旦安装了这个库,运行一个快速的 Python 检查是一个好主意。
好的,这个看起来不错。我们继续吧。
为分布式培训打开端口
主节点和工作节点需要相互通信以共享数据集以及训练结果。因此,我们需要改变我们的安全组的配置来允许这样做。
做到这一点最简单的方法是允许 MXNet 集群实例之间的所有 TCP 通信,即使用相同安全组的实例。
为此,请转到 EC2 控制台,编辑主节点的安全组的入站规则。添加一条规则,允许所有 TCP 流量,并使用安全组的实际名称限制源流量。
我们的实例现在已经准备好了。让我们创建工作节点。
创建工作节点
我们将基于主节点创建一个新 AMI 。然后,我们用它来发动工人。在 EC2 控制台中找到您的实例并创建一个映像。
几分钟后,您将在 EC2 控制台的“Images”部分看到新的 AMI。您现在可以使用它来启动您的工作节点。
这里没有什么复杂的:选择您想要启动的实例类型、实例的数量(在我的例子中是 3 个)和与主节点相同的安全组**。**
再过几分钟,您的实例就准备好了。
很可爱。记下每个实例的私有 IP 地址,我们马上会用到它们。
配置集群
让我们登录到主节点,移动到工具目录并查看启动器。
这是我们将用来在所有节点(包括主节点)上开始训练的工具。它做两件事:
- 使用 rsync,在每个节点上复制 /tmp/mxnet 中的数据集。或者,我们可以通过与自制的 NFS 或亚马逊 EFS 共享节点上的数据集来避免这种情况。
- 使用 ssh,运行开始训练的 python 脚本。如您所见,其他协议也是可用的,但我们今天不讨论它们。
创建主机文件
launch.py 需要在一个文件中声明所有节点(包括主节点)的私有 IP 地址。它应该看起来像这样。
配置 SSH
我们需要主节点和工作节点之间的无密码 ssh 访问。如果您已经准备好了,可以跳过这一部分。
为了简单起见,我们将在本地计算机上创建一个新的密钥对,并在集群中分发它。
请不要重复使用 ec2 密钥对,这是不好的做法。另外,有些人可能想在 AMI 中烘焙密钥对,以避免将它分发给所有实例,但是我建议不要这样做,因为这意味着将私钥存储在所有节点上,而不仅仅是主节点上。还有宋承宪代理转发也不好。
接下来,还是从我们的本地计算机,我们将把公钥复制到所有节点(包括主节点),只把私钥复制到主节点。
最后,在主节点上,我们将启动 ssh-agent 并添加 mxnet 身份。
现在,您应该能够从主节点登录到每个工作节点(包括主节点本身)。在继续之前,请确保此功能正常工作。
如果是的话,你已经准备好训练了,伙计:)
开展分布式培训
下面是这个神奇的命令: hosts 文件中列出的 4 个节点将通过 rsync 接收一份 /tmp/mxnet 中数据集的副本。然后,主节点将在每个节点上运行 train_cifar10.py 脚本,在所有 8 个 GPU 上训练一个 110 层的 ResNext 模型。
如果您运行在 CPU 实例上,只需删除 GPU 参数。
PS_VERBOSE 变量将输出额外的信息。万一出了问题,非常有用;)
您可以通过登录不同的节点并运行’ nvidia-smi -l '命令来检查进度。
那么这有多快呢?正如我之前提到的,在一个 g2.8xlarge 实例的 4 个 GPU 上运行 300 个 epochs 需要大约 12 个小时。4 个 p2.8xlarge 实例的 32 个 GPU 加起来用了 91 分钟!
这是一个8 倍的加速,这是有道理的,因为我们有8 倍多的 GPU。我曾经读到过,现在我亲眼看到了:确实是线性缩放!这让我想把它推到 256 个 GPU:毕竟它只需要 16 个 p 2.16 大:D
最后但同样重要的是,我的同事 Naveen Swamy 和 Joseph Spisak 写了一篇非常有趣的博文,讲述了如何使用 AWS CloudFormation 自动完成大部分工作。如果你在 AWS 中运行所有的东西,这绝对值得一读。
今天到此为止。非常感谢你的阅读和最近给我的友好支持。这对我意义重大!
接下来:
使用循环学习率从头开始训练对象检测(YOLOv2)
对象检测的任务是识别图像中的所有对象以及它们的类别标签和边界框。这是一项具有挑战性的计算机视觉任务,最近已被 Faster-RCNN、SSD、Yolo 等深度学习算法接管。这篇文章重点介绍了最新的 Yolo v2 算法,据说它是最快的(在 Titan X 上运行时,在低分辨率图像上大约 90 FPS),比 SSD 更准确,在少数数据集上比 RCNN 更快。我将讨论 Yolo v2 的工作原理和训练步骤。如果你想更深入地了解物体检测算法,你可以参考这里和这里。
这篇文章假设你对卷积层,最大池,批处理有基本的了解。如果没有,我建议你在附加的链接中得到一个关于主题的简要想法。
Yolo v2:你只看一次
在下图中,我们需要识别人、电视监视器和自行车的边界框。
按照 Yolo 算法,我们将输入图像分成 N×N(这里是 13x13)个正方形。
在每个方块中,Yolo 网络(下面讨论)预测 5 个具有不同纵横比的边界框。
An example of 5 boxes is shown for a square positioned at (7, 9) from top left.
对于每个边界框,Yolo 网络预测其在正方形内的中心位置、框的宽度、高度、图像宽度、高度和在该框中具有任何对象的置信度得分,以及属于 M 个类别中的每一个的概率。
然而,不是每个边界框都有一个对象。给定这些预测,为了找到最终的边界框,我们需要执行以下两个步骤:
Predicted bounding boxes
YOLOv2 网络:
以上步骤是图像通过 Yolo 网络后得到最终包围盒所需的后处理步骤。然而,我们还没有讨论 Yolo 网络如何产生这种输出。在这里,我要讨论一下 Yolo 网络。
YOLOv2 的架构可以在这里看到。将鼠标悬停在块上可以看到可视化中每个块的详细信息。除了最后一个卷积块之外,每个卷积块都有 BatchNorm 归一化和泄漏 Relu 激活。
Conv13_512 之后的重组层(参见可视化)是一个重组层。如果输入图像的尺寸为 3x416x416(通道 x 高度 x 宽度— CHW),则 Conv13_512 的输出尺寸为 512x26x26 (CHW)。重组层将每一个交替的像素放入不同的通道。让我们以一个 4x4 像素的单通道为例,如下所示。重组层将大小减少一半,并创建 4 个通道,相邻像素位于不同的通道中。因此,来自 Conv13_512 的 Reorg 层的输出将是 2048x13x13。
Reorg layer in YOLO v2
concat 层接受 Reorg 层的输出(大小:2048x13x13)和 Conv20_1024 的输出(大小:1024x13x13),并生成大小为 3072x13x13 的连接层。
损失函数:
目标函数是多部分函数,如
YOLO v2 Loss function
上述函数定义了迭代 t 的损失函数。如果边界框没有任何对象,则需要降低其对象置信度,并将其表示为第一损失项。因为边界框坐标预测需要与我们的先验信息对齐,所以为少数迭代(t < 12800)添加了减少先验和预测之间的差异的损失项。如果边界框 k 负责真值框,那么预测需要与表示为第三损失项的真值对齐。𝞴值是每个损失项的预定义权重。
训练 YOLOv2:
在训练 YOLOv2 之前,作者定义了一个架构,称为 Darknet-19,用于在 ImageNet 数据集上训练。Darknet-19 具有与 YOLOv2 网络相同的前 19 层(直到 Conv18_1024),然后附加了 1024 个滤波器的 1x1 卷积,之后是全局 AvgPool 和 Softmax 层。Darknet-19 在 ImageNet 上训练,达到 91.2%的 top-5 精度,并且训练的权重直到层 Conv18_1024 稍后在训练 YOLOv2 网络时使用。
我已经用 SGD 和 Adam 做了几次实验。我已经尝试过使用动量,如论文中提到的重量衰减。我不能在使用 SGD 的测试中得到 65.7 以上的地图。然而,亚当能够比 SGD 达到 68.2 地图表现更好。
后来,我尝试了在精彩的快速人工智能讲座中解释的重启循环学习率。这是一个非常有趣的技术,因为我发现在使用 lr_find()找到的学习率开始训练后,测试精度在短短 4 个时期内就开始从以前的结果提高。我遵循的策略是:
- 使用 lr_find 技术发现学习率为 0.00025,我使用 PyTorch 重新实现了该技术
- 用 n _ epochs 训练最后的层 5 个周期,每个周期加倍,得到 31 个 epoch。我在 PyTorch 中使用 CosineAnnealingLR 方法实现了循环学习率。
- 以不同的学习速率训练所有层 3 个周期,每个周期的时期加倍。
使用上述策略,我可以在测试中获得 71.8 的地图,这比论文中提到的策略要好,我也可以在更短的时间内获得。但离论文中提到的精度(76.8 图)还是有相当大的差距。我相信我还需要进一步尝试一些东西,以接近论文中提到的精度。
- 多尺度训练,因为我无法在 PyTorch 中定期重复多尺度训练
- 为更多的时代而训练。
- 处理困难样品(包围盒的宽度或高度【https://github.com/santoshgsk/yolov2-pytorch
I will be adding the code soon. Hit the clap if you like the post and please do let me know your thoughts about this finding.
I would like to thank Jeremy Howard and Rachel Thomas for their incredible effort of sharing useful tips on training neural networks.
Please find the code here: https://github.com/santoshgsk/yolov2-pytorch
基于 Supervisely、Tensorflow 和 UNet 的城市道路场景分割训练
自 2012 年 Alex Krizhevsky 发表他的开创性 AlexNet 以来,深度学习工具集已经走过了漫长的道路,从一堆 CUDA C++文件到像 Tensorflow 和 Caffe 这样的易用框架,配备了像 UNet 或 SSD 这样的强大架构。
也有很多来自不同领域的免费数据集,如标志识别或图像字幕。
现在每个人都可以建立和训练自己的模型。此时此地有这么多东西——还会出什么差错呢?
Cooking data may be hard.
不幸的是,有几件事你应该担心:
- 首先,你需要获得有趣的数据集。有时,这并不是一件容易的事情,因为一些链接断开了,一些数据集需要你发送请求并等待几天(或几周,或永远)。
- 你必须小心统计和分布。如果不太了解你的数据,很容易花很多时间训练你的模型却没有结果。
- 有时你想注释一些特定的东西,这些东西在公共数据集中还没有。例如,您可以在汽车牌照上标注实际的车牌号码或标记道路缺陷。
- (在深度学习中)数据越多越好。将几个数据集组合在一起使训练更容易总是一个好主意。当然,您应该首先做一些预处理:例如,在一个数据集中,您只有“车辆”,而在另一个数据集中,您有“汽车”、“自行车”和“公共汽车”。重新映射类标签是必须做的事情。
- 扩充也是一个让数据变大的好主意。是的,大多数框架都没有这个特性。
在 Deep Systems 这里,我们每天都会遇到这种困难。准备数据并不是构建模型的乐趣所在,但却非常重要,因此我们创建了一个服务来帮助解决上述所有问题(甚至更多!).
在本文中,我们想向您介绍 Supervise.ly ,并向您展示一个现实世界问题的例子:我们将在 Tensorflow、Keras 和名为 UNet 的有前途的架构的帮助下,在几个公开可用的数据集的组合上训练我们自己的道路分割模型。
免责声明:你可以跳过监督数据准备部分,自己做,但是可能会花更多的时间。
准备城市景观
Cityscapes 是一个来自 50 个城市的街道场景数据集。它有 5000 个高质量的注释帧和 30 个类,如“人行道”或“摩托车”。
Cityscapes annotation example
与类似数据集不同的是,Cityscapes 以多边形和点的形式提供标注,而不仅仅是大位图。
步骤 1:下载数据集
你可以在这里获得数据集——你可能需要等一两天才能获得确认链接:数据集许可不允许分发。
登录后,下载以下档案:gtFine_trainvaltest.zip (241MB)
和leftImg8bit_trainvaltest.zip (11GB)
。
我们只对 Cityscapes 数据集的像素级子集感兴趣,所以您不必下载其他档案。
现在,将下载的归档文件解压缩到一个文件夹中,这样您将以下面的结构结束:
gtFine
和leftImg8bit
都包含类似train
和val
的文件夹,这些文件夹包含类似aachen
的文件夹-城市。
如你所见,Cityscapes 是一个大数据集。如果您愿意,可以使用整个 Cityscapes 数据集来完成本教程,但我们建议只留下几个城市:至少对于第一次尝试来说是这样。所以,最后,你应该有这样的东西:
$ tree -d
.
├── gtFine
│ ├── train
│ │ ├── aachen
│ │ ├── bochum
│ │ └── bremen
│ └── val
│ └── frankfurt
└── leftImg8bit
├── train
│ ├── aachen
│ ├── bochum
│ └── bremen
└── val
└── frankfurt
将整个目录打包到一个新的归档文件中,使用一种支持的超级导入格式:.zip
、.tar
或.tar.gz
。现在我们准备向前迈进。
第二步:注册 Supervise.ly
创建一个账户——只需一分钟,完全免费。
Signup page
步骤 3:导入 Cityscapes 数据集
太好了!现在你没有超级数据集——是时候创建你的第一个数据集了。你可以上传自己的图片,但现在我们将使用城市景观。打开“导入”页面,选择“开源数据集格式”选项。我们支持几个最流行的公共数据集。选择“城市景观”。在右侧,您会看到一个您必须上传的归档示例—这是我们在第一步中创建的文件。
输入项目名称(对于本教程,输入“cityscapes”)并移动到最后一步:在您的计算机上选择准备好的存档并开始上传。
您可以在“任务状态”页面监控进度。
第四步:查看统计数据
当你看到任务的状态是“完成”时,这意味着一切正常,你可以开始用你的图像做一些很酷的事情了。
首先,我们来看看一些数字。打开你新创建的项目“cityscapes ”,进入“Statistics”页面。
在这里你将会得到一些关于班级分布,人物区域和更多的信息。你可以从这里的数据中获得一些见解。例如,人们可以看到,只有 10%的图像至少有一辆公共汽车,或者电线杆多于汽车。
步骤 5:导出数据
我们不想改变数据集中的注释,所以我们可以直接跳到导出。
Supervise.ly 最强大的功能之一是导出工具。它允许您使用简单的基于 JSON 的配置来建立转换管道。我们在那里支持许多有用的东西:
- 图像裁剪和旋转
- 亮度和对比度校正
- 过滤掉一些数字
- 重新映射分类标签
- 分割数据集以进行训练和验证
还有更多。
您可以保存和传输这些配置,在不同的项目中使用它们,当然,不需要编码。
为了培训 UNet,我们需要:
- 将类别数量从 30 个减少到几个(例如,四个:“bg”、“车辆”、“道路”和“中性”)
- 将图像调整为固定大小(例如,224x224)
- 过滤掉非常小的数字(例如,小于面积的 0.15%)
- 根据数据集名称(基本上按城市)拆分数据以进行训练和验证
- 用“中性”类填充背景
- 生成地面实况位图
我们将使用 Supervise.ly 导出配置来完成上述所有工作。
单击“导出”选项卡开始新的导出。在左侧,您可以使用 JSON 定义您的导出配置,或者通过按“添加层”按钮在 UI 中添加新的转换层。
每一个改变都会更新右边,你会看到一个代表导出转换的图表。
我们为本教程做了一个预定义的配置。您可以通过克隆我们的存储库来获得它:
git clone [https://github.com/DeepSystems/supervisely-tutorials](https://github.com/DeepSystems/supervisely-tutorials)
然后从unet_training/src/experiment_001/config.json
文件中复制配置并将内容粘贴到左侧面板的编辑器中。
你会看到类似上面截图的东西。让我解释一下这是怎么回事:
你可以在文档中阅读更多关于导出和图层的内容。
点击“开始导出”,输入本次导出的名称,Supervise.ly 将开始准备您的数据。您可以在“任务”页面上监控进度。
导出完成后,您将看到“完成”状态。点击“三点”图标,然后点击“下载”。
培训 UNet
现在,您应该有一个包含理想图像的档案。让我们看一些图片。
Folder “check” contains debug output with original and ground-truth images
是时候训练我们的模特了。在 Github 库supervisely-tutorials
中,我们已经做好了一切准备。
解压文件夹unet_training/data/cityscapes
中下载的档案。您将得到类似这样的结果:
$ cd unet_training/data
$ tree -d
.
└── cityscapes
└── city2
├── aachen
│ └── train
│ ├── check
│ ├── gt
│ └── orig
└── frankfurt
└── val
├── check
├── gt
└── orig
要开始训练,你需要 GPU Cuda,Tensorflow 和 libs。有可能解决所有的依赖并手动安装库或者(更好的主意!)只需构建并运行 docker 映像:
cd unet_training/docker
./build.sh
./run.sh
Docker 将构建包含 Tensorflow 和 GPU 支持的图像。它还会在容器内安装文件夹src
和data/cityscapes
。现在将 Jupyter 笔记本中的链接复制到您最喜欢的浏览器中。
在上面的例子中,链接是[http://localhost:8888/?token=48938f4268b9c230cd450fa614d33abbb0ed3f98c8c245fe](http://localhost:8888/?token=48938f4268b9c230cd450fa614d33abbb0ed3f98c8c245fe)
。
导航到文件夹experiment_001
并打开unet_train.ipynb
。
点击Cell → Run All
运行笔记本。如果一切顺利,您将在几个时期后看到一些结果。
The road is recognised (kinda). Do more epochs to get better results.
经过一天的训练,你可以达到这样的效果(这里我们使用了更多的类):
结论
我们已经完成了从下载数据集到探索数据、使用 Tensorflow 和 Keras 进行导出转换和训练模型的每一步。
你也可以尝试使用其他可用的道路场景数据集,像的瞳孔数据集——超级支持它。
如果你有问题,我们很乐意帮助你。
前期教程:用 Supervisely 和 Tensorflow 进行车牌检测。
在数据科学方面培训您的员工?以下是如何选择正确的编程语言
超越技术辩论,为您的团队获得最佳结果
各个行业的企业都在投资数据科学教育项目。在科技教育公司 Decoded 工作时,我发现看到数据技能可以给各个领域带来巨大价值是一件令人着迷的事情——从银行和零售商,到慈善机构和政府。当着手这样一项计划时,我们的客户需要做出大量的战略决策。我们最常见的问题之一是:
“我们应该教我们的员工哪种编程语言?”
数据科学社区定期讨论这个问题,快速的谷歌搜索会发现大量讨论每种语言的技术优点和优雅的博客和视频。但是从商业角度来看,决策通常取决于一系列不同的因素。
这里有一个快速问答,可能会帮助你做出决定。
问:对于数据科学或数据分析,我们的员工应该学习哪种编程语言?
Python 或者 r。
这是目前最流行和最通用的两种语言。它们都是免费和开源的。每个都有数百个库,简化了转换、探索、分析和可视化数据的过程。
在线数据科学社区 Kaggle 的年度调查“数据科学和机器学习的现状”提出了一个问题“工作中使用什么工具?”
在最新公布的调查结果中,r 和 Python 出现在列表的顶部。76.3%的受访者使用 Python,59.2%使用 R。(值得注意的是,接下来流行的物品并不是等价的工具。比如 SQL 是一种允许你查询数据库的语言,在数据分析的时候不会有太大帮助)。
接下来的编程语言远没有那么常用:C/C++占 19.2%,MATLAB 占 18.4%,Java 占 18.3%。所有这些语言都有自己的优点,但当涉及到学习数据科学时,它们就不那么容易理解、灵活和受支持了。
问:好的,那么你为我们的学员推荐哪一款呢?Python 还是 R?
通常,最大的决定因素是您现有的数据科学团队是否已经偏好 Python 或 r。在一致的环境中工作有巨大的好处,因为:
- 如果学习者遇到任何问题,他们可以利用现有的内部支持网络。
- 代码可以在团队之间共享和重用。
- 对于您的 IT 团队来说,白名单和安装可能会更简单。
所以如果你现有的数据科学家主要用 Python,那就用 Python 吧。如果他们大部分时间都在休息,那就去休息吧
问:如果我没有现有的数据科学团队,或者他们没有偏好,该怎么办?
Python。因为:
- Python 是最流行的数据科学语言(也是发展最快的)。因此,您可以期待更好的在线学习和故障排除资源,以及支持现代数据分析常见任务的大量代码库。
- 对于 IT 团队来说,Python 通常比 R 更容易管理(例如花旗风险投资刚刚投资了一个流行的 Python 数据科学平台 Anaconda )。
- Python 在数据科学之外的环境中也很流行(例如 web 开发)。这意味着学习者可以获得更广泛的教育资源,并将其应用到生活的其他领域。
问:R 有什么优势吗?
是啊!Kaggle 的调查显示,虽然 Python 总体上更受欢迎,但 R 在统计学家中更受欢迎。r 可能是一个不错的选择,因为它是专门为统计分析而构建的。
这意味着许多常见的统计工具都内置在 R 中(而 Python 更依赖于外部包)。传统上,R 也有更大范围的统计和专家可视化软件包。然而,随着 Python 越来越受欢迎,它也开始迎头赶上。如今,你在 R 中可以做的几乎任何事情都可以很容易地在 Python 中复制。
好的,我想我已经做出了决定。如果事实证明我犯了一个可怕的错误呢?
不要惊慌。你可能已经注意到了,Kaggle 的调查显示,76.3%的受访者使用 Python,59.2%的人使用 R——所以社区中有很大的重叠。大多数数据科学家都习惯使用这两种工具,即使他们固执地偏爱其中一种。
学习任何一种语言都会使学习另一种语言变得简单得多。别忘了,除了编程本身,还有很多东西要学——从数学和统计概念,到数据管道和可视化。这两种语言都是探索这些主题的良好基础,并开始您作为数据科学家的旅程。
基于 Kaggle 核的迁移学习和图像分类。
在我上一篇 帖子 中,我们训练了一只 convnet 来区分狗和猫。我们从零开始训练 convnet,得到了 80%左右的准确率。对于在非常少的数据集(4000 张图像)上训练的模型来说,这已经不错了。
但是在现实世界/生产场景中,我们的模型实际上表现不佳。
尽管我们建议调整一些超参数——历元、学习率、输入大小、网络深度、反向传播算法等——看看我们是否能提高我们的准确度。
嗯,我试过了…
事实是,在调音、重新调音、不调音之后,我的准确度不会超过 90%,在某个点上它是无用的。
当然,有更多的数据会有助于我们的模型;但请记住,我们正在处理一个小数据集,这是深度学习领域的一个常见问题。
但是唉!有一种方法…
Image from pixabay
转学走进…
但接下来你会问,什么是迁移学习?
嗯,TL(迁移学习)是深度学习中常用的训练技术;其中已经为任务训练的模型被重新用作另一个模型的基础/起点。
为了训练一个图像分类器,使其在图像分类上达到接近或超过人类水平的精度,我们需要大量的数据、强大的计算能力和大量的时间。这一点我相信我们大多数人都没有。
知道这对于资源很少或没有资源的人来说是一个问题,一些聪明的研究人员建立了模型,在大型图像数据集上进行训练,如【ImageNet】COCOOpen Images,并决定将他们的模型分享给公众以供重用。
Image from Marvel comics
这意味着你再也不用从头开始训练图像分类器了,除非你有一个非常非常大的不同于上面的数据集,或者你想成为一个英雄或者 thanos。
我知道你有疑问,比如…
- 迁移学习为什么有效?
井转移学习对图像分类问题有效,因为神经网络以越来越复杂的方式学习。也就是说,你在网络中走得越深,学到的图像特定特征就越多。
A neural network learns to detect objects in increasing level of complexity | Image source: cnnetss.com
让我们建立一些直觉来更好地理解这一点。在一个试图检测人脸的神经网络中,我们注意到网络学习检测第一层中的边缘,第二层中的一些基本形状以及随着深入的复杂特征。
因此,这里的想法是,所有的图像都有形状和边缘,只有当我们开始提取更高层次的特征时,我们才能识别它们之间的差异,比如说脸上的鼻子或汽车的轮胎。只有这样我们才能说,好吧;这是一个人,因为它有鼻子,这是一辆汽车,因为它有轮胎。
这里的要点是,神经网络的早期层将总是检测汽车和人的图片中存在的相同的基本形状和边缘。
现在,将这种直觉用于我们区分狗和猫的问题,这意味着我们可以使用在包含不同类型动物的庞大数据集上训练过的模型。
这很有效,因为这些模型已经学会了动物的基本形状和结构,因此我们需要做的就是教会它(模型)我们新图像的高级特征。
我想说的是,我们需要一个已经在大型图像数据集上训练过的网络,如 ImageNet (包含大约 140 万张标记图像和 1000 个不同类别,包括动物和日常物品)。
既然这个模型已经知道如何对不同的动物进行分类,那么我们可以利用这些现有的知识快速训练一个新的分类器来识别我们的特定类别(猫和狗)。
我的意思是一个会煮鸡蛋的人应该知道如何煮水,对吗?
既然我们对什么是迁移学习有了理解/直觉,我们就来谈谈预训练网络。
预训练网络有不同的变体,每种都有自己的架构、速度、大小、优点和缺点。
Keras 预装了许多类型的这些预训练模型。其中一些是:
- VGGNET:Simon Yan 和 Zisserman 在他们 2014 年的论文 中介绍了用于大规模图像识别的超深度卷积网络 。
- RESNET :由何等人在 2015 年的论文 中首次提出,用于图像识别的深度残差学习
- INCEPTION:“INCEPTION”微体系结构是由 Szegedy 等人在他们 2014 年的论文 中首次提出的,该论文名为“用卷积进行深入研究 :
- 例外(XCEPTION):例外是由 Keras 图书馆的创建者弗朗索瓦·乔莱提出的。
还有很多。其中一些架构的详细解释可以在 这里 找到。
我们将在本教程中使用 InceptionResNetV2 ,请随意尝试其他模型。
InceptionResNetV2 model | Image source: researchgate
InceptionResNetV2 是来自 INCEPTION 系列的最新架构。它确实工作得很好,并且由于许多原因超级快,但是为了简洁起见,我们将留下细节并坚持在这篇文章中使用它。
如果你对盗梦空间模式如何运作的细节感兴趣,那么就去 这里 。
不那么简单的介绍结束后,让我们开始实际的编码。
我们将使用第一个笔记本中几乎相同的代码,不同之处非常简单明了,因为 Keras 使调用预训练模型变得很容易。
Fork your previous notebook on kaggle
如果你遵循了我之前的 帖子 并且已经在 kaggle 上有了内核,那么简单地分叉你的笔记本创建一个新版本。我们将编辑这个版本。
将为您创建上一个笔记本的分支,如下所示
The new version opens like this.
- 关闭设置栏,因为我们的 GPU 已经被激活。请确认您的 GPU 已打开,因为这可能会极大地影响培训时间。
- 取消提交消息。暂时不要提交您的工作,因为我们还没有做出任何更改。
现在,从头开始一个接一个地运行代码块,直到到达我们创建 Keras 模型的单元格,如下所示。
Keras model block
点击箭头指向上方的 +按钮,在当前代码单元格的基础上创建一个新的代码单元格。
empty code cell created
现在,让我们称我们的预训练模型为…
- 这里我们导入 InceptionResNetV2 模型。
- 这里,我们告诉 keras 下载模型的预训练的权重,并保存在变量conv _ 基地中。 为了配置我们实际下载的内容,我们传入一些重要的参数,例如:
- 权重 [ imagenet ]:我们告诉 keras 获取在 imagenet 数据集上训练的 InceptionReNetV2。
- include _ top[False]:这告诉 Keras 不要下载预训练模型的完全连接层。这是因为顶层(完全连接的层)进行最终分类。
即在卷积层从输入图像中提取边缘、斑点或线条等基本特征后,全连接层将它们分类。
由于我们只需要两个类(狗和猫)分类器,我们将删除前者并添加我们自己的分类器。
Removing the top classifier and adding our own. Image source: Deep Learning with Python by Francois Chollet
5.这里我们指定我们的输入维度。
点击 shift+Enter 运行代码块。
This error appears when your internet on kaggle is blocked.
如果您在运行代码时遇到这个错误,那么您在 Kaggle 内核上的互联网访问被阻止了。
要激活它,打开您的设置菜单,向下滚动并点击互联网并选择 互联网连接。 你的内核自动刷新。因此,您必须从头开始再次运行每个单元格,直到到达当前单元格。
重新运行代码从 github 上的 keras 库下载预训练的模型。
Downloading our pretrained model from github
我们可以给。 summary( ) 我们下载的模型上的函数可以看到它的架构和参数个数。
你注意到一个令人欢呼的 5400 万 plus 参数。这是巨大的,我们肯定不能从头开始训练它。但是由于迁移学习,我们可以简单地重复使用它而无需培训。
接下来,我们创建完全连接的层(分类器),并将其添加到我们下载的模型之上。这是我们要训练的分类器。即在将 InceptionResNetV2 连接到我们的分类器后,我们将告诉 keras 只训练我们的分类器,并冻结 InceptionResNetV2 模型。
- 我们从 keras 导入层和模型。
- 我们创建一个序列模型。
- 重要的!别担心,我没有尖叫…这里我们将我们的conv _ 基地( InceptionResNetV2)添加到模型中。
- 这里,我们展平来自conv _ 基地的输出,因为我们想把它传递给我们完全连接的层(分类器)。
- 为了简单起见,我添加了一个输出为 256 ( 号不固定)的密集网络,并使用了我们在我上一篇 帖子 中谈到的流行的 ReLU 激活。
- 我们像上次一样用一个s 形做最后一层。
- 最后一层只有一个输出。(职业概率)
见我上一篇 帖子 了解更多澄清。
按住 Shift+Enter 运行您的代码。
接下来,让我们预览一下我们的架构:
Full model summary
我们可以看到,我们的参数从大约 5400 万增加到将近 5800 万,这意味着我们的分类器有大约 300 万个参数。
现在我们要冻结 conv 的基地,只训练我们自己的。
Freeze!
- 我们在冻结conv _ base(492)之前打印模型中的重量数。
- 在这里,我们将conv _ 基地图层的 可训练 属性设置为 False(我们不想训练你)。
- 打印冻结 conv_base 后的重量数( 下降到刚好 4 个 )。
几乎完成,只是一些小的变化,我们可以开始训练我们的模型。
第一个小小的改变是将我们的学习率从我们上一款中的**0.0001(1e-5)略微提高到0.0002(2e-5)。经过一些试验后,我决定使用 0.0002 ,它工作起来更好一些。(**你可以做这里再调一些 )
Increase the learning rate slightly
接下来,运行模型下的所有单元格。编译 块,直到到达我们在模型上称之为 fit 的单元格。这里我们将改变最后一个参数,即纪元大小。
我们将时段大小减少到 20 。当我们稍后绘制精度和损耗图时,其原因会更清楚。
**注:**我尝试了不同的数字后决定用 20。这就是深度学习中我们所说的 超参数 调优。
终于,开始训练的时间到了。
运行你的代码,去喝杯水。不,不是咖啡!水,因为水是生命。
嗯,我还没来得及喝水,我的模特就训练完了。所以我们来评价一下它的性能。
展示迁移学习力量的图片。
We reach an accuracy of about 96% in just 20 epochs
我们清楚地看到,在仅仅 20 个时期内,我们已经达到了大约 96%的准确度。超级快速准确。
如果 狗 vs 猫 的比赛没有结束,我们用这个模型预测,我们就算不是第一,也一定会名列前茅。
请记住,我们仅使用了 25,000 张图片中的 4000 张。
当我们使用所有 25000 幅图像结合我们刚刚学习的技术(迁移学习)进行训练时,会发生什么?
A wise man thinking… Image source Pixabay
嗯,一位非常聪明的科学家曾经说过…
拥有足够数据的不太花哨的算法肯定会比拥有少量数据的花哨算法做得更好。
事实证明这是真的!
好了,我们已经讨论了一段时间的数字,让我们来看一些图像…
在不更改打印代码的情况下,运行单元块以绘制一些精度和损耗图。
我们得到了下面这些图…
那么我们能从这个情节中读到什么呢?我们可以清楚地看到,我们的验证准确性甚至从一开始就表现良好,然后在几个时期后就稳定下来了。现在你知道我为什么把我的纪元大小从 64 减少到 20 了。
最后,我们来看一些预测。我们将使用相同的预测代码。只需运行代码块。
运行我的后,我得到了 10 张图像的预测,如下所示…
Predictions for ten Images from our test set
我们的分类器得到了满分 10 分。很好很简单,对吧?
嗯,就是这样。这就是我停止打字的地方,让你去驾驭迁移学习的力量。
所以,编码快乐…
链接到本笔记本 上的 Github 。
我引用了一些令人惊叹的帖子和文章。
- 用于视觉识别的 CS231n 卷积神经网络。
- Keras 的创建者 Francois Chollet 用 python 进行深度学习。
- 协进化神经网络基础知识。
- 一个关于迁移学习的很棒的媒体帖子。
- 又一个关于盗梦空间模型的媒体帖子。
- 一种温和的迁移学习方法。
欢迎提问、评论和投稿。
在 twitter 上和我联系。
在insta gram上跟我连线。
基于 Keras 的图像分类迁移学习
用几个简单的步骤训练一个图像分类器
我为学习者写了一份名为《强大的知识》的时事通讯。每一期都包含链接和最佳内容的关键课程,包括引文、书籍、文章、播客和视频。每一个人都是为了学习如何过上更明智、更快乐、更充实的生活而被挑选出来的。 在这里报名 。
在本教程中,您将学习如何为图像分类任务进行迁移学习。Keras 的高级 API 使这变得非常容易,只需要几个简单的步骤。
迁移学习允许我们使用比我们从头开始训练时少得多的数据来训练深度网络。通过转移学习,我们实际上是将模型从之前的任务中学到的“知识”转移到我们当前的任务中。这个想法是,这两个任务并不是完全分离的,因此我们可以利用模型通过大量训练学习到的任何网络参数,而不必自己进行训练。
迁移学习一直被证明可以提高模型准确性并减少所需的训练时间。更少的数据,更少的时间,更高的准确性。
装东西
我们要做的第一件事是准备我们的数据。对于 Keras 中的影像分类,最简单的方法是将您的数据分成每个类别的文件夹。例如,如果你的数据集有 3 个类:Pizza、Burger 和 Taco,那么你应该有 3 个名为 Pizza、Burger 和 Taco 的文件夹。你的每个文件夹都应该包含该特定类别的图像。您的文件夹结构应该如下所示:
food_dataset
---> Pizza
-------> p_1.jpg
-------> p_2.jpg
-------> p_3.jpg
-------> ....
---> Burger
-------> b_1.jpg
-------> b_2.jpg
-------> b_3.jpg
-------> ....
---> Taco
-------> ....
接下来,我们可以选择要对其执行迁移学习的模型。Keras 为此提供了许多选项。在进行选择时,您可以大致相信(出于我们的目的)较小的模型(以 MB 为单位)会更快但不太准确,而较大的模型会更慢但更准确。截至今天的文章,MobileNet 是最快的,NASNetLarge 是最准确的。我们今天将选择 ResNet50 型号,它位于光谱的中间。
查看下面的代码。我们从导入必要的模型和预处理函数开始。ResNet50 模型使用一些非常特殊的预处理进行训练,我们希望重用这些预处理,以便正确地重新训练它。请注意,当我们初始化基本模型时,我们是如何设置include_top=False
的。这个设置很重要,因为这意味着我们不会在模型的末尾保留全连接(FC)层。这正是我们想要的,因为我们要为迁移学习训练我们自己的全新的 FC 层。
流动数据
现在我们需要创建一个数据生成器,以自动的方式从我们的文件夹中获取数据并放入 Keras。为此,Keras 提供了方便的 python 生成器函数。
我们定义了名为“food_dataset”的训练目录,其中包含我们之前设置的每类图像的文件夹。我们还定义了图像尺寸和批量大小;Keras 生成器将使用双线性插值法自动将所有加载的图像调整到target_size
的大小。
我们将向生成器添加一些额外的数据增强,翻转和旋转,以尝试提高我们模型的准确性。我们使用flow_from_directory
函数创建我们的最终生成器,它将使用一个队列来保持加载和准备图像的连续流!
弹出图层
是时候建立我们迁移学习的最终模型了。如果将来要再次使用它,您可能会发现为此编写一个函数非常方便。下面有一个你可以从它开始。
我们从冻结基本模型的所有层开始。我们不想训练这些层,因为我们试图利用网络从以前的数据集(在这种情况下是 ImageNet)中学习的知识。通过设置layer.trainable=False
,我们告诉 Keras 而不是在训练期间更新那些权重,这正是我们想要的!
现在,我们可以添加 FC 层。我们在一个循环中这样做,因为许多网络有多个 FC 层,循环通过一个列表使事情变得简单明了。我们还将在每个 FC 层中添加一些 dropout,以减少过度拟合的机会(这部分是可选的)。最后,我们加上最终的 Softmax 层,建立 Keras 模型。
一旦我们的功能都设置好了,创建最终模型就变得非常简单了。只需忽略 softmax 层的类的数量、列表中 FC 层的大小(因为我们对它进行了循环)和丢失概率。
训练它
最后一步是设置我们的训练,并点击大红色按钮,使所有运行!
我们将使用 Adam 优化器,它的学习率值很小。我们选择 Adam 是因为它比 SGD 更快更容易使用。我们将学习率设置得很小,因为我们在这里只是微调我们的模型,特别是 FC 层;我们不寻求任何大的改变,只是微调。
我们还将设置一些检查点,为以后保存权重。应用fit_generator
函数运行整个训练团,可选择时期数、批量大小和数据混排。一旦训练全部完成,我们可以使用history
输出来绘制我们的训练结果。
瞧,转移学习!
喜欢学习?
在推特上关注我,我会在那里发布所有最新最棒的人工智能、技术和科学!也在 LinkedIn 上和我联系吧!
从预先训练的模型中转移学习
如何快速简单地解决任何图像分类问题
本文教你如何利用迁移学习解决图像分类问题。为了演示的目的,给出了一个使用 Keras 及其预训练模型的实例。
The beauty of code by Chris Ried on Unsplash
深度学习正在迅速成为人工智能应用的关键工具(LeCun et al. 2015)。例如,在计算机视觉、自然语言处理和语音识别等领域,深度学习已经产生了显著的成果。因此,对深度学习的兴趣越来越大。
深度学习擅长的问题之一是图像分类 (Rawat & Wang 2017)。图像分类的目标是根据一组可能的类别对特定图片进行分类。图像分类的一个经典例子是在一组图片中识别猫和狗(例如狗对猫 Kaggle 比赛)。
从深度学习的角度来看,图像分类问题可以通过迁移学习来解决。实际上,图像分类中的几个最先进的结果都是基于迁移学习解决方案(Krizhevsky 等人 2012,Simonyan & Zisserman 2014,he 等人 2016)。潘&杨(2010)对迁移学习进行了全面综述。
**本文展示了如何针对图像分类问题实现迁移学习解决方案。**本文提出的实现基于 Keras (Chollet 2015),它使用编程语言 Python。按照这个实现,您将能够快速而轻松地解决任何图像分类问题。
这篇文章是按以下方式组织的:
- 迁移学习
- 卷积神经网络
- 重新利用预先训练的模型
- 迁移学习过程
- 深度卷积神经网络上的分类器
- 例子
- 摘要
- 参考
1.迁移学习
迁移学习是计算机视觉中一种流行的方法,因为它允许我们以省时的方式建立精确的模型 (Rawat & Wang 2017)。使用迁移学习,你不是从零开始学习过程,而是从解决一个不同的问题时已经学到的模式开始。这样你可以利用以前的经验,避免从头开始。就当是深度学习版的沙特尔‘表情’站在巨人的肩膀上。
在计算机视觉中,迁移学习通常通过使用预训练模型来表达。预训练模型是在大型基准数据集上训练的模型,用于解决与我们想要解决的问题类似的问题。因此,由于训练这种模型的计算成本,通常的做法是从出版的文献(例如,, Inception , MobileNet )中导入和使用模型。Canziani 等人(2016 年)使用 ImageNet (Deng 等人,2009 年)挑战赛中的数据,对预训练模型在计算机视觉问题上的表现进行了全面综述。
2.卷积神经网络
迁移学习中使用的几个预训练模型都是基于大型卷积神经网络****(CNN)(Voulodimos et al . 2018)。总的来说,CNN 在广泛的计算机视觉任务中表现出色(Bengio 2009)。它的高性能和易于训练是过去几年来推动 CNN 流行的两个主要因素。
典型的 CNN 有两部分:
- 卷积基,由一堆卷积层和池层组成。卷积库的主要目标是从图像中生成特征。关于卷积层和池层的直观解释,请参考 Chollet (2017)。
- 分类器,通常由全连接层组成。分类器的主要目标是基于检测到的特征对图像进行分类。全连接层是其神经元与前一层中的所有激活具有全连接的层。
图 1 显示了一个基于 CNN 的模型的架构。请注意,这是一个简化版本,符合本文的目的。事实上,这种模型的架构比我们在这里提出的要复杂得多。
Figure 1. Architecture of a model based on CNN.
这些深度学习模型的一个重要方面是,它们可以自动学习层次特征表示。这意味着第一层计算的要素是通用的,可以在不同的问题域中重复使用,而最后一层计算的要素是特定的,取决于所选的数据集和任务。根据 Yosinski et al. (2014),'如果第一层特征是一般的,而最后一层特征是特定的,那么在网络的某个地方肯定有从一般到特定的过渡’。因此,我们的 CNN 的卷积基(尤其是其较低层(那些更接近输入的层))指的是一般特征,而分类器部分以及卷积基的一些较高层指的是专门特征。
3.重新利用预先训练的模型
当您根据自己的需要重新调整预训练模型的用途时,您首先要删除原始的分类器,然后添加一个符合您的目的的新分类器,最后您必须根据三种策略之一对您的模型进行微调:
- **训练整个模型。**在这种情况下,您使用预训练模型的架构,并根据您的数据集对其进行训练。您正在从头开始学习模型,因此您将需要一个大的数据集(和强大的计算能力)。
- 训练一些层,让其他层保持冷冻。如您所知,较低层指的是一般特性(与问题无关),而较高层指的是特定特性(与问题相关)。这里,我们通过选择我们想要调整网络权重的程度(一个冻结的层在训练期间不会改变)来处理这种二分法。通常,如果你有一个小的数据集和大量的参数,你会保持更多的层冻结,以避免过度拟合。相比之下,如果数据集很大而参数数量很少,则可以通过为新任务训练更多的层来改进模型,因为过度拟合不是问题。
- **冻结卷积基数。**这种情况对应于训练/冻结权衡的极端情况。主要思想是保持卷积基的原始形式,然后使用其输出来馈送分类器。您正在使用预训练模型作为固定的特征提取机制,这在您计算能力不足、数据集较小和/或预训练模型解决的问题与您想要解决的问题非常相似的情况下非常有用。
图 2 以示意图的方式展示了这三种策略。
Figure 2. Fine-tuning strategies.
与策略 3 的应用简单明了不同,策略 1 和策略 2 要求你小心卷积部分使用的学习速率。学习率是一个超参数,它控制着你调整网络权重的程度。当您使用基于 CNN 的预训练模型时,使用小的学习率是明智的,因为高学习率会增加丢失先前知识的风险。假设预训练模型已经被很好地训练,这是一个公平的假设,保持小的学习率将确保你不会过早和过多地扭曲 CNN 权重。
4.迁移学习过程
从实践的角度来看,整个迁移学习过程可以总结如下:
- 选择预先训练好的模型。从大量可用的预训练模型中,您可以选择一个看起来适合您的问题的模型。例如,如果您正在使用 Keras,您可以立即访问一组模型,如(Simonyan & Zisserman 2014)、InceptionV3 (Szegedy 等人 2015)和 ResNet5(何等人 2015)。在这里你可以看到 Keras 上所有的车型。
- **根据规模-相似度矩阵对你的问题进行分类。**在图 3 中,你有一个“矩阵”来控制你的选择。该矩阵根据数据集的大小及其与训练预训练模型的数据集的相似性,对您的计算机视觉问题进行分类。根据经验,如果每个类的图像少于 1000 幅,则认为数据集很小。关于数据集相似性,让常识占上风。例如,如果您的任务是识别猫和狗,ImageNet 将是一个类似的数据集,因为它有猫和狗的图像。然而,如果你的任务是识别癌细胞,ImageNet 就不能被认为是一个类似的数据集。
- **微调你的模型。**在这里,您可以使用大小-相似性矩阵来指导您的选择,然后参考我们之前提到的关于重新调整预训练模型用途的三个选项。图 4 提供了以下文本的可视化摘要。
- 象限 1 。大型数据集,但不同于预训练模型的数据集。这种情况会把你引向策略 1 。因为你有一个大的数据集,你可以从头开始训练一个模型,做任何你想做的事情。尽管数据集不同,但在实践中,使用预训练模型的架构和权重从预训练模型初始化模型仍然是有用的。
- **象限 2。**大型数据集,类似于预训练模型的数据集。你现在在啦啦世界。任何选择都可行。可能,最有效的选择是策略 2 。由于我们有一个大的数据集,过度拟合应该不是问题,所以我们可以想学多少就学多少。然而,由于数据集是相似的,我们可以通过利用以前的知识来节省大量的训练工作。因此,训练分类器和卷积基的顶层应该足够了。
- **第三象限。**小数据集,与预训练模型的数据集不同。这是计算机视觉问题的第 2-7 手脱衣牌。一切都和你作对。如果抱怨不是一个选项,你唯一的希望就是策略 2。很难在训练和冷冻的层数之间找到平衡。如果你深入研究,你的模型可能会过拟合,如果你停留在模型的浅层,你将不会学到任何有用的东西。很可能,您需要比象限 2 更深入,并且您需要考虑数据扩充技术(这里提供了关于数据扩充技术的很好的总结)。
- **象限 4。**小数据集,但类似于预训练模型的数据集。我向尤达大师询问过这个问题,他告诉我‘是最好的选择,策略 3 应该是’。我不知道你怎么想,但我不会低估原力。相应地,转到策略 3 。你只需要去掉最后一个全连接层(输出层),把预训练好的模型作为固定特征提取器运行,然后用得到的特征训练一个新的分类器。
Figures 3 and 4. Size-Similarity matrix (left) and decision map for fine-tuning pre-trained models (right).
5.深度卷积神经网络上的分类器
如前所述,基于预训练卷积神经网络的迁移学习方法产生的图像分类模型通常由两部分组成:
- 卷积基,进行特征提取。
- 分类器,根据卷积基提取的特征对输入图像进行分类。
因为在这一节中我们关注分类器部分,所以我们必须首先说明可以遵循不同的方法来构建分类器。一些最受欢迎的是:
- **完全连接的层。**对于图像分类问题,标准方法是使用一堆完全连接的层,然后是 softmax 激活层(Krizhevsky 等人 2012 年,Simonyan & Zisserman 2014 年,泽勒& Fergus 2014 年)。softmax 层输出每个可能类别标签上的概率分布,然后我们只需要根据最可能的类别对图像进行分类。
- **全球平均统筹。**林等人(2013 年)提出了一种基于全球平均池的不同方法。在这种方法中,我们没有在卷积基础之上添加完全连接的层,而是添加了一个全局平均池层,并将其输出直接馈入 softmax 激活层。Lin 等人(2013 年)详细讨论了这种方法的优缺点。
- **线性支持向量机。**线性支持向量机(SVM)是另一种可能的方法。根据唐(2013),我们可以通过在卷积基提取的特征上训练线性 SVM 分类器来提高分类精度。关于 SVM 方法的优点和缺点的更多细节可以在该文件中找到。
6.例子
在这个例子中,我们将看到如何在图像分类的迁移学习解决方案中实现这些分类器。根据 Rawat 和 Wang (2017),'在深度卷积神经网络上比较不同分类器的性能仍需要进一步研究,因此成为一个有趣的研究方向。因此,看看每个分类器在标准图像分类问题中的表现会很有趣。
你可以在我的 GitHub 页面上找到这个例子的完整代码。
6.1.准备数据
在本例中,我们将使用原始数据集的较小版本。这将允许我们更快地运行模型,这对于计算能力有限的人(像我一样)来说是非常好的。
为了构建更小版本的数据集,我们可以修改 Chollet (2017)提供的代码,如代码 1 所示。
Code 1. Create a smaller dataset for Dogs vs. Cats.
6.2.从卷积基中提取特征
卷积基底将用于提取特征。这些特征将提供给我们想要训练的分类器,以便我们可以识别图像中是否有狗或猫。
再次改编 Chollet (2017)提供的代码。代码 2 显示了所使用的代码。
Code 2. Extract features from convolutional base.
6.3.分类器
6.3.1.完全连接的层
我们提出的第一个解决方案基于完全连接的层。这个分类器添加了一个全连接层的堆栈,该堆栈由从卷积基提取的特征提供。
为了保持简单(和快速),我们将使用 Chollet (2018)提出的解决方案,稍加修改。特别是,我们将使用 Adam 优化器而不是 RMSProp,因为 Stanford 是这么说的(多么美妙的 argumentum ad verecundiam )。
代码 3 显示了所使用的代码,而图 5 和图 6 显示了学习曲线。
Code 3. Fully connected layers solution.
Figure 5. Accuracy of the fully connected layers solution.
Figure 6. Loss of the fully connected layers solution.
成绩简述:
- 验证精度约为 0.85,考虑到数据集的规模,这是令人鼓舞的。
- 该模型严重过度拟合。训练曲线和验证曲线之间有很大的差距。
- 由于我们已经使用了 dropout,我们应该增加数据集的大小来改善结果。
6.3.2.全球平均池
这种情况与前一种情况的区别在于,我们将添加一个全局平均池层,并将其输出馈送到 sigmoid 激活层,而不是添加一个完全连接的层堆栈。
请注意,我们讨论的是 sigmoid 激活层,而不是 softmax 激活层,后者是 Lin 等人(2013)推荐的。我们改为 sigmoid 激活,因为在 Keras 中,要执行二进制分类,您应该使用 sigmoid 激活和 binary_crossentropy 作为损失(Chollet 2017)。因此,有必要对林等人(2013)的原始提案进行这一小小的修改。
代码 4 显示了构建分类器的代码。图 7 和图 8 显示了最终的学习曲线。
Code 4. Global average pooling solution.
Figure 7. Accuracy of the global average pooling solution.
Figure 8. Loss of the global average pooling solution.
结果简述:
- 验证精度与全连接图层解决方案的结果相似。
- 该模型不会像前一种情况那样过度拟合。
- 当模型停止训练时,损失函数仍在减小。或许,可以通过增加历元数来改进模型。
6.3.3 线性支持向量机
在这种情况下,我们将在卷积基提取的特征上训练线性支持向量机(SVM)分类器。
为了训练这个分类器,传统的机器学习方法是优选的。因此,我们将使用 k-fold 交叉验证来估计分类器的误差。由于将使用 k-fold 交叉验证,我们可以连接训练集和验证集以扩大我们的训练数据(我们保持测试集不变,就像我们在前面的案例中所做的那样)。代码 5 显示了数据是如何连接的。
Code 5. Data concatenation.
最后,我们必须知道 SVM 分类器有一个超参数。这个超参数是误差项的惩罚参数 C。为了优化这个超参数的选择,我们将使用穷举网格搜索。代码 6 展示了用于构建这个分类器的代码,而图 9 展示了学习曲线。
Code 6. Linear SVM solution.
Figure 9. Accuracy of the linear SVM solution.
结果的简要讨论:
- 模型的精度约为 0.86,与之前解决方案的精度相似。
- 过度合身指日可待。而且训练精度总是 1.0,这是不常见的,可以解释为过拟合的标志。
- 模型的准确性应该随着训练样本的数量而增加。然而,那似乎不会发生。这可能是由于过度拟合。当数据集增加时,观察模型如何反应会很有趣。
7.摘要
在本文中,我们:
- 介绍了迁移学习、卷积神经网络和预训练模型的概念。
- 定义了基本的微调策略,以重新调整预训练模型的用途。
- 描述了一种基于数据集的大小和相似性来决定应该使用哪种微调策略的结构化方法。
- 介绍了三种不同的分类器,它们可以用在从卷积基提取的特征之上。
- 为本文中的三个分类器提供了一个端到端的图像分类示例。
我希望你有动力开始开发关于计算机视觉的深度学习项目。这是一个伟大的研究领域,每天都有令人兴奋的新发现出现。
我很乐意帮助你,所以如果你有任何问题或改进建议,请告诉我!
8.参考
1.纽约州本吉奥市,2009 年。学习人工智能的深度架构。机器学习的基础和趋势,2(1),第 1–127 页。
2.Canziani,a .,Paszke,a .和 Culurciello,e .,2016 年。面向实际应用的深度神经网络模型分析。arXiv 预印本 arXiv:1605.07678。
4.乔莱,女,2017。用 python 进行深度学习。曼宁出版公司…
5.邓军,董文伟,索契,李,李力军,李,,李,2009 年 6 月。Imagenet:一个大规模分层图像数据库。计算机视觉和模式识别,2009。CVPR 2009。IEEE 关于(第 248–255 页)的会议。Ieee。
6.何刚,张,徐,任,孙,2016。用于图像识别的深度残差学习。IEEE 计算机视觉和模式识别会议论文集(第 770-778 页)。
7.Krizhevsky,a .,Sutskever,I .和 Hinton,G.E .,2012 年。基于深度卷积神经网络的图像网分类。神经信息处理系统进展(第 1097-1105 页)。
8.LeCun、y . beng io 和 and Hinton,2015 年。深度学习。自然,521(7553),第 436 页
9.2013 年,林,硕士,陈,秦,严。网络中的网络。arXiv 预印本 arXiv:1312.4400。
10.潘世杰和杨,2010。迁移学习研究综述。IEEE 知识与数据工程汇刊,22(10),第 1345–1359 页。
11.Rawat,w .和王,z .,2017 年。用于图像分类的深度卷积神经网络:综述。神经计算,第 29 卷第 9 期,第 2352–2449 页。
12.Simonyan,k .和 Zisserman,a .,2014 年。用于大规模图像识别的非常深的卷积网络。arXiv 预印本 arXiv:1409.1556。
13.Szegedy,c .,Vanhoucke,v .,Ioffe,s .,Shlens,j .和 Wojna,z .,2016 年。重新思考计算机视觉的初始架构。IEEE 计算机视觉和模式识别会议论文集(第 2818-2826 页)。
14.唐,2013 年。使用线性支持向量机的深度学习。arXiv 预印本 arXiv:1306.0239。
15.Voulodimos,a .,Doulamis,n .,Doulamis,a .和 Protopapadakis,e .,2018。计算机视觉的深度学习:简要综述。计算智能与神经科学,2018。
16.约辛斯基、克鲁内、本吉奥和利普森,2014 年。深度神经网络中的特征有多大的可转移性?。神经信息处理系统进展(第 3320-3328 页)。
17.泽勒医学博士和弗格斯研究中心,2014 年 9 月。可视化和理解卷积网络。在欧洲计算机视觉会议上(第 818-833 页)。斯普林格,查姆。
感谢
感谢若昂·科埃略阅读本文的草稿。
想了解更多? 我正在为那些想学习 Python 中机器学习基础知识的人建立一个互动的、基于群组的 5 周课程,并且不再怀疑他们是否能够在这个领域开始职业生涯。请 填写这份简短的调查问卷 加入等候名单,并享受特别早到优惠。
Tensorflow 中的迁移学习(CIFAR-10 上的 VGG19):第二部分
Photo by Lacie Slezak on Unsplash
这是 Tensorflow 中迁移学习的第二部分(CIFAR-10 上的 VGG19)。第一部分可以在这里找到。前一篇文章已经给出了关于“迁移学习”、“模型选择”、“模型实现选择”、“知道如何创建模型”和“知道最后一层”的描述。
简而言之,第一部分是训练和预测前的准备工作。在本文(第 2 部分)中,我将介绍如何加载预先训练的参数,如何重新缩放输入图像,如何选择批量大小,然后我们将研究结果。你可以在我的 Github 库上找到 jupyter 笔记本。
知道如何加载预先训练好的重量
如果您从官方网站下载重量,并试图将它们加载到您自己的模型中,这将是一项艰巨的工作。这将在一个单独的故事中解释,我以后会写它。然而,如果您已经找到了一个方便的实现,那么这一步就没有必要了。事实上,几乎每个第三方实现都附带了实用函数。
对于张量网,当你在 tf 上运行 pretrained()方法时。会话,它将开始下载预先训练好的参数并为您加载。这很简单。(提醒一下,logits 是 tensornets 自己创建的 VGG19 模型。VGG19())
知道如何重新缩放原始图像(数据)以适合模型
在第 1 部分中,我们看到 ImageNet 的输入图像的形状是(224,224,3),我们准备了大小完全相同的 tf.placeholder。然而, CIFAR-10 中的图像有一个不同的形状,(32,32,3),相当小。不同形状的图像不能输入到现有的模型中,因为矩阵乘法不起作用。相反,我们应该做的是将图像重新缩放到(224,224,3)。
重新缩放的过程可以通过skimage . transform包来处理。skim age . transform包附带了resize方法。它有点像 resize(image,output_shape,…) 。有很多参数需要传递,但前两个是最重要的。您传递带有所需 output_shape 的原始图像,在我们的例子中是(224,224,3),然后 resize 将返回重新缩放的图像。
在重新缩放图像之后,我们需要将它们堆叠在一个数组中,以便可以将一批图像输入到模型中。
批量
批量大小会受到您的设置环境和您选择的模型的影响。如第 1 部分所示,VGG16 和 VGG19 的尺寸相对较大。这意味着如果你批量分配大量的输入图像,物理内存将无法处理它。如果在 GPU 上运行,这个问题可能会更敏感,因为 GPU 通常内存较少。
就我而言,我已经在 11GB 内存的英伟达 GTX 1080Ti 上运行了培训。我已经试验过像 256 这样的大批量,并且随着时间的推移我减少了这个数量。原来我的 GPU 一次只能负担 32 的批量大小。
有效集内的精度测量
如果你在那里寻找一些简单的深度学习例子,你会发现他们试图评估整个有效集的准确性。但是,我发现 VGG16 和 VGG19 型号并不是这样。正如我在上一节中解释的那样,我的 GPU 一次只能处理 32 张图片,而我的有效图片集中有 5000 张图片。
因此,我决定对批处理中的有效集运行精度测量过程。
结果
下面的截图就是结果。我从测试集中随机抽取了 10 张图片。正如你所看到的,VGG19 模型在 CIFAR-10 图像数据集上学习得很好,即使它只有这么小的图像。
摘要
在结束这个故事之前,我想简单总结一下。
- 迁移学习是建立图像分类系统的良好起点**
- 选择型号取决于你的物理(硬件) 环境和你的团队的目标(有多少种类?).
- 选择模型实现并不重要,但是有助于简化整个过程。
- 使用第三方实现时,要知道三件事。‘如何创建模型?’、‘最后一层是什么?’,以及“如何加载预训练参数?’
- 重要的是到知道如何重新缩放*你自己的输入图像以适合所选的模型(使用 skimage.transform 包)。*
- 应根据您的物理(硬件)环境仔细考虑批次大小。