用龙与地下城理解概率论
第一章:独立事件&二项分布
http://strangerthings.wikia.com/wiki/Dungeons_%26_Dragons
概率论是一个丰富的数学分支,也与哲学、神学和逻辑交叉。概率论起源于 17 世纪,当时数学家帕斯卡和费马开始分析概率游戏的数学。帕斯卡和费马不仅对数学,而且对哲学和神学都有贡献。神学家和哲学专业的学生可能还记得帕斯卡的赌注,用简单的话来说,就是人类用自己的生命打赌上帝是否存在。因此,我们可以看到概率论的广泛影响。
我们可以认为概率论是一个涉及面很广的领域,但我相信只要给出有用的例子,它既直观又容易掌握。概率论也是数据科学不可或缺的一部分,了解这一领域的基础知识将为更高级的主题提供坚实的基础,如回归和贝叶斯分析。
最近几个月,我花时间阅读了各种关于概率论和统计学的书籍,包括库珀和韦克斯开创性的数据、模型和统计分析。鉴于这些文本通常是实验和分析的跳板,我觉得将 Cooper 和 Weekes 所涉及的一些公理转化为现实世界的例子可能会很有趣。鉴于更奇怪的东西暂时还不会回来,我想浏览一下概率论,用龙与地下城来比喻所讨论的各种公理。
在这第一篇文章中,我将介绍概率论中独立和相关事件的含义,以及二项式分布,这是任何数据科学家工具箱中必不可少的一部分。
Image by Diacritica
独立和非独立事件;滚动一个二十面模具
在概率论中,我们有独立事件和非独立事件。Cooper 和 Weekes 将依赖事件定义为第一个事件的结果影响第二个事件的结果。因此,独立事件是指第一个事件的结果不会影响第二个事件。
一个独立事件的完美例子是两次掷骰子;事实上,这是概率论中的一个经典例子。在今天的帖子中,我们将对它进行一点 D&D 扭曲。
让我们想象一下,我们已经在每周一次的 D&D 游戏中安定下来。我们的地牢主人分发我们的骰子,我们看一看那个有二十面的骰子。我们可以注意到,如果我们掷两次,第一次的结果不会影响第二次的结果。不像我们在 D&D 的许多选择,我们的第一卷不会影响我们的下一卷。
不像地下城主,也不像那个当你的探险队询问桥边地精时一点帮助都没有的古怪村民,骰子不记得!
通过理解概率的数学,我们可以计算两个或更多独立事件的概率,因此可以连续两次掷出 20 个。找出这一点的乘法定理如下:
如果 A 和 B 是独立的,那么 p(A 和 B) = P(A) * P(B)
让我们想象一下,我们需要用 D&D 的招牌骰子让掷出两个二十个骰子。就其本身而言,20 卷的概率是 1/20。因此,p(A 和 B)的概率为:
1/20 * 1/20 = 0.0025
如您所见,这种情况发生的概率非常低!让我们希望我们不需要在我们的游戏中做两个 20 的卷。
https://www.flickr.com/photos/42405591@N02/11013366686
介绍二项式分布
这一切都很好;我们现在知道我们的掷骰子不会相互影响。然而,我们还想知道在游戏中达到一定数量的 x 次掷骰数( n )的可能性有多大。我们知道,我们在游戏中的表现取决于我们掷骰子的结果——正如任何以前玩过 D & D 的人一样,有时 6 和 8 之间的差异可能意味着一切。
让我们回到谈判桌前,赶上我们的进度。我们的冒险就要结束了,情况不妙。我们走投无路了——对我们这群勇敢的冒险家来说,情况看起来不妙。我们在游戏中还有四次机会。我们需要在其中的三个上得到 20!
在概率论的框架下;我们有 n 次试验,我们的目标是 x 次成功,或者 n = 4,x = 3。
有了概率论,就可以理解我们勇敢的冒险者接这个任务的可能性有多大,或者说我们的地下城主在这些掷骰子的时候有多残忍(剧透;相当残忍)。我们可以使用二项式分布来做到这一点,二项式分布“描述了随机变量 x 在 n 次实验中出现次数的概率分布”(Cooper & Weekes,1983)。
分布的方程式如下:
关于阶乘的一个注记(n!还有 x!)
如果你是第一次统计 n!看起来会很困惑。n!指阶乘,即 n 乘以一系列递减的自然数。所以如果 n = 4,那么 n!是:
4 * 3 * 2 * 1
回到二项式
在 R 中,我们可以使用二项式函数来找出 4 次掷骰中有 3 次成功的可能性,例如,我们将在 4 次中掷出 23 次。我们知道掷出 20 的概率是 1/20。我们将使用 R 的 dbinom 函数,它采用以下值:
##Sample values
dbinom(x, size, prob, log = FALSE)dbinom(3,4,(1/20))
= 0.000475
几率肯定对我们不利。这是一个残酷的地下城主!对于你们当中勇敢的人来说,这里有一个 R 版本的文本游戏,它要求你从四个骰子中掷出三个二十来拯救你的勇敢冒险者。被警告;你可能会死(没有骰子相关的双关语)。要玩这个游戏,只需将代码复制并粘贴到你的 R 控制台上,然后输入 startGame()
用 D&D 理解二项分布
github.com](https://github.com/hollyemblem/dd-binomial/blob/master/binomial-script.R)
重温我们的冒险
因此,我们已经了解了如何用概率论来理解用我们的骰子掷出两个 20 的机会,或者更广泛地说,乘法定理如何适用于独立事件。我们还学习了如何使用二项式分布来预测 n 次试验中的 x 次成功。我们也知道我们的地下城主有点刻薄,这不是什么好消息,但我们还是继续冒险!
掷骰子很有趣,但在我们的下一个游戏中,我们想改变一些事情。我们的地下城主承诺她会为我们的玩家准备一些新的角色表,但是,因为她有点刻薄,我们不能选择我们的新职业,相反,我们会从桌子上随机抽取一个。有 6 张,2 个德鲁伊,1 个野蛮人,1 个圣骑士,1 个术士和 1 个吟游诗人。我们需要计算出得到每个角色类别的概率。
在下一篇文章中,我们将着眼于相关事件和条件概率来帮助回答这个问题。我们可能还会问为什么我们的地下城主如此刻薄。
有用的资源
https://www . varsitytutors . com/hotmath/hotmath _ help/topics/binomial-probability
http://www . r-tutor . com/elementary-statistics/probability-distributions/binomial-distribution
https://stat . ethz . ch/R-manual/R-devel/library/stats/html/binomial . html
通过聚类分析了解卡纳塔克邦的初等教育质量
tldr;为什么要进行这项研究,研究结果是什么?
新千年见证了小学入学率的大幅提升,从 2001 年的 79%上升到 2014 年的 93%。但正如我在之前的博客“通过数据可视化解读印度:印度教育系统”中所展示的,印度许多邦已经很低的学习水平在最近几年进一步下降。尽管本应影响学习成果的因素显示出有利的趋势,但还是发生了这种情况。私立学校在增加,辍学率很低并且保持稳定,一个班级的学生人数在下降,每个教师的学生人数也在下降。随着 2009 年《实时教育法》的通过,更多的资金以设施、学习材料等形式注入教育系统。那么,如何解释这种糟糕的学习状态呢?社会经济因素如成人文化程度、种姓制度是否在起作用?在本研究中,我使用聚类算法通过卡纳塔克邦的案例研究来挖掘潜在的原因。该算法创建了以小学学习成果为重点的学区群,并对每个学区群的特征进行了分析。
聚类分析产生 3 个聚类,标记为“第 1 层”、“第 2 层”和“第 3 层”。在各学区中,第 1 级的学习成果最高,第 3 级最低。每个组群的地区如下。
那么,区别特征是什么呢?请继续读下去…
来自 ASER、DISE 和 SocialCops 的数据
在我之前的博客文章中,我已经提到了 DISE 和阿瑟。概括地说,ASER(年度教育状况报告)是一项年度调查,旨在为印度每个地区和邦的儿童入学率和基本学习水平提供可靠的估计。这项调查由非政府组织 Pratham 与当地伙伴组织的志愿者合作进行。
DISE(地区教育信息系统)收集全国所有学校的入学率、基础设施、教师和其他可用设施的信息。该数据库由国立教育规划和管理大学开发和维护。
第三,其中一个参数,即 RTE 符合性分数,来自 socialcops.com 网站。这里提取了 DISE 数据库中的 RTE 值,并计算了一个综合分数,以评估每个区的 RTE 实施水平。想了解更多关于 RTE 的知识?参考这篇文章。
准备集群
数据分析参数有哪些?【2014 年收集了所有来源的数据。为什么是 2014 年?那一年来自所有三个来源的数据质量要好得多。例如,RTE 合规分数在随后几年无法在 socialcops.com 网站上获得。这项研究使用了卡纳塔克邦 26 个区的小学数据。Ramanagar、Yadgir、Chikkaballapur 和 Bangalore Urban 等地区不包括在内,因为 ASER 调查没有收集这些地区 2014 年的学习成果。这里使用了 18 个参数进行分析,包括社会经济特征、入学率、学校类型、教学媒介、学习水平。
**一如既往的 R:**R 依然是我的最爱。所有用于数据准备、模型建立和可视化的代码都是用 r 编写的。
**探索数据:**这里的分析单位是区。使用箱线图和汇总函数进行数据探索。箱线图检测了变量的异常值,如男女比例、教师的性别分布、非在校儿童、私立学校入学率和阅读水平。经过进一步检查,发现这些值是适当的,没有应用异常值处理。
**关于聚类分析的更多信息:**聚类分析是一种基于无监督学习的数据挖掘技术。无监督学习探索“未标记”或“未分类”的数据,以找到隐藏的模式。这里没有目标属性。聚类分析将描述相似特征的对象分组。由于观测值较少,这里选择凝聚层次聚类技术。在各种凝聚过程中,使用沃兹方法。这种方法会合并对象,从而尽可能降低簇内方差。
**缩放和加权:**每个变量使用不同的测量类型。在本研究使用的变量中,教师的男女比例和性别分布是比率,RTE 合规分数以 10 分制衡量,而其余变量是百分比。对于有效的聚类,将变量调整到一个共同的范围是非常重要的。这被称为“缩放”。应用基础包中的函数“scale ”,将所有值标准化为 z 分数。下一步是“称重”。因为我们希望基于它们的性能来区分集群,所以我们给学习结果变量增加了更多的权重。我们将结果值增加了三倍。
建立模型
**确定聚类数:**如何确定聚类数?为此,使用了肘法、剪影法和间隙统计法等方法。r 包 factoextra 用于确定给定聚类方法和数据可视化的最佳聚类数。
所以,在 2 和 3 之间很难抉择。为了收集更多关于区分因素的信息,我决定分成 3 组。
**计算距离矩阵:*凝聚式层次聚类算法以距离矩阵为输入。距离矩阵是显示对象对之间距离的表格。这里,r 包 factoextra 再次用于计算和可视化距离。*计算每个特征的一对区域之间的欧几里德距离。生成的热图如下,随着距离的增加,颜色从红色变为蓝色。
**算法:**在凝聚层次聚类中,每个对象被分配到自己的聚类中,然后算法迭代进行,在每个阶段加入两个最相似的聚类,继续进行,直到只有一个聚类。这里,来自集群包的 hclust 函数用于构建算法。被监护人的方法。“D2”用于在每次迭代中合并两个相似的聚类。该算法生成以下树状图。
使用 cutree 功能,在 3 处截取树状图,确定为最佳数量。
通过专题地图可视化集群
使用 sp 、 rgdal 、raster 和 tmap 软件包构建了一个显示学习成果的卡纳塔克邦专题地图。
我们来分析一下集群
学习成果不太令人满意
即使在这些地区中学习水平最高的一级地区,也只有四分之三的儿童(STD 3-5)能够阅读标准 1 课文,只有三分之二的儿童(STD 3-5)能够做减法。在占总区一半以上的三级区中,平均值分别下降到 50%和 30%。
第三级的更多地区
表现最差的第 3 层集群有 14 个区。这个数字比其他两个性能更高的集群加起来还要多。性能最高的集群,第 1 层只有 4 个地区。
区分集群的因素
**识字率:**与第二层相比,第一层的总体识字率和女性识字率至少高出 10%,第二层是表现第二好的组群。一级教育的总体识字率超过 80%,而女性识字率约为 75%。三级学校的整体识字率和女性识字率最低,分别徘徊在 70%和 60%左右。
**种姓分布:**在一级地区,在册种姓和在册部落的入学率较低,分别为 11%和 3%。对于二级和三级学校,在册种姓入学率超过 20%。在三级学校中,ST 的入学率最高,为 11%。
OBC 的入学率在一级区最高,为 77%,其次是二级区的 66%和三级区的 56%。
**在册种姓和在册部落教师:**在一级区,在册种姓和在册部落教师的比例较低。在册种姓教师占教师总数的 8%,而在册部落教师约占 3%。在二线和三线城市,在册种姓和在册部落教师的比例分别约为 15%和 5%。
**男教师:**在一级地区,男教师比女教师多 2:1。在第二级和第三级,男女教师人数相当。
**教学语言:**在一级区,五分之一的儿童以英语为教学语言,是三级区平均水平的两倍。在二级学校,15%的学生选择英语作为教学语言。
**私立学校入学率:**私立学校入学率在一级区很高,为 35%,其次是二级区的 26%和三级区的 22%
**失学儿童:**在三级区,失学儿童的比例很高,为 3%。在一级和二级地区,不到 1%的儿童失学。
**学生教室比率(SCR) > 30 和学生教师比率(PTR) > 30 的学校百分比:**学生教室比率> 30 和学生教师比率> 30 的学校百分比在三级区更多,分别为 22%和 13%。一级和二级地区的选择性接种率约为 10 %, PTR 约为 7%。
集群之间的相似性
儿童性别比例 : 各区儿童性别比例差异不大。每一级的平均男女比例都在 0 . 9 以上
RTE 得分:集群的平均 RTE 得分高于 8。
事实检验
每个聚类中的平均值可以显示在下表中。
结论
这项研究表明了影响学习成果的因素。一些积极影响学习成果的因素包括私立学校教育、英语作为教学媒介、整体和女性识字率、学生课堂比率和学生教师比率。这项研究还表明,即使在成绩最好的地区,学习成绩也达不到理想水平。所以,我们需要更多的数据来解释糟糕的学习状态。这可能包括学生和教师出勤率、教学质量、教师积极性水平、学生认知水平等方面的数据。这样的数据还不能从二手资料中获得,而且像教学质量、教师激励水平、学生认知水平等也很难量化。因此,任何深入研究这个问题的未来研究都需要收集原始数据。这既费时又费钱。但是我一定会继续努力…
想看看代码吗?参考我的 github 库。
理解随机变量
随机变量在统计学和概率学中非常重要,如果有人想了解概率分布,这是必须的。随机变量经常与传统变量混淆。在这篇博文中,我们将看到什么是随机变量,以及为什么我们需要它们而不是传统变量。
Photo by Alois Komenda on Unsplash
在概率统计中,随机变量、随机数量或随机变量是一个变量,其可能值是随机现象的结果——维基百科
随机变量不同于我们传统的变量,就它所取的值而言。这是一个将随机过程的结果映射成数值的函数。
由于它具有随机性,所以取不同的值。
为什么是随机变量?
随机变量允许我们用数学的方式提问。
如果我们抛 5 枚硬币,想回答这样的问题:
1.恰好得到 3 个头的概率是多少?
2.少于 4 头的概率有多大?
3.得到 1 头以上的概率有多大?
那么我们一般的写法是:
p(当我们掷 5 次硬币时,恰好得到 3 个正面的概率)
p(当我们掷 5 次硬币时,得到少于 4 个正面的概率)
p(当我们掷 5 次硬币时,得到 1 个以上人头的概率)
但是,如果我们用随机变量来表示上述问题,那么我们会写:
1.P(X=3)
2.P(X <4)
3. P(X> 1)
正如我们在上面看到的,随机变量使我们的任务更容易量化任何随机过程的结果,应用数学和执行进一步的计算。
假设我们有一个投掷硬币的随机过程/实验。两种可能结果中的一种可能是正面或反面。所以这里我们用 X 来表示随机变量,它代表这个随机过程的结果。
因此我们可以写作
X= 1,如果结果是正面
X= 0,如果结果是尾巴
这里,随机变量 X 将随机过程(抛硬币)的结果映射为数值(1 和 0)。
用来表示头部和尾部的值可以是任何值,不一定是 1 和 0。
为了便于理解,我们使用了 1 和 0。
将数值分配给随机过程结果的其他方式可以是:
X= 100,如果结果是正面
X= 50,如果结果是尾巴
总结为三点
我们有一个实验(扔硬币)
我们给每个事件赋予价值
这组值是一个随机变量。
随机变量与代数中使用的传统变量有何不同?
假设代数中使用的变量为 x,y,z,这里 x 可以是手机的数量,y =人头数,z=学生数。变量不过是一个字母字符,代表一个未知数。
例如:
x + 5 = 10
x 是一个变量,它的值是未知的,我们试图找到它的值。
经过评估,x=5。
随机变量不同于代数中的变量,因为它有一组完整的值,并且可以随机取其中的任何一个。代数中使用的变量一次只能有一个值。
如果随机变量 X={0,1,2,3}
那么 X 可以是随机的 0、1、2 或 3,其中每一个可能具有不同的概率。
我们用大写字母表示随机变量,以避免与传统变量混淆。
随机变量可以是离散的,也可以是连续的。
如果一个变量可以取可数个不同的值,那么它就是一个离散随机变量。
举个例子:在一个投掷 2 枚硬币的实验中,我们需要找出可能的人头数。
在这种情况下,X 是随机变量,它取的可能值是 0、1 和 2,这是离散的。
因此 X= {0,1,2}
如果一个随机变量在一个区间内取无穷多个值,则称其为连续的。
例如:假设一个城市的温度介于 30⁰和 45⁰之间。温度可以取 30⁰到 45⁰.之间的任何值所以温度可能是 30.13⁰或 40.15⁰,也可能是 30.13⁰和 40.15⁰.当我们说温度是 38⁰时,意思是它在 37.5 到 38.5 之间。所以在连续的随机变量中没有精确的或离散的观测值。
这是对随机变量的简单介绍。
感谢阅读!!
了解剩余网络
由于大型数据集和强大的 GPU 的可用性,图像识别近年来取得了进展,这使得非常深入的架构训练成为可能。Simonyan 等人,《VGG》的作者证明了通过简单地堆叠更多的层,我们可以提高精确度,在此之前,Yoshua Bengio 在他的专著《学习人工智能的深度架构》中对深度架构的有效性进行了令人信服的理论分析。
在以前的帖子中,我演示了如何将各种技术应用于卷积神经网络,包括批量标准化、丢弃和数据扩充。通过简单地叠加越来越多的卷积-批量归一化-relu 层,能建立更精确的系统吗?在某种程度上,精确度会提高,但是超过大约 25+层,精确度会下降。
明凯等人 2015 首次演示了深度问题,并提出了一个卓越的解决方案,此后允许训练超过 2000 层!越来越准确。在这篇文章中,我将解释他们的技术以及如何应用。
首先,由于渐变消失,许多层的精度下降,随着层深入,渐变变小,导致性能变差。这与过度拟合无关,因此,辍学者无法挽救它。微软亚洲研究院的何和他的同事设计的最终解决方案是引入剩余连接。这只是描述将先前层的输出连接到新层的输出的简单术语。
假设您有一个七层网络。在残差设置中,不仅要将第 1 层的输出传递到第 2 层,还要将第 1 层的输出加到第 2 层的输出上。
在标准网络中用***【f(x)*** 表示每一层 y = f(x)
然而,在残差网络中,
y = f(x)+x
Typical Structure of A Resnet Module
应用这一原理,作者赢得了 Imagenet 2015 ,并在所有标准计算机视觉基准测试中取得了新的最先进的结果。这个想法后来被扩展到深度学习的所有其他领域,包括语音和自然语言处理。
基础数学讲够了,让我们用代码来弄脏我们的手。
标准的两层模块如下
***def** Unit(x,filters):
out = BatchNormalization()(x)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
out = BatchNormalization()(out)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
**return** out*
概括地说,在这个模块中,我们传入一个输入 x,对它进行批处理规范化— relu- conv2d,然后输出通过同一个堆栈。
下面是一个 resnet 模块
***def** Unit(x,filters):
res = x
out = BatchNormalization()(x)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
out = BatchNormalization()(out)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
out = keras.layers.add([res,out])
**return** out*
这看起来非常相似,但有一个主要区别,首先,我们存储一个对原始输入的引用“res ”,在通过 batchnorm-relu-conv 层后,我们将输出添加到残差中,为了清楚起见,这是在该行中完成的
*out = keras.layers.add([res,out])*
这部分对应方程 y = f(x) + x
因此,我们可以通过将许多模块堆叠在一起来构建一个 resnet。
在此之前,我们需要稍微修改一下代码来考虑池。
***def** Unit(x,filters,pool=**False**):
res = x
**if** pool:
x = MaxPooling2D(pool_size=(2, 2))(x)
res = Conv2D(filters=filters,kernel_size=[1,1],strides=(2,2),padding=**"same"**)(res)
out = BatchNormalization()(x)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
out = BatchNormalization()(out)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
out = keras.layers.add([res,out])
**return** out*
请注意上面的一些内容,当我们合并时,我们输出的维数将不再匹配我们残差的维数,因此,我们不仅将合并应用于输入,而且残差也将通过步长为 1×1 的 conv 变换,该变换将滤波器投影为与输出相同,并且步长为 2 将是维数的一半,就像最大合并一样。
解释完之后,我现在将给出完整的答案。
***def** Unit(x,filters,pool=**False**):
res = x
**if** pool:
x = MaxPooling2D(pool_size=(2, 2))(x)
res = Conv2D(filters=filters,kernel_size=[1,1],strides=(2,2),padding=**"same"**)(res)
out = BatchNormalization()(x)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
out = BatchNormalization()(out)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
out = keras.layers.add([res,out])
**return** out**def** MiniModel(input_shape):
images = Input(input_shape)
net = Conv2D(filters=32, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(images)
net = Unit(net,32)
net = Unit(net,32)
net = Unit(net,32)
net = Unit(net,64,pool=**True**)
net = Unit(net,64)
net = Unit(net,64)
net = Unit(net,128,pool=**True**)
net = Unit(net,128)
net = Unit(net,128)
net = Unit(net, 256,pool=**True**)
net = Unit(net, 256)
net = Unit(net, 256)
net = BatchNormalization()(net)
net = Activation(**"relu"**)(net)
net = Dropout(0.25)(net)
net = AveragePooling2D(pool_size=(4,4))(net)
net = Flatten()(net)
net = Dense(units=10,activation=**"softmax"**)(net)
model = Model(inputs=images,outputs=net)
**return** model*
这不包括训练代码,你可以看到,下面是训练代码,纪元设置为 50 个纪元。
你可以用谷歌实验室在 GPU 上免费运行这个
**#import needed classes* **import** keras
**from** keras.datasets **import** cifar10
**from** keras.layers **import** Dense,Conv2D,MaxPooling2D,Flatten,AveragePooling2D,Dropout,BatchNormalization,Activation
**from** keras.models **import** Model,Input
**from** keras.optimizers **import** Adam
**from** keras.callbacks **import** LearningRateScheduler
**from** keras.callbacks **import** ModelCheckpoint
**from** math **import** ceil
**import** os
**from** keras.preprocessing.image **import** ImageDataGenerator
**def** Unit(x,filters,pool=**False**):
res = x
**if** pool:
x = MaxPooling2D(pool_size=(2, 2))(x)
res = Conv2D(filters=filters,kernel_size=[1,1],strides=(2,2),padding=**"same"**)(res)
out = BatchNormalization()(x)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
out = BatchNormalization()(out)
out = Activation(**"relu"**)(out)
out = Conv2D(filters=filters, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(out)
out = keras.layers.add([res,out])
**return** out
*#Define the model* **def** MiniModel(input_shape):
images = Input(input_shape)
net = Conv2D(filters=32, kernel_size=[3, 3], strides=[1, 1], padding=**"same"**)(images)
net = Unit(net,32)
net = Unit(net,32)
net = Unit(net,32)
net = Unit(net,64,pool=**True**)
net = Unit(net,64)
net = Unit(net,64)
net = Unit(net,128,pool=**True**)
net = Unit(net,128)
net = Unit(net,128)
net = Unit(net, 256,pool=**True**)
net = Unit(net, 256)
net = Unit(net, 256)
net = BatchNormalization()(net)
net = Activation(**"relu"**)(net)
net = Dropout(0.25)(net)
net = AveragePooling2D(pool_size=(4,4))(net)
net = Flatten()(net)
net = Dense(units=10,activation=**"softmax"**)(net)
model = Model(inputs=images,outputs=net)
**return** model
*#load the cifar10 dataset* (train_x, train_y) , (test_x, test_y) = cifar10.load_data()
*#normalize the data* train_x = train_x.astype(**'float32'**) / 255
test_x = test_x.astype(**'float32'**) / 255
*#Subtract the mean image from both train and test set* train_x = train_x - train_x.mean()
test_x = test_x - test_x.mean()
*#Divide by the standard deviation* train_x = train_x / train_x.std(axis=0)
test_x = test_x / test_x.std(axis=0)
datagen = ImageDataGenerator(rotation_range=10,
width_shift_range=5\. / 32,
height_shift_range=5\. / 32,
horizontal_flip=**True**)
*# Compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied).* datagen.fit(train_x)
*#Encode the labels to vectors* train_y = keras.utils.to_categorical(train_y,10)
test_y = keras.utils.to_categorical(test_y,10)
*#define a common unit* input_shape = (32,32,3)
model = MiniModel(input_shape)
*#Print a Summary of the model* model.summary()
*#Specify the training components* model.compile(optimizer=Adam(0.001),loss=**"categorical_crossentropy"**,metrics=[**"accuracy"**])
epochs = 50
steps_per_epoch = ceil(50000/128)
*# Fit the model on the batches generated by datagen.flow().* model.fit_generator(datagen.flow(train_x, train_y, batch_size=128),
validation_data=[test_x,test_y],
epochs=epochs,steps_per_epoch=steps_per_epoch, verbose=1, workers=4)
*#Evaluate the accuracy of the test dataset* accuracy = model.evaluate(x=test_x,y=test_y,batch_size=128)
model.save(**"cifar10model.h5"**)*
希望你喜欢这一点,未来的帖子将致力于通过宽度和深度轻松扩展剩余网络的方法,以及调整学习速度的方法。
玩得开心,别忘了留下一些掌声!
你可以随时在推特上通过 @johnolafenwa 联系我
了解 RMSprop —更快的神经网络学习
免责声明:我假定关于神经网络优化算法的基础知识。特别是关于 SGD 和 SGD 带动量 的知识,会对理解这篇帖子很有帮助。
一、简介
RMSprop—是为神经网络设计的未发布的优化算法,由 Geoff Hinton 在在线课程“用于机器学习的神经网络”【1】的第 6 讲中首次提出。RMSprop 属于自适应学习率方法领域,这种方法近年来越来越受欢迎,但也受到一些批评[6]。它因没有出版而出名,但却非常出名;大多数深度学习框架都包括开箱即用的实现。
有两种方法可以引入 RMSprop。首先,将它视为 rprop 算法对小批量学习的适应。这是开发这种算法的最初动机。另一种方法是看看它与 Adagrad[2]的相似之处,并将 RMSprop 视为应对其学习率急剧下降的一种方式。我将尝试触及这两点,这样就能更清楚为什么这个算法有效。
二。RPROP
让我们先来了解一下rprop
——用于整批优化的算法。Rprop [3]试图解决梯度幅度可能变化很大的问题。一些梯度可能很小,而另一些可能很大,这导致了非常困难的问题——试图为算法找到单一的全局学习速率。如果我们使用整批学习,我们可以通过只使用梯度的符号来处理这个问题。这样,我们可以保证所有权重更新的大小相同。这种调整对鞍点和平台有很大帮助,因为我们即使在很小的坡度下也能迈出足够大的步伐。请注意,我们不能仅仅通过提高学习率来做到这一点,因为我们在大梯度下采取的步骤会更大,这将导致发散。Rprop 结合了仅使用梯度符号的思想和为每个权重单独调整步长的思想。因此,我们不看梯度的大小,而是看为特定权重定义的步长。步长随着时间的推移而不断调整,这样我们就可以朝着我们需要的方向加速学习。为了调整某些权重的步长,使用以下算法:
- 首先,我们看看重量的最后两个梯度的符号。
- 如果它们具有相同的符号,这意味着我们正朝着正确的方向前进,并且应该将它加速一小部分,这意味着我们应该成倍地增加步长(例如,增加 1.2 倍)。如果它们不同,这意味着我们做了太大的步长并且跳过了局部最小值,因此我们应该成倍地减小步长(例如通过因子 0.5)。
- 然后,我们将步长限制在两个值之间。这些值实际上取决于您的应用程序和数据集,默认的好值是 50 和百万分之一,这是一个好的开始。
- 现在我们可以应用权重更新。
注意,作者定义了不同版本的 rprop 算法。为了让您熟悉它,我已经展示了最简单的一个。虽然我喜欢用等式正式定义优化算法,但这种算法最好通过代码来表达;因此,rprop 更新规则的最简单版本如下所示:
三。Rprop 至 RMSprop
当我们拥有非常大的数据集并且需要执行小批量权重更新时,Rprop 实际上不起作用。为什么它不适用于小批量?人们已经尝试过了,但是发现很难成功。它不起作用的原因是它违反了随机梯度下降背后的中心思想,即当我们有足够小的学习率时,它会在连续的小批量上平均梯度。考虑重量,九个小批量的梯度为 0.1,十分之一小批量的梯度为-0.9。我们想要的是这些梯度大致互相抵消,这样保持大致相同。但 rprop 不是这样。使用 rprop,我们将权重增加 9 次,只减少一次,因此权重会增加很多。
要结合 rprop 的稳定性(仅通过使用梯度的符号)、我们从小批量获得的效率以及对小批量求平均值(允许以正确的方式结合梯度),我们必须从不同的角度来看待 rprop。Rprop 相当于使用梯度,但也除以梯度的大小,因此无论特定梯度有多小,我们都会得到相同的幅度。小批量的问题是,我们每次除以不同的梯度,那么为什么不强制我们除以的数字对于相邻的小批量是相似的呢?RMSprop
的中心思想是保持每个权重的平方梯度的移动平均值。然后我们将梯度除以均方根。这就是它被称为 RMSprop(均方根)的原因。使用数学等式,更新规则如下所示:
E[g] — moving average of squared gradients. dC/dw — gradient of the cost function with respect to the weight. n — learning rate. Beta — moving average parameter (good default value — 0.9)
从上面的等式可以看出,我们通过除以梯度的平方根来调整学习率,但是由于我们只有当前小批量的梯度估计值,因此我们需要使用它的移动平均值。您可以在项目中使用的移动平均参数的默认值是 0.9。对于大多数应用程序来说,它工作得非常好。在代码中,该算法可能如下所示:
四。与阿达格拉德相似。
Adagrad[2]是自适应学习速率算法,看起来很像 RMSprop。Adagrad 基于每个维度中的历史平方和添加元素式渐变缩放。这意味着我们保留了一个梯度平方和。然后我们通过除以总和来调整学习率。在代码中,我们可以这样表达它:
当我们有高条件数时,这个比例有什么作用?如果我们有两个坐标——一个总是有大的梯度,另一个有小的梯度,我们将通过相应的大或小的数字潜水,所以我们在小的方向上加速运动,在梯度大的方向上,我们将减速,因为我们除以某个大的数字。
培训过程中会发生什么?步数变得越来越小,因为我们在训练中不断更新增长的平方梯度。所以我们每次都除以较大的数。在凸优化中,这很有意义,因为当我们接近 minina 时,我们希望慢下来。在非凸的情况下,这是不好的,因为我们可以卡在鞍点。我们可以将 RMSprop 视为解决这一问题的算法。
使用 RMSprop,我们仍然保留平方梯度的估计值,但我们保留了它的移动平均值,而不是让该估计值在训练中不断累积。
动词 (verb 的缩写)结果
我为不同的优化算法找到了这些令人敬畏的可视化效果,展示了它们在不同情况下的表现。
Source: https://imgur.com/a/Hqolp#NKsFHJb
如你所见,在鞍点的情况下,RMSprop(黑线)直线下降,梯度有多小并不重要,RMSprop 缩放学习速率,因此算法通过鞍点的速度比大多数算法都快。
Source: https://imgur.com/a/Hqolp#NKsFHJb
在这种情况下,算法从初始梯度非常大的点开始。RMSprop(黑线)走的几乎是最优路径,而动量法超调很多。阿达格拉德在那一瞬间变得不稳定。
不及物动词结论(了解更多信息)
RMSprop 是一款优秀、快速且非常受欢迎的优化器。Andrej Karpathy的《机器学习趋势一瞥【4】显示,它是深度学习中使用的最流行的优化算法之一,其受欢迎程度仅次于 Adam【5】。如果你想了解更多关于深度学习中的优化,你应该查看以下一些来源:
- Sebastian Ruder 的博客有几篇关于深度学习优化趋势的文章。
- fast.ai 是一门很棒的关于深度学习的课程,他们通过最流行的优化算法,在 excel 表格上解释它们。
- 吴恩达在 coursera 上的深度学习专业的第二门课程也触及了流行的算法,以非常清晰的方式解释了它们。
七。参考
[1] Geoffrey Hinton 用于机器学习的神经网络 nline 课程。https://www.coursera.org/learn/neural-networks/home/welcome
[2]阿达格勒:杜奇,j .,哈赞,e .,辛格,Y. (2011 年)。在线学习和随机优化的自适应次梯度方法。机器学习研究杂志,12,2121–2159。从 http://jmlr.org/papers/v12/duchi11a.html取回
[3]克里斯蒂安·伊格尔和迈克尔·̈usken(2000 年)。改进 Rprop 学习算法。【http://citeseerx.ist.psu.edu/viewdoc/summary? doi=10.1.1.17.1332
[4]安德烈·卡帕西(2017)。机器学习趋势一瞥。https://medium . com/@ karpathy/a-peek-at-trends-in-machine-learning-ab8a 1085 a 106
[5]金马,D. P .,&巴,J. L. (2015 年)。亚当:一种随机优化方法。学习表征国际会议,1–13
[6] Ashia C. Wilson 、Rebecca Roelofs 、Mitchell Stern 、Nati Srebro、Benjamin Recht(2017)机器学习中自适应梯度方法的边际价值。arXiv:1705.08292v2
了解设置 SettingWithCopyWarning
是人们在学习熊猫时遇到的最常见的障碍之一。快速的网络搜索会发现大量的堆栈溢出问题、GitHub 问题和来自程序员的论坛帖子,他们试图理解这个警告在他们的特定情况下意味着什么。这并不奇怪,许多人都在为此挣扎;有很多方法来索引 pandas 数据结构,每种方法都有其独特的细微差别,甚至 pandas 本身也不能保证两行看起来相同的代码有一个单一的结果。
本指南解释了产生警告的原因,并向您展示了解决方法。它还包括引擎盖下的细节,让您更好地了解正在发生的事情,并提供了一些关于该主题的历史,让您了解为什么它都是这样工作的。
为了探究SettingWithCopyWarning
,我们将使用《建模在线拍卖一书中易贝 3 天拍卖中销售的 Xboxes 价格的数据集。让我们来看看:
正如你所看到的,我们数据集的每一行都涉及到一次特定的易贝 Xbox 拍卖的单一出价。以下是对每列的简要描述:
auctionid
—每个拍卖的唯一标识符。bid
—投标的价值。bidtime
—投标时拍卖的期限,以天为单位。bidder
—投标人的易贝用户名。bidderrate
-投标人的易贝用户评级。openbid
—卖家为拍卖设定的开价。price
—拍卖结束时胜出的出价。
什么是 SettingWithCopyWarning?
首先要明白的是SettingWithCopyWarning
是一个警告,而不是一个错误。
虽然错误表明出现了问题,例如无效的语法或试图引用未定义的变量,但警告的作用是提醒程序员他们的代码存在潜在的错误或问题,而这些错误或问题在该语言中仍然是允许的操作。在这种情况下,警告很可能表示一个严重但不明显的错误。
SettingWithCopyWarning
通知您您的操作可能没有按预期运行,您应该检查结果以确保没有出错。
如果您的代码仍然像预期的那样工作,忽略这个警告是很有诱惑力的。这是不好的做法,并且SettingWithCopyWarning
不应该被忽略。在采取行动之前,花些时间去理解为什么你会得到警告。
为了理解SettingWithCopyWarning
是关于什么的,理解 pandas 中的一些操作可以返回您的数据的视图,而其他操作将返回副本是有帮助的。
View vs copy
正如你在上面看到的,左边的视图df2
只是原始视图df1
的一个子集,而右边的副本创建了一个新的、唯一的对象df2
。
当我们试图进行更改时,这可能会导致问题:
Modifying a view vs modifying a copy
根据我们正在做的事情,我们可能想要修改原始的df1
(左),或者我们可能想要只修改df2
(右)。警告是让我们知道我们的代码可能做了一件事,而我们希望它做了另一件事。
稍后我们将深入探讨这个问题,但是现在让我们先来解决这个警告的两个主要原因以及如何修复它们。
链式分配
Pandas 在检测到一种叫做链式分配的东西时会发出警告。让我们定义几个我们将用来解释事情的术语:
- 赋值——设置值的操作,例如
data = pd.read_csv('xbox-3-day-auctions.csv')
。通常称为组。 - 访问—返回某个值的操作,例如下面的索引和链接示例。通常被称为 get 。
- 索引—引用数据子集的任何分配或访问方法;比如
data[1:5]
。 - 链接——连续使用多个索引操作;比如
data[1:5][1:3]
。
链式赋值是链接和赋值的组合。让我们快速看一个例子,它包含了我们之前加载的数据集。我们稍后将更详细地讨论这一点。为了这个例子,假设我们被告知用户'parakeet2004'
的投标人评级不正确,我们必须更新它。让我们从当前值开始。
我们有三行来更新bidderrate
字段;让我们继续做那件事。
哦不!我们神秘地发现了SettingWithCopyWarning
!
如果我们看一下,我们可以看到在这种情况下,值没有改变:
生成该警告是因为我们将两个索引操作链接在一起。这更容易发现,因为我们已经使用了两次方括号,但是如果我们使用其他访问方法,如.bidderrate
、.loc[]
、.iloc[]
、.ix[]
等等,情况也是如此。我们的连锁经营包括:
data[data.bidder == 'parakeet2004']
['bidderrate'] = 100
这两个连锁操作一个接一个地独立执行。第一个是访问方法(get 操作),它将返回一个包含所有行的DataFrame
,其中bidder
等于'parakeet2004'
。第二个是赋值操作(set 操作),在这个新的DataFrame
上调用。我们根本没有在原来的DataFrame
上操作。
解决方案很简单:使用loc
将链接的操作组合成一个操作,这样 pandas 可以确保原始的DataFrame
被设置。熊猫将始终确保不被束缚的集合操作(如下所示)正常工作。
这是警告建议我们做的,并且在这种情况下非常有效。
隐藏链接
接下来是人们遇到的第二种最常见的方式SettingWithCopyWarning
。让我们调查中标情况。我们将创建一个新的数据框架来处理它们,注意使用loc
,现在我们已经学习了关于链式赋值的课程。
我们可能会用 winners 变量写几行后续代码。
一个偶然的机会,我们在DataFrame
中遇到了另一个错误。这一次,标记为304
的行中缺少了bidder
值。
为了我们的例子,让我们说,我们知道这个投标人的真实用户名,并更新我们的数据。
又一个SettingWithCopyWarning
!但是我们用了loc
,怎么又出现这种情况了?为了进行研究,让我们看看代码的结果:
这次成功了,那我们为什么会收到警告呢?
链式索引既可以出现在两行中,也可以出现在一行中。因为winners
是作为 get 操作(data.loc[data.bid == data.price]
)的输出创建的,所以它可能是原始DataFrame
的副本,也可能不是,但是在我们检查之前没有办法知道!当我们索引winners
时,我们实际上使用的是链式索引。
这意味着当我们试图修改winners
时,我们可能也修改了data
。
在真正的代码库中,这些代码行可能相隔很远,因此追踪问题的根源可能更困难,但情况是一样的。
为了防止在这种情况下出现警告,解决方案是明确地告诉 pandas 在我们创建新的数据帧时制作一个副本:
就是这样!就这么简单。
诀窍是学会识别链式索引,并不惜一切代价避免它。如果你想改变原来的,使用单一的赋值操作。如果你想要一份拷贝,确保你强迫熊猫这么做。这将节省时间,并使您的代码滴水不漏。
还要注意的是,即使SettingWithCopyWarning
只会在你设置的时候出现,也最好避免 gets 的链式索引。链式操作速度较慢,如果您决定稍后添加赋值操作,会导致问题。
处理设置 SettingWithCopyWarning 的提示和技巧
在我们下面做更深入的分析之前,让我们拿出显微镜,看看SettingWithCopyWarning
的一些细微之处和本质细节。
关闭警告
首先,如果不讨论如何显式控制SettingWithCopy
设置,这篇文章将是不完整的。熊猫mode.chained_assignment
选项可以取其中一个值:
'raise'
—引发异常而不是警告。'warn'
—生成警告(默认)。None
—完全关闭警告。
例如,让我们关闭警告:
因为这不会给我们任何警告,所以除非你完全明白自己在做什么,否则不推荐这样做。如果你感到一丝怀疑,这是不可取的。一些开发人员非常认真地对待SettingWithCopy
,并选择将其提升为一个例外,就像这样:
如果您的团队中有一个没有经验的 pandas 开发人员,或者一个需要高度严谨性或完整性的确定性的项目,这可能会特别有用。
使用该设置的更精确的方法是使用上下文管理器。
如您所见,这种方法支持细粒度的警告抑制,而不是不加区别地影响整个环境。
is_copy 属性
另一个可以用来避免警告的技巧是修改熊猫用来解释SettingWithCopy
场景的工具之一。每个DataFrame
都有一个默认为None
的is_copy
属性,但是如果是副本,则使用一个[weakref](https://docs.python.org/3/library/weakref.html)
来引用源DataFrame
。通过将is_copy
设置为None
,可以避免生成警告。
然而,请注意,这将而不是奇迹般地解决问题,但是它确实使 bug 检测变得非常困难。
单类型与多类型对象
值得强调的另一点是单数据类型和多数据类型对象之间的区别。如果一个DataFrame
的所有列都是相同的数据类型,那么它就是单数据类型的;例如:
而如果DataFrame
的列不都具有相同的数据类型,那么它就是多数据类型的,例如:
由于下面的历史部分解释的原因,在多数据类型对象上的索引器获取操作将总是返回一个副本。然而,主要为了提高效率,索引器对单数据类型对象的 get 操作几乎总是返回一个视图;这里需要注意的是,这取决于对象的内存布局,并且不能保证。
假阳性
假阳性,或无意中报告了连锁分配的情况,过去在早期版本的 pandas 中更常见,但后来基本上被消除了。为了完整起见,这里包括一些固定误报的例子是有用的。如果您在使用早期版本的 pandas 时遇到以下任何情况,那么可以安全地忽略或取消警告(或者通过升级来完全避免警告!)
使用用于的当前列的值向DataFrame
添加新列会生成警告,但此问题已得到解决。
直到最近,当在一个DataFrame
的片上使用apply
方法设置时,一个假阳性也发生了,尽管这也已经被修复。
最后,直到版本 0.17.0,在[DataFrame.sample](http://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.sample.html)
方法中有一个错误导致了虚假的SettingWithCopy
警告。sample
方法现在每次都返回一个副本。
深度链式赋值
让我们重新使用之前的例子,我们试图用'parakeet2004'
的bidder
值更新data
中每一行的bidderrate
列。
pandas 用这个SettingWithCopyWarning
真正告诉我们的是,我们代码的行为是不明确的,但是要理解为什么是这样以及警告的措辞,回顾一些概念将是有帮助的。
我们之前简单地讨论了视图和副本。有两种方法可以访问一个DataFrame
的子集:要么在内存中创建一个对原始数据的引用(一个视图),要么将子集复制到一个新的、更小的DataFrame
(一个副本)。视图是查看原始数据特定部分的一种方式,而副本是数据在内存中新位置的 T21 克隆。正如我们前面的图表所示,修改视图会修改原始变量,但修改副本不会。
由于我们将在后面讨论的原因,熊猫的“get”操作的输出不能保证。当您索引一个 pandas 数据结构时,可能会返回一个视图或一个副本,这意味着对一个DataFrame
的 get 操作会返回一个新的DataFrame
,其中可能包含:
- 原始对象中数据的副本。
- 对原始对象数据的引用,但不制作副本。
因为我们不知道会发生什么,每种可能性都有非常不同的行为,忽视警告是在玩火。
为了更清楚地说明视图、副本和这种模糊性,让我们创建一个简单的DataFrame
并将其编入索引:
让我们将df1
的子集分配给df2
:
根据我们所了解的,我们知道df2
可能是df1
上的一个视图,或者是df1
的一个子集的副本。
在我们着手解决这个问题之前,我们还需要再看一看链式索引。用'parakeet2004'
扩展我们的例子,我们将两个索引操作链接在一起:
其中__intermediate__
代表第一次调用的输出,对我们完全隐藏。请记住,如果我们使用属性访问,也会得到同样有问题的结果:
这同样适用于任何其他形式的链式调用**,因为我们正在生成这个中间对象**。
实际上,链式索引意味着不止一次调用__getitem__
或__setitem__
来完成一个操作。这些是特殊的 Python 方法,通过在实现它们的类的实例上使用方括号来调用,这是所谓的语法糖的一个例子。让我们看看 Python 解释器将在我们的例子中执行什么。
您可能已经意识到,SettingWithCopyWarning
是这个链式__setitem__
调用的结果。您可以自己尝试一下——上面几行的功能完全相同。为了清楚起见,请注意第二个__getitem__
调用(针对bidder
列)是嵌套的,根本不属于这里的链接问题。
一般来说,如前所述,pandas 不保证 get 操作将返回数据的视图还是副本。如果在我们的例子中返回一个视图,那么我们的链式赋值中的第二个表达式将是对原始对象的__setitem__
调用。但是,如果返回一个副本,将被修改的是该副本——原始对象不会被修改。
这就是警告所说的“试图在数据帧的切片副本上设置值”的含义。由于没有对该副本的引用,它最终将被垃圾收集。SettingWithCopyWarning
让我们知道 pandas 不能确定第一个__getitem__
调用返回的是视图还是副本,因此不清楚赋值是否改变了原始对象。另一种思考熊猫为什么给我们这个警告的方式是因为“我们在修改原作吗?”是未知的。
我们确实想修改原始操作,警告建议的解决方案是使用loc
将这两个独立的链式操作转换成一个赋值操作。这将从我们的代码中删除链式索引,我们将不再收到警告。我们的固定代码及其扩展版本将如下所示:
我们的 DataFrame 的loc
属性保证是原始的DataFrame
本身,但是具有扩展的索引功能。
假阴性
使用loc
并不能解决我们的问题,因为使用loc
的 get 操作仍然可以返回视图或副本。让我们快速检查一个有点复杂的例子。
这次我们抽出了两列,而不是一列。让我们尝试设置所有的bid
值。
没有效果也没有警告!我们在一个切片的拷贝上设置了一个值,但熊猫没有检测到它—这是一个假阴性。仅仅因为我们使用了loc
并不意味着我们可以再次开始使用链式赋值。GitHub 上有一个关于这个特殊 bug 的旧的未解决的问题。
正确的做法如下:
您可能想知道在实践中怎么可能有人会遇到这样的问题,但是当我们在下一节中将DataFrame
查询的结果赋给变量时,这比您想象的要容易。
隐藏链接
让我们再来看看前面的隐藏链接示例,我们试图从我们的winners
变量中标有304
的行中设置bidder
值。
即使我们使用了loc
,我们还是得到了另一个SettingWithCopyWarning
。这个问题非常令人困惑,因为警告信息似乎在建议我们做我们已经做过的事情。
但是想想winners
这个变量。到底是什么?假设我们通过data.loc[data.bid == data.price]
实例化了它,我们无法知道它是视图还是原始data
T5 的副本(因为 get 操作要么返回视图,要么返回副本)。将实例化与生成警告的代码行结合起来,可以清楚地看出我们的错误。
我们再次使用了链式赋值,但是这次它被分成了两行。思考这个问题的另一种方式是问这样一个问题“这是修改了一个还是两个东西?”在我们的例子中,答案是未知的:如果winners
是一个副本,那么只有winners
受到影响,但是如果它是一个视图,winners
和data
都将显示更新的值。这种情况可能发生在脚本或代码库中相距很远的代码行之间,使得问题的根源很难追踪。
这里警告的目的是防止我们认为我们的代码会修改原来的DataFrame
,而实际上它不会,或者我们正在修改一个副本而不是原来的。深入研究熊猫 GitHub repo 的老问题,你可以阅读开发者自己对此的解释。
我们如何解决这个问题在很大程度上取决于我们自己的意图。如果我们乐于使用原始数据的副本,解决方案就是简单地强迫熊猫制作一个副本。
另一方面,如果您要求更新原始的DataFrame
,那么您应该使用原始的DataFrame
,而不是实例化具有未知行为的其他变量。我们之前的代码会变成:
在更复杂的情况下,例如修改一个DataFrame
的子集的子集,而不是使用链式索引,可以通过在原始DataFrame
上的loc
修改正在制作的切片。例如,您可以更改上面的新winner_mask
变量,或者创建一个新变量来选择获胜者的子集,如下所示:
这种技术对于未来的代码库维护和扩展更加健壮。
历史
您可能想知道为什么不能通过显式地指定返回视图或副本的索引方法来完全避免整个SettingWithCopy
问题,而不是制造我们发现自己所处的混乱局面。为了理解这一点,我们必须了解熊猫的过去。
pandas 用来确定它是返回一个视图还是一个副本的逻辑源于它对 NumPy 库的使用,这是 pandas 操作的基础。观点实际上是通过 NumPy 进入熊猫词典的。事实上,视图在 NumPy 中非常有用,因为它们是可预测地返回的。因为 NumPy 数组是单一类型的,pandas 试图通过使用最合适的数据类型来最小化空间和处理需求。因此,包含单个 dtype 的DataFrame
的片可以作为单个 NumPy 数组上的视图返回,这是处理操作的高效方式。然而,在 NumPy 中,多数据类型片不能以同样的方式高效地存储。Pandas 将通用的索引功能与最有效地使用其 NumPy 内核的能力结合在一起。
最终,pandas 中的索引被设计成有用和通用的,其核心并不完全结合底层 NumPy 数组的功能。随着时间的推移,设计和功能的这些元素之间的相互作用导致了一组复杂的规则,这些规则决定了视图或副本是否可以被返回。有经验的 pandas 开发人员通常对 pandas 的行为感到满意,因为他们可以轻松地导航其索引行为。
不幸的是,对于库的新手来说,链式索引几乎是不可避免的,尽管这并不是想要的方法,因为 get 操作返回可索引的 pandas 对象。更进一步,用熊猫几年的核心开发者之一 Jeff Reback 的话说,“从语言的角度来说,直接检测链式索引根本不可能;必须推断出来”。
因此,该警告在 2013 年底的版本 0.13.0 中引入,作为许多开发人员遇到的链式分配的静默失败的解决方案。
在 0.12 版本之前,[ix](http://pandas.pydata.org/pandas-docs/version/0.19.2/generated/pandas.DataFrame.ix.html)
索引器是最流行的(在 pandas 命名法中,ix
、loc
和iloc
等“索引器”是简单的构造,允许对象像数组一样用方括号索引,但具有特殊的行为)。但是大约在这个时候,也就是 2013 年年中,熊猫项目开始获得动力,迎合新手用户变得越来越重要。从这个版本开始,loc
和iloc
索引器因其更清晰的本质和更容易解释的用法而更受青睐。
Google Trends: pandas
在推出之后,SettingWithCopyWarning
一直在继续发展,几年来在许多 GitHub 问题上被热烈讨论,甚至现在还在更新,但是它还在这里,理解它对于成为熊猫专家仍然至关重要。
包扎
隐藏在SettingWithCopyWarning
背后的复杂性是熊猫库中为数不多的粗糙边缘之一。它的根源深深植根于图书馆,不应该被忽视。用 Jeff Reback 自己的话来说,“就我所知,没有任何情况下你应该忽略这个警告。…如果你做某些类型的索引,它永远不会工作,其他的它会工作。你真是在玩火。”
幸运的是,解决这个警告只需要您识别链式赋值并修复它。如果说我们能从这一切中吸取什么的话,那就是。
原文 发表 于data quest。
了解 SSD 多盒—深度学习中的实时对象检测
Example of end-to-end object detection (from Microsoft)
这篇文章旨在直观地解释固态硬盘多盒物体检测技术。我试图将数学最小化,而是慢慢地引导你理解这个架构的原则,包括解释多盒算法的作用。看完这篇文章后,我希望你对 SSD 有更好的了解,并亲自试用它!
自从 AlexNet 在 2012 ImageNet 大规模视觉识别挑战赛(ILSVRC)上席卷研究界以来,深度学习已经成为图像识别任务的首选方法,远远超过了文献中使用的更传统的计算机视觉方法。在计算机视觉领域,卷积神经网络擅长图像分类,它包括对图像进行分类,给定一组类(例如猫、狗),并让网络确定图像中存在的最强的类。
Images of cats and dogs (from kaggle)
如今,深度学习网络在图像分类方面比人类更好,这表明了这项技术的强大。然而,我们人类在观察世界和与世界互动时,不仅仅是对图像进行分类。我们还定位和分类我们视野内的每个元素。这些任务要复杂得多,机器仍然难以像人类一样完成。事实上,我认为当物体检测表现良好时,会使机器更接近真实场景的理解。
Does the image show cat, a dog, or do we have both? (from kaggle)
区域卷积神经网络(R-CNN)
几年前,通过利用 CNN 在计算机视觉中实现的一些飞跃,研究人员开发了 R-CNN 来处理对象检测、定位和分类的任务。概括地说,R-CNN 是一种特殊类型的 CNN,能够定位和检测图像中的对象:输出通常是一组与每个检测到的对象紧密匹配的边界框,以及每个检测到的对象的类输出。下图显示了典型的 R-CNN 的输出:
Example output of R-CNN
在这个领域有一个详尽的论文列表,对于任何渴望进一步探索的人,我建议从以下围绕该主题的论文“三部曲”开始:
正如你可能已经猜到的,接下来的每篇论文都提出了对 R-CNN 所做的开创性工作的改进,以开发更快的网络,目标是实现实时物体检测。通过这组工作展示的成就确实令人惊讶,然而这些架构中没有一个能够创建实时对象检测器。在不涉及太多细节的情况下,确定了上述网络的以下问题:
- 训练数据既麻烦又耗时
- 训练发生在多个阶段(例如,训练区域提议与分类器)
- 在推断 时间(即处理非训练数据时)网络太慢
幸运的是,在过去几年中,新的架构被创建来解决 R-CNN 及其后继者的瓶颈,实现实时对象检测。最著名的有 YOLO (你只看一次)和 SSD MultiBox(单发探测器)。在本帖中,我们将讨论 SSD,因为关于这种架构的报道似乎比 YOLO 少。此外,一旦你了解了固态硬盘,你应该会发现更容易掌握 YOLO。
单发多盒探测器
关于SSD:Single Shot multi box Detector(作者 C. Szegedy 等人)的论文于 2016 年 11 月底发布,并在对象检测任务的性能和精度方面创下新纪录,在标准数据集如 PascalVOC 和 COCO 上以每秒 59 帧的速度获得超过 74%的 mAP ( 均值 平均精度)。为了更好地理解 SSD,我们先来解释一下这种架构的名称来源:
- **单镜头:**这意味着物体定位和分类的任务是在网络的单次 前向传递中完成的
- 多框:这是 Szegedy 等人开发的一种包围盒回归技术的名字(我们将很快简要介绍)
- **检测器:**网络是一个对象检测器,它也对那些检测到的对象进行分类
体系结构
Architecture of Single Shot MultiBox detector (input is 300x300x3)
从上图中可以看出,SSD 的架构建立在古老的 VGG-16 架构之上,但抛弃了完全连接的层。VGG-16 被用作基础网络的原因是它在高质量图像分类任务中的强大性能,以及它在解决转移学习有助于改善结果的问题中的受欢迎程度。取代原来的 VGG 全连接层,增加了一组辅助卷积层(从 conv6 开始),从而能够在多个尺度上提取特征,并逐渐减小每个后续层的输入大小。
VGG architecture (input is 224x224x3)
多框
SSD 的边界框回归技术受到 Szegedy 在多框上的工作的启发,这是一种快速类不可知边界框坐标提议的方法。有趣的是,在 MultiBox 上完成的工作中,使用了 Inception 风格的卷积网络。您在下面看到的 1x1 卷积有助于降维,因为维度的数量会减少(但“宽度”和“高度”将保持不变)。
Architecture of multi-scale convolutional prediction of the location and confidences of multibox
MultiBox 的损失功能还结合了进入 SSD 的两个关键组件:
- 置信度损失:测量网络对计算边界框的对象的置信度。分类交叉熵用于计算这种损失。
- **位置损失:**这度量了距离多远网络的预测边界框与训练集中的地面真实边界框有多远。这里使用的是 L2 规范。
在不深究数学的情况下(如果你很好奇,想要一个更精确的符号,请阅读这篇论文),损失的表达式是这样的,它衡量我们的预测“着陆”有多远:
多框 _ 损失=置信度 _ 损失+阿尔法位置 _ 损失*
α项帮助我们平衡位置损失的贡献。像通常在深度学习中一样,目标是找到最佳地减少损失函数的参数值,从而使我们的预测更接近地面事实。
多箱前科和欠条
围绕边界框生成的逻辑实际上比我前面所说的更复杂。但不要害怕:它仍然触手可及。
在 MultiBox 中,研究人员创建了我们所谓的 priors (或 fast-R-CNN 术语中的锚点),它们是预先计算好的固定大小的边界框,与原始地面真相框的分布紧密匹配。事实上,那些先验是以这样一种方式选择的,即它们的交集/并集比(又名 IoU,有时也称为 Jaccard index )大于 0.5。正如您可以从下图中推断的那样,IoU 为 0.5 仍然不够好,但它确实为边界框回归算法提供了一个强有力的起点-这是一个比用随机坐标开始预测好得多的策略!因此,多框以先验作为预测开始,并试图回归更接近真实边界框。
Diagram explaining IoU (from Wikipedia)
所得到的架构(再次检查上面的多盒架构图以供参考)每个特征地图单元包含 11 个先验(8×8、6×6、4×4、3×3、2×2)并且在 1×1 特征地图上只有一个先验,导致每幅图像总共有 1420 个先验,从而能够以多种比例稳健地覆盖输入图像,以检测各种大小的对象。
最后,MultiBox 仅保留使位置( LOC )和置信度( CONF )损失最小化的前 K 个预测。
固态硬盘的改进
回到 SSD,增加了一些调整,使这个网络更有能力定位和分类对象。
**固定先验:**与多框不同,每个特征映射单元都与一组不同尺寸和纵横比的默认边界框相关联。这些先验是手动(但仔细)选择的,而在 MultiBox 中,选择它们是因为它们相对于地面真值的 IoU 超过 0.5。这在理论上应该允许 SSD 针对任何类型的输入进行推广,而不需要针对前一代的预训练阶段。例如,假设我们已经为每个 b 默认边界框配置了 2 个对角相对的点 (x1,y1) 和 (x2,y2) 以及 c 类进行分类,在给定大小为f =mn*的特征图上,SSD 将计算 f *
SSD default boxes at 8x8 and 4x4 feature maps
位置损失: SSD 使用平滑 L1 范数计算位置损失。虽然不像 L2 范数那样精确,但它仍然非常有效,并给 SSD 更多的操作空间,因为它不会试图在其边界框预测中做到“像素完美”(即,几个像素的差异对我们许多人来说很难察觉)。
分类: MultiBox 不执行对象分类,而 SSD 执行。因此,对于每个预测的边界框,为数据集中每个可能的类计算一组 c 类预测。
培训和运行固态硬盘
数据集
您将需要带有地面真实边界框和分配的类标签(每个边界框只有一个)的训练和测试数据集。Pascal VOC 和 COCO 数据集是一个很好的起点。
Images from Pascal VOC dataset
默认边界框
建议配置不同比例和长宽比的一组不同的默认边界框,以确保可以捕捉大多数对象。SSD 文件中每个要素地图像元大约有 6 个边界框。
特征地图
特征图(即卷积块的结果)是图像在不同比例下的主要特征的表示,因此在多个特征图上运行多框增加了任何物体(大的和小的)最终被检测、定位和适当分类的可能性。下图显示了网络如何通过其要素地图“看到”给定图像:
VGG Feature Map Visualisation (from Brown Uni)
硬负开采
在训练期间,由于大多数边界框将具有低 IoU,因此被解释为负训练示例,我们可能会在训练集中以不成比例数量的负示例结束。因此,不要使用所有的负面预测,建议保持负面与正面的比例在 3:1 左右。之所以需要保留阴性样本,是因为网络也需要学习并被明确告知什么构成了不正确的检测。
Example of hard negative mining (from Jamie Kang blog)
数据扩充
SSD 的作者表示,与许多其他深度学习应用一样,数据增强对于教会网络变得对输入中的各种对象大小更加鲁棒至关重要。为此,他们使用不同 IoU 比率(例如,0.1、0.3、0.5 等)的原始图像的补丁来生成额外的训练示例。)和随机补丁。此外,每个图像还以 0.5 的概率随机水平翻转,从而确保潜在的对象以相似的可能性出现在左侧和右侧。
Example of horizontally flipped image (from Behavioural Cloning blog post)
非最大抑制(NMS)
假设在推理时间 SSD 的向前传递期间产生大量的盒子,通过应用被称为非最大值抑制的技术来修剪大部分边界盒子是必要的:置信损失阈值小于 ct (例如 0.01)并且 IoU 小于 lt (例如 0.45)的盒子被丢弃,并且仅顶部的 N 预测被保留。这确保了网络只保留最有可能的预测,而去除更嘈杂的预测。
NMS example (from DeepHub tweet)
固态硬盘的附加说明
SSD 文件提出了以下附加意见:
- 默认框越多,检测就越准确,尽管对速度有影响
- 由于检测机在多个分辨率的要素上运行,因此在多个图层上使用多盒子也能实现更好的检测
- 80%的时间花在基本的 VGG-16 网络上:这意味着如果有更快和同样准确的网络,SSD 的性能可能会更好
- SSD 混淆了具有相似类别的对象(例如动物)。这可能是因为多个类共享位置
- SSD-500(使用 512x512 输入图像的最高分辨率变体)在 Pascal VOC2007 上实现了 76.8%的最佳 mAP,但以速度为代价,其帧速率降至 22 fps。因此,SSD-300 是一个更好的折衷方案,在 59 fps 时具有 74.3 的 mAP。
- SSD 在较小的对象上产生较差的性能,因为它们可能不会出现在所有的要素地图上。提高输入图像分辨率可以缓解这个问题,但不能完全解决它
玩 SSD
网上有一些 SSD 的实现,包括来自本文作者的原始 Caffe 代码。在我的例子中,我选择了 Paul Balanç的 TensorFlow 实现,可以在 github 上获得。为了更好地理解所有东西是如何组合在一起的,阅读代码和文章是值得的。
我最近还决定重新实施一个使用传统计算机视觉技术的车辆检测项目,这次采用 SSD。我使用 SSD 输出的一个小 gif 显示它工作得非常好:
GIF of vehicle detection Using SSD
超越固态硬盘
这一领域的最新研究成果已经问世,我建议有兴趣在这一领域进一步拓展知识的人继续阅读以下两篇论文:
- YOLO9000:更好更快更强(那是论文的题目;不开玩笑)
- 屏蔽 R-CNN :像素级非常精确的实例分割
瞧啊。我们已经完成了单次多盒探测器的参观。我试图用简单的术语来解释这种技术背后的概念,尽我所能地理解它们,并用许多图片来进一步说明这些概念并促进您的理解。我真的建议你读读报纸(如果你像我一样反应迟钝的话,可能要读几遍)🙃),包括在这项技术的一些数学背后形成良好的直觉,以巩固你的理解。如果这篇文章的某些部分有助于你理解这篇文章,你可以随时查看。一路平安!
感谢你阅读这篇文章。希望你觉得有用。我现在正在建立一个新的创业公司,叫做 EnVsion !在 EnVsion,我们正在为 UX 的研究人员和产品团队创建一个中央存储库,以从他们的用户采访视频中挖掘见解。当然我们用人工智能来做这个。).
如果你是 UX 的研究人员或产品经理,对与用户和客户的视频通话感到不知所措,那么 EnVsion 就是为你准备的!
你也可以关注我的 推特 。
理解数据科学中的主观性
在一个完美的世界中,数据科学家在检查发现时会将主观性从他们的结论中剔除。
然而,在人们意识到发生了什么之前,偏见就已经悄然而至。意识到可能的主观性允许研究人员在相对确信其尽可能客观之前,努力将其最小化,并且不发表他们的工作。
人类是会犯错的
一个常见的思路是,仅仅在研究中使用大数据工具就可以消除偏见。但是,尽管这些进步将众多信息流汇集在一起进行分析,但人类仍然在该过程的各个阶段参与收集数据——人类天生就是主观的。
2016 年 9 月的一项研究希望利用大数据建立一个影响全球文明的事件的综合集合。它发现美国和拉丁美洲的系统很少通过将它们注册为重要来复制相同的情况。
这是因为即使是最强大、最智能的大数据工具背后也有人,尤其是那些培训数据科学平台的人。由于人不是公正的存在,即使数据科学可以消除一些主观性,但人类天生就拥有它。
数据越多,找到支持材料就越容易
人们表现出确认偏差,这是一种倾向,即寻找支持某个观点的东西,而忽略冲突的信息。
数据科学的进步可能会恶化这一特征,因为它让个人能够访问大量数据,从而增加了他们找到支持他们观点的材料的可能性,只要他们足够努力地寻找。
如果发生这种情况,他们可能会发现将研究推向一个方向的信息,而忽略导致完全不同结论的相反发现。
主观数据是可变的
人们通过与他人交流获得主观数据。他们也可以通过基于通信做出假设和判断来收集信息。因此,数据的特征可能因人而异,甚至根据一个人在特定时刻的感受而变化。
相比之下,客观数据来自可验证的事实或事件,即使在多个来源之间也具有一致性。
主观数据包含个人解释的成分,而客观数据主要依赖于使用准确的细节来确认发生了什么或某人假设了什么。
主观性并不总是负面的。例如,某人可以主观地修改显示销售区域或类似信息的映射数据,以支持公司的需求,并使利益相关者更容易获得统计数据。
然而,使用映射数据来解释事物的人必须注意彻底解释变量,否则可能会使个人得出错误的结论。
例如,当收集的样本不能充分反映总体情况时,抽样偏差经常出现在研究中。
他们可以使用地图上的注释来阐明样本大小和用于收集信息的技术。这些额外的见解给人们提供了他们得出明智结论所需的知识。
主观性可能会忽视重要的现实
如前所述,人类倾向于关注支持他们信念的材料,而忽略不支持的材料。有时,这个问题意味着数据科学家没有注意到他们研究中隐藏的发现。
然而,来自低收入社区的人怎么办?他们可能住在坑坑洼洼的地方,却买不起该应用程序所需的智能手机来简化报告过程。
大数据是在恶化种族偏见吗?
警察部门越来越依赖大数据来预测未来的犯罪,并找出如何在多个社区中最佳地分配警察。
然而,分析人士指出,种族偏见在执法部门非常普遍。研究表明,与非洲裔美国人和拉丁美洲人相比,警察不太可能阻止白人,即使这两个群体表现出相同的行为。
执法人员必须评估输入数据的所有特征,并确定输入数据的某些方面是否会教授算法来强调和延续种族偏见,而不是仅仅相信大数据的结果是准确的。
即使没有大数据平台,这样的事情也可能发生。例如,一个特定管辖区的官员可能会说,“我的经验告诉我,我因暴力犯罪而逮捕的非裔美国人比白种人多,”一个同事可能会说同样的话。
然而,仔细观察统计数据可以发现,非裔美国人在这些非法活动中只占一小部分,但官员们过于依赖个人经验,无法做出客观的结论。
努力减少有偏见的大数据
从科学家每天处理的信息数据中去除主观性是不可能的。
然而,一个负责任的数据科学家必须意识到这种偏见的存在,并有意识地尝试最小化它们,无论是通过检查数据中不太明显的方面,还是回答最重要的问题,“我是否忽略了什么?”
图像由 Rawpixel
支持向量机:完整理论
了解 SVM 系列:第一部分
在这篇文章中,我将介绍支持向量机分类器。这篇文章将是我将解释支持向量机(SVM)的系列文章的一部分,包括它背后所有必要的细节和数学。这很容易,相信我!没有任何延迟,让我们开始吧—
假设我们得到了蓝色星星和紫色心的这两个样本(只是为了示意性的表示,这里没有使用真实的数据),我们的工作是找出一条线来最好地分开它们。这里我们所说的最好是什么意思?
Figure 1: Samples in a 2D plane with some separation between them
我们来看下图。你能猜出哪条线能更好地分开这两个样本吗?
Figure 2: Lines (Hyperplanes?) that could potentially separate the two samples
是的,左边的红线比橙线好,因为,我们说红线在两组之间创造了’最宽的路’(边距)。见下图
Figure 3: Widest road approach for separating two groups
边界线(虚线)边缘的样本线,被称为’**支持向量’。**与右侧的样本相比,左侧有两个这样的样本(蓝色星星)。关于支持向量的几个要点是-
- 支持向量是最难分类的样本。
- 它们直接影响寻找决策边界(虚线)最佳位置的过程。
- 只有一个非常小的训练样本子集(支持向量)可以完全指定决策函数(一旦我们了解 SVM 背后的数学,我们将会看到更多细节)。
- 如果从数据集中移除支持向量,将有可能改变分割线 的位置(对于维数高于 2 的空间,该线称为超平面)。
我们已经认识到这是一个受约束的优化问题。优化 —因为,我们要找到支持向量分离最大的线约束— 因为,支持向量应该远离道路,而不是在道路上。我们将使用拉格朗日乘数来解决这个问题,所以让我们从一个非常简单的使用拉格朗日乘数的例子开始。
拉格朗日乘数:何时和如何使用
假设我们给定一个函数 f(x,y,z,…) ,我们想要找到它的极值,服从条件 *g(x,y,z,…)= k。*拉格朗日乘子中使用的思想是,目标函数 f 的梯度在一个最佳点上与约束 g 的梯度平行或反平行排列。在这种情况下,一个梯度应该是另一个梯度的倍数。让我们看一个例子——
使用拉格朗日乘数法,我们解决它如下
所以我们找到了函数的最大值和最小值,并且看到它有一个唯一的最小值,两个最大值和一个鞍点。如果我们画出这些函数 f 和 g,,那么我们将更好地理解拉格朗日乘数的概念。
Figure 4: Visualizing Lagrange Multiplier Method
从上图我们可以清楚地体会到 约束函数 f 的极值,位于约束 g 的曲面上, 是一个单位半径的圆。这是一个必要条件。此外,函数和约束的切向量在每个极值处平行或反平行。用于这个情节的代码可以在我的 github 中找到。
我们现在准备深入 SVM 背后的数学,并成功地应用这一技术。
支持向量机的数学;
如果你忘记了问题陈述,让我再次提醒你。在图 1 中,我们要找到一条能最好地分离两个样品的线。我们考虑一个垂直于中线(红线)的向量(W)和一个未知样本,该样本可由向量 x. 表示
Figure 5: Determine on which side of the road a new sample X lies
为了确定未知样本 X 位于中线(红色实线)的哪一侧,我们首先取 X 沿中线垂线的投影,即 w 。如果这个投影大于某个数(称为偏差),那么我们说未知样本 X 在线的右侧。它通常被称为决策规则。让我们把它放进一个等式里
在这一点上,我们对数字 b 一无所知。我们对 w 也一无所知,只知道它垂直于中线。为了确定 w 和 b ,我们现在考虑已知样本并坚持如下条件
因此,对于右边(左边)的已知样本,我们坚持判定规则(等式。1.4)大于(小于)或等于 1。对于边界线上的样本(支持向量),等号成立。接下来,我们的目标是用一个等式代替两个,为此,我们引入一个变量,它对右边的样本为正,对左边的样本为负。
随着这一新变量的引入,我们将把两个条件方程的 L.H.S .相乘。1.5)我们得到
我们将在这里强加的另一个条件(相当直观)是,对于槽(“支持向量”)上的样本,L.H.S 将正好为零。
*由于我们的主要目的是找到样本之间最宽的道路,*我们现在将继续定义两条平行线之间的距离(或道路的宽度)。
为此,我们首先在任一侧选择任意两个支持向量,并计算差向量
Figure 6: Difference of two support vectors
从上图可以了解到道路的宽度将是这个差向量与一个垂直于道路的单位向量的点积。
但是等等!我们已经定义了一个垂直于最佳直线的矢量,即 w. ,因此我们准备将道路的距离公式化为
我们能简化这个等式吗?让我们回头看看情商。1.8,看看能不能想出点什么。
使用 eq。1.8 并且利用 y 对于右边的样本为正,对于左边的样本为负的事实,我们可以将等式 1.9 简化为
因为我们想要最大化道路的宽度,我们现在的整个问题可以归结为一个非常重要的信息—
牢记我们之前的约束条件,即 eq。1.8.
因此,我们不再像以前那样凭直觉,现在我们可以从数学上理解,找到最佳线路确实是一个约束优化问题。
我们现在准备应用我们对拉格朗日方法的理解。
首先,取决于支持向量的数量,将有几个约束,因此包含乘数的约束项将是
我们想要最小化的拉格朗日量,可以写成
扩展表达式,
现在,在开始最小化之前,我们应该确定变量 w.r.t .,我们将对其进行拉格朗日微分,并将其设置为零。如果你记住了问题陈述,回到 eq。1.4.,我们看到向量 w 和偏差 b 是独立变量。因此
标量微分和往常一样,但矢量微分是在标量上执行的,首先是垂直矢量的大小,其次是支持矢量和法向矢量的点积。向量微分的后一项很容易解决,对第一项来说很直观,我想给你们一个提示
使用这个我们可以最终写出如下结果
到目前为止,上述结果在这篇文章中是最重要的,我们已经发现**法向量( w )是支持向量的线性组合。**我们将使用这个条件来得到我们的决策规则,但是让我们意识到我们已经减少了公式中的另一个问题,那就是——因为等式的条件。1.16.现在我们可以去掉 w 和 b,取而代之的是只用拉格朗日乘数。所以我们从等式中使用这些条件。1.16,并尽量简化 eq。1.13
让我们进一步简化这个表达式
最后,我们在文章末尾发现最大化将只取决于支持向量对的点积。多棒啊!!!!
一个更有趣的结果可以得到,一旦我们把 w 放回去,我们从等式。1.16.决策规则,即等式。1.4 我们得到
因此,新样本是否将位于道路右侧取决于支持向量和未知样本的点积(这里由向量 u 表示)。
本质上,与 SVM 相关的一切都依赖于样本的简单点积,这对我来说是令人兴奋的。希望它也能给你提供一些思考的素材。
让我们总结一下我们学到的最重要的两点
- 通过简单的直觉和严格的数学,我们知道 SVM 问题是约束最小化问题。
- 我们学习了求解约束优化问题的简单拉格朗日方法,并成功地应用于开发 SVM 算法。
下面是我下一篇关于 SVM 背后的数学以及使用 python 和 scikit-learn 的应用的文章的链接。
第二贴: 内核绝招&默塞尔定理
第三贴: 现实生活中 SVM 的例子
第四帖: 标图决定功能为
保持坚强!干杯!!
如果你对更深入的基础机器学习概念感兴趣,可以考虑加盟 Medium 使用 我的链接 。你不用额外付钱,但我会得到一点佣金。感谢大家!!
更多来自 Saptashwa(以及媒体上的所有其他作者)。你的会员费直接支持 Saptashwa 和其他作家…
medium.com](https://medium.com/@saptashwa/membership?source=publishing_settings-------------------------------------)
支持向量机:核技巧;默瑟定理
了解 SVM 系列:第二部分
先决条件:1。关于支持向量机算法的知识,我在的上一篇文章中已经讨论过了。2.代数的一些基础知识。
在本系列的第一部分中,从支持向量的数学公式中,我们发现了 SVM 的两个重要概念,它们是
- SVM 问题是一个约束最小化问题,我们已经学会了使用拉格朗日乘数法来处理这个问题。
- 为了找到不同样本之间的最宽路径,我们只需要考虑支持向量和样本的点积。
在 SVM 的上一篇文章中,我举了一个简单的线性可分样本的例子来演示支持向量分类器。如果我们有一个如下的样本集,会发生什么?
Blue and Red samples all over the place !!! At least it seems like (Source: Author)
该图使用sklearn.
的内置make_circles
数据集生成
import numpy as np
import sklearn
import matplotlib.pyplot as plt
from sklearn.datasets.samples_generator import make_circlesX,y = make_circles(90, factor=0.2, noise=0.1)
#noise = standard deviation of Gaussian noise added in data.
#factor = scale factor between the two circlesplt.scatter(X[:,0],X[:,1], c=y, s=50, cmap='seismic')
plt.show()
如你所知,在这个 2d 图中不可能画出一条线来区分蓝色样品和红色样品。我们还有可能应用 SVM 算法吗?
如果我们给这个 2d 空间一点震动,红色样本飞离平面,看起来与蓝色样本分离,会怎么样?看一看!
After ‘shaking’ the data samples now it seems there is a great possibility of classification! Find the code in my github (Source: Author)
看来摇动数据样本确实有效,现在我们可以很容易地画一个平面(而不是我们以前使用的线)来分类这些样本。那么在摇晃过程中到底发生了什么呢?
当我们没有如上例的线性可分训练数据集时(在现实生活中,大多数数据集都相当复杂),内核技巧就派上用场了。其思想是将非线性可分离数据集映射到一个更高维的空间,在那里我们可以找到一个可以分离样本的超平面。
因此,这一切都是为了找到将 2D 输入空间转换为 3D 输出空间的映射函数。或者是?内核技巧到底是什么?
从上一篇关于支持向量的帖子中,我们已经看到(请查看理解数学公式)最大化只取决于支持向量的点积,
不仅如此,由于决策规则还依赖于支持向量和新样本的点积
这意味着,如果我们使用映射函数将数据映射到更高维度的空间,那么,最大化和决策规则将取决于不同样本的映射函数的点积,如下所示
瞧啊。!如果我们有一个函数 K 定义如下
那么我们只需要知道 K 而不是映射函数本身。这个函数被称为核函数,它降低了寻找映射函数的复杂性。所以,核函数在变换空间定义了内积。
让我们看看一些最常用的内核函数
我已经使用径向基函数核绘制了图 2,其中从 2D 空间到 3D 空间的映射确实有助于我们分类。
除了这个预定义的内核,*哪些条件决定了哪些函数可以被认为是内核?这是由**默瑟定理给出的。第一个条件相当简单,即内核函数必须对称。**作为核函数是点积(内积)*的映射函数我们可以写成如下——
Mercer 定理给出了函数是核函数的充要条件。理解这个定理的一种方式是—
**换句话说,在有限输入空间中,如果核矩阵(也称为 Gram 矩阵)是正半定的那么,矩阵元素即函数 K 可以是核函数。**因此 Gram matrix 将学习算法所需的所有信息、数据点和映射函数合并成内积。
让我们看一个从核函数中找到映射函数的例子,这里我们将使用高斯核函数
调谐参数
既然我们已经讨论了非线性核,特别是高斯核(或 RBF 核),我将以对 SVM 中的一个调整参数—γ的直观理解来结束这篇文章。
观察 RBF 核,我们看到它取决于两点之间的欧几里德距离,即如果两个向量越近,则该项越小。由于方差总是正的,这意味着对于较近的向量,RBF 核比较远的向量分布更广。当 gamma 参数较高时,核函数值会较小,即使对于两个邻近的样本也是如此,这可能导致复杂的判定边界或引起过拟合。你可以在我的另一篇文章中读到更多。
Example of over-fitting and complex decision boundary with high values of gamma. Image Courtesy : [Chris Albon]
在结束讨论之前,让我们回顾一下到目前为止我们在本章中学到了什么
- 将数据点从低维空间映射到高维空间可以使得即使对于非线性数据样本也可以应用 SVM。
- 我们不需要知道映射函数本身,只要知道核函数即可; 内核绝招
- 函数被认为是核函数的条件;半正定格拉姆矩阵。
- 最常用的内核类型。
- 调节参数γ如何导致 RBF 核的过度拟合或偏差。
希望你喜欢这篇文章,在下一章,我们将看到一些使用 SVM 算法的机器学习例子。
SVM 算法背后的完整数学在这里讨论:
SVM 的决策规则
towardsdatascience.com](/understanding-support-vector-machine-part-1-lagrange-multipliers-5c24a52ffc5e)
关于绘制和理解支持向量机决策边界的更多信息,请查看这篇文章:
[## 用 Python 实现流水线中的主成分分析和 SVM
管道、网格搜索和等高线图
towardsdatascience.com](/visualizing-support-vector-machine-decision-boundary-69e7591dacea)
保持坚强!干杯!!
如果你对更深入的基础机器学习概念感兴趣,可以考虑加盟 Medium 使用 我的链接 。你不用额外付钱,但我会得到一点佣金。感谢大家!!
[## 每当 Saptashwa Bhattacharyya 发表文章时,收到一封电子邮件。
每当 Saptashwa Bhattacharyya 发表文章时,收到一封电子邮件。通过注册,您将创建一个中等帐户,如果您没有…
medium.com](https://medium.com/subscribe/@saptashwa?source=publishing_settings-------------------------------------)
参考资料:
用 Dialogflow 理解基本的对话式人工智能概念
这是一个初学者指南,旨在理解围绕设计对话和使用 Google Dialogflow 实现对话的不同概念。其他对话式人工智能工具使用相同的概念,因此这些应该可以转移到任何平台。我使用过各种各样的机器人构建器,在我看来,Dialogflow 是最容易快速创建简单机器人或非程序员的工具。本概述涵盖了如何创建意图及其组成的不同部分,培训您的机器人,以及其他有助于使用 Dialogflow 的有用提示。
在将你的第一个机器人实现到 dialogflow 之前,最好先绘制出对话流,就像思维导图一样。当一些对话可能会很长并且很难跟上时,拥有这种观想将会派上用场。注意:下面的截图来自 Dialogflow,用例是针对内部业务流程助理的。
创作意图
意图用于定义当机器人获得用户的意图时,或者当您希望基于其他事件触发响应时,您希望机器人做出什么响应。基本上,如果一个用户说 X,我们希望我们的机器人用 y 来回应。
话语——或训练短语
这些是用户所说的被机器人理解为某种意图的短语。许多不同的短语可能实际上描述了该短语的同一个动机。例如:“我需要找人”,“我在找人帮忙…”和“你能帮我找一个人吗?”是指用户想要找到一个人的所有话语。最好在一个意图中有大约 10 个不同的短语,作为自然语言理解(NLU)引擎的良好基础。在此基础上,Dialogflow 可以自信地连接来自用户的新短语和最接近的意图。我们永远无法真正假设我们会知道我们的用户会为每一个意图说话的每一种方式,所以这就是利用谷歌的 NLU 功能真正帮助我们的地方。
此外,对于后续对话,你可能只需要非常简单的话语,如是或否,并将其与上下文相关联,但我们将在稍后讨论。
Example of training phrases in Dialogflow
实体
实体是用户输入的一部分,它描述了一些有用的信息,Dialogflow 可以从中提取并执行操作。例如,如果用户输入“我想找人帮我修车”,其意图将是找人,主题的实体将被选择为汽车。要定义一个新的实体,您需要在 Dialogflow 中的 entity 部分定义一组在一个实体中具有相同目的的相关信息。
还有一些系统定义的实体,比如位置、日期、数字等等,您可以加以利用。
Entities in the definition screen and when they are being picked up inside user phrases
响应—标准
这些是当一个意图匹配时,您的 bot 服务将发送回用户的响应。以某种方式确认响应中的意图是很好的,比如“好的,所以你想找到一个人……”,这样用户就可以看到机器人确实理解他们所说的话。如果你想每次都给人一种稍微不同的体验,你可以给一个意图添加不同的回答,dialogflow 会随机选择一个。如果您希望在同一个输出中显示多个单独的消息,可以通过添加文本响应模块来实现。
响应——特定于渠道的丰富消息
要利用通道独特的消息传递功能,您可以通过选择+图标并选择您喜欢的通道,在响应部分添加该功能。您还可以选择让这些特定于通道的响应取代标准响应,或者将其添加到总输出中。特定于渠道的响应通常包括易于使用的富 UI 消息类型,包括按钮、卡片和图像等元素。例如在 Slack 中,我经常使用快速回复给用户一个选项列表和卡片来显示图片和/或链接。这些使得用户的体验更加容易。
An example of a rich UI element, Quick Replies, and the slack tab in responses
如果你想跨频道做任何丰富的 UI,或者做任何更加定制化的事情,那么你必须利用定制有效载荷响应选项,或者在实现中对它进行编码。您可以在 dialogflow 文档中了解更多信息。
这些丰富的 UI 元素在 slack 中是什么样子的:
参数
参数与用户输入中的实体相关联,可用于在履行中执行某些动作或用于响应。通过在参数部分中定义一个实体,意味着它们可以在该意图中用作变量。您还可以将一个参数设置为强制参数,机器人会询问后续问题,直到给出合适的答案。如果查找一个人的意图需要一个主题参数,对话流将询问“你到底要找谁?”所以它能给出一个合适的答案。您可以通过勾选该字段将参数设置为强制参数;如果你这样做,你还需要写下必要的跟进问题。
Parameters in the intent window
**注意:**有一个已知的问题是,如果用户不理解后续问题,并且回答与所需实体不匹配的响应,那么机器人会无休止地循环相同的问题。所以如果你要用这个,最好把问题弄清楚。
您可以通过编写$和参数名在响应中使用该参数
Calling a parameter in a response
实体和参数是一回事吗??为什么两者都有?参数与实体值相关联,但是有时您可能希望跟踪意图对话中的多个参数,并且所有这些参数可能是一个实体的不同情况。例如,在两个意图中,您可能希望找出某件事情的开始日期和结束日期,这将是两个不同的参数,都对应于一个“日期”实体。
语境——进行更长的对话
上下文用于跟踪用户在对话中的位置。它们代表当前状态。要使一个意图跟随另一个意图,可以从第一个意图创建一个输出上下文,并将相同的上下文放在第二个意图的输入上下文字段中。您可以同时使用多个上下文。每个上下文旁边的数字对应于您希望上下文持续的响应数量,这是可以更改的。如果您想让上下文在某个意图之后不再继续,您可以将它放在传出上下文中,并将数字设置为 0。
上下文还保存在该上下文中定义的参数,所以您可以在以后再次使用它们,但是我还没有对此进行过实验。
An example of an output context
事件
当您希望机器人在没有用户输入但发生特定事件时被触发时,例如,如果您希望机器人在某人第一次开始聊天时或可能在每天中午 12 点时说些什么,则可以使用这些。
命名意图
最佳实践是描述用户的意图。可以用空格。名称越明显越好,因为各种后端用户可能需要解释这些意图的内容。
例如,如果用户想为某个主题找到合适的人,名称可以是“查找一个人”
如果在较长的对话中有后续意图,最好在命名约定中表明这一点(我建议不要使用实际的“后续”意图,因为它们不灵活),所以如果你在较长的对话中,你可以做类似“餐厅->预订->确认”的事情。使用像“Q1”、“Q2”这样的系统……对于机器人的工程师来说,一系列问题可能是有意义的,但当涉及到与其他管理员一起训练机器人时,就很难理解其中的内容了。
履行
当你想要一个引发某种行动的意图时,就使用满足感。例如,如果你想将对话输入到外部数据库,调用外部服务来查找某个位置的天气,执行一些计算,给某人发送电子邮件,在预订系统中检查可用性,或者只是搜索随机的 GIF。实现在每个意图中被打开。您可以在 dialogflow 内部对此进行编码,也可以将您的 bot 连接到另一个名为 webhook 的服务,该服务可以处理该操作。这更复杂,通常需要开发来创建适当的动作。我只是在一些基本的方面使用了满足感。
示例:我希望多个 intent 共享一个响应,因此创建了一个函数来保存共享部分,并使用一个命令来调用在 intent 中管理的初始响应。
Fulfilment code example
要了解更多关于如何编写代码实现的信息,文档中有很多相关内容,还有很多例子可以下载。对于非开发人员来说,过多地涉及履行确实意味着 bot 变得更难管理。
最佳实践意图包括
为了机器人的可用性,包含一些标准响应总是好的。
介绍或欢迎——回答你好或任何其他问候,它应该给出机器人做什么的概述,可能还有一些示例问题。这也可以由一个事件触发,比如当你打开一个聊天。
- 默认的后退意图或不理解-当没有其他意图匹配时,此意图匹配,并且应该给用户一些关于接下来要问什么的指导。
- 与人交谈——一些用户可能会对机器人的回答感到失望,可能会要求与真人交谈。有这个选择总是好的。你也许不能马上把他们和聊天中的人联系起来,但即使是一些联系方式也是值得的。
- 错误的答案——如果用户说机器人给了他们错误的答案,那么最好提出反馈,并给用户其他联系方式。
在某个意图或对话的一部分之后包含一组常用选项也是很好的,这样可以将用户引导到机器人可以协助的方向。例如,在预订了一家餐馆之后,用户接下来可能要做的就是想出如何到达那里,或者将预订添加到您的日历中。
知识库
知识库是从电子表格中制作 FAQ 类型列表的简单方法。这是 Dialogflow 的一个非常新的功能,所以不要期望能够通过这种方式上传你所有的意图,最好保持非常简单的问答回复。在 CSV 电子表格中,第一列是用户输入,第二列是响应。它为列表中的每个条目都创建了一个单独的意图。由于每个条目只有一个用户短语,所以它们不是很强大,但是对于 FAQ 列表来说很有用。例如,对于一个内部业务聊天机器人,我使用知识库上传一个业务缩写和术语列表。
您也可以将知识库连接到 FAQ 格式的网页,但是我认为这只是扫描页面一次,而不是实时连接,因此如果您稍后更改网页,知识库将不会保持最新。
您可以管理如何在 dialogflow 的知识库部分实际显示响应。
训练
我们在这里讨论的训练是你训练机器人,并有效地让它变得更聪明。在培训窗口中,您可以看到对话日志。打开对话会显示每个用户输入和 dialogflow 触发的匹配意图,您可以选择确认 dialogflow 给出了正确的答案(在您进行确认之前,机器人不会将这些新的话语提交到内存中,即机器人无法自行学习),将其更改为另一个意图,或者将其添加到默认的回退意图(如果它超出了机器人的知识范围)。这就是为什么给意图一个容易理解的名字是好的;如果其他团队成员正在训练不是他们自己创建意图的机器人,那么他们可以很容易地找到匹配的那个。通过批准对话,您有效地将任何新的用户短语添加到您已经确认正确匹配的意图中。
example training conversation log
训练有点有限,如果你想在对话中准确地看到机器人的响应,并按日期或频道过滤,那么你可以在 Dialogflow 的历史部分中完成这一操作。
集成
Dialogflow 可以很容易地将 bot 服务连接到多个频道:slack、facebook、kik 等。完全完成连接通常需要几个步骤,其中大部分都在通道端。连接 slack 需要创建一个应用程序,然后在相关字段中插入一些 URL。这种设置通常不需要编码。所有这些联系都有很好的记录。
Integrations available from Dialogflow, plus of course google assistant actions.
如果您想要连接到这些简单集成之外的自定义接口,那么这需要一些额外的工作来连接到您可以在 bot 的设置中找到的 dialogflow API 端点。我找不到关于这方面的很好的文档,但这确实取决于您选择使用的 UI。
闲聊
闲聊是对机器人个性的一个有趣的小补充。这给非常简单的流行输入,如“怎么了”或“我恨你”,添加了大量预先制造的意图,dialogflow 机器人会用一组随机答案来响应它们。你可以打开它,也可以选择自定义一些答案。第一个“你是谁?”可能是一个很好的更新。
分析
简而言之,你可以看到你的机器人获得了多少流量,你可以看到最匹配的意图列表和一些基本的对话旅程。这让你很好地了解人们是否在使用这个机器人,他们什么时候使用它最多,以及他们真正使用它的目的是什么。然而,直到你有一个大的用户群,这不是很强大。
你也可以将你的机器人连接到另一个谷歌平台——https://chatbase.com
向后端添加用户
你可以在 dailogflow 的设置->共享部分进行设置。最好用谷歌邮箱添加用户。在 bot 设置中添加该地址,确保保存。您可以授予用户“审阅者”角色(可以查看所有内容,但不能进行修改),或者授予用户“开发人员”角色(可以更新除管理设置之外的所有内容)。
一旦你设置好了,他们就可以在 https://console.dialogflow.com 找到机器人
如果你想改变机器人的所有者或添加一名管理员,那么你必须在谷歌云中这样做。这是说明。
https://dialogflow.com/docs/concepts/sharing#gcpconsole
更多资源
文档中的更多帮助
https://dialogflow.com/docs
希望这对您有所帮助!如果你需要更多的机器人帮助,请联系我们。
理解偏差-方差权衡
每当我们讨论模型预测时,理解预测误差(偏差和方差)是很重要的。在模型最小化偏差和方差的能力之间有一个权衡。正确理解这些误差不仅有助于我们建立准确的模型,而且有助于我们避免过拟合和欠拟合的错误。
所以让我们从基础开始,看看它们如何对我们的机器学习模型产生影响。
什么是偏见?
偏差是我们模型的平均预测值和我们试图预测的正确值之间的差异。具有高偏差的模型很少关注训练数据,并且过度简化了模型。它总是导致训练和测试数据的高误差。
什么是方差?
方差是给定数据点或值的模型预测的可变性,它告诉我们数据的分布。高方差模型非常重视训练数据,不会对以前没有见过的数据进行归纳。结果,这样的模型在训练数据上表现得非常好,但是在测试数据上有很高的错误率。
数学上
假设我们试图预测的变量为 Y,其他协变量为 x。我们假设两者之间存在这样的关系
Y=f(X) + e
其中 e 是误差项,正态分布,均值为 0。
我们将使用线性回归或任何其他建模技术来制作 f(X)的模型 f^(X。
所以 x 点的期望平方误差是
Err(x)可以进一步分解为
Err(x)是偏差、方差和不可约误差之和。
不可约误差是不能通过创建好的模型来减少的误差。这是对我们数据中噪声量的一种度量。在这里,重要的是要明白,无论我们的模型做得多好,我们的数据都会有一定数量的噪声或不可减少的误差,这些是无法消除的。
使用靶心图的偏差和方差
在上图中,目标的中心是一个完美预测正确值的模型。随着我们远离靶心,我们的预测变得越来越糟糕。我们可以重复我们的建模过程,以获得对目标的单独命中。
在监督学习中,欠拟合发生在模型无法捕捉数据的底层模式时。这些模型通常具有高偏差和低方差。当我们只有很少的数据来建立一个精确的模型时,或者当我们试图用非线性数据建立一个线性模型时,就会发生这种情况。此外,这种模型非常简单,可以捕捉数据中的复杂模式,如线性和逻辑回归。
在监督学习中,当我们的模型捕捉到数据中的噪声和潜在模式时,过拟合就会发生。当我们在嘈杂的数据集上训练我们的模型时,就会发生这种情况。这些模型具有低偏差和高方差。这些模型像决策树一样非常复杂,容易过度拟合。
为什么是偏差方差权衡?
如果我们的模型太简单,参数很少,那么它可能会有高偏差和低方差。另一方面,如果我们的模型有大量的参数,那么它将有高方差和低偏差。因此,我们需要在不过度拟合和欠拟合数据的情况下找到正确/良好的平衡。
这种复杂性的权衡就是为什么在偏差和方差之间存在权衡。一个算法不能同时更复杂和更不复杂。
总误差
为了建立一个好的模型,我们需要在偏差和方差之间找到一个好的平衡,使总误差最小化。
偏差和方差的最佳平衡不会使模型过拟合或欠拟合。
因此,理解偏差和方差对于理解预测模型的行为至关重要。
感谢您的阅读!
理解层次聚类技术的概念
层次聚类技术是机器学习**中流行的聚类技术之一。**在我们试图理解层次聚类技术的概念之前让我们先了解一下聚类…
什么是聚类??
聚类基本上是一种对相似数据点进行分组的技术,使得同一组中的点比其他组中的点更加相似。一组相似的数据点被称为簇。
聚类和分类/回归模型的区别:
在分类和回归模型中,我们得到一个数据集(D ),其中包含数据点(Xi)和类别标签(易)。其中,Yi 属于分类模型的{0,1}或{0,1,2,…,n ), Yi 属于回归模型的真实值。
说到聚类,我们得到的数据集只包含数据点(Xi)。这里我们没有提供的类标签(Yi)。
现在,让我们回到最初的主题,即层次聚类技术。
这里有一个小礼物,特别送给我的读者,作为善意的表示:)亚马逊音乐无限免费3 个月:【https://amzn.to/2ZBlWI7】(注册支持)感谢。
层次聚类技术:
层次聚类是一种流行且易于理解的聚类技术。这种聚类技术分为两种类型:
- 结块的
- 分裂的
点击此处申领免费麦当劳礼品卡
****凝聚层次聚类技术:在该技术中,最初每个数据点被认为是一个单独的聚类。在每次迭代中,相似的聚类与其他聚类合并,直到形成一个聚类或 K 个聚类。
凝聚的基本算法是简单明了的。
- 计算邻近矩阵
- 让每个数据点成为一个集群
- 重复:合并两个最近的聚类并更新邻近矩阵
- 直到只剩下一个集群
关键操作是计算两个聚类的接近度
为了更好地理解,让我们看一个凝聚层次聚类技术的图示。假设我们有六个数据点{A,B,C,D,E,F}。
- 步骤 1:在初始步骤中,我们计算各个点的接近度,并将所有六个数据点视为独立的聚类,如下图所示。
Agglomerative Hierarchical Clustering Technique
- 步骤 2:在步骤 2 中,相似的聚类被合并在一起并形成单个聚类。让我们考虑 B、C 和 D、E 是在第二步中合并的相似集群。现在,我们剩下四个集群,分别是 A,BC,DE,f。
- 步骤 3:我们再次计算新聚类的接近度,并合并相似的聚类以形成新的聚类 A、BC、DEF。
- 步骤 4:计算新群的接近度。聚类 DEF 和 BC 是相似的,并且合并在一起以形成新的聚类。我们现在剩下两个星团 A,BCDEF。
- 第 5 步:最后,所有的集群合并在一起,形成一个单一的集群。
可以使用树状图来可视化分层聚类技术。****
****树状图是一个树形图,记录了合并或拆分的顺序。
****
Dendrogram representation
**2。分裂式 **层次聚类技术:由于分裂式层次聚类技术在现实世界中使用不多,我就简单介绍一下分裂式层次聚类技术。
简单来说,我们可以说分裂式层次聚类与凝聚式层次聚类正好相反。在分裂层次聚类中,我们将所有数据点视为单个聚类,并且在每次迭代中,我们从聚类中分离不相似的数据点。每个被分离的数据点被认为是一个单独的聚类。最终,我们会剩下 n 个集群。
由于我们将单个聚类分成 n 个聚类,因此称之为分裂式** 层次聚类。**
因此,我们已经讨论了两种类型的层次聚类技术。
但是等等!!我们还剩下层次聚类的重要部分**。**
“我们如何计算两个聚类之间的相似度???"
计算两个聚类之间的相似性对于合并或划分聚类是重要的。有一些方法可用于计算两个聚类之间的相似性:
- 部
- 马克斯(男子名ˌ等于 Maximilian)
- 群体平均值
- 质心之间的距离
- 沃德方法
- MIN: 也称为单链算法可以定义为两个聚类 C1 和 C2 的相似度等于点 Pi 和 Pj 之间的相似度的最小值**使得 Pi 属于 C1,Pj 属于 C2。**
从数学上讲,这可以写成:
Sim(C1,C2) = Min Sim(Pi,Pj)使得 Pi ∈ C1 & Pj ∈ C2
简而言之,选取两个最近的点,使得一个点位于聚类 1 中,另一个点位于聚类 2 中,并获取它们的相似性,将其声明为两个聚类之间的相似性。
敏的优点:
- 只要两个簇之间的间隙不小,这种方法就可以分离非椭圆形状。
************
Original data vs Clustered data using MIN approach****
MIN 的缺点:
- 如果聚类之间存在噪声,最小方法不能正确地分离聚类。
************
Original data vs Clustered data using MIN approach****
- MAX: 也称为完全联动算法,这与 MIN 方法正好相反。两个群集 C1 和 C2 的相似性等于点 Pi 和 Pj 之间的相似性的最大值,使得 Pi 属于 C1,Pj 属于 C2。****
从数学上讲,这可以写成:
Sim(C1,C2) = Max Sim(Pi,Pj)使得 Pi ∈ C1 & Pj ∈ C2
简而言之,选取两个最远的点,使得一个点位于聚类 1 中,另一个点位于聚类 2 中,并获取它们的相似性,将其声明为两个聚类之间的相似性。
MAX 的优点:
- 如果聚类之间存在噪声,最大值方法在分离聚类方面表现良好。
************
Original data vs Clustered data using MAX approach****
Max 的缺点:
- Max 方法偏向球状星团。
- 最大值方法倾向于打破大的集群。
************
Original data vs Clustered data using MAX approach****
- ****组平均:取所有的点对,计算它们的相似度,并计算相似度的平均值。
从数学上讲,这可以写成:
sim(C1,C2) = ∑ sim(Pi,Pj)/|C1||C2|*
其中,π∈C1 & Pj∈C2
组平均的优点:
- 如果聚类之间存在噪声,则组平均方法在分离聚类方面表现良好。
组平均的缺点:
- 群平均法偏向球状星团。
- ****质心距离:计算两个聚类 C1 & C2 的质心,将两个质心之间的相似度作为两个聚类之间的相似度。这是现实世界中不太流行的技术。
- ****沃德方法:除了沃德方法计算距离 Pi 和 PJ 的平方和之外,这种计算两个聚类之间相似性的方法与组平均完全相同。
从数学上讲,这可以写成:
sim(C1,C2) = ∑ (dist(Pi,Pj)) /|C1||C2|*
沃德方法的优点:
- 如果聚类之间存在噪声,Ward 的方法在分离聚类方面也做得很好。
沃德方法的缺点:
- 沃德的方法也偏向球状星团。
层次聚类技术的空间和时间复杂度:
****空间复杂度:当数据点的数量很大时,层次聚类技术所需的空间非常大,因为我们需要将相似性矩阵存储在 RAM 中。空间复杂度是 n 的平方的数量级。
空间复杂度= O(n)其中 n 是数据点的数量。
****时间复杂度:由于我们要进行 n 次迭代,并且在每次迭代中,我们需要更新相似度矩阵和恢复矩阵,所以时间复杂度也很高。时间复杂度是 n 的立方的数量级。
时间复杂度= O(n)其中 n 是数据点的数量。
层次聚类技术的局限性:
- 分层聚类没有数学目标。
- 所有计算聚类之间相似度的方法都有其自身的缺点。
- 层次聚类的高空间和时间复杂度。因此,当我们有大量数据时,不能使用这种聚类算法。
相关文章:K 近邻入门
我们将在本文中了解到:
medium.com](https://medium.com/datadriveninvestor/machine-learning-getting-started-with-k-nearest-neighbours-6851280d4c93)
参考文献:
- https://cs . wmich . edu/alfuqaha/summer 14/cs 6530/lectures/clustering analysis . pdf
- www.appliedaicourse.com
- https://en.wikipedia.org/wiki/Hierarchical_clustering
****
理解疾病周期:斯坦福大学使用 TDA 的突破性研究
这篇原创的博客于 2017 年首次出现在 Ayasdi 网站上。
我们合作项目的最大回报之一就是看到开创性的工作使用我们的软件发表。史丹福微生物学,特别是大卫·施奈德博士和他的实验室似乎每年都达到这个地位。
也就是说,他们最近从 DARPA 获得了 600 万美元的资助,以继续他们在理解疾病康复方面的开创性工作。他们的工作如此重要,以至于在 PLOS 的两家独立的报纸上发表。两篇论文都展示了我们的底层技术拓扑数据分析(TDA) 如何被用于绘制宿主循环通过疾病空间的方式。
这项工作是使用我们的平台的无监督学习能力进行的,并通过使用横截面数据的疾病地图的可视化来区分。
目前,当动物/人类从疾病中康复时,没有/几乎没有收集到数据,因此潜在的商业影响是显著的,并且将因疾病指征而异。
Schneider 实验室使用 TDA 对数据进行聚类,而没有强加连接结构,例如层次模式或最小分支树。拓扑网络提供了一个健康空间的惊人表示,类似于疾病地图,其中网络的不同区域对应于疾病的不同部分:舒适、疾病和康复。事实上,老鼠和人类的数据集形成了这些优雅的、定义清晰的循环结构。
施尼德博士的团队绘制了寄生虫、红细胞、粒细胞或网织红细胞等参数的强度——发现小鼠和人类感染在许多方面是共线的,具有相同的事件顺序。TDA 图被用来将活的和死的老鼠分成两条不同的路径,然后确定两组之间基因表达的差异。研究人员证明,红细胞和网织红细胞在存活和死亡小鼠中的表现不同,因为它们通过疾病空间的路径不同。
一个有趣的因素是,TDA 是在这种情况下唯一可行的技术。
TDA 制作的图形更明显是循环的,因为拓扑网络拉近了间隙。他们将被感染的宿主穿越的“疾病空间”可视化,并确定了感染过程的不同状态。弹性系统不适合用树来描述,用环来描述更好——但是环避开了大多数分析方法。
另一方面,TDA 对数据的“形状”很敏感,不会任意线性化一个循环,然后强迫它适应一棵树。相反,这种分析只是将相关的数据点聚集起来,用网络图上的节点表示,图形的形状揭示了时间点之间的联系。在弹性系统的情况下,如从感染中恢复的主机,此图形成一个循环。
下面是每篇论文的作者摘要和实际论文的链接。
“当我们生病时,我们渴望康复;因此,医学的一个主要目标是促进复原力——宿主在感染后恢复健康的能力。虽然在实验室中,我们可以通过对接种时间和剂量的精确了解来研究对感染的反应,但诊所中的病人却没有这些信息。这就产生了一个问题,因为我们不容易区分处于感染早期阶段的患者和在感染后期出现的更具疾病耐受性的患者,前者将发展为严重疾病。这两类患者之间的区别很重要,因为对疾病耐受性较差的患者需要更积极的治疗方案。为了确定患者在感染时间线上的位置,我们绘制了“疾病地图”,通过“疾病空间”追踪患者的路线。“我们选择在病人生病和康复时产生循环图的症状。通过使用小鼠-疟疾模型,我们证明了弹性较低的个体在这个空间中走更宽的回路,这表示感染时间更长,症状更严重。我们发现这种循环行为也适用于人类,并表明携带镰状细胞特征的人对疟疾感染更有抵抗力。”
“这是一个直观的假设,即感染期间症状的严重程度必须与病原体载量相关联。然而,解释健康如何随病原体负荷变化的剂量-反应关系是非线性的,可以描述为“疾病耐受曲线”;这种关系随着宿主或病原体的遗传特性以及环境条件而变化。我们研究了这条曲线形状的变化可以告诉我们免疫反应的潜在回路。使用一个模型系统,我们用细菌病原体单核细胞增生李斯特氏菌感染果蝇,我们观察到一个 S 形的疾病耐受曲线。这种类型的曲线可以用标准方式用三个或四个参数来描述,这使我们能够开发一个简单的数学模型来解释随着免疫反应的变化,曲线预计会如何改变形状。在观察了由于宿主和病原体遗传变异导致的曲线形状变化后,我们得出结论,李斯特菌感染造成的损害不是由过度旺盛的免疫反应造成的,而是由病原体更直接地造成的。”
要成为合作者,请发电子邮件给我们,姓名为collaborations@ayasdi.com。
理解内核技巧。
我观察到,就像我一样,我们中的许多人试图学习支持向量机,发现很难理解内核的智慧。这花了我相当多的时间和资源,但我终于渡过了这条河,我打算帮助你们也这样做。这中间可能看起来很混乱,但是只要有一点耐心和坚持,我很确定你最终会有一个好主意。那么,让我们现在就开始吧!
对于那些不熟悉 SVM 的人,这里有一个简短的介绍。在数据分类问题中,SVM 可以用来为线性可分的数据集提供最大的分离间隔。也就是说,在可以被选择来分离用于分类的数据集的所有可能的决策边界中,它从两个类中选择离所述决策边界最近的点最远的决策边界。这应该有点令人困惑,所以这里有一个图来帮助你得到一个直觉。
这里有两个班级,红色和蓝色。中间的线是决策边界。突出显示的点是支持向量。所有这些点和直线之间的距离是所有可能的决策边界中的最大值,因此这是最佳值。
现在这样不好吗?它是,除了这是适用的事实;以它的原始形式;仅适用于线性可分数据。如果不是呢?输入内核。这个想法是,我们的数据,在我们的 n 维空间中是不可线性分离的,在一个更高维的空间中可能是可线性分离的。为了理解内核是如何工作的,一些数学知识是必要的,所以做好准备!
比方说决策边界。即,分离类的超平面具有由向量 w 给出的权重(系数)。这是我们需要找到的。我们试图最大化从这个 w 向量到最近点(支持向量)的距离,所以这现在成为我们的约束。省去了后面的一些数学知识,我要请你们在这里假定,为了解决这个问题,我们解决了以下问题
我会给你一个简单的解释这个看起来可怕但本质简单的等式。l 是我们训练数据中数据点的数量。y 表示数据点的输出,为了方便起见,我们表示为+1 或-1。x 是每个训练示例中的特征向量。α现在……嗯,α是拉格朗日常数。为了对此进行简要概述,拉格朗日乘数用于包含解决最小化或最大化问题的约束,从而使我们在达到我们的解决方案时不必担心它们。
无论如何,当最小化 W(alpha)[作为 alpha 的函数的权重向量]时,我们看到术语 x*x(转置)。也就是说,我们不需要确切的数据点,只需要它们的内积来计算我们的决策边界。有什么大不了的,对吧?那么如果是这样呢?这有什么帮助?
这意味着,如果我们想要将现有数据转换为更高维度的数据,这在许多情况下有助于我们更好地分类(参见下图中的示例),我们不需要计算数据的精确转换,我们只需要高维度空间中数据的内积。这在不可线性分离的数据集中非常有效!
得到高维空间的内积比得到高维空间的实际点要容易得多。通过简单地使用‘d’的指数将我们的数据映射到‘d’维空间的多项式核对于我们的解决方案是有效的。高斯核,在数学上,将我们的数据映射到一个无限维的空间(是的,我没有拼错)。这些只是众多可用内核中的一部分。通过这种方式,我们甚至不需要访问高维空间就可以得到我们的解。
当然,这里涉及的数学和逻辑比我在这里解释的要多得多,但是我希望我已经能够给你一个关于内核技巧的像样的直觉。快乐学习!
在神经网络的上下文中理解 L 正则化的缩放
你是否曾经看到过神经网络成本函数的 L 正则化项,并想知道为什么它同时被 2 和 m 缩放?
Equation 1: An L2-regularized version of the cost function used in SGD for NN
您可能在众多使用它来正则化神经网络模型的论文中遇到过它,或者在学习关于神经网络主题的课程时遇到过它。令人惊讶的是,当 L 正则化的概念在这种情况下出现时,该术语通常与这些因素一起引入,而没有进一步的解释。
我最近在学习 改进深度神经网络 课程(吴恩达/ deeplearning.ai 在 Coursera 的优秀深度学习专业化中的第二门课程)时再次遇到了这个术语,其中确实没有对这些比例因子做出解释,所以我开始在互联网上搜索。下面的帖子总结了我在搜索过程中所学到的东西。
提醒:神经网络中梯度下降的 L 正则化
只是为了确保我们都在同一页上,这里有一个在神经网络的随机梯度下降背景下什么是 L 正则化的简要回顾。
通常在机器学习中,当我们拟合我们的模型时,我们在解空间中搜索最合适的解;在神经网络的上下文中,解空间可以被认为是我们的网络可以表示的所有函数的空间(或者更准确地说,接近任何期望的程度)。我们知道这个空间的大小取决于(至少)网络的深度和使用的激活函数。我们还知道,使用“挤压” 函数,至少有一个隐藏层后跟一个激活层,这个空间非常大,并且它随着网络的深度呈指数增长(参见 通用近似定理 )。
当我们使用随机梯度下降 (SGD)来使我们的网络参数适合手头的学习问题时,我们在算法的每次迭代中,在解空间中朝着损失函数J(θ;x,y) 相对于网络的参数 θ 。由于深度神经网络的解空间非常丰富,这种学习方法可能会过度适应我们的训练数据。如果不使用应对措施,这种过度拟合可能会导致显著的泛化误差和对看不见的数据(或模型开发环境中的测试数据)的不良性能。那些反措施被称为正则化技术。
Figure 1: An unregularized model can overfit to noise/outliers in the training data
“正则化是我们对学习算法进行的任何修改,旨在减少其泛化误差,而不是训练误差。”伊恩·古德菲勒
在迭代学习算法的一般情况下,有几种正则化技术,如早期停止,特别是神经网络,如辍学。统计学和机器学习中的一种常见方法是在损失函数中添加一个正则项,这意味着将模型复杂性的一种度量纳入到要最小化的函数中。这种方法既不是迭代学习算法也不是神经网络所独有的,它将众多学习算法的共同形式化为优化问题。
现在,我们不再只是在解决方案空间中搜索训练集损失最小的解决方案,而是考虑解决方案的简单性。这增加了选择更简单且因此更通用的解决方案的机会,同时保持训练数据的低误差。用 Tim Roughgarden 的话说,我们变得*“偏向于更简单的模型,因为它们捕捉的是更基本的东西,而不是特定数据集的一些工件”*。
Figure 2: Applying regularization can help prevent overfitting on the training data
现在我们已经讨论了泛化错误和正则化,让我们回到 L 正则化。这种技术在统计学中也被称为 吉洪诺夫正则化 和岭回归,是一种通过添加复杂性表示项来正则化成本函数的特定方式。在神经网络中的 L 正则化的情况下,该术语简单地是网络的隐藏层的权重矩阵的平方欧几里德范数 (或者在多个隐藏层的情况下,包括输出层,是所有这种平方范数的总和)。添加附加参数 λ ,以允许控制正则化的强度。
添加 L 项通常会导致整个模型的权重更小。其他类型的基于项的正则化可能具有不同的效果;例如, L 正则化导致更稀疏的解,其中更多的参数将以零值结束。
具有 L 和 L 的正则化也有一个漂亮的概率解释:它相当于在权重矩阵的分布上添加一个先验W;这将优化问题从执行 最大似然估计 (MLE) 转换为执行 最大后验概率 (MAP) 估计;即从使用频率主义推理移动到贝叶斯推理。Brian Keng 的一篇伟大的文章中可以找到对这一解释的全面概述。
回到 L 正则化,我们得到一个形式的项
Equation 2 : Adding L² regularization to a cost function
其中∨≈∨是 L 范数。这确实是我们在经典 吉洪诺夫正则化 中遇到的形式。
那么被 m 和 2 的划分又是从何而来呢?此处将该项减半似乎特别多余,因为它只增加了除以一个常数,因此如果我们也像通常所做的那样搜索超参数(如 λ )的最佳值,则没有任何意义。事实上,在经典机器学习中,没有这两个因素也会遇到相同的正则化项。
一个可能的答案是,L 正则化可能是通过引入相关但不相同的概念权重衰减而进入深度学习领域的。
重量衰减
权重衰减的想法很简单:为了防止过度拟合,每当我们用相对于 w 的梯度 ∇J 更新权重 w 时,我们还要从中减去λ∏w。这使得重量趋向于衰减为零,因此得名。
这其实是深度学习历史上相当早期的概念。Nowlan 和 hint on 1992 年的一篇论文 通过软权重共享 简化神经网络,不经意地引用了 Plaut、Nowlan 和 hint on 1986 年 6 月的一篇论文 通过反向传播 进行学习的实验。因为那里引用的几篇论文似乎都没有使用这个概念,这实际上可能是在神经网络的上下文中引入这个概念的地方。甚至汉森&普拉特(1988) 似乎也在脚注中暗示,他们当时找不到发表的论文来引用这个概念。
Equation 3: Weight decay for neural networks
当从这个角度看正则化时,常见形式开始变得清晰。为了将这一项添加到权重更新中,我们“劫持”了成本函数 J ,并且添加了一项,该项在被导出时将产生这个期望的*-λ∙w*;要加的项当然是 -0.5 λ∙w 。对 J -0.5 λ∙w 求导,将得到∇j-λ∙w,这就是我们的目标。
Equation 4 : L² regularization from a weight decay perspective
Plaut 等人已经在上述论文中指出了这种与 L 范数的关系:
“看待术语 h∙w 的一种方式是将其视为 0.5 h∙w 的导数,因此我们可以将学习过程视为最小化 E (误差)和最小化权重的平方和之间的折衷。”
事实上,L 正则化和权重衰减正则化对于标准随机梯度下降是等价的(当通过学习率重新调整时)。对于所有基于梯度的学习算法来说,这并不一定是真的,最近显示对于自适应梯度算法来说,例如 Adam 。
为什么要除以 m?
所以,我们仍然有被 m 分割的问题。毕竟,适当的超参数优化也应该能够处理规模的变化(至少在理论上)。
选项 1:批量梯度下降的副作用
让我们从重量衰减的角度来看这个问题。在梯度下降 (SGD)的随机变量中,我们每次在单个训练样本上评估损失函数的梯度(关于参数 θ )。如果我们认为权重衰减是在每个示例级别中引入的(如最初那样),我们自然会得到,当梯度下降的单次迭代在整个训练集上被形式化时,导致算法有时被称为批量梯度下降, 1/m 的比例因子(被引入以使成本函数在不同大小的数据集之间具有可比性)自动应用于权重衰减项。
选项 2:重新调整单个示例的权重
我在一个由用户 grez 验证的关于交叉的答案中遇到的第二种方式是,这种缩放确保正则化项对损失函数的影响大致对应于单个训练示例。这确保了正则化的实际效果不会随着数据量的增加而爆炸——这可能解释了为什么当 SGD 用于神经网络时,这个比例因子开始具体出现,神经网络在大数据时代再次出现。
从单个例子的角度考虑这个术语,考虑没有这种缩放的正则化术语:在学习算法解决的一些第一批问题中,一个术语可能具有 1000 个例子的权重,在大数据集时代,突然在算法的每次迭代中获得与 10,000,000 个例子相同的权重。从信息论的角度来看,这个论点在某种程度上是有道理的;这是很多与我们之前提到的假设相关的信息,更简单的模型捕捉一些基本的东西,当训练集变得非常大时,这可能成为太强的假设。
选项 3:训练集代表性
我还想就这个问题提出一个统计学的观点。我们可以把我们的训练集想象成未知复杂性的未知分布的样本。然而,无论这种看不见的分布有多复杂,随着我们的训练集的增长,它成为这种看不见的源分布的代表性样本的概率也在增长,这总是事实。因此,它也更能代表未来未知数据(或测试集)的任何足够大的样本。简而言之,训练集越有代表性,需要做的过度拟合就越少。
在这个意义上,随着例子数量的增加,缩小正则化项编码了这样一个概念,即我们拥有的数据越多,在查看任何特定的 SGD 步骤时,我们可能需要的正则化就越少;毕竟,当损失项应该随着 m 增长而保持不变时,网络的权重也应该增长,使得正则化项本身相对于原始损失项收缩。
最近的一篇论文(以及的后续论文)提出,如果引入足够的数据扩充,权重衰减和丢失对于目标识别 NNs 来说可能不是必要的,这或许可以被视为支持这一概念,即我们拥有的数据越多,需要的正则化就越少。
选项 4:使 λ可比
最后一个很好的动机是:当 m 改变时,通过希望减轻改变 λ 的需要,这种缩放使得 λ 本身在不同大小的数据集之间具有可比性。这使得 λ 成为针对特定学习问题的特定模型所需的实际正则化程度的更具代表性的估计值。
选项 5:经验值
无论你觉得哪个直观的理由令人满意,至少对于使用 ReLU 作为激活函数的前馈网络来说,通过 1/m 缩放正则项的经验值在下面的笔记本中由前述的grez:
https://github . com/grez 911/machine-learning/blob/master/L2 . ipynb优雅地展示
最后的话
就是这样!我希望你喜欢这个小而重要的数学术语。如果你对这些比例术语的形成原因和方式有任何更正、补充或其他想法,请在评论中告诉我,或者通过我在个人网站上链接的任何方式联系我。😃
脚注:
- 在这种情况下,“挤压”函数是任何非常数、有界且连续的函数,因此是满足通用逼近定理条件的函数,而不是通常称为“挤压函数”的任何特定函数,如 sigmoid 函数。
- 欧几里德范数是一般的p-范数(又名lᵖ-范数)当 p=2 时的情况;L-定额。因此,取名为 L 正规化。
Python 的 Lambda 表达式、映射和过滤器
函数式编程值得吗?
Welcome to the Functional Church, where laziness is not a sin. Source: Pixabay
Python 的 Lambda 表达式,使用 lambda 运算符,是颇有争议的。有人说它们笨重,有人说它们优雅。
作为一个喜欢函数式编程范例的人,我喜欢不时地在我的代码中加入一些表达式,只要是少量的。
然而,我确实看到了如何将一个有点长的关键字放在一行的中间,并在假设它不会在程序的其余部分中使用的情况下匿名定义一个函数,这可能最终会成为一个问题。
但是,不要急于求成,让我们从定义相关术语开始:
Lambdas are Anonymous. They never forgive, they never forget. Expect them. Source: Pixabay
什么是 Lambda 表达式?
表达式是一个函数的匿名内联声明,通常作为参数传递。它可以做常规函数能做的任何事情,除了它不能在定义它的行之外被调用,因为它是匿名的:它没有名字。
上面的代码片段显示了使用一个定期定义的函数(或强制定义的,对于那些在角落里感觉被我的命令式特权谈话歧视的功能人员来说)、一个由 lambda 定义并分配给变量的函数(这是可以做到的,但通常被视为一种不好的做法)和一个对 lambda 函数的内联调用之间的比较(我甚至不需要告诉你为什么这不应该做得太多)。
这三段代码最终返回相同的值,但是每一段在作用域和内存方面都有不同的效果:两段代码为程序的其余部分定义了一个可调用的对象,而最后一段代码创建了一个不会在任何其他行中调用的匿名函数。
如果你还不能流利地理解列表,这里有一个常规的、命令式的 for 循环示例:
你可能会同意 map 比常规的 for-loops 不那么笨拙,占用的空间也更少,但是可能比 List Comprehensions 稍欠直观。
我们已经谈论了太多的批评(代码更难阅读,一个笨拙的关键字),让我们谈谈实际的一面。
映射和过滤:利用 lambda 表达式
下面我们再介绍两个 Python 的原生关键词:贴图和滤镜。
对于不熟悉函数式编程的人来说,map 函数是一个高阶函数,即至少接受一个函数作为输入,或者产生一个函数作为输出。
在它的正式定义中,它的参数是一个函数和一个序列(任何可迭代对象),它的输出是另一个序列,包含将给定函数应用于所提供序列中每个元素的结果,顺序相同。
听起来熟悉吗?那是因为在一个列表上调用一个函数的映射几乎等同于使用一个列表理解!不过,这种说法有一些注意事项,我会尽快解决。
以下等价关系几乎成立:
注意,在最后两行中,我传递了三次和三次函数作为参数,这要感谢 map 是一个高阶函数。
如果你迭代这五个变量中的每一个,它们都会产生相同的值。然而在 Python 3+中,在打印它们时,你会看到一些是列表,而另一些是地图对象。没错,在一个列表上应用映射会返回一个生成器!这基本上意味着它将生成一个延迟求值的序列,可以迭代,并且必须转换到一个列表中才能切片或索引。另一方面,在 Python 2.7 中, map 返回一个普通的列表。
这就是图和图产生协同作用的地方:就像用图和 T21 写一条线一样流畅,如果你能即时发明你的小功能,它会变得更加流畅。一旦你掌握了它,你将开始考虑映射,并欣赏这个特性。但是请注意,如果地图无人看管,不可读的代码会很快溃烂。
作为补充,我还将向您介绍滤镜。在序列中调用过滤器与在列表理解的末尾添加一个 if 是一样的,除了它留下了功能性的余味。以下代码片段是等效的:
与映射一样,过滤器返回一个生成器(在这种情况下是一个过滤器对象),但是将它转换成一个列表表明它相当于在一个列表理解中使用一个*。*
地图比列表理解更快吗?滤镜呢?
我运行了几个基准测试,比较普通的 for-loops ,List Comprehensions 和 map 。我不确定结果会是什么,但是有一些关于它们的理论。
以下是我在进行实验之前定义的一些东西:
这是我运行的基准测试的代码:
我比较了一个使用追加调用的常规命令式列表声明,一个使用列表理解,最后一个调用映射。
在 Python 2.7 中,我的结果如下:
- 列表 a 为 6.00 秒
- 名单 b 为 4.12 秒
- 列表 c 的 3.53 秒(使用映射的列表)
关于 Python 2.7 中的优化 map 用了什么,我其实不知道也没有什么理论,但是出来的速度比列表理解还快!因此,在后者的清晰度和前者的速度之间做出选择时,需要做出权衡。需要注意的是,我多次运行这个实验,并且得到了一致的结果。
在 Python 3 中,我得到了令人惊讶的结果:map测试用了不到一毫秒,而 list comprehension 测试用了 5 秒!这时,我记得将结果转换成一个列表以使操场公平,因为生成器当然会加载得更快,这要感谢不必初始化它的值。这些是结果:**
- 列表 a 为 7.08 秒
- 列表 b 为 5.1 秒
- 列表 c 为 5.1 秒
我不得不多次运行这个程序来检查,但是它们基本上花费相同的时间。很明显,他们都在做非常相似的事情,于是他们之间的选择就变成了清晰和懒惰是否有用。
综上所述, lambdas 可能很笨重,但是它们也为你的代码增加了很多表达能力。 Filter 和 map 对某些人来说可以是优雅的,但在性能方面不会给表格增加很多(并且被一些人视为不如 List Comprehensions 那么 Pythonic 化)。
我个人的观点是,我喜欢 Python 有这些特性,因为它们让一些代码行更漂亮,但通常不像列表理解那样喜欢它们。如果没有尾部调用消除和其他优化,除了风格和懒惰(好的那种)之外,要举出在 Python 中使用函数式编程的好理由可能有点困难(尽管我们实际上可以从在 Haskell 中使用函数式编程中获得很多好处)!)。
你的观点是什么?你还想让我讨论其他功能性话题吗?我不提减或折你生气吗?你希望 Python 中引入哪些其他功能性的东西?哪些是你不喜欢的?我相信你对此有自己的看法,我也很想了解更多。我也很想知道是否有一些非平凡的例子,在这些例子中, map 实际上比 List Comprehensions 更快,但我没有看到它们。
这是我对 Python 中函数式编程特性的介绍,我希望您发现它很有用,或者至少在阅读它的过程中获得了一些乐趣。
你可以在我的 个人网站 中看到我正在做的事情以及我最近的文章和笔记。
通过可视化了解您的卷积网络
Convolution layer outputs from InceptionV3 model pre-trained on Imagenet
自从卷积神经网络出现以来,计算机视觉领域已经取得了巨大的进步。在过去的几年里,这一领域令人难以置信的研究速度,加上网上大量图像数据库的开放可用性,给了我们令人难以置信的结果。大型卷积神经网络的兴起始于 2012 年的 AlexNet ,由 Alex Krizhevsky 、 Ilya Sutskever 和 Geoffrey Hinton 创建,是当年 ImageNet 大规模视觉识别挑战赛的获奖作品。从那以后,这个领域的研究人员再也没有回头看,计算机视觉各个领域的结果就是一个明显的证明。从手机中的人脸识别到驾驶汽车,CNN 的巨大力量正被用来解决许多现实世界的问题。
但是,尽管大型数据库和预先训练的 CNN 模型广泛可用,但有时很难理解你的大型模型到底在学习什么以及如何学习,特别是对于没有机器学习所需背景的人来说。虽然,阅读基础统计和概率有助于克服一些障碍,但当涉及到调试大型卷积架构(如 Inception 模型)时,许多人会上当。大多数人的目标只是使用预先训练好的模型来进行一些图像分类或任何其他相关的问题,以得到最终的结果。他们最不关心网络的内部工作,这实际上可以告诉他们很多关于他们的网络如何学习和学习什么,以及调试它的故障。
最近偶然看到这本Fran ois Chollet(Twitter)用 Python 深度学习的超棒的书。如果你正开始你的深度学习之旅,这本书是一个瑰宝。它使用 Keras,这是一个优秀的深度学习库,运行在 TensorFlow,MXNET 和 Theano 上,解释了深度学习的基础知识以及前沿和最新的事情和结果。在我阅读这本书学到的许多新东西中,真正激发我兴趣的是可视化如何用于学习 conv 网。在这篇博客中,我总结了我学到的三种技术以及我复制它们的结果。
Eenter 可视化
可视化机器学习模型的输出是一种很好的方式来查看它的进展情况,无论是基于树的模型还是大型神经网络。在训练深度网络时,大多数人只关心训练误差(精度)和验证误差(精度)。虽然判断这两个因素确实可以让我们了解我们的网络在每个时代的表现,但当涉及到像 Inception 这样的深度 CNN 网络时,我们可以看到更多信息,从而了解网络架构。
在这篇文章中,我将演示几种可视化模型输出的方法(中间层和最终层),这可以帮助你更深入地了解模型的工作。我训练了 Keras 中的 InceptionV3 模型(在 ImageNet 上进行了预训练),训练了 Kaggle 上的花卉识别数据集。如果你不熟悉 Inception 模型,我建议你先浏览一下 Inception 架构 的原始论文,然后再浏览一下 InceptionV3 论文 以了解这些架构背后的理论。
我对模型进行了 10 个时期的训练,批次大小为 32,每个图像的大小调整为(299,299,3)的形状,这是预训练的 InceptionV3 模型所需要的。我的模型能够达到 0.3195 的训练损失和 0.6377 的验证损失。我使用 Keras 内置的 ImageDataGenerator 模块来扩充图像,这样模型就不会过拟合得太快。可以看看我的 github 库 上的代码。
可视化中间层激活
为了理解我们的深度 CNN 模型如何能够对输入图像进行分类,我们需要理解我们的模型如何通过查看其中间层的输出来查看输入图像。通过这样做,我们能够更多地了解这些层的工作原理。
例如,当提供来自测试集的花的图像时,以下是训练的 InceptionV3 模型的一些中间卷积及其相应激活层的输出。
Original Image
Filters from layers First, Fourth and Ninth convolution layers in InceptionV3
Filters from ReLU activation layers respective to First, Fourth and Ninth convolution layers in InceptionV3
上图显示了分别来自 InceptionV3 网络的几个中间卷积和 ReLU 层的滤波器。我通过在一个测试图像上运行训练好的模型来捕获这些图像。
如果你看看不同的图像从卷积层过滤器,很清楚地看到不同的过滤器在不同的层是如何试图突出或激活图像的不同部分。一些过滤器充当边缘检测器,其他的检测花的特定区域,如其中心部分,还有一些充当背景检测器。在起始层中更容易看到卷积层的这种行为,因为随着你越深入,卷积核捕获的模式变得越来越稀疏,所以可能这种模式甚至可能不存在于你的图像中,因此它不会被捕获。
进入相应卷积层的 Relu(校正线性单位)激活,它们所做的就是将 ReLU 函数应用于每个像素ReLU(z) = max(0, z)
,如下图所示。因此,基本上,在每个像素上,激活函数要么为所有负值设置 0,要么在像素值大于 0 时设置像素值本身。
ReLU function
通过以这种方式可视化来自不同卷积层的输出,您将注意到的最重要的事情是,网络中较深的层可视化更多训练数据特定特征,而较早的层倾向于可视化一般模式,如边缘、纹理、背景等。当您使用迁移学习时,这些知识非常重要,通过迁移学习,您可以在完全不同的数据集上训练预训练网络(在不同的数据集上进行预训练,如本例中的 ImageNet)的某个部分。总的想法是冻结早期层的权重,因为它们无论如何都会学习一般特征,并且只训练更深层的权重,因为这些层实际上识别你的对象。
可视化 Convnet 滤波器
了解卷积网络在图像中寻找什么的另一种方法是可视化卷积图层过滤器。通过显示网络层过滤器,您可以了解每个过滤器将响应的模式。这可以通过对 convnet 的值运行梯度下降来实现,以便从空白输入图像开始最大化特定滤波器的响应。
以下是我在 Flowers 数据集上训练的 InceptionV3 模型中的一些模式。
Filters from third convolution layer in InceptionV3
Filters from eight convolution layer in InceptionV3
Filters from fortieth convolution layer in InceptionV3
仔细观察这些来自不同卷积层的滤波器图像后,就可以清楚地看到不同的层实际上试图从提供给它们的图像数据中学习什么。在起始层的过滤器中发现的图案似乎非常基本,由线条和其他基本形状组成,这告诉我们早期的层了解图像中的基本特征,如边缘、颜色等。但是,随着你向网络的更深处移动,模式变得更加复杂,这表明更深的层实际上正在学习更抽象的信息,这有助于这些层概括关于类而不是特定图像的信息。这就是为什么在前面的部分中,我们在更深的层中看到一些空的过滤器激活,因为该特定过滤器没有为该图像激活,换句话说,该图像没有过滤器感兴趣的信息。
可视化课程激活热图
预测图像的类别标签时,有时您的模型会为您的类别预测错误的标签,即正确标签的概率不是最大的。在这种情况下,如果你能想象出你的 convnet 在看图像的哪一部分并推断出类别标签,这将会很有帮助。
这种技术的一般类别称为类激活图 (CAM)可视化。使用 CAM 的技术之一是在输入图像上产生类激活的热图。类别激活热图是与特定输出类别相关联的分数的 2D 网格,针对输入图像的每个位置计算,指示每个位置相对于该输出类别有多重要。
在上面的图片中,你可以看到这种技术是如何工作的。从左开始,首先是输入图像,然后是 InceptionV3 架构中最后一个混合层的激活热图,最后我将热图叠加在输入图像上。因此,基本上,热图试图告诉我们的是图像中的位置,这些位置对于特定图层将其分类为目标类非常重要,在本例中是雏菊****。
在第一幅图像中,很明显网络在分类花方面没有问题,因为在整个图像中没有其他对象。在下一幅图像中,网络无法将图像分类为**雏菊,**但是如果你看一下激活图的热图,很明显网络正在图像的正确部分寻找花朵。与第三个图像的情况类似,网络能够突出显示图像的左下部分,小雏菊花位于该部分。因此,很明显,虽然网络不能正确地对第二和第三幅图像进行正确分类,但做出这一决定的原因不是网络的不正确,而是两幅图像中的其他对象占据了图像的较大部分。
对于网络中的不同层,激活热图可能会有所不同,因为所有层都以不同的方式查看输入图像,从而基于其过滤器创建图像的独特抽象。在这个例子中,我将重点放在模型的最后一层,因为类预测标签将在很大程度上依赖于它。但是比较不同层的激活热图是一个很好的实验。
结论
在这篇文章中,我描述了三种不同的方法来可视化你的深层卷积网络。正如前面所解释的,这样的可视化可以帮助我们理解黑盒技术的工作,更好地像神经网络一样,这对于调试任何错误或网络的整体性能都是有用的。
Tensorflow 的不公平反向传播
GIF from this website
我一直在思考反向传播,在传统的神经网络中,我们似乎总是线性地执行前馈操作和反向传播。(1:1 的比例)但是我对自己说,我们真的不需要这么做。所以我想做些实验。
案例 a)反向传播(无数据增强)
案例 b)反向传播(数据增强)
案例 c)不公平的后支撑(从后面)(无数据增强)
案例 d)不公平的后支撑(从后面)(数据增强)
案例 e)不公平的后支撑(从前面)(无数据增强)
案例 f)不公平的后支撑(从前面)(数据增强)
请注意,这个帖子是为了好玩,也是为了表达我的创意。因此不是面向性能的。
网络架构/数据集/典型反向传播
红色方块 →输入图像批次
黑色方块 →有/无均值合并的卷积层
橙色方块 →用于分类的 Softmax 层
橙色箭头 →前馈操作方向
紫色箭头 →反向传播方向。
如上所述,我们将使用我的旧帖子“全卷积网”中的基本网络,这是一个仅由卷积运算组成的 9 层网络。此外,我们将使用 CIFAR 10 数据集。
不公平反向传播
现在为了解释不公平反向传播的概念,让我们首先假设我们刚刚完成了前馈操作(如上所示)。通过查看粉色箭头,我们已经可以知道我们已经反向传播到第 9 层。
现在,我们可以再次执行前馈操作来获得另一轮分类,而不是继续反向传播到第八层等等。(但是这次第 9 层已经更新了一次它的权重。)
我们可以再次重复这个过程,但是这次我们也要更新第 8 层的权重。
我们可以一次又一次地遵循这个概念。直到我们到达第一层,完成整个反向传播。总之,我们对网络的开始层不公平,因为后面的部分会更新更多。我们也可以在 GIF 格式中看到不同。
最后,我们可以把对网络开始部分不公平的概念反过来,对网络的后面部分不公平。(换句话说,我们网络的开始部分比后面部分更新得更多。)
结果:情况 a)反向传播(无数据增加)(50 个时期)
左图 →一段时间内测试图像的精度/成本
右图 →一段时间内列车图像的精度/成本
如上所述,网络测试图像的准确率已经开始停滞在 83%左右。然而,这里要注意的是,网络需要 13 个历元才能使测试图像的准确率达到 80%以上。
训练图像的最终准确率为 98 %,而测试图像的准确率为 83 %,这表明网络正遭受过拟合。
左图 →训练后权重直方图
右图 →训练前权重直方图
如上所示,所有的权重范围都从-0.1/0.1 增加到-0.5/0.5。
结果:情况 b)反向传播(数据扩充)(10 个时期)
左侧图像 →一段时间内测试图像的精度/成本
右侧图像 →一段时间内训练图像的精度/成本
现在,由于我们执行了数据扩充,我们可以清楚地观察到训练图像的准确性下降(因为数据中有更多的差异。).
如上所示,在训练 10 个时期后,网络最终达到了 79%的准确率(在测试图像上)。值得庆幸的是,网络并没有过度拟合。
左图 →训练后权重直方图
右图 →训练前权重直方图
就像我们没有执行数据扩充的情况一样,权重的范围也增加了。
结果:案例 c)不公平的后道具(从后面) (无数据增强)(10 个历元)
左侧图像 →一段时间内测试图像的精度/成本
右侧图像 →一段时间内列车图像的精度/成本
与用普通(典型)反向传播方法训练的网络相比,该网络表现得更好。在测试图像上完成训练的准确率约为 82 %,在训练图像上完成训练的准确率约为 89%。表明仍然存在过度拟合,但是与情况 a)相比没有那么多。
观察到不公平反向传播似乎具有某种正则化效应的事实是相当令人惊讶的。
左图 →训练后权重直方图
右图 →训练前权重直方图
到目前为止,最有趣的观察是权重的直方图。如上所述,当我们将注意力集中到网络最终层生成的直方图时,我们可以观察到直方图偏向一侧。(-左侧范围为-0.5,而右侧没有 0.5。)表明分布的对称性有些受阻。中间层的直方图也是如此。
结果:案例 d)不公平背道具(从后面) (数据增强)(10 Epoch)
左图 →一段时间内测试图像的精度/成本
右图 →一段时间内列车图像的精度/成本
同样,当我们执行数据扩充时,我们可以观察到训练图像的准确性下降。
并且当比较来自情况 b)的结果(10 个历元的正常反向支持)时,我们可以观察到训练图像上的准确度彼此相似(49%)的事实。然而,不管是什么原因,由不公平反向支持训练的网络在测试图像上具有更高的准确性。
左图 →训练后权重直方图
右图 →训练前权重直方图
与情况 c)不同,我们可以观察到这种情况下权重分布的一些对称性。
结果:情况 e)不公平的后道具(来自前方) (无数据增强)(10 个历元)
左侧图像 →一段时间内测试图像的精度/成本
右侧图像 →一段时间内训练图像的精度/成本
最后,我想看看,当我们对网络的后半部分不公平时,是否有区别。从表面上看,对我们网络的开始部分不公平比后面部分不公平要好。
我这么说的一个原因是因为测试图像的最终准确性。我们可以观察到在训练图像上的准确性是相似的,但是该网络在测试图像上具有较低的准确性。
左图 →训练后权重直方图
右图 →训练前权重直方图
有趣的是,不管我们对网络的开始部分还是后面部分不公平,权重的分布似乎是相似的。
结果:案例 f)不公平的后道具(来自正面) (数据增强)(10 个历元)
左侧图像 →一段时间内测试图像的精度/成本
右侧图像 →一段时间内列车图像的精度/成本
最后,我在训练来自案例 e 的相同网络时执行了数据扩充。
如上所述,这里也可以观察到精度没有提高。
左图 →训练后权重直方图
右图 →训练前权重直方图
重量分布也有类似的结果。在普通的 CNN 中,我们知道后面的层捕捉更高级的特征。我怀疑网络更努力训练比较好?捕捉更高层次的特征。
交互代码
对于 Google Colab,你需要一个 Google 帐户来查看代码,而且你不能在 Google Colab 中运行只读脚本,所以在你的操场上复制一份。最后,我永远不会请求允许访问你在 Google Drive 上的文件,仅供参考。编码快乐!同样为了透明,我在 github 上上传了所有的训练日志。
要访问案例 a 的代码,请点击此处,要查看日志,请点击此处。
访问案例 b 的代码请点击此处,日志的请点击此处。
要访问案例 c 的代码,请点击此处,要查看日志,请点击此处。
要访问案例 d 的代码,请点击此处,要查看日志,请点击此处。
要访问案例 e 的代码,请点击此处,要查看日志,请点击此处。
要访问案例 f 的代码,请点击此处,要查看日志,请点击此处。
最后的话
关于我为什么发这篇博文,我其实有更深层次的原因,很快就会揭晓。这种不成比例的反向传播的想法真的让我很感兴趣。
如果发现任何错误,请发电子邮件到 jae.duk.seo@gmail.com 给我,如果你希望看到我所有写作的列表,请在这里查看我的网站。
同时,在我的 twitter 上关注我这里,访问我的网站,或者我的 Youtube 频道了解更多内容。我还实现了广残网,请点击这里查看博文 t。
参考
- tf.cond |张量流。(2018).张量流。检索于 2018 年 6 月 17 日,来自https://www.tensorflow.org/api_docs/python/tf/cond
- TensorFlow?,H. (2018)。如何在 TensorFlow 中打印一个张量对象的值?。堆栈溢出。检索于 2018 年 6 月 17 日,来自https://stack overflow . com/questions/33633370/how-to-print-the-value-of-a-tensor-object-in-tensor flow
- 数学|张量流。(2018).张量流。检索于 2018 年 6 月 17 日,来自https://www.tensorflow.org/api_guides/python/math_ops
- tf.floormod | TensorFlow。(2018).张量流。检索于 2018 年 6 月 17 日,来自https://www.tensorflow.org/api_docs/python/tf/floormod
- tf.cond |张量流。(2018).张量流。检索于 2018 年 6 月 17 日,来自https://www.tensorflow.org/api_docs/python/tf/cond
- 使用 tf。TensorFlow 中的 print()—走向数据科学。(2018).走向数据科学。检索于 2018 年 6 月 17 日,来自https://towards data science . com/using-TF-print-in-tensor flow-aa 26 E1 cf F11 e
- Tensorflow?,H. (2018)。如何在 Tensorflow 中给 tf.cond 内部的函数传递参数?。堆栈溢出。检索于 2018 年 6 月 17 日,来自https://stack overflow . com/questions/38697045/how-to-pass-parameters-to-functions-inside-TF-cond-in-tensor flow
- TensorFlow?,H. (2018)。如何在 TensorFlow 中打印一个张量对象的值?。堆栈溢出。检索于 2018 年 6 月 17 日,来自https://stack overflow . com/questions/33633370/how-to-print-the-value-of-a-tensor-object-in-tensor flow
- 规范化的方向保持亚当,从亚当到 SGD 的转换,和内斯特罗夫动量亚当与…(2018).走向数据科学。检索于 2018 年 6 月 17 日,来自https://towards data science . com/normalized-direction-preserving-Adam-switching-from-Adam-to-SGD-and-nesterov-momentum-Adam-with-460 be 5 ddf 686
- 谷歌合作实验室。(2018).Colab.research.google.com。检索于 2018 年 6 月 17 日,来自https://colab . research . Google . com/drive/1 okr 4 jfqbmoq 8 q 4 ctzdjmp 8 jqea 4 xdqbk
- 反向传播|杰出的数学和科学维基。(2018).Brilliant.org。检索于 2018 年 6 月 17 日,来自https://brilliant.org/wiki/backpropagation/
- tf.while_loop,I. (2018)。tf.while_loop 中是否可以定义多个条件。堆栈溢出。检索于 2018 年 6 月 17 日,来自https://stack overflow . com/questions/45595419/is-possible-have-multiple-conditions-defined-in-TF-while-loop
- Python,E. (2018)。Python 中每 N 次迭代执行一次语句。堆栈溢出。检索于 2018 年 6 月 17 日,来自https://stack overflow . com/questions/5628055/execute-statement-every-n-iterations-in-python
- 示例:基础— imgaug 0.2.5 文档。(2018).img aug . readthe docs . io . 2018 年 6 月 18 日检索,来自http://img aug . readthe docs . io/en/latest/source/examples _ basics . html
- CIFAR-10 和 CIFAR-100 数据集。(2018).Cs.toronto.edu。检索于 2018 年 6 月 19 日,来自https://www.cs.toronto.edu/~kriz/cifar.html
- [ ICLR 2015 ]追求简单:具有交互码的全卷积网。(2018).走向数据科学。检索于 2018 年 6 月 19 日,来自https://towards data science . com/iclr-2015-forwards-for-simplicity-the-all-convolutional-net-with-interactive-code-manual-b 4976 e 206760