TowardsDataScience-博客中文翻译-2019-二十八-

龙哥盟 / 2024-10-13 / 原文

TowardsDataScience 博客中文翻译 2019(二十八)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

人工智能中的博弈论

原文:https://towardsdatascience.com/game-theory-in-artificial-intelligence-57a7937e1b88?source=collection_archive---------1-----------------------

博弈论的介绍以及它如何应用于人工智能的不同领域。

(Source: https://www.thegreatcourses.com/media/catalog/product/cache/1/plus_image/800x451/0f396e8a55728e79b48334e699243c07/1/4/1426.1549051731.jpg)

介绍

博弈论是数学的一个分支,用于在具有预定义规则和结果的上下文中对不同参与者之间的战略交互进行建模。

博弈论可以应用于人工智能的不同领域:

  • 多智能体人工智能系统。
  • 模仿和强化学习。
  • 生成对抗网络中的对手训练。

博弈论也可以用来描述我们日常生活和机器学习模型中的很多情况(图 1)。

例如,诸如 SVM(支持向量机)的分类算法可以用两人游戏来解释,其中一个玩家挑战另一个玩家,以找到给他最难分类的点的最佳超平面。然后,游戏将收敛到一个解决方案,这将是两个玩家的战略能力之间的权衡(例如,第一个玩家挑战第二个玩家对困难数据点进行分类的能力有多强,第二个玩家识别最佳决策边界的能力有多强)。

Figure 1: Game Theory Applications [1]

博弈论

博弈论可以分为 5 种主要类型的游戏:

  • 合作与非合作游戏:在合作游戏中,参与者可以建立联盟以最大化他们赢得游戏的机会(例如谈判)。在非合作游戏中,参与者不能结成联盟(例如战争)。
  • 对称与非对称游戏:在对称游戏中,所有参与者都有相同的目标,而他们为实现这些目标而实施的策略将决定谁赢得游戏(如国际象棋)。相反,在非对称游戏中,参与者有不同或冲突的目标。
  • 完美与不完美信息博弈:在完美信息博弈中,所有的参与者都可以看到其他参与者的行动(例如国际象棋)。相反,在不完美信息游戏中,其他玩家的行动是隐藏的(如纸牌游戏)。
  • 同时游戏 vs 顺序游戏:在同时游戏中,不同的玩家可以同时采取行动。相反,在顺序游戏中,每个玩家都知道其他玩家之前的行为(例如棋盘游戏)。
  • 零和与非零和游戏:在零和游戏中,如果一个玩家获得了某些东西,而导致其他玩家的损失。相反,在非零和游戏中,多个玩家可以从另一个玩家的收益中获益。

博弈论的不同方面通常用于人工智能,我现在将向您介绍纳什均衡,逆博弈论,并给你一些实际的例子。

如果您对用 Python 实现博弈论算法感兴趣, Nashpy 库是一个很好的起点。

纳什均衡

纳什均衡是这样一种状态,参与博弈的所有参与者都同意,除了他们此时所处的实际情况之外,没有其他最优解。没有一个玩家会在改变他们当前的策略(基于其他玩家所做的决定)中获得优势。

按照我们之前的例子,纳什均衡的一个例子可以是当 SVM 分类器同意使用哪个超平面来分类我们的数据。

用来解释纳什均衡的一个最常见的例子是囚徒困境。让我们想象一下,两个罪犯被捕了,他们被关在牢房里,没有任何可能互相交流(图 2)。

  • 如果两个囚犯中的任何一个承认另一个犯了罪,第一个将被释放,而另一个将在监狱度过 10 年。
  • 如果两人都不承认,他们每人只需在监狱里呆一年。
  • 如果他们都坦白,他们都要在监狱里呆 5 年。

Figure 2: Payoff Matrix [2]

在这种情况下,当两个罪犯都背叛对方时,纳什均衡就达到了。

一个简单的方法来找出一个游戏是否达到了纳什均衡,可以向你的对手透露你的策略。如果在你的启示之后,没有人改变他们的策略,纳什均衡就被证明了。

不幸的是,纳什均衡在对称博弈中比在非对称博弈中更容易达到。不对称游戏实际上在现实世界的应用和人工智能中是最常见的。

逆博弈理论

博弈论旨在理解游戏的动态,以优化参与者的可能结果。相反,反向博弈理论旨在根据玩家的策略和目标来设计游戏。逆博弈理论在设计人工智能主体环境中起着重要的作用。

实际例子

生成对抗网络中的对手训练

GANs 由两个不同的模型组成:一个 生成型模型 和一个 判别型 模型(图 3)。

Figure 3: GAN Architecture [3]

生成模型将一些特征作为输入,检查它们的分布,并试图理解它们是如何产生的。生成模型的一些例子是隐马尔可夫模型(hmm)和受限玻尔兹曼机器(RBM)。

判别模型采用输入特征来预测样本可能属于哪个类别。支持向量机(SVM)是判别模型的一个例子。

在 GANs 中,生成模型使用输入特征来创建新样本,新样本旨在非常接近地模仿原始样本的主要特征。然后,新生成的样本与原始样本一起被传递到判别模型,该模型必须识别哪些样本是真的,哪些是假的[4]。

GANs 的一个示例应用是生成图像,然后区分真假图像(图 4)。

Figure 4: Images generated by NVIDIA GAN! [5]

这个过程非常类似于游戏的动态。在这场比赛中,我们的球员(两个模型)正在相互挑战。第一个玩家制造假样本来迷惑另一个玩家,而第二个玩家试图越来越好地识别正确的样本。

这个游戏然后被迭代地重复,并且在每次迭代中,学习参数被更新,以便减少整体损失。

这个过程将继续下去,直到达到纳什均衡(这两个模型在执行它们的任务时变得熟练,并且它们不再能够改进)。

多智能体强化学习

强化学习(RL)的目的是让一个主体(我们的“模型”)通过与环境(可以是虚拟的,也可以是真实的)的交互来学习。

RL 最初被开发来遵循马尔可夫决策过程。在这个范围内,一个智能体被放置在一个随机稳定的环境中,并试图通过奖惩机制学习一个策略。在这种情况下,证明了代理将收敛到一个满意的策略。

但是,如果将多个代理放在同一个环境中,这个条件就不再成立。事实上,以前智能体的学习只依赖于智能体与环境的交互,现在它也依赖于智能体之间的交互(图 5)。

让我们想象一下,我们正在试图使用一组人工智能驱动的自动驾驶汽车来改善城市的交通流量。就其本身而言,每辆车都可以与外部环境完美互动,但如果我们想让汽车作为一个群体来思考,事情会变得更加复杂。例如,一辆车可能会与另一辆车发生冲突,因为对双方来说,沿着某条路线行驶是最方便的。

这种情况可以很容易地用博弈论来模拟。在这种情况下,我们的汽车将代表不同的球员和纳什均衡的平衡点之间的合作,不同的汽车。

Figure 5: Multi-Agents Reinforcement Learning Tennis 6

用大量的代理对系统建模可能会成为一项非常困难的任务。这是因为,增加代理的数量,使得不同代理相互作用的可能方式的数量呈指数增长。

在这些情况下,用平均场场景(MFS) 建模多智能体强化学习模型可能是最好的解决方案。事实上,平均场方案可以通过预先假设所有代理都具有相似的报酬函数来降低 MARL 模型的复杂性。

联系人

如果你想了解我最新的文章和项目,请通过媒体关注我,并订阅我的邮件列表。以下是我的一些联系人详细信息:

  • 领英
  • 个人博客
  • 个人网站
  • 中等轮廓
  • GitHub
  • 卡格尔

文献学

[1]博弈论和最优决策。访问地点:http://euler.fd.cvut.cz/predmety/game_theory/

[2]量子概率模型再探:认知中的分离效应。Catarina Moreira 等人。访问:https://www . research gate . net/publication/304577699 _ Quantum _ probabilical _ Models _ Revisited _ The _ Case _ of _ 析取 _Effects_in_Cognition/figures?lo=1

[3] GAN 深度学习架构—综述,Sigmoidal。访问地址:https://sigmoidal.io/beginners-review-of-gan-architectures/

[4]概述:生成性对抗网络——当深度学习遇上博弈论。艾哈迈德·哈尼·易卜拉欣。访问位置:https://ahmedhanibrahim . WordPress . com/2017/01/17/generative-adversarial-networks-when-deep-learning-meets-game-theory/comment-page-1/

[5]英伟达人工智能根据真实的名人 Geek.com 生成假脸。访问:https://www . geek . com/tech/NVIDIA-ai-generates-fake-faces-based-on-real-celes-1721216/

6大卫·布朗,网球环境——多智能体强化学习。访问地点:【https://github.com/david-wb/marl

Reddit 上的游戏,重温

原文:https://towardsdatascience.com/gaming-on-reddit-revisited-74f12c8a95d2?source=collection_archive---------51-----------------------

Photo by JESHOOTS.COM on Unsplash

自然语言处理和迭代数据科学的练习

大会数据科学沉浸式项目中最受欢迎的项目之一是围绕 reddit 展开的。你的目标是:选择两个子编辑,从每个子编辑中收集一千篇文章,然后建立一个模型,将文章分类到标题中正确的子编辑中。很容易看出为什么这是一个如此受欢迎的项目,它在 5 个项目中排名第 3,所以我们开始适应我们的新技能,我们可以选择自己的子项目,所以我们也可以从中获得一些乐趣。这是对数据科学家触手可及的强大技术的一个很好的体验。

对于我的实现,我选择了一个主题中的两个子主题,在这个主题中我有相当多的领域知识——游戏!至少从我出生的那一天起,我就已经是一名游戏玩家了(有传言但未经证实),所以我非常兴奋能够找到自己对游戏世界的见解。我选择了两个主题相似但不同的子主题,r/gaming 和 r/pcgaming。

Photo by Abdul Barie on Unsplash

如果这两个子主题之间的区别不是很明显,其中一个涉及一般的游戏,可以包括任何家用游戏机、手机,甚至棋盘游戏。另一个子编辑专门处理电脑游戏,不仅仅是游戏本身,还有硬件、软件、外围设备等等,这往往是在电脑上玩游戏的独特体验。当然,两个子网格之间有很多重叠,这就是为什么这是一个很大的问题!

我最近决定花些时间再次运行这个项目,不仅是为了收集更多的数据,也是为了尝试实现一些我最初没有实现的改进。作为一名程序员,我确实成长了,所以即使从效率和可读性的角度来看,我也知道我想做很多改变。在项目中循环不仅仅是提高 ML 训练的机会,也是提高你的代码的好时机!

数据收集

和往常一样,第一步是实际获取将要使用的数据。最初,我只是编写了进行拉操作的代码,并就此打住。这一次,我想把它变成一个真正的函数,这样我就可以继续做这些事情,而不会用大量复制的代码块堵塞笔记本。

**def** reddit_puller(url, params, user_agent, pulls, post_list):
    *# adapting code from Boom Devahastin Na Ayudhya*

    **for** pull_num **in** range(int(pulls)):

        *# stating which pull is being attempted*
        print("Pulling data attempted", pull_num+1, "times")

        *# establishing the request code*
        res = requests.get(url, headers=user_agent, params=params)

        *# pull the correct data if the code is good*
        **if** res.status_code == 200:
            json_data = res.json()                      *#  Pull JSON*
            post_list.extend(json_data['data']['children']) *#  Get posts and extend the `posts` list* 

            *# updating url with the id of the last post in the pull*
            *# next pull will grab the following entries*
            after = json_data['data']['after']
            params["after"] = after

        **else**:
            print("There has been an error. The code is: ", res.status_code)
            **break**

        *# sleeping the func so we aren't locked out*
        time.sleep(2)

当我第一次从每个子编辑中提取帖子时,大量返回的内容都是重复的,第二次也是如此。在第二次搜索结束时,总共有大约 2400 个不同的条目。

清洁和分析

随着新数据的增加,我最初采取的清理步骤基本上没有改变。还有一些交叉帖子(帖子显示在两个子编辑中)和离群值(只有表情符号/表情符号的标题),所以在我以前手动解决这些问题的地方,我编写了一些新的可扩展代码,不必在每次数据变化时都进行更改。

*# saving the cross-posts as new dfs*
gaming_cross_posts = gaming_df[gaming_df["title"].isin(pcgaming_df["title"]) == **True**]
pc_cross_posts = pcgaming_df[pcgaming_df["title"].isin(gaming_df["title"]) == **True**]*# dropping all the cross-posts*
gaming_df.drop(gaming_cross_posts.index, inplace=**True**)
pcgaming_df.drop(pc_cross_posts.index, inplace=**True**)

我还从上一次迭代中创建了一个新列,计算每个标题的字数。我已经制作了一个总字符长度的特性,但是我想给这个信息添加另一个维度。它不仅有助于深入了解数据和子数据本身,还可以在以后的建模阶段作为一个预测器。将数据可视化在直方图上,我可以清楚地看到标题长度的大量重叠,以及与 r/gaming 相比,r/pcgaming 中帖子的标题长度的明显变化。

事实上,越来越多的帖子标题在 10-15 个单词范围内,这表明 r/pcgaming 中讨论的内容可能更复杂。从建模的角度来看,这可能意味着一个较长的标题可能更有可能来自 r/pcgaming 而不是 r/gaming,但其有效性仍有待观察。

我还深入研究了单词本身,以便更好地了解哪些类型的语言构成了目标。我通过一个简单的CountVectorizer来运行数据,找出哪些单词是最常见的。然后通过几次迭代,我决定使用PorterStemmer来简化单词,并确定要删除的典型停用词,包括一些特定于该数据的附加停用词。

有了新数据,我不得不将这个过程重复几次,找出更多的停用词添加到我的列表中。最终,r/gaming 中大约有一半的热门词汇这次有所不同,r/pcgaming 的变化较少,其热门词汇的领先优势要高得多。

在经历数据科学项目的生命周期时,获取新数据并直接跳回建模阶段可能很有诱惑力,但 EDA 是重要的一步。并非每种情况都是一样的,因此,向已经有数百万条记录的数据集中添加几千条记录可能不会产生很大的影响,但在这种情况下,我将数据加倍,因此可能会有很大的变化。

建模

第一次,建模已经是一个相当复杂的过程。我对高度过度拟合的模型有很大的问题,但最终得到了一个方差很低、精确度在 70%左右的AdaBoostClassifier。我将矢量化步骤与带有GridSearchCVPipeline中的模型训练相结合,以便能够充分优化每种类型的分类算法。

这次我做了一些改变。因为我想添加我的工程功能——标题的字数和字符数——我知道我不能只保留我的旧管道。我还发现使用TfidfVectorizerCountVectorizer给我带来了更好的结果,所以我决定做一个永久的改变,把它转移到预处理步骤,而不是网格搜索的一部分(这可能不是最好的主意,但是我会再回来)。因此,随着我的单词矢量化(现在是一个稀疏矩阵),我将它们和我的额外数字列转换为数组,并将它们堆叠在一起,以获得我的新训练数据。

我再次运行了我所有的旧模型(逻辑回归、随机森林等等),我注意到的第一件事是之前在这些模型中看到的过度拟合大幅下降。然而,对准确性分数似乎没有太大的影响(在任一方向上)。自从我第一次做这个项目以来,我遇到了更多类型的算法,所以我也想尝试一些新的东西,可能会更好地解决这个 NLP 问题。我在我的队列中添加了一个支持向量分类器,并希望得到一个惊人的结果。

我没有得到一个。我找出了我所有模型的度量标准——我在这个项目中做得很准确,因为这些类很好地平衡了,并且对假阳性或假阴性没有更大的损害——并对它们进行了比较。虽然 SVC 在我的列表中排在首位,但它实际上与逻辑回归模型有着相似的性能。

因此,在挑选“最佳”模型时,基本上取决于这两个模型,因为它们似乎给出了最佳的偏差/方差平衡(不像 KNN 或随机森林)。最后,我选择了 SVC 作为“最好的”,因为它使方差最小化的程度超过了逻辑回归对性能的改善。然而,由于 SVC 是一个“黑盒”模型,我仍然想利用逻辑回归来解释它。将系数与特征进行匹配,我能够找到在为模型做出决策时最重要的因素。

我们可以看到,我们在 EDA 中看到的单词最终在建模过程中非常重要——“Steam”、“trailer”和“release”是 r/pcgaming 中使用最多的三个单词。另一方面,有“快乐”和“朋友”这样的词意味着帖子不太可能来自 r/pcgaming。我不认为我想深究这可能会对 PC 游戏玩家说些什么,但我知道这对这个模型很有帮助。我还注意到,我制作的两个额外特性没有出现在系数列表的顶部,这有点令人失望。

包扎

那么,这个新的和改进的迭代(带有新的数据、特性和模型)实际上给我带来了什么呢?事实证明,并不多。我没有对性能产生很大的影响(我已经在 78%的准确范围内了),但是我能够进一步减少我的方差,老实说,它并不是很大。

发生了什么事?我想到了几种可能性。一个是我没有给足够的新信息——也许 2400 个帖子不足以有效地训练一个关于这个问题的模型——但这感觉像是一种逃避,因为你几乎总是可以说你“需要更多数据”,我已经看到两次迭代之间相当一致的性能。另一个原因是我没有做足够的功能工程——也许我需要更深入地挖掘,并添加关于有多少评论的数据,或者隐藏在原始 JSON 文件中的这些帖子的另一个方面。我也可能对此过于简单,它需要更高级的 NLP,如 Word2Vec 和使用嵌入而不是“单词包”。

我看到的另一个大问题是我的建模。在最初的版本中,我测试和优化了不同的矢量器,作为网格搜索/管道功能的一部分。这一次,我添加了单独设计的功能,并决定重新配置我的预处理以使其更容易。在这样做的过程中,我删除了与新功能一起优化矢量化的能力——也许有了这些附加信息,TF-IDF 会有一组不同的参数来提高某些模型的精度,或者也许 CVEC 实际上是正确的选择。我最近了解到 ScitKit-Learn 的ColumnTransformer正是为了将不同的特性转换组合成一个管道,所以我想下一次我会修改我的代码来使用它

这绝对值得在 GA 课程结束后再来一次,并提供了一个很好的经验,让我们了解经历一个项目的多个周期是什么样的(并降低期望)。当然,你总是带着改善的意图回到某件事情上,但是有时你并没有产生太大的影响。不管怎样,这是一个学习和成长的机会,所以不要错过。

一如既往,感谢您乘坐数据科学列车,并让我知道您对该项目的想法 SVC 真的是最好的模型吗?我不应该设计更多的功能吗?下面评论!

请点击查看完整项目回购。

也可以在 LinkedIn 上找我。

伽马分布——直觉、推导和例子

原文:https://towardsdatascience.com/gamma-distribution-intuition-derivation-and-examples-55f407423840?source=collection_archive---------0-----------------------

为什么这很重要?

在设置伽马的两个参数 α,β 并将其代入公式之前,我们先暂停一下,问几个问题…

为什么我们必须发明伽马分布?(即为什么会存在这种分布?)

伽玛分布应该在什么时候用于建模?

1.我们为什么要发明伽马分布?

答:预测未来事件发生前的等待时间。

嗯,好吧,但我认为这就是指数分布的用途。
那么,指数分布和伽玛分布有什么区别?

指数分布预测等待时间,直到第一个 事件。另一方面,伽马分布预测等待时间,直到第*** k ***事件发生。

2.让我们从零开始推导伽玛的 PDF!

在我们之前的文章中,我们从泊松过程中推导出了指数分布的 PDF。如果你还没有学过,我强烈推荐你学习泊松分布。很好地理解它们对于理解伽马井是绝对必要的。你阅读的顺序应该是 1。阿松,2。指数,3。伽马射线。

伽玛分布的 PDF 的推导与指数分布的 PDF 非常相似,除了一点——它是直到第 k 个事件的的等待时间,而不是第一个事件

< Notation! >* **T** : the random variable for **wait time until the k-th event** (This is the random variable of interest!)
* **Event arrivals are modeled by a Poisson process with rate λ.*** **k** : the 1st parameter of Gamma. **The # of events** for which you are waiting.
* **λ** : the 2nd parameter of Gamma. **The rate of events** happening which follows the Poisson process.* **P(T > t) :** The probability that the waiting time until the **k**-th event is greater than **t** time units
* **P(X = k in t time units) :** The Poisson probability of **k** events occuring during **t** time units

和往常一样,为了得到 PDF,我们会先找到 CDF,然后微分。

现在,我们来区分一下。

为了便于微分,我们从求和中去掉 x = 0 时的项(【e^(-λt】))。

我们得到了伽玛分布的 PDF!

推导看起来很复杂,但我们只是重新排列变量,应用微分的乘积法则,展开求和,并划掉一些。

如果你看看求导的最终输出,你会注意到它和指数分布的 PDF 是一样的,当 k =1 时。

由于 k 是正整数(事件 k 的数量),𝚪(k)=(k1)!其中𝚪表示伽玛函数。最终产品可以改写为:

如果事件的到达遵循速率为λ的泊松过程,则直到 k 个到达的等待时间遵循γ(k,λ)。

3.伽玛的参数:形状还是尺度?!

伽马的参数化有两个方面让我们困惑!

From https://en.wikipedia.org/wiki/Gamma_distribution

一个是它有两个不同的参数化集合——(kθ ) & ( αβ)——以及不同形式的 PDF。另一个原因是,对于“标度”参数应该是什么,还没有普遍的共识。

让我们澄清这一点。

第一个问题很容易解决。

对于( αβ )参数化:使用我们的符号 k (事件数量)& λ (事件发生率),简单地用 k 代替 α ,用 λ 代替 β 。PDF 保持和我们推导的一样的格式。
对于 (k,θ) 参数化 : θ事件率λ 的倒数,也就是平均等待时间(事件到达的平均间隔时间)。

即使 pdf 有不同的格式,两个参数化生成相同的模型。就像为了定义直线,一些使用斜率和 y 截距,而另一些使用 x 截距和 y 截距,选择一个参数化而不是另一个参数化是一个品味问题。在我看来,使用λ作为速率参数更有意义,考虑到我们如何使用泊松速率λ推导出指数和伽马。我还发现( αβ )参数化更容易集成。

第二,一些作者称 λ 为标度参数,而另一些作者称 θ=1/λ 为标度参数。依我看,“形状”或“比例”参数实际上更像是用词不当。我用不同的 k & λ 集合绘制了多个 Gamma pdf(kkλ 有无限多种参数选择,因此有无限多种可能的 Gamma 分布),并实现了 k (和 λ)同时改变“形状”和“比例”。无论是谁认真地给它们命名,都可以给出更直观的名字,例如——事件的数量和泊松比!

眼见为实!让我们想象一下🌈

Recap:**k** : **The number of events** for which you are waiting to occur.
**λ** : **The rate of events** happening which follows the Poisson process.

对于一个固定的速率 λ ,如果我们等待更多的事件( k )发生,等待时间( T )会更长。

对于固定数量的事件 k ,当事件率 λ 较高时,我们等待的时间 T 较短。

下面是生成上面美丽情节的 Python 代码。(自己画出来,看看两个参数是怎么改变“比例”和“形状”的!)

import numpy as np
from scipy.stats import gamma
import matplotlib.pyplot as pltdef plot_gamma_k():
    """
    k : the number of events for which you are waiting to occur.
    λ : the rate of events happening following Poisson dist.
    """
    x = np.linspace(0, 50, 1000)
    a = 1  # k = 1
    mean, var, skew, kurt = gamma.stats(a, moments='mvsk')
    y1 = gamma.pdf(x, a)
    a = 5  # k = 5
    mean, var, skew, kurt = gamma.stats(a, moments='mvsk')
    y2 = gamma.pdf(x, a)
    a = 10  # k = 15
    mean, var, skew, kurt = gamma.stats(a, moments='mvsk')
    y3 = gamma.pdf(x, a)plt.title("PDF of Gamma Distribution")
    plt.xlabel("T")
    plt.ylabel("Probability Density")
    plt.plot(x, y1, label="k = 1", color='palegreen')
    plt.plot(x, y2, label="k = 5", color='yellowgreen')
    plt.plot(x, y3, label="k = 10", color='olivedrab')
    plt.legend(bbox_to_anchor=(1, 1), loc='upper right',
               borderaxespad=1, fontsize=12)
    plt.ylim([0, 0.40])
    plt.xlim([0, 20])
    plt.savefig('gamma_k.png')
    plt.clf()def plot_gamma_lambda():
    """
    k : the number of events for which you are waiting to occur.
    λ : the rate of events happening following Poisson dist.
    """
    a = 10  # k = 10
    x = np.linspace(0, 50, 1000)
    lambda_ = 1
    mean, var, skew, kurt = gamma.stats(a, scale=1/lambda_, moments='mvsk')
    y1 = gamma.pdf(x, a, scale=1/lambda_)
    lambda_ = 2
    mean, var, skew, kurt = gamma.stats(a, scale=1/lambda_, moments='mvsk')
    y2 = gamma.pdf(x, a, scale=1/lambda_)
    lambda_ = 3
    mean, var, skew, kurt = gamma.stats(a, scale=1/lambda_, moments='mvsk')
    y3 = gamma.pdf(x, a, scale=1/lambda_)plt.title("PDF of Gamma Distribution (k = 10)")
    plt.xlabel("T")
    plt.ylabel("Probability Density")
    plt.plot(x, y1, label="λ = 1", color='gold')
    plt.plot(x, y2, label="λ = 2", color='burlywood')
    plt.plot(x, y3, label="λ = 3", color='darkorange')
    plt.legend(bbox_to_anchor=(1, 1), loc='upper right',
               borderaxespad=1, fontsize=12)
    plt.ylim([0, 0.40])
    plt.xlim([0, 20])
    plt.savefig('gamma_lambda.png')
    plt.clf()

ipynb 中的代码:https://github . com/aerinkim/towards data science/blob/master/Gamma % 20 distribution . ipynb

4.示例 IRL🔥

我们可以在使用指数分布的每个应用中使用伽马分布— 等待时间建模、可靠性(故障)建模、服务时间建模(排队论)等。 —因为指数分布是伽马分布的特例(只需将 1 插入 k )。

【排队论举例】 你去了 Chipotle,排在你前面的是两个人的队。一个在被服务,另一个在等待。他们的服役时间 S2 都是独立的,指数随机变量用一个 的 2 分钟平均值 表示。(因此平均服务率为. 5/分钟* )。如果这个“速率对时间”的概念让你困惑,读读 这个 就能搞清楚。)*

你排队等 5 分钟以上的概率是多少?

我们所做的只是将 t = 5λ = 0.5 代入我们已经导出的伽马分布的 CDF 中。这就是我们在中提到的指数随机变量之和的例子。如你所见,我们也可以用伽玛的 CDF 来解决这个问题。

我在 Chipotle 等 5 分钟以上的几率不到 30%?我要那个!

需要注意一些事情:

  1. 泊松、指数和伽玛分布对同一过程(泊松过程)的不同方面进行建模。
    泊松分布用于模拟未来事件的数量,指数分布用于预测直到第一个事件的等待时间,伽马分布用于预测直到第 k 个事件的等待时间
  2. 伽马的两个参数都是严格正的,因为一个是事件数,一个是事件率。他们不可能是消极的。
  3. 伽玛分布的特殊情况
*╔═════════════╦══════════════════════╦══════════════════════╗
║    Dist.    ║           **k**          ║           **λ**          ║
╠═════════════╬══════════════════════╬══════════════════════╣
║ Gamma       ║ **positive** **real number** ║ positive realnumber ║
║ Exponential ║           **1**          ║"║
║ Erlang      ║   **positive** **integer** ║           "          ║
╚═════════════╩══════════════════════╩══════════════════════╝*

Erlang 和 Gamma 的区别在于,在 Gamma 分布中, k 可以是非整数(正实数),而在 Erlang 中, k 只能是正整数。

你可能喜欢的其他直观的文章:

* [## 泊松分布直觉(和推导)

…为什么会有这种分布?(=泊松为什么要发明这个?)…](/poisson-distribution-intuition-and-derivation-1059aeab90d) [## 伽马函数——直觉、推导和例子

…什么样的函数可以平滑地连接这些点,并给出所有实数值的阶乘?…](/gamma-function-intuition-derivation-and-examples-5e5f72517dee) [## 什么是指数分布

…指数参数λ与泊松中的参数相同吗?…](/what-is-exponential-distribution-7bdd08590e2a) [## 贝塔分布——直觉、例子和推导

…二项式和贝塔式的区别在于前者模拟成功的次数,而后者模拟成功的概率…](/beta-distribution-intuition-examples-and-derivation-cf00f4db57af)*

伽马函数——直觉、推导和例子

原文:https://towardsdatascience.com/gamma-function-intuition-derivation-and-examples-5e5f72517dee?source=collection_archive---------3-----------------------

它的性质、证明和图形

我为什么要在乎?

许多概率分布都是用伽玛函数定义的——如伽玛分布、贝塔分布、狄利克雷分布、卡方分布、学生 t 分布等。对于数据科学家、机器学习工程师、研究人员来说,伽马函数可能是使用最广泛的函数之一,因为它在许多分布中被采用。然后,这些分布用于贝叶斯推理、随机过程(如排队模型)、生成统计模型(如潜在的狄利克雷分配)和变分推理。所以,如果你很好的理解了伽马函数,你就会对它出现的很多应用有更好的理解!

1.为什么我们需要伽马函数?

因为我们要推广阶乘!

f(1) = 1, f(2) = 2!, f(3) = 3!, f(4) = 4!, … https://en.wikipedia.org/wiki/Gamma_function

阶乘函数仅针对离散点定义(正整数的——上图中的黑点),但是我们想要连接黑点。我们希望将阶乘函数扩展到所有复数。阶乘的简单公式, x!= 1 * 2 …… x,不能直接用于小数值,因为它仅在 x 为整数时有效。

所以数学家们一直在寻找…

"什么样的函数能平滑地连接这些点,并给出所有实数值的阶乘?"

然而,他们找不到可以表达 x 的和、积、幂、指数或对数的有限组合。对于实数,直到…

2.欧拉发现了伽马函数。(在 18 世纪)

The Gamma Function: Euler integral of the second kind

上面的公式用于为 z 的任何真实值找到伽马函数的值。

假设你要计算γ(4.8)。你会如何解决上面的整合?
可以手算γ(4.8)吗?也许用分部积分?

试试看,如果你找到了一个有趣的方法,请告诉我!对我来说(到目前为止还有很多人),没有快速简单的方法来手动计算分数的伽玛函数。(如果有兴趣手工解决,这里有一个很好的起点。)

好吧,那么,忘掉分析吧。能不能用编程的方式实现这个从 0 到无穷大的积分——加上无限次这个项?

您可以通过几种方式实现这一点。最常用的两种实现是 斯特林近似兰佐斯近似

For implementation addicts: [the codes of Gamma function (mostly Lanczos approximation) in 60+ different language - C, C++, C#, python, java, etc.](https://rosettacode.org/wiki/Gamma_function)

让我们使用已经实现的计算器来计算γ(4.8)

我们得到了 17.837

17.837 落在 3!(=γ(4)= 6)4!(=γ(5)= 24)—不出我们所料。

(当 z 为自然数时,γ(z)=(z-1)!我们很快就会证明这一点。)

与阶乘只取正整数不同,我们可以在 z 中输入任何实数/复数,包括负数。Gamma 函数连接黑点,并很好地绘制曲线。

**Confusion-buster**: We are **integrating over x (NOT z)** from 0 to infinity. • **x** is a helper variable that is being integrated out.
• We are NOT plugging 4.8 into **x**. We are plugging 4.8 into **z**.

3.伽玛函数如何插值阶乘函数?

如果你看一下伽玛函数,你会注意到两件事。

首先,它肯定是一个关于 z 的递增函数

二、当 z 为自然数时,γ(z+1)= z!
(我保证我们很快就会证明这一点!)

因此,我们可以期望伽马函数连接阶乘。

伽马函数怎么会以现在的术语 x^z 和 e^-x 结束?

我不知道欧拉的思想过程到底是怎样的,但他是发现自然数 e 的人,所以他一定做了很多实验,用 e 乘以其他函数来找到现在的形式。

4.伽马函数的图形会是什么样子?

当 x 趋于无穷大时∞,第一项(xz)也趋于无穷大∞,但第二项(e-x)趋于零。

那么,伽玛函数会收敛到有限值吗?

我们可以用洛必达法则严格证明它是收敛的。但我们也可以毫不费力地看到它的收敛。你想想,我们是在积分一个 x^z的乘积一个多项式递增函数 — 和 e^-x一个 指数递减函数因为 e^-x 的值比 x^z 的值下降得更快,所以伽马函数很可能收敛并具有有限的值。

让我们画出每个图表,从眼见为实开始。

The first term x^z — polynomially increasing function.

The second term e^-x — exponentially decreasing function.

x^z * e^-x 的图

再来看γ(4.8)的情况。

图下绿色阴影区域,表示从 0 到无穷大,为γ(4.8)= 3.8!

Python 代码用于生成上面的美丽情节。自己画出来,看看 z 如何改变伽玛函数的形状!

**########################
# f(x) = exp(-x) graph #
########################**import matplotlib.pyplot as plt
import numpy as np# Create x and y
x = np.linspace(-2, 20, 100)
y = np.exp(-x)# Create the plot
fig, ax = plt.subplots()
plt.plot(x, y, label='f(x) = exp(-x)', linewidth=3, color='palegreen')# Make the x=0, y=0 thicker
ax.set_aspect('equal')
ax.grid(True, which='both')
ax.axhline(y=0, color='k')
ax.axvline(x=0, color='k')# Add a title
plt.title('f(x) = exp(-x)', fontsize=20)# Add X and y Label
plt.xlabel('x', fontsize=16)
plt.ylabel('f(x)', fontsize=16)# Add a grid
plt.grid(alpha=.4, linestyle='--')# Show the plot
plt.show()**####################
# f(x) = x^z graph #
####################**import matplotlib.pyplot as plt
import numpy as np# Create x and y
x = np.linspace(0, 2, 100)
y1 = x**1.3
y2 = x**2.5 
y3 = x**3.8# Create the plot
fig, ax = plt.subplots()
plt.plot(x, y1, label='f(x) = x^1.3', linewidth=3, color='palegreen')
plt.plot(x, y2, label='f(x) = x^2.5', linewidth=3, color='yellowgreen')
plt.plot(x, y3, label='f(x) = x^3.8', linewidth=3, color='olivedrab')# Make the x=0, y=0 thicker
ax.set_aspect('equal')
ax.grid(True, which='both')
ax.axhline(y=0, color='k')
ax.axvline(x=0, color='k')# Add a title
plt.title('f(x) = x^z', fontsize=20)# Add X and y Label
plt.xlabel('x', fontsize=16)
plt.ylabel('f(x)', fontsize=16)# Add a grid
plt.grid(alpha=.4, linestyle='--')# Add a Legend
plt.legend(bbox_to_anchor=(1, 1), loc='best', borderaxespad=1, fontsize=12)# Show the plot
plt.show()**###############################
# f(x) = x^(3.8)*e^(-x) graph #
###############################**import matplotlib.pyplot as plt
import numpy as np# Create x and y
x = np.linspace(0, 20, 100)
y = x**3.8 * np.exp(-x)# Create the plot
fig, ax = plt.subplots()
plt.plot(x, y, label='f(x) = x^(3.8) * np.exp(-x)', linewidth=3, color='palegreen')
ax.fill_between(x, 0, y, color='yellowgreen')# Make the x=0, y=0 thicker
ax.set_aspect('equal')
ax.grid(True, which='both')
ax.axhline(y=0, color='k')
ax.axvline(x=0, color='k')# Add a title
plt.title('f(x) =  x^(3.8)*e^(-x) ', fontsize=20)# Add X and y Label
plt.xlabel('x', fontsize=16)
plt.ylabel('f(x)' ,fontsize=16)# Add a grid
plt.grid(alpha=.4, linestyle='--')# Add a Legend
plt.legend(bbox_to_anchor=(1, 1), loc='upper right', borderaxespad=1, fontsize=12)# Show the plot
plt.show()

ipynb 中的代码:https://github . com/aerinkim/towards data science/blob/master/Gamma % 20 function . ipynb

5.伽玛函数属性

如果你从这篇文章中拿走一样东西,那应该是这一部分。

**Property 1.****given z > 1****Γ(z)   = (z-1) * Γ(z-1)** or you can write it as
**Γ(z+1) =  z    * Γ(z)**

让我们用分部积分和伽玛函数的定义来证明它。

Red Arrow: the value of e^-x decreases much more quickly than that of x^z

证明得很漂亮!

**Property 2\.** If **n** is a positive integer**Γ(n) = (n-1)!**

让我们用性质 1 来证明它。

什么是γ(1)

所以,γ(n)=(n-1)!

You might have also seen the expression **Γ(n+1) = n!** instead of 
**Γ(n) = (n-1)!**.This is just to make the right hand side **n!**, instead of **(n-1)!** 
All we did was to shift n by 1.

6.利用伽玛函数的性质,显示伽玛分布的 PDF 积分为 1。

快速回顾一下伽马“分布”(不是伽马“功能”!):伽玛分布直觉和推导。

证据如下:

对于证明上瘾者:让我们证明上面的红色箭头。

我们将使用代换积分。

再次漂亮证明!

需要注意一些事情:

  1. 伽马函数有多老了?

很老了。大约 300 年了。(你今天是不是在做一件 300 年后还会用到的东西?;)

一个有趣的旁注:欧拉在 64 岁时失明,但他在失明后创作了几乎一半的作品。

2.一些有趣的值:

**Γ(1/2) = sqrt(𝜋)**Many interesting ways to show this:
[https://math.stackexchange.com/questions/215352/why-is-gamma-left-frac12-right-sqrt-pi](https://math.stackexchange.com/questions/215352/why-is-gamma-left-frac12-right-sqrt-pi)**Γ(-1/2) = -2 * sqrt(𝜋)****Γ(-1) = Γ(-2) = Γ(-3) = infinity ∞**

你能证明这些吗?

3.这是实数伽马函数的图表。

https://en.wikipedia.org/wiki/Gamma_function

伽马函数,蓝色的γ(z),以及绿色的γ(z)+sin(πz)。(注意正整数处的交集,因为 sin(πz)为零!)两者都是非整数阶乘的有效解析延拓。

4.伽马函数也出现在n 球体积的一般公式中。

GAN 基因座

原文:https://towardsdatascience.com/gan-loci-e2bbd1b4926f?source=collection_archive---------13-----------------------

神经网络能揭示使“空间”成为“场所”的隐性属性吗?

这个项目应用生成性对抗网络(或 GANs)来制作合成图像,捕捉城市场所的主要视觉特性。以这种方式描绘城市代表了第一次尝试用计算机来记录一个城市的场所精神:那些形式、空间和光的质量,它们体现了一个特定的位置,并使它区别于类似的地方。

Nine synthetic images of urban places.

本文介绍了收集城市图像数据的方法,对这些数据进行必要的处理和格式化的方法,以及训练两种已知的计算统计模型( StyleGAN 和 Pix2Pix )的方法,这两种模型可以识别特定地点的视觉模式,并复制这些模式以生成新的图像。这些方法已经被应用到美国和欧洲的六个城市的九个不同的城市环境中,其结果将在我们的下一篇文章中展示。

当一个城镇因其独特的个性而让我们高兴时,通常是因为它的大多数建筑都以同样的方式与大地和天空联系在一起;它们似乎表达了一种常见的生活形式,一种地球上常见的生存方式。因此,它们构成了一个允许人类识别的场所。克里斯蒂安·诺伯格-舒尔茨,《场所精神:走向建筑现象学》,第 63 页

动机

虽然对于许多建筑师和城市设计师来说 设计意图是一个必然默认的概念 ,但大多数 CAD 工具只支持明确表达其作者的意图。相比之下,该项目代表了向基于机器学习技术的 CAD 工具的新方法迈出的一小步,这些工具旨在更好地支持隐性或难以表达的设计意图 。为了清楚地展示这样的设计意图的需要,我们在这里考虑一个场景,它提供了一个特别难以明确表达的建筑环境的质量:“场所”现象。

克里斯蒂安·诺伯格-舒尔茨(Christian Norberg-Schulz)在他定义现象学方法的开创性著作《场所精神:走向建筑现象学》中指出,城市和建筑的设计必须以“场所”的建设为中心,他将其定义为“具有独特特征的空间”(诺伯格-舒尔茨 94)。但是,这种“独特的特征”是如何定义的呢?如何使用数字工具以提供计算媒体优势的方式捕捉它呢?在对更好地支持隐性设计意图发展的未来工具的预期中,我们寻求利用机器学习中的方法来试图捕捉“位置”,正如 Norberg-Schulz 所描述的。

这个项目的目标是使用 GAN 作为隐性设计的工具,并应用这种技术的能力来捕捉一组图像的隐含而突出的视觉属性。我们推测,这种能力将被证明有助于揭示和编码对场所的现象学理解。本文概述了训练生成性对抗网络(GAN)以生成捕捉城市环境主要视觉属性的图像所需的步骤。这项工作分三个阶段进行:数据准备、模型训练和潜在空间探索。

数据准备

在数据准备阶段,我们首先收集、清理和整理大量与城市环境相关的图像,这些城市环境是明显不同类型的地方,并将这些图像编辑成不同的集合。然后,这些图像的每一组被处理以用作两个 ML 模型之一的训练数据。

为此,开发了一个 Python 库,支持使用 Google 的 StreetView API 收集、管理和处理全景图像。本节详细描述了这一过程,包括:与识别期望的地理位置相关的任务,从该位置收集大量不同的图像集,管理该图像集以定义有效图像的相关子集,以及最后,处理这些图像以使它们被适当地格式化用于训练。

Coordinate locations of 560 requests for panoramic images in Cambridge, MA (left) and the actual geo-locations from which 470 panoramic images were taken (right)

数据收集从识别感兴趣的地理位置开始。由于拍摄全景图的图像可能与感兴趣的给定地理位置不一致,因此必须考虑许多故障情况。例如:不是所有感兴趣的位置都与全景相关,也不是所有的全景都描绘外部城市环境(也有内部全景)。对于下面列出的九个城市环境中的每一个,大约有 500 个全景被采样。

  • 荷兰鹿特丹 Blijdorp
  • 佛罗里达州杰克逊维尔匹克威克公园
  • 纽约州布鲁克林区威廉斯堡
  • 佛罗里达州盖恩斯维尔东校区
  • 加州旧金山阿拉莫广场
  • 加利福尼亚州奥克兰市亚当斯角
  • 马萨诸塞州剑桥中心广场
  • 加州柏克莱克拉克·克尔社区
  • 纽约布鲁克林布什维克

除了上面提到的基本验证之外,由于返回数据的结构,即使成功调用了 API,也需要许多辅助处理步骤。这些辅助处理步骤中最值得注意的是收集与每个街景全景相关的深度信息。虽然没有从谷歌街景界面中明确,但这项服务提供的许多二维全景图也保存了一些描述城市场景中物体的基本三维数据(通常是建筑形式)。

A greyscale depthmap image (left) and sceneographic image (right) of a scene in downtown Berkeley, CA.

总之,数据的收集始于对感兴趣的单个地理点的定义,并导致数百个样本的汇编,这些样本可被进一步处理用于训练。

每个样品包括:

  • 等矩形全景图像。
  • 描述所描述场景中遮挡对象的一组三维平面,编码为 base-64 字符串。
  • 一组相关的元数据。

通过收集和管理与给定城市地点相关的一组图像,数据处理步骤的任务是为这组图像在训练 GAN 模型中的作用做准备。总之,该训练数据最好被描述为成对的相关方形裁剪光栅图像:一个 RGB 图像表示较大全景图像场景的裁剪,另一个灰度图像表示该场景的“深度图”,每个像素的值表示从相机到任何遮挡物体的最小距离。

Pairs of corresponding depthmap (top) and sceneographic (bottom) images.

场景图像的产生在很大程度上是简单的,只有一个过程值得一提:全景图像的等矩形投影必须被转换以获得更好地接近我们期望产生的合成图像的立方体环境图。这是根据之前描述相关转换的工作完成的( Bourke,2006 )。值得注意的是,相同的全景图像可以沿着 z 轴任意旋转(相当于立方体水平旋转的变换),以产生相同场景的微小变化,这些变化仍然可以无缝地平铺在一起。以这种方式通过轻微的转换来扩展训练集的宽度,这种做法被称为“数据扩充”,是 ML 中的一种常见做法。

Data augmentation by rotation by 0 degrees (left) 30 degrees (middle) 60 degrees (right)

总之,任何给定城市地点的数据准备步骤从全景等矩形图像和相关信息(包括遮挡平面的描述)的精选集合开始,并产生两组立方体图投影图像:一组描述城市场景的 RGB 图像,一组描述该场景中物体的有效深度的灰度图像。

模特培训

在模型训练阶段,我们使用收集的图像集来训练 GAN 模型,该模型能够生成与每个选定的城市背景相关的新图像。为此,采用了两种不同的 GAN 架构:StyleGAN 和 Pix2Pix,其具体实现将在下面讨论。一旦经过训练,这些模型中的每一个都以自己的方式证明是有价值的,因为每一个都为合成城市图像的制作提供了一个独特的界面。

Pix2Pix

Pix2Pix (Isola et al .,2016)是一种特定类型的 GAN 的架构:一种条件对抗网络,它学习从给定的输入图像到期望的输出图像的映射。从一个经过训练的 Pix2Pix 模型的用户的角度来看,我们提供一个符合某种映射约定的输入图像(比如一个正面的彩色编码图,或者一只猫的边缘图),并作为回报接收一个将该输入转换成某种所需输出的图像(比如一个正面或一只猫的照片表示)。

指导 Pix2Pix 模型训练的细节很大程度上取决于所采用的实现的细节。该项目依托于在 Pytorch (王,2019)中实现的该架构的“高清”版本。需要对该实现进行一些修改:特别是为了纠正在低对比度源图像的情况下形成的不想要的伪影的问题(如下图所示)。根据 Pix2Pix 用户社区提供的建议,零填充被替换为反射填充,学习率暂时调整为 0.0008。

Synthetic image artifacts encountered while training.

一旦被训练,每个模型如条件 GAN 的性质和训练数据的结构所暗示的那样操作:给定描述期望的三维城市场景的灰度深度图图像,返回合成的 RGB 场景地理图像。由于这些模型是在按地点划分的数据子集上训练的,因此每个模型都只生成一个城市特定的合成图像:鹿特丹模型生成的图像“感觉”像鹿特丹,而旧金山模型生成的图像看起来更像旧金山。该特征允许进行直接比较。

Results derived from Pix2Pix model: synthetic images of San Francisco, CA (left) and Rotterdam, NL (right).

StyleGAN

与传统的 GAN 架构相比, StyleGAN (Karras 等人,2018 年)借鉴了“风格转移”技术,为 GAN 的生成器部分提供了一种替代设计,可以将粗糙的图像特征(如在人脸上训练时的头部姿势)与精细或纹理特征(如头发和雀斑)分开。这里,与 Pix2Pix 模型相比,用户体验非常不同:用户不是通过将输入图像映射到期望的输出来操作,而是从训练模型的潜在空间中选择一对图像,并将它们混合。然而,这些混合对应于给定对的粗略和精细特征,而不是潜在空间中的点之间的简单插值。

Fake images drawn from all nine sites studied.

如上所述,指导 StyleGAN 模型训练的细节很大程度上取决于实现的细节。该项目依赖于 StyleGAN 的官方 TensorFlow 实现,该实现在没有修改的情况下被用于在从所有九个城市地点提取的 RGB 场景数据的组合上训练单个模型。一旦被训练,可以通过对潜在空间中的位置进行采样,或者通过提供潜在空间中的粗-细位置对来查询模型,以更精确地控制合成图像的不同方面。

建立在前一种在潜在空间中采样的技术上,可以组合样本的线性序列来产生诸如下面讨论的动画。

图象生成

在图像生成阶段,我们开发了以有用的方式与经过训练的模型进行交互的方法。这项任务并不简单,因为每个 GAN 模型一旦被训练,就能够产生大量的合成图像,这些图像是用高维潜在空间来描述的。StyleGAN 模型提供了一种独特的形式来指导图像的生成,这些图像是从潜在空间中选择的其他图像中提取的特征的组合。Pix2Pix 模型提供了一个完全不同的界面,通过任意给定源图像的变换生成新的合成图像:在我们的例子中,这些是城市空间的深度图。我们在这里对这些方法做一个简要的概述,并在以后的文章中对结果图像进行更完整的解包和可视化分析。

Pix2Pix 图像生成

这里,灰度深度图图像是通过对 3d CAD 模型中描述的场景进行采样而产生的。这些构建场景的深度图随后被用作源图像,通过该源图像,每个城市地点的 Pix2Pix 模型产生合成的摄影场景。通过向在不同城市地点训练的模型提供精确的相同输入,可以在由转换模型拾取的显著特征之间进行直接比较。

例如,虽然下面的每个合成图像都是通过采样相同的深度图产生的,但我们可以清楚地看到这些表征每个采样城市的意象属性。鹿特丹模型将深度图中出现的一大片地块解释为一大片砖房,这在荷兰城市中是很典型的,而皮克威克公园模型以北佛罗里达植物区系的典型方式呈现了这一地块,暗示了一片长满苔藓的活橡树。阿拉莫广场模型将一堵长长的后退的城墙分割成一系列小比例的形式,这种解释表达了主导这个旧金山社区的一排爱德华时代的联排别墅的聚集;这种相同的城市形式被布鲁克林布什维克地区的图像训练模型理解为类似红砖工业仓库建筑的东西。

A depthmap (left) and cooresponding images for Jacksonville, FL (middle) and Rotterdam, NL (right)

StyleGAN 图像生成

这里开发的另外两种图像生成方法依赖于 StyleGAN 模型。

Synthetic urban places generated by StyleGAN. Vertical columns define course features, such as camera direction and orientation, while horizontal rows define fine features, such as textures, colors, and lighting effects of each urban place.

与上面讨论的方法一样,这两种方法中的第一种提供了在被抽样的城市地点之间进行比较的机会。按照作者的意图使用 StyleGAN 接口,可以分别断言对生成图像的精细和粗糙方面的控制。由此产生的界面可以被看作是城市场景的“示例”设计:用户只需要提供包含某个地方所需特征的图像示例,而无需明确说明这些是什么,它们来自哪里,或者如何构建它们。在这项研究的背景下,如上所述,这使得可以在城市地区之间进行比较。例如,附近的图展示了粗糙特征和精细特征可以如何组合以形成混合现有场景的各方面的新场景。

最后,开发了一种通过对 StyleGAN 模型所隐含的图像潜在空间的线性序列进行采样来生成动画的方法。虽然没有直接支持对城市场所的受控比较研究,但这些动画确实提供了对 StyleGAN 模型潜在空间结构的洞察,包括哪些特征和场景被类似地参数化,以及哪些彼此远离。

反射

如上所述,GAN 利用了两个相关神经网络之间的竞争。由于这一竞赛的有效结果是给定图像集所共有的隐性属性的编码,该项目建议对 GAN 生成的合成图像进行询问,将揭示某些有助于揭示城市场所本质的属性。根据诺伯格-舒尔茨对“场所”的描述,场所被理解为“具有独特特征的空间”,并包括体现特定城市位置的形式、纹理、颜色和光的质量,我们可以看到直接的目标已经达到,因为上面记录的初步结果展示了每个研究地点独特的意象特征。然而,要实现这个项目的更大目标——开发支持建筑设计中隐含意图的工具,还有许多工作要做。这一领域的未来工作包括将“范例设计”范式从城市场所的图像(如本文所示)扩展到更直接的建筑表现,如三维形式和空间。

文献学

艾西,罗伯特,鲁拉里·格林和鲍勃·谢尔。“前言。”制作 2011:制作数字建筑,DGO-数字原创。, 10–11.UCL 出版社,2017。

柏克德、威廉和阿黛尔.亚伯拉罕森。网络中的并行处理、动力学和进化。威利-布莱克威尔,2002 年。

程,池莉,还有侯君豪。"仿生机器人建造过程:一种适应大量不规则形状自然材料的方法."第 34 届 ECAADe 会议论文集。2016 年,芬兰奥卢。

钟,贾珍和郑泰生。“智能城市的网络抓取信息提取方法:使用机器学习训练智能城市的空气质量监测员。”在 ca adria 2018–第 23 届亚洲计算机辅助建筑设计研究国际会议上,由 Suleiman Alhadidi,Tomohiro Fukuda,黄卫新,帕特里克·让桑和 Kristof Crolla 编辑,2:515–524。亚洲计算机辅助建筑设计研究协会(CAADRIA),2018。

古德菲勒、伊恩、让·普吉-阿巴迪、迈赫迪·米尔扎、徐炳、戴维·沃德-法利、谢尔吉尔·奥泽尔、亚伦·库维尔和约舒阿·本吉奥。"生成性对抗网络。"神经信息处理系统进展 27,Z. Ghahramani,M. Welling,C. Cortes,N. D. Lawrence 和 K. Q. Weinberger 编辑,2672-2680。柯伦联合公司,2014 年。http://papers . nips . cc/paper/5423-generative-adversarial-nets . pdf。

伊索拉、菲利普、、周廷辉和阿列克谢·埃夫罗斯。"用条件对抗网络进行图像到图像的翻译."CoRR abs/1611.07004 (2016 年)。http://arxiv.org/abs/1611.07004。

卡拉斯,泰罗。斯泰勒根。英伟达,2019。【https://github.com/NVlabs/stylegan】T4。

卡拉斯、泰罗、萨穆利·莱恩和蒂莫·艾拉。"一种基于风格的生成对抗网络生成器体系结构."CoRR abs/1812.04948 (2018)。http://arxiv.org/abs/1812.04948。

基利安阿克塞尔。"设计探索和设计导向."在内部 Smartgeometry 中,122–29。约翰威利父子有限公司,2014 年。https://doi.org/10.1002/9781118653074.ch10。

Ledig,Christian,Lucas Theis,Ferenc Huszar,Jose Caballero,安德鲁·坎宁安,Alejandro Acosta,Andrew Aitken 等人,“使用生成式对抗网络的照片级单幅图像超分辨率”,105–14,2017。https://doi.org/10.1109/CVPR.2017.19。

Ng,Andrew Y,和 Michael I. Jordan。"区别性与生成性量词的比较:逻辑回归和朴素贝叶斯."《第 14 届神经信息处理系统国际会议论文集:自然与合成》, 841–848。NIPS 01。美国麻省剑桥:麻省理工学院出版社,2001 年。http://dl.acm.org/citation.cfm?id=2980539.2980648。

克里斯蒂安·诺伯格-舒尔茨。走向建筑现象学。学院版,1980 年。

彭、、和长仓武彦。“机器对空间的感知。建筑计算机辅助设计协会(ACADIA)第 37 届年会论文集。麻省剑桥:建筑计算机辅助设计协会,2017 年。

斯卡利博士、贾斯珀·斯诺克、亚历克斯·威尔特施科和阿里·拉希米。“胜利者的诅咒?速度、进度和经验严谨性。”加利福尼亚州温哥华,2018 年。https://openreview.net/forum?id=rJWF0Fywf。

斯坦菲尔德,凯尔。“梦想可能会实现。”建筑计算机辅助设计协会(ACADIA)第 37 届年会论文集。麻省剑桥:建筑计算机辅助设计协会,2017 年。

保罗·瓦格纳。街景探索者,2013。【https://github.com/PaulWagener/Streetview-Explorer】T4。

王,杰森,路易斯·佩雷斯。"使用深度学习的图像分类中数据扩充的有效性."卷积神经网络。Recognit,2017。

王,丁俊。Pix2PixHD:用条件 gan 合成和操作 2048x1024 图像。英伟达,2017。https://github.com/NVIDIA/pix2pixHD。

GANs 和缺失数据插补

原文:https://towardsdatascience.com/gans-and-missing-data-imputation-815a0cbc4ece?source=collection_archive---------12-----------------------

基于生成对抗网络的缺失数据填补新方法

https://www.flickr.com/photos/crdot/6212236687/

介绍

看看 GANs 令人印象深刻的表现,他们变得如此受欢迎也就不足为奇了。它们广泛用于编辑或生成图像、安全目的以及许多其他领域,优于大多数神经网络架构。它们也有一些不太重要的应用,比如将马变成斑马,或者将城市景观渲染成 GTA 风格。

Rendering cityscape into GTA style. [Source]

看来它们被用于输入缺失数据只是时间问题。使用 GANs 处理缺失数据的想法相对较新,主要存在于研究文献中。然而,这是一种非常有前途的方法,我们可能很快就会看到用于缺失数据插补的现成 GAN 模型。事实上,Github 上现有的实现很少,我将在文章的底部提到。在本文中,我将解释缺失数据插补最流行的 GAN 架构,同时摒弃科学术语,以更简单、直观的方式进行解释😉让我们开始吧!

开始之前

在我们研究处理缺失数据的不同 GAN 架构之前,我们需要确保基础知识是正确的。

在处理真实数据集时,缺失数据是一个常见问题。我们中的一些人只能在 Kaggle 上使用近乎理想且格式良好的数据。不幸的是,现实生活中并不是这样。数据经常会丢失,它可能以三种不同的方式发生:MCAR(完全随机丢失),马尔(随机丢失)和 NMAR(非随机丢失)。如果你想了解更多细节,可以看看这篇文章。幸运的是,有各种方法可以处理缺失数据。为了深入了解现有的插补算法(例如 KNN、老鼠、MissForest)和它们各自的 Python 包,我推荐阅读我以前的文章。

gan 非常适合处理缺失数据。他们很好地学习隐藏的数据分布,并且发生器和鉴别器之间的反馈回路产生非常高精度的结果。如果你觉得你需要刷新一下关于甘斯的记忆,看看下面欧文·凯里在这篇惊人文章中写的一小段话。

一个称为生成器的神经网络生成新的数据实例,而另一个称为鉴别器的神经网络评估它们的真实性。

你可以把一个 GAN 想象成造假者(发生者)和警察(鉴别者)之间的猫捉老鼠的游戏。伪造者正在学习制造假币,而警察正在学习检测假币。两个人都在学习,都在提高。造假者在不断学习制造更好的假货,而警察在检测假货方面也在不断进步。最终结果是伪造者(制造者)现在被训练来创造超现实的货币!

GAN 架构

增加

GAIN 代表生成式对抗插补网。在撰写本文时,它似乎是处理缺失数据的最流行的 GAN 架构。其背后的思想很简单:生成器获取一些缺失值的真实数据的向量,并相应地对它们进行估算。估算的数据被反馈给鉴别器,鉴别器的工作是找出最初丢失的数据。下图更详细地解释了该架构。

GAIN architecture [1]

有一个屏蔽矩阵,它告诉发生器哪些值缺失或存在。随机矩阵增加了估算值的随机性(所以它们每次都不一样)。还有提示向量,提供给鉴别器,确保鉴别器强制发生器学习。

增益插补的准确性与其他最先进的插补算法进行了比较,并证明其明显优于所有算法[1]。听起来是个不错的估算,是吧?

米斯甘

MisGAN 是另一个处理缺失数据的 GAN 框架。它的架构与 GAIN 略有不同,因为它有 2 个发生器和 2 个鉴别器[2]。下图展示了 MisGAN 架构。

The overall structure of the MisGAN framework [2]

发生器 Gx 产生完整的数据,发生器 Gm 产生缺失数据的掩码(它是一个二进制矩阵,其中‘1’代表非缺失数据,而‘0’代表缺失数据)。然后在鉴别器 DxDm 中对其进行比较,以检查其是否可以与真实数据矩阵 x 和真实缺失值掩码矩阵m区分开来。这里需要注意的重要一点是,在成功训练 MisGAN 架构后,我们可以分别生成完整的数据和缺失值掩码。很酷吧。

对上面的架构有一个调整,可以直接创建一个缺失数据估算器。在这种情况下,我们有可以生成完整数据的预训练生成器 Gx 和充当估算器的生成器 Gi 。它被馈送到单个鉴别器 Di 并检查 Gi 是否从带有缺失值的数据中产生令人满意的结果。下图更详细地展示了该架构。

Architecture for MisGAN imputation [2]

维甘

VIGAN 以不同的方式处理缺失数据的问题。为了向你介绍这个问题,让我们想象我们有一个实验,在这个实验中,一家医院为某个样本的病人收集神经图像,为一个完全不同的样本的病人收集大脑信号。这导致了不成对的数据,从而导致多模态(,即以不同的方式表达同一事物;图像和文字描述就是一个很好的例子)数据分析。使用这两个数据集时,患者数据没有一对一的映射。我们不能简单地将它们结合起来,因为患者在数据集中是独一无二的。它需要不同的数学建模来解决这个问题,这通常是大数据中的一个常见问题[3]。通常,您甚至不能将不同来源的数据集组合在一起(所谓的多视图数据),因为它们实在太大了。

The missing view problem extremely limits the cross-view collaborative learning [3]

这种 GAN 架构解决了多模态或多视图数据集中缺失数据的问题。作者声称他们的解决方案是高度可扩展的,并且是将域映射与缺失数据的跨视图插补相结合的第一种方法[3]。

其背后的思想比 GAIN 和 MisGAN 更复杂,解释其背后的数学概念需要很长时间。如果你想冒险,看看这里的论文。

It can take a while to read — you’ve been warned! [Source]

科拉根

协作 GAN 处理稍微不同类型的丢失数据。它用于缺失图像数据插补。根据论文作者的观点,该架构在图像领域优于其他 GAN 架构的优势如下:

  • 缺失数据估计更加准确
  • 单发生器架构仍然存在,这使得它更节省内存

该框架的新颖之处在于,它“将图像插补问题转化为多域图像到图像的转换任务,使得单个生成器和鉴别器网络可以使用剩余的干净数据集成功地估计缺失数据。[4]"

在我个人看来,这篇论文的措辞有点模糊,我发现很难完全理解他们是如何实现他们的 GAN 架构的。如果你觉得这个想法很有趣,可以在这里看一下最初的论文。

Github 仓库

在 Github 中快速浏览之后,我发现这些 GAN 架构已经有了一些实现!为了方便起见,我在下面列出了它们。

增益

这个库似乎是 GAIN 中最受欢迎的,它使用了 Tensorflow。它在 Github 上有> 70 颗星,但是从 2019 年 3 月开始就没有更新过。

维甘

VIGAN 已经在 PyTorch 中实现了,但是它在拥有 20 颗星的情况下似乎不是很受欢迎。回购的链接是这里的。

最后几句话要说

虽然用 GANs 输入缺失数据是一个相对较新的概念,但它显示了非常有前途的结果。在不久的将来,我们可能会看到更多的 GAN 架构以更高的精度处理缺失数据。

希望你觉得我的文章有用。如果你有任何问题,请在评论中告诉我,或者随时在 LinkedIn 上与我联系。

参考

[1]增益,https://arxiv.org/abs/1806.02920

[2]米斯根,https://openreview.net/pdf?id=S1lDV3RcKm

[3]维根,https://arxiv.org/abs/1708.06724

[4]科拉甘,https://arxiv.org/abs/1901.09764

甘斯与应用 ML @ ICLR 2019

原文:https://towardsdatascience.com/gans-applied-ml-iclr-2019-20d16cade735?source=collection_archive---------21-----------------------

Ian Goodfellow filled the whole Great Hall at New Orleans.

TL;大卫:在底部。

我刚刚从 2019 年在纽奥良举行的国际学习代表大会回来,这是甘论文硕果累累的一年。在第一部分中,我讨论了图像合成(BigGAN)、音频(WaveGAN)、特征选择(KnockoffGAN)、3D、文本&表格和许多其他主题的论文。然后,本文的第二部分重点关注更实际的 ML 考虑事项。

幸运偏爱有准备的人

在去 ICLR 之前,我列了一个清单,上面列出了所有我想学的东西。这意味着一个非常忙碌的星期一——在这一点上,四个有趣的研讨会同时进行(更多研讨会在“应用 ML”部分)。这也意味着一个繁忙的星期二,组织者在这一天投入了 37 篇 GAN 论文。这意味着海报会议开始得早,结束得晚。我用一个电子表格记录了这一切。

我包含了我提到的所有论文的链接,甚至还有到直播研讨会以及全体会议的链接,其中也包含了大量的 GANs 。

生成的对抗部分

在这里,我想探讨这些变化,特别是讨论生成性对抗网络。正如许多人所说,这是一项令人兴奋的新技术,与大多数其他 ML 不同,它出现的时间还不到 5 年。本着之前 ICML 2018 文章的精神,我与学术界人士进行了交谈,所以你不必这样做,但鉴于内容的量,不可能再浏览每篇论文,所以我只会挑选一些主题。

Brock et al. presented even better BigGAN-deep at ICLR ‘19.

主题 1:图像合成日趋成熟

Ian Goodfellow 经常谈论2012 年的深度学习革命如何实现了机器学习应用的“寒武纪大爆发”。这是因为在任何技术领域,首要任务是让一项技术可靠地工作,并使大量下游应用成为可能。

这种情况在图像合成中有所发生。现在 BigGAN 可以可靠地生成非常多样的高保真图像,我们可以开始考虑将其应用于其他用例。一个例子是使用 BigGAN 作为增加现有训练数据的方式(即,通过合成新的数据点来人工增加数据点的数量)。尽管有的另一篇论文在 ICLR 被接受,它显示了这项技术的局限性。在这种平衡数据集的情况下,GAN 数据增加似乎对下游任务的影响有限。但这是一个被认真研究的提议,这一事实似乎是一个好迹象,但仍有许多数据增强途径未被探索。

我们可能关心的另一个下游任务是使用较少标签的图像合成。在最初的 BigGAN 中,我们使用 ImageNet 中的所有标签来合成 1000 种类型的对象。然而在另一篇 ICLR 论文中,我们可以看到同样高质量的图片,只有 10%的标签,甚至比 BigGAN 只有 20%的标签使用自我和半监督学习的结果更好。

此外,ICLR 还展示了几篇 论文,它们提出了对生成的图像进行更精细控制的有趣建议。所以现在,你一直想在照片中出现的长颈鹿,而不是你的前任,可以出现在正确的位置了。

我只是惊讶于这个领域发展的如此之快,在不到 5 年的时间里,我们已经成功制作了 1000 类 512x512 的图像,这些图像足够逼真,可以在下游应用中使用。用 Károly Zsolnai-Fehér 的话说,活着是多么美好的时光啊!

主题 2:外来数据类型/应用。

今年 ICLR 的另一个重要主题是更多“奇异”数据类型和应用的出现。我只讲几个更有趣的例子。对我来说,这似乎再次表明了 GANs 作为一个领域的日益成熟。

  • WaveGAN :是一种使用扩展卷积和 DCGAN 类架构的 GAN 的音频条件合成。
  • TimbreTron :使用 CycleGAN 将音乐从一个乐器(域)传输到另一个(域)乐器。
  • PateGAN :生成合成数据的 GAN,具有不同的隐私保证。
  • 山寨版:是一种用山寨版的 GANs 进行健壮特征选择的方法。总的来说,这篇论文将会是比较复杂的论文之一。
  • LayoutGAN :通过在 2D 空间中合理地组合不同的 UI 元素,使用 GANs 生成 UI 线框的方法。
  • 合成 GAN :通过匹配不同的 3D 对象并合成它们以产生具有真实照明和遮挡的新场景来生成真实外观合成的方法。
  • 3D 点云生成,蛋白质骨架生成 & 生成标签图:这些论文超出了我的专业领域,也超出了 ICML 2018 上展示的这一广泛领域的论文,但很高兴看到这项工作仍在继续。

主题 3:理论进展

一如既往,有许多论文涉及训练的某些方面(拒绝采样、相对论甘、变分鉴别器瓶颈)或生成模型的某些理论性质(例如潜在空间插值或甘的可逆性)。

虽然学者们倾向于热爱这一领域,但在 ICML 大学 18 届毕业生中,结果却有些喜忧参半。我觉得许多论文引入了大量额外的复杂性来推导一些我不认为非常有趣或不期望它们以同样的方式成为事实上的标准的属性,例如 Wasserstein GAN 或 gradient penalties。

幸运的是,在 ICLR,情况并非如此。上面的三种技术加上训练中的平均技术看起来都很简单有效,很容易成为未来艺术的标准模式。

应用机器学习

Many industry presentations at ICLR ’19.

作为一个经常不得不担心如何生产我正在建造的系统的人。令我非常惊喜的是,甚至来自 ICLR 的研讨会组织者也认为这很重要。因此,我试图从以下研讨会中捕捉所有有趣的内容:

  • ML 中的再现性:这最终成为一个非常有用的研讨会。顺便提一下,我在那里的时候只有 7 个人,所以我想知道这说明了我们领域的状况。一般来说,我认为再现性是一个非常重要的话题,因为再现性实际上是理解已部署的 ML 系统如何运行的 0 级水平。因此,如果我们不能正确对待这一点,所有这些关于公平偏见的谈论几乎毫无意义。
  • 调试 ML :这是一个非常有用的研讨会,但遗憾的是,许多演示要么没有发布代码,要么非常学术性。我肯定会尝试研究模型断言,因为这个想法对我来说很有意义。总的来说,再次调试对我们来说非常关键,以确保我们多少理解了模型是如何构建的。从对立的例子到神经网络能够适应随机分配的标签,一切都表明我们需要更多的工具来理解深度学习。
  • 从有限的标记数据中学习:这非常有趣,因为很少的数据是常见的商业现实。克里斯托弗·雷的参与让我很受鼓舞,但是,我并不觉得有什么特别重要的收获。
  • 生成高度结构化的数据:尽管本吉奥一开始的演讲很拥挤,但我并不觉得口头报告有什么用处,尽管我强烈建议查看已被接受的论文。

结论

总的来说,我一直对 ML 的进展速度感到惊讶,学术会议也有其缺点,但如果你相应地计划和准备,你会比我参加过的任何其他会议获得更多。

TL;博士:

  • 我们生成各种各样的逼真的 512x512,这导致了进一步的应用。
  • GANs 似乎在其他数据类型中得到更多的关注,但是成熟度大约是。影像在 2016 年的位置。
  • 甚至学者们现在也更多地考虑实际问题& ML 工具——尽管他们并不总是这样称呼它。

感谢丹尼尔·杜马博士和哈帕尔·辛格博士的精彩反馈。

除了甘

原文:https://towardsdatascience.com/gans-or-d0fb38ff8ddb?source=collection_archive---------35-----------------------

在这篇博文中,我将讨论更精确地使用 GANs 的替代方法。我建议读者阅读 GANs 来理解和比较下面解释的策略。让我们开始吧。

Image by Gerd Altmann from Pixabay

我希望到现在为止,你们都非常熟悉 GANs 的概念。但是,我们仍然不能用 GANs 达到很高的精确度。如果你看过我在 GANs 上的博客,下面是最后阶段的输出。

中间的图像是 GAN 预测的。虽然它有点类似于目标图像,但仍然不是可接受的图像,因为预测图像中猫的眼睛不亮,猫的爪子不清晰。如果我们开始根据特征来区分猫,这些小事情就很重要了。

我们可能会在更大程度上改进结果,但 GANs 仍然无法提供足够的特征间隙,因为我们没有以这种方式训练模型。甘不在乎猫的眼睛,也不在乎猫的爪子和其他东西。

我们能摆脱甘一家吗?

Fastai 想出了一些更好的东西,恢复图像的力量。现在,当我们谈论一个更好的模型时,首先想到的是改进 loff 函数。如果我们可以增强损失函数,那么我们的模型将训练得更好,从而得到更准确的结果。所以,我们的主要目的是创建一个更好的损失函数。现在,我们还可以提出更复杂的架构设计,但这无疑是最后一个要实施的选项。

我在这里关心的事情在实时风格转换和超分辨率的感知损失中有所解释。

Image source — research paper mentioned above

  • 图像转换网络——它基本上是 GANs 的 UNet 或生成器部分。它产生输出,即预测的图像。
  • 上述类型的模型被称为生成模型。在这些类型的模型中,我们有一个下采样部分,也称为编码器,还有一个上采样部分,称为解码器。
  • Ŷ是预测图像。Yc是我们想要得出的目标图像。
  • 现在,我们将预测图像和目标图像通过预先训练的图像分类模型,如 ResNet34、VGG-16 等。这些模型在许多类别的图像上被预先训练,并且它们对输入图像进行分类。
  • 通常,它的输出会告诉你,“嘿,这个生成的东西是狗,猫,飞机,还是别的什么。”但是在最终分类的过程中,它会经过许多不同的层次。在这种情况下,他们使用相同的格网大小对所有图层进行了颜色编码,并使用相同的颜色对要素地图进行了颜色编码。所以每次我们改变颜色,我们就改变了网格的大小。所以有一个跨步二卷积,或者在 VGG 的情况下,他们使用最大池层。
  • 现在,我们可以做的是,我们可以比较中间层的激活,然后找出预测图像层和目标图像层之间的像素损失,而不是比较最后几层。如果我们可以这样做,那么我们就可以引导模型的中间层变得更加具体和准确。
  • 让我们用一个例子来理解这个比较中间层的概念。

max-pooling 层之前的输出中的层的结构是 2162828。这意味着我们有 216 个通道,图像大小为 28*28。每个通道告诉我们图像中不同种类的特征。可能第 100 个频道比较了猫形象的眼球。如果我们可以比较预测图像和目标图像的第 100 层,那么我们的模型将为期望的结果准备得更好。

  • 在我们的例子中,特征图会说,“这里有眼球(在目标图像中),但在生成的版本中没有,所以请多训练,做得更好。制造更好的眼球。”这就是我们的想法。这就是 fastai 所说的特征损失或 Johnson 等人所说的感知损失。

这就是我们如何在不使用 GANs 的情况下改进图像恢复的方法。

让我们了解损失在实际中是如何起作用的。我正在使用 fastai 库的代码。

class class **FeatureLoss**(nn.Module):
    def __init__(self, m_feat, layer_ids, layer_wgts):
        super().__init__()
        **self.m_feat** = m_feat
        **self.loss_features** = [self.m_feat[i] for i in layer_ids]
        **self.hooks** = hook_outputs(self.loss_features, detach=False)
        **self.wgts** = layer_wgtsdef **make_features**(self, x, clone=False):
        **self.m_feat**(x)
        **return** [(o.clone() if clone else o) for o in self.hooks.stored]

    def **forward**(self, input, target):
        **out_feat** = self.make_features(target, clone=True)
        **in_feat** = self.make_features(input)
        **self.feat_losses** = [base_loss(input,target)]
        **self.feat_losses** += [base_loss(f_in, f_out)*w
                             for f_in, f_out, w in zip(in_feat, out_feat, self.wgts)]
        **self.feat_losses** += [base_loss(gram_matrix(f_in), gram_matrix(f_out))*w**2 * 5e3
                             for f_in, f_out, w in zip(in_feat, out_feat, self.wgts)]
       ** self.metrics** = dict(zip(self.metric_names, self.feat_losses))
        **return sum(self.feat_losses)**

    def __del__(self): self.hooks.remove()(nn.Module):
  • m_feat —是预训练的模型;在我们的例子中,我们使用的是 VGG。
  • layer_ids —这是变化前的图层 id 列表。这是我们在最大池层数之前的层数列表。毫不奇怪,所有这些都是 ReLU 的。这些是我们想要抓住一些特征的地方。只是一串身份证。
  • out_feat —它包括目标图像中 layer_ids 中提到的相关层的列表。
  • in_feat —由预测图像的 layer_ids 中指定的相关图层列表组成。
  • self.feat_losses —它是发生在 out_feat 和 in_feat 层的损失以及预测图像和目标图像之间的基本 MSE 损失的总和,也在 GANs 中定义。

这就是我们如何改进损失函数。在对模型进行了相当长时间的训练后,我们得到了下面的输出。

现在,我们预测图像,它与目标图像非常相似。目前,与目标图像相比,我们预测的猫具有更合理的特征。

值得注意的是,这就是我们如何使用不同于 GANs 的东西。如上所述,我建议用户更多地探索 fastai 库,以了解该方法背后的更多信息。

GANs 与自动编码器:深度生成模型的比较

原文:https://towardsdatascience.com/gans-vs-autoencoders-comparison-of-deep-generative-models-985cf15936ea?source=collection_archive---------0-----------------------

想把马变成斑马?制作 DIY 动漫人物或名人?生成敌对网络是你新的最好的朋友。

生成对抗网络是过去 10 年机器学习中最有趣的想法——扬·勒村,脸书人工智能研究中心主任

本教程的第 1 部分可以在这里找到:

[## 图灵学习和 GANs 简介

想把马变成斑马?制作 DIY 动漫人物或名人?生成敌对网络是…

towardsdatascience.com](/comprehensive-introduction-to-turing-learning-and-gans-part-1-81f6d02e644d)

本教程的第 2 部分可以在这里找到:

[## GANs 中的高级主题

想把马变成斑马?制作 DIY 动漫人物或名人?生成敌对网络是…

towardsdatascience.com](/comprehensive-introduction-to-turing-learning-and-gans-part-2-fd8e4a70775)

这些文章基于哈佛大学关于 AC209b 的讲座,主要归功于哈佛大学 IACS 系的讲师 Pavlos Protopapas 。

这是专门使用生成性对抗网络创建深度生成模型的三部分教程的第三部分。这是上一个关于变型自动编码器主题的自然延伸(在这里找到)。我们将看到,与可变自动编码器相比,GANs 作为深度生成模型通常更优越。然而,众所周知,它们很难使用,并且需要大量的数据和调整。我们还将研究一种称为 VAE-GAN 的混合 GAN 模型。

Taxonomy of deep generative models. This article’s focus is on GANs.

教程的这一部分将主要是变分自动编码器(VAEs)的编码实现,也将向读者展示如何制作 VAEs 甘。

  • CelebA 数据集的 VAE
  • 西里巴数据集的 DC-甘
  • 动漫数据集 DC-甘
  • 动漫数据集 VAE-甘

我强烈建议读者在进一步阅读之前,至少先阅读一下 GAN 教程的第 1 部分,以及我的自动编码器变化演练,否则,读者可能对实现没有太多的了解。

所有相关代码现在都可以在我的 GitHub 存储库中找到:

[## 龙熊先生/甘-教程

GitHub 是超过 5000 万开发人员的家园,他们一起工作来托管和审查代码、管理项目和构建…

github.com](https://github.com/mrdragonbear/GAN-Tutorial)

我们开始吧!

CelebA 数据集的 VAE

CelebFaces 属性数据集(CelebA)是一个大规模的人脸属性数据集,拥有超过 20 万张名人图像,每张图像都有 40 个属性注释。该数据集中的图像覆盖了较大的姿态变化和背景混乱。西里巴有很大的多样性,数量大,注释丰富,包括

  • 10177 个身份,
  • 202,599 个面部图像,以及
  • 5 个标志位置,每幅图像 40 个二元属性注释。

你可以从 Kaggle 这里下载数据集:

[## 名人面孔属性(CelebA)数据集

超过 200,000 张名人图片,带有 40 个二元属性注释

www.kaggle.com](https://www.kaggle.com/jessicali9530/celeba-dataset)

第一步是导入所有必要的函数并提取数据。

进口

import shutil
import errno
import zipfile
import os
import matplotlib.pyplot as plt

提取数据

# Only run once to unzip images
zip_ref = zipfile.ZipFile('img_align_celeba.zip','r')
zip_ref.extractall()
zip_ref.close()

自定义图像生成器

这一步可能是大多数读者以前没有用过的。由于我们的数据非常庞大,可能无法将数据集加载到 Jupyter 笔记本的内存中。在处理大型数据集时,这是一个很正常的问题。

解决这一问题的方法是使用流生成器,它将成批的数据(本例中是图像)按顺序流入内存,从而限制该函数所需的内存量。需要注意的是,理解和编写它们有点复杂,因为它们需要对计算机内存、GPU 架构等有合理的理解。

# data generator
# source from https://medium.com/@ensembledme/writing-custom-keras-generators-fe815d992c5a
from skimage.io import imread

def get_input(path):
    """get specific image from path"""
    img = imread(path)
    return img

def get_output(path, label_file = None):
    """get all the labels relative to the image of path"""
    img_id = path.split('/')[-1]
    labels = label_file.loc[img_id].values
    return labels

def preprocess_input(img):
    # convert between 0 and 1
    return img.astype('float32') / 127.5 -1

def image_generator(files, label_file, batch_size = 32):
    while True:

        batch_paths = np.random.choice(a = files, size = batch_size)
        batch_input = []
        batch_output = []

        for input_path in batch_paths:

            input = get_input(input_path)
            input = preprocess_input(input)
            output = get_output(input_path, label_file = label_file)
            batch_input += [input]
            batch_output += [output]
        batch_x = np.array(batch_input)
        batch_y = np.array(batch_output)

        yield batch_x, batch_y

def auto_encoder_generator(files, batch_size = 32):
    while True:
        batch_paths = np.random.choice(a = files, size = batch_size)
        batch_input = []
        batch_output = []

        for input_path in batch_paths:
            input = get_input(input_path)
            input = preprocess_input(input)
            output = input
            batch_input += [input]
            batch_output += [output]
        batch_x = np.array(batch_input)
        batch_y = np.array(batch_output)

        yield batch_x, batch_y

关于用 Keras 编写定制生成器的更多信息,我在上面的代码中引用了一篇很好的文章:

[## 编写定制的 Keras 生成器

使用 Keras 生成器背后的想法是在训练期间动态地获得成批的输入和相应的输出…

medium.com](https://medium.com/@ensembledme/writing-custom-keras-generators-fe815d992c5a)

加载属性数据

我们不仅有这个数据集的图像,而且每个图像还有一个与名人的各个方面相对应的属性列表。例如,有描述名人是否涂口红或戴帽子、他们是否年轻、他们是否有黑头发等的属性。

# now load attribute

# 1.A.2
import pandas as pd
attr = pd.read_csv('list_attr_celeba.csv')
attr = attr.set_index('image_id')

# check if attribute successful loaded
attr.describe()

完成发电机的制作

现在我们完成了发电机的制作。我们将图像名称长度设置为 6,因为我们的数据集中有 6 位数的图像。阅读定制 Keras 生成器文章后,这部分代码应该有意义。

import numpy as np
from sklearn.model_selection import train_test_splitIMG_NAME_LENGTH = 6file_path = "img_align_celeba/"
img_id = np.arange(1,len(attr.index)+1)
img_path = []
for i in range(len(img_id)):
    img_path.append(file_path + (IMG_NAME_LENGTH - len(str(img_id[i])))*'0' + str(img_id[i]) + '.jpg')# pick 80% as training set and 20% as validation set
train_path = img_path[:int((0.8)*len(img_path))]
val_path = img_path[int((0.8)*len(img_path)):]train_generator = auto_encoder_generator(train_path,32)
val_generator = auto_encoder_generator(val_path,32)

我们现在可以选择三个图像,并检查属性是否有意义。

fig, ax = plt.subplots(1, 3, figsize=(12, 4))
for i in range(3):    
    ax[i].imshow(get_input(img_path[i]))
    ax[i].axis('off')
    ax[i].set_title(img_path[i][-10:])
plt.show()

attr.iloc[:3]

Three random images along with some of their attributes.

建立和训练一个 VAE 模型

首先,我们将为名人面孔数据集创建并编译一个卷积 VAE 模型(包括编码器和解码器)。

更多进口商品

from keras.models import Sequential, Model
from keras.layers import Dropout, Flatten, Dense, Conv2D, MaxPooling2D, Input, Reshape, UpSampling2D, InputLayer, Lambda, ZeroPadding2D, Cropping2D, Conv2DTranspose, BatchNormalization
from keras.utils import np_utils, to_categorical
from keras.losses import binary_crossentropy
from keras import backend as K,objectives
from keras.losses import mse, binary_crossentropy

模型架构

现在,我们可以创建并总结该模型。

b_size = 128
n_size = 512
def sampling(args):
    z_mean, z_log_sigma = args
    epsilon = K.random_normal(shape = (n_size,) , mean = 0, stddev = 1)
    return z_mean + K.exp(z_log_sigma/2) * epsilon

def build_conv_vae(input_shape, bottleneck_size, sampling, batch_size = 32):

    # ENCODER
    input = Input(shape=(input_shape[0],input_shape[1],input_shape[2]))
    x = Conv2D(32,(3,3),activation = 'relu', padding = 'same')(input)    
    x = BatchNormalization()(x)
    x = MaxPooling2D((2,2), padding ='same')(x)
    x = Conv2D(64,(3,3),activation = 'relu', padding = 'same')(x)
    x = BatchNormalization()(x)
    x = MaxPooling2D((2,2), padding ='same')(x)
    x = Conv2D(128,(3,3), activation = 'relu', padding = 'same')(x)
    x = BatchNormalization()(x)
    x = MaxPooling2D((2,2), padding ='same')(x)
    x = Conv2D(256,(3,3), activation = 'relu', padding = 'same')(x)
    x = BatchNormalization()(x)
    x = MaxPooling2D((2,2), padding ='same')(x)

    # Latent Variable Calculation
    shape = K.int_shape(x)
    flatten_1 = Flatten()(x)
    dense_1 = Dense(bottleneck_size, name='z_mean')(flatten_1)
    z_mean = BatchNormalization()(dense_1)
    flatten_2 = Flatten()(x)
    dense_2 = Dense(bottleneck_size, name ='z_log_sigma')(flatten_2)
    z_log_sigma = BatchNormalization()(dense_2)
    z = Lambda(sampling)([z_mean, z_log_sigma])
    encoder = Model(input, [z_mean, z_log_sigma, z], name = 'encoder')

    # DECODER
    latent_input = Input(shape=(bottleneck_size,), name = 'decoder_input')
    x = Dense(shape[1]*shape[2]*shape[3])(latent_input)
    x = Reshape((shape[1],shape[2],shape[3]))(x)
    x = UpSampling2D((2,2))(x)
    x = Cropping2D([[0,0],[0,1]])(x)
    x = Conv2DTranspose(256,(3,3), activation = 'relu', padding = 'same')(x)
    x = BatchNormalization()(x)
    x = UpSampling2D((2,2))(x)
    x = Cropping2D([[0,1],[0,1]])(x)
    x = Conv2DTranspose(128,(3,3), activation = 'relu', padding = 'same')(x)
    x = BatchNormalization()(x)
    x = UpSampling2D((2,2))(x)
    x = Cropping2D([[0,1],[0,1]])(x)
    x = Conv2DTranspose(64,(3,3), activation = 'relu', padding = 'same')(x)
    x = BatchNormalization()(x)
    x = UpSampling2D((2,2))(x)
    x = Conv2DTranspose(32,(3,3), activation = 'relu', padding = 'same')(x)
    x = BatchNormalization()(x)
    output = Conv2DTranspose(3,(3,3), activation = 'tanh', padding ='same')(x)
    decoder = Model(latent_input, output, name = 'decoder')

    output_2 = decoder(encoder(input)[2])
    vae = Model(input, output_2, name ='vae')
    return vae, encoder, decoder, z_mean, z_log_sigma

vae_2, encoder, decoder, z_mean, z_log_sigma = build_conv_vae(img_sample.shape, n_size, sampling, batch_size = b_size)
print("encoder summary:")
encoder.summary()
print("decoder summary:")
decoder.summary()
print("vae summary:")
vae_2.summary()

定义 VAE 损失

def vae_loss(input_img, output):
    # Compute error in reconstruction
    reconstruction_loss = mse(K.flatten(input_img) , K.flatten(output))

    # Compute the KL Divergence regularization term
    kl_loss = - 0.5 * K.sum(1 + z_log_sigma - K.square(z_mean) - K.exp(z_log_sigma), axis = -1)

    # Return the average loss over all images in batch
    total_loss = (reconstruction_loss + 0.0001 * kl_loss)    
    return total_loss

编译模型

vae_2.compile(optimizer='rmsprop', loss= vae_loss)
encoder.compile(optimizer = 'rmsprop', loss = vae_loss)
decoder.compile(optimizer = 'rmsprop', loss = vae_loss)

训练模型

vae_2.fit_generator(train_generator, steps_per_epoch = 4000, validation_data = val_generator, epochs=7, validation_steps= 500)

我们随机选择训练集的一些图像,通过编码器运行它们以参数化潜在代码,然后用解码器重建图像。

import random
x_test = []
for i in range(64):
    x_test.append(get_input(img_path[random.randint(0,len(img_id))]))
x_test = np.array(x_test)
figure_Decoded = vae_2.predict(x_test.astype('float32')/127.5 -1, batch_size = b_size)
figure_original = x_test[0]
figure_decoded = (figure_Decoded[0]+1)/2
for i in range(4):
    plt.axis('off')
    plt.subplot(2,4,1+i*2)
    plt.imshow(x_test[i])
    plt.axis('off')
    plt.subplot(2,4,2 + i*2)
    plt.imshow((figure_Decoded[i]+1)/2)
    plt.axis('off')
plt.show()

Random samples from training set compared to their VAE reconstruction.

请注意,重建的图像与原始版本有相似之处。然而,新的图像有点模糊,这是一个已知的 VAEs 现象。这被假设是由于变分推理优化了似然性的下限,而不是实际的似然性本身。

潜在空间表征

我们可以选择两个不同属性的图像,并绘制它们的潜在空间表示。请注意,我们可以看到潜在代码之间的一些差异,我们可以假设解释原始图像之间的差异。

# Choose two images of different attributes, and plot the original and latent space of it

x_test1 = []
for i in range(64):
    x_test1.append(get_input(img_path[np.random.randint(0,len(img_id))]))
x_test1 = np.array(x_test)
x_test_encoded = np.array(encoder.predict(x_test1/127.5-1, batch_size = b_size))
figure_original_1 = x_test[0]
figure_original_2 = x_test[1]
Encoded1 = (x_test_encoded[0,0,:].reshape(32, 16,)+1)/2 
Encoded2 = (x_test_encoded[0,1,:].reshape(32, 16)+1)/2

plt.figure(figsize=(8, 8))
plt.subplot(2,2,1)
plt.imshow(figure_original_1)
plt.subplot(2,2,2)
plt.imshow(Encoded1)
plt.subplot(2,2,3)
plt.imshow(figure_original_2)
plt.subplot(2,2,4)
plt.imshow(Encoded2)
plt.show()

从潜空间取样

我们可以随机抽取 15 个潜在代码,解码后生成新的名人面孔。我们可以从这个表示中看到,由我们的模型生成的图像与我们训练集中的那些图像具有非常相似的风格,并且它也具有良好的真实性和变化性。

# We randomly generated 15 images from 15 series of noise informationn = 3
m = 5
digit_size1 = 218
digit_size2 = 178
figure = np.zeros((digit_size1 * n, digit_size2 * m,3))

for i in range(3):
    for j in range(5):
        z_sample = np.random.rand(1,512)
        x_decoded = decoder.predict([z_sample])
        figure[i * digit_size1: (i + 1) * digit_size1,
               j * digit_size2: (j + 1) * digit_size2,:] = (x_decoded[0]+1)/2 plt.figure(figsize=(10, 10))
plt.imshow(figure)
plt.show()

所以看起来我们的 VAE 模式并不是特别好。如果有更多的时间和更好地选择超参数等等,我们可能会取得比这更好的结果。

现在让我们将这个结果与相同数据集上的 DC-甘进行比较。

CelebA 数据集上的 DC-甘

因为我们已经设置了流生成器,所以没有太多的工作要做来启动和运行 DC-甘模型。

# Create and compile a DC-GAN model, and print the summary

from keras.utils import np_utils
from keras.models import Sequential, Model
from keras.layers import Input, Dense, Dropout, Activation, Flatten, LeakyReLU,\
      BatchNormalization, Conv2DTranspose, Conv2D, Reshape
from keras.layers.advanced_activations import LeakyReLU
from keras.optimizers import Adam, RMSprop
from keras.initializers import RandomNormal
import numpy as np
import matplotlib.pyplot as plt
import random
from tqdm import tqdm_notebook
from scipy.misc import imresize

def generator_model(latent_dim=100, leaky_alpha=0.2, init_stddev=0.02):

    g = Sequential()
    g.add(Dense(4*4*512, input_shape=(latent_dim,),
                kernel_initializer=RandomNormal(stddev=init_stddev)))
    g.add(Reshape(target_shape=(4, 4, 512)))
    g.add(BatchNormalization())
    g.add(Activation(LeakyReLU(alpha=leaky_alpha)))
    g.add(Conv2DTranspose(256, kernel_size=5, strides=2, padding='same',
                kernel_initializer=RandomNormal(stddev=init_stddev)))
    g.add(BatchNormalization())
    g.add(Activation(LeakyReLU(alpha=leaky_alpha)))
    g.add(Conv2DTranspose(128, kernel_size=5, strides=2, padding='same', 
                kernel_initializer=RandomNormal(stddev=init_stddev)))
    g.add(BatchNormalization())
    g.add(Activation(LeakyReLU(alpha=leaky_alpha)))
    g.add(Conv2DTranspose(3, kernel_size=4, strides=2, padding='same', 
                kernel_initializer=RandomNormal(stddev=init_stddev)))
    g.add(Activation('tanh'))
    g.summary()
    #g.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0001, beta_1=0.5), metrics=['accuracy'])
    return g

def discriminator_model(leaky_alpha=0.2, init_stddev=0.02):

    d = Sequential()
    d.add(Conv2D(64, kernel_size=5, strides=2, padding='same', 
               kernel_initializer=RandomNormal(stddev=init_stddev),
               input_shape=(32, 32, 3)))
    d.add(Activation(LeakyReLU(alpha=leaky_alpha)))
    d.add(Conv2D(128, kernel_size=5, strides=2, padding='same', 
               kernel_initializer=RandomNormal(stddev=init_stddev)))
    d.add(BatchNormalization())
    d.add(Activation(LeakyReLU(alpha=leaky_alpha)))
    d.add(Conv2D(256, kernel_size=5, strides=2, padding='same', 
               kernel_initializer=RandomNormal(stddev=init_stddev)))
    d.add(BatchNormalization())
    d.add(Activation(LeakyReLU(alpha=leaky_alpha)))
    d.add(Flatten())
    d.add(Dense(1, kernel_initializer=RandomNormal(stddev=init_stddev)))
    d.add(Activation('sigmoid'))
    d.summary()
    return d

def DCGAN(sample_size=100):
    # Generator
    g = generator_model(sample_size, 0.2, 0.02)

    # Discriminator
    d = discriminator_model(0.2, 0.02)
    d.compile(optimizer=Adam(lr=0.001, beta_1=0.5), loss='binary_crossentropy')
    d.trainable = False
    # GAN
    gan = Sequential([g, d])
    gan.compile(optimizer=Adam(lr=0.0001, beta_1=0.5), loss='binary_crossentropy')

    return gan, g, d

以上代码只是针对发生器和鉴别器网络的架构。将这种编码 GAN 的方法与我在第 2 部分中使用的方法进行比较是一个好主意,您可以看到这种方法不太清晰,并且我们没有定义全局参数,因此有许多地方我们可能会有潜在的错误。

现在,我们定义了一些函数来简化我们的工作,这些函数主要用于图像的预处理和绘图,以帮助我们分析网络输出。

def load_image(filename, size=(32, 32)):
    img = plt.imread(filename)
    # crop
    rows, cols = img.shape[:2]
    crop_r, crop_c = 150, 150
    start_row, start_col = (rows - crop_r) // 2, (cols - crop_c) // 2
    end_row, end_col = rows - start_row, cols - start_row
    img = img[start_row:end_row, start_col:end_col, :]
    # resize
    img = imresize(img, size)
    return img

def preprocess(x):
    return (x/255)*2-1

def deprocess(x):
    return np.uint8((x+1)/2*255)

def make_labels(size):
    return np.ones([size, 1]), np.zeros([size, 1])  

def show_losses(losses):
    losses = np.array(losses)

    fig, ax = plt.subplots()
    plt.plot(losses.T[0], label='Discriminator')
    plt.plot(losses.T[1], label='Generator')
    plt.title("Validation Losses")
    plt.legend()
    plt.show()

def show_images(generated_images):
    n_images = len(generated_images)
    cols = 5
    rows = n_images//cols

    plt.figure(figsize=(8, 6))
    for i in range(n_images):
        img = deprocess(generated_images[i])
        ax = plt.subplot(rows, cols, i+1)
        plt.imshow(img)
        plt.xticks([])
        plt.yticks([])
    plt.tight_layout()
    plt.show()

训练模型

我们现在定义训练函数。正如我们之前所做的,请注意,我们在将鉴别器设置为可训练和不可训练之间进行了切换(我们在第 2 部分中隐式地这样做了)。

def train(sample_size=100, epochs=3, batch_size=128, eval_size=16, smooth=0.1): batchCount=len(train_path)//batch_size
    y_train_real, y_train_fake = make_labels(batch_size)
    y_eval_real,  y_eval_fake  = make_labels(eval_size)

    # create a GAN, a generator and a discriminator
    gan, g, d = DCGAN(sample_size)

    losses = [] for e in range(epochs):
        print('-'*15, 'Epoch %d' % (e+1), '-'*15)
        for i in tqdm_notebook(range(batchCount)):

            path_batch = train_path[i*batch_size:(i+1)*batch_size]
            image_batch = np.array([preprocess(load_image(filename)) for filename in path_batch])

            noise = np.random.normal(0, 1, size=(batch_size, noise_dim))
            generated_images = g.predict_on_batch(noise) # Train discriminator on generated images
            d.trainable = True
            d.train_on_batch(image_batch, y_train_real*(1-smooth))
            d.train_on_batch(generated_images, y_train_fake) # Train generator
            d.trainable = False
            g_loss=gan.train_on_batch(noise, y_train_real)

        # evaluate
        test_path = np.array(val_path)[np.random.choice(len(val_path), eval_size, replace=False)]
        x_eval_real = np.array([preprocess(load_image(filename)) for filename in test_path]) noise = np.random.normal(loc=0, scale=1, size=(eval_size, sample_size))
        x_eval_fake = g.predict_on_batch(noise)

        d_loss  = d.test_on_batch(x_eval_real, y_eval_real)
        d_loss += d.test_on_batch(x_eval_fake, y_eval_fake)
        g_loss  = gan.test_on_batch(noise, y_eval_real)

        losses.append((d_loss/2, g_loss))

        print("Epoch: {:>3}/{} Discriminator Loss: {:>6.4f} Generator Loss: {:>6.4f}".format(
            e+1, epochs, d_loss, g_loss))  

        show_images(x_eval_fake[:10])

    # show the result
    show_losses(losses)
    show_images(g.predict(np.random.normal(loc=0, scale=1, size=(15, sample_size))))    
    return gnoise_dim=100
train()

该函数的输出将为我们提供每个时期的以下输出:

它还将绘制鉴别器和发生器的验证损失。

生成的图像看起来很合理。在这里,我们可以看到我们的模型表现得足够好,尽管图像质量不如训练集中的图像质量好(因为我们对图像进行了整形,使其变得更小,并使它们比原始图像更模糊)。但是,它们足够生动,可以创建有效的人脸,并且这些人脸足够接近现实。此外,与 VAE 制作的图像相比,这些图像更有创意,看起来更真实。

所以看起来 GAN 在这种情况下表现更好。现在,让我们尝试一个新的数据集,看看 GAN 与混合变体 VAE-GAN 相比表现如何。

动漫数据集

在这一节中,我们将使用 GAN 以及另一种特殊形式的 GAN,即 VAE-GAN,来生成与动画数据集风格相同的人脸。术语 VAE-甘首先由 Larsen 等人使用。al 在他们的论文“使用学习的相似性度量进行像素以外的自动编码”。VAE-甘模型与甘模型的区别在于它们的生成器是变异自动编码器

VAE-GAN architecture. Source: https://arxiv.org/abs/1512.09300

首先,我们将重点放在 DC-甘。动漫数据集由超过 20K 张 64x64 图像形式的动漫头像组成。我们还需要创建另一个 Keras 定制数据生成器。该数据集的链接可在此处找到:

[## McKinsey 666/动漫人脸数据集

🖼收集了高质量的动漫面孔。为 Mckinsey666/Anime-Face-Dataset 开发做出贡献,创建一个…

github.com](https://github.com/Mckinsey666/Anime-Face-Dataset)

动漫数据集上的甘

我们需要做的第一件事是创建动漫目录并下载数据。这可以通过上面的链接来完成。在继续之前检查数据总是好的做法,所以我们现在就这样做。

from skimage import io
import matplotlib.pyplot as plt

filePath='anime-faces/data/'
imgSets=[]

for i in range(1,20001):
    imgName=filePath+str(i)+'.png'
    imgSets.append(io.imread(imgName))

plt.imshow(imgSets[1234])
plt.axis('off')
plt.show()

我们现在创建并编译我们的 DC-甘模型。

# Create and compile a DC-GAN modelfrom keras.models import Sequential, Model
from keras.layers import Input, Dense, Dropout, Activation, \
    Flatten, LeakyReLU, BatchNormalization, Conv2DTranspose, Conv2D, Reshape
from keras.layers.advanced_activations import LeakyReLU
from keras.layers.convolutional import UpSampling2D
from keras.optimizers import Adam, RMSprop,SGD
from keras.initializers import RandomNormalimport numpy as np
import matplotlib.pyplot as plt
import os, glob
from PIL import Image
from tqdm import tqdm_notebook image_shape = (64, 64, 3)
#noise_shape = (100,)
Noise_dim = 128
img_rows = 64
img_cols = 64
channels = 3def generator_model(latent_dim=100, leaky_alpha=0.2):
    model = Sequential()

    # layer1 (None,500)>>(None,128*16*16)
    model.add(Dense(128 * 16 * 16, activation="relu", input_shape=(Noise_dim,)))

    # (None,16*16*128)>>(None,16,16,128)
    model.add(Reshape((16, 16, 128)))

   # (None,16,16,128)>>(None,32,32,128)
    model.add(UpSampling2D())
    model.add(Conv2D(256, kernel_size=3, padding="same"))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Activation("relu")) #(None,32,32,128)>>(None,64,64,128)
    model.add(UpSampling2D())

    # (None,64,64,128)>>(None,64,64,64)
    model.add(Conv2D(128, kernel_size=3, padding="same"))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Activation("relu")) # (None,64,64,128)>>(None,64,64,32) model.add(Conv2D(32, kernel_size=3, padding="same"))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Activation("relu"))

    # (None,64,64,32)>>(None,64,64,3)
    model.add(Conv2D(channels, kernel_size=3, padding="same"))
    model.add(Activation("tanh")) model.summary()
    model.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0001, beta_1=0.5), metrics=['accuracy'])
    return model def discriminator_model(leaky_alpha=0.2, dropRate=0.3):
    model = Sequential()

    # layer1 (None,64,64,3)>>(None,32,32,32)
    model.add(Conv2D(32, kernel_size=3, strides=2, input_shape=image_shape, padding="same"))
    model.add(LeakyReLU(alpha=leaky_alpha))
    model.add(Dropout(dropRate)) # layer2 (None,32,32,32)>>(None,16,16,64)
    model.add(Conv2D(64, kernel_size=3, strides=2, padding="same")) # model.add(ZeroPadding2D(padding=((0, 1), (0, 1))))
    model.add(BatchNormalization(momentum=0.8))
    model.add(LeakyReLU(alpha=leaky_alpha))
    model.add(Dropout(dropRate)) # (None,16,16,64)>>(None,8,8,128)
    model.add(Conv2D(128, kernel_size=3, strides=2, padding="same"))
    model.add(BatchNormalization(momentum=0.8))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dropout(dropRate)) # (None,8,8,128)>>(None,8,8,256)
    model.add(Conv2D(256, kernel_size=3, strides=1, padding="same"))
    model.add(BatchNormalization(momentum=0.8))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dropout(dropRate)) # (None,8,8,256)>>(None,8,8,64)
    model.add(Conv2D(64, kernel_size=3, strides=1, padding="same"))
    model.add(BatchNormalization(momentum=0.8))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dropout(dropRate))

    # (None,8,8,64)
    model.add(Flatten())
    model.add(Dense(1, activation='sigmoid')) model.summary() sgd=SGD(lr=0.0002)
    model.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0001, beta_1=0.5), metrics=['accuracy'])
    return model def DCGAN(sample_size=Noise_dim):
    # generator
    g = generator_model(sample_size, 0.2) # discriminator
    d = discriminator_model(0.2)
    d.trainable = False
    # GAN
    gan = Sequential([g, d])

    sgd=SGD()
    gan.compile(optimizer=Adam(lr=0.0001, beta_1=0.5), loss='binary_crossentropy')
    return gan, g, d def get_image(image_path, width, height, mode):
    image = Image.open(image_path)
    #print(image.size) return np.array(image.convert(mode)) def get_batch(image_files, width, height, mode):
    data_batch = np.array([get_image(sample_file, width, height, mode) \
                           for sample_file in image_files])
    return data_batch def show_imgs(generator,epoch):
    row=3
    col = 5
    noise = np.random.normal(0, 1, (row * col, Noise_dim))
    gen_imgs = generator.predict(noise) # Rescale images 0 - 1
    gen_imgs = 0.5 * gen_imgs + 0.5 fig, axs = plt.subplots(row, col)
    #fig.suptitle("DCGAN: Generated digits", fontsize=12)
    cnt = 0 for i in range(row):
        for j in range(col):
            axs[i, j].imshow(gen_imgs[cnt, :, :, :])
            axs[i, j].axis('off')
            cnt += 1 #plt.close()
    plt.show()

我们现在可以在动画数据集上训练模型。我们将以两种不同的方式来实现这一点,第一种方式将涉及以 1:1 的训练时间比例来训练鉴别器和生成器。

# Training the discriminator and generator with the 1:1 proportion of training timesdef train(epochs=30, batchSize=128):
    filePath = r'anime-faces/data/' X_train = get_batch(glob.glob(os.path.join(filePath, '*.png'))[:20000], 64, 64, 'RGB')
    X_train = (X_train.astype(np.float32) - 127.5) / 127.5 halfSize = int(batchSize / 2)
    batchCount=int(len(X_train)/batchSize) dLossReal = []
    dLossFake = []
    gLossLogs = [] gan, generator, discriminator = DCGAN(Noise_dim) for e in range(epochs):
        for i in tqdm_notebook(range(batchCount)):
            index = np.random.randint(0, X_train.shape[0], halfSize)
            images = X_train[index] noise = np.random.normal(0, 1, (halfSize, Noise_dim))
            genImages = generator.predict(noise) # one-sided labels
            discriminator.trainable = True
            dLossR = discriminator.train_on_batch(images, np.ones([halfSize, 1]))
            dLossF = discriminator.train_on_batch(genImages, np.zeros([halfSize, 1]))
            dLoss = np.add(dLossF, dLossR) * 0.5
            discriminator.trainable = False noise = np.random.normal(0, 1, (batchSize, Noise_dim))
            gLoss = gan.train_on_batch(noise, np.ones([batchSize, 1])) dLossReal.append([e, dLoss[0]])
        dLossFake.append([e, dLoss[1]])
        gLossLogs.append([e, gLoss]) dLossRealArr = np.array(dLossReal)
        dLossFakeArr = np.array(dLossFake)
        gLossLogsArr = np.array(gLossLogs)        # At the end of training plot the losses vs epochs
        show_imgs(generator, e) plt.plot(dLossRealArr[:, 0], dLossRealArr[:, 1], label="Discriminator Loss - Real")
    plt.plot(dLossFakeArr[:, 0], dLossFakeArr[:, 1], label="Discriminator Loss - Fake")
    plt.plot(gLossLogsArr[:, 0], gLossLogsArr[:, 1], label="Generator Loss")
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.legend()
    plt.title('GAN')
    plt.grid(True)
    plt.show()

    return gan, generator, discriminator GAN,Generator,Discriminator=train(epochs=20, batchSize=128)  
train(epochs=1000, batchSize=128, plotInternal=200)

输出现在将开始打印一系列的动漫人物。它们起初非常粗糙,随着时间的推移逐渐变得越来越明显。

我们还将得到发电机和鉴频器损耗函数的曲线图。

现在我们将做同样的事情,但是用不同的训练时间来训练鉴别器和生成器,看看效果如何。

在继续之前,最好将模型的权重保存在某个地方,这样您就不需要再次运行整个训练,而是可以将权重加载到网络中。

为了节省重量:

discriminator.save_weights('/content/gdrive/My Drive/discriminator_DCGAN_lr0.0001_deepgenerator+proportion2.h5')
gan.save_weights('/content/gdrive/My Drive/gan_DCGAN_lr0.0001_deepgenerator+proportion2.h5')
generator.save_weights('/content/gdrive/My Drive/generator_DCGAN_lr0.0001_deepgenerator+proportion2.h5')

要加载砝码:

discriminator.load_weights('/content/gdrive/My Drive/discriminator_DCGAN_lr0.0001_deepgenerator+proportion2.h5')
gan.load_weights('/content/gdrive/My Drive/gan_DCGAN_lr0.0001_deepgenerator+proportion2.h5')
generator.load_weights('/content/gdrive/My Drive/generator_DCGAN_lr0.0001_deepgenerator+proportion2.h5')

现在,我们转到第二个网络实施,而不用担心比之前的网络节省成本。

# Train the discriminator and generator separately and with different training timesdef train(epochs=300, batchSize=128, plotInternal=50):
    gLoss = 1
    filePath = r'anime-faces/data/'

    X_train = get_batch(glob.glob(os.path.join(filePath,'*.png'))[:20000],64,64,'RGB')
    X_train=(X_train.astype(np.float32)-127.5)/127.5
    halfSize= int (batchSize/2) dLossReal=[]
    dLossFake=[]
    gLossLogs=[]    for e in range(epochs):
        index=np.random.randint(0,X_train.shape[0],halfSize)
        images=X_train[index] noise=np.random.normal(0,1,(halfSize,Noise_dim))
        genImages=generator.predict(noise)

        if e < int(epochs*0.5):    
            #one-sided labels
            discriminator.trainable=True
            dLossR=discriminator.train_on_batch(images,np.ones([halfSize,1]))
            dLossF=discriminator.train_on_batch(genImages,np.zeros([halfSize,1]))
            dLoss=np.add(dLossF,dLossR)*0.5
            discriminator.trainable=False cnt = e while cnt > 3:
                cnt = cnt - 4 if cnt == 0:
                noise=np.random.normal(0,1,(batchSize,Noise_dim))
                gLoss=gan.train_on_batch(noise,np.ones([batchSize,1]))

        elif e>= int(epochs*0.5) :
            cnt = e while cnt > 3:
                cnt = cnt - 4 if cnt == 0:
                #one-sided labels
                discriminator.trainable=True
                dLossR=discriminator.train_on_batch(images,np.ones([halfSize,1]))
                dLossF=discriminator.train_on_batch(genImages,np.zeros([halfSize,1]))
                dLoss=np.add(dLossF,dLossR)*0.5
                discriminator.trainable=False noise=np.random.normal(0,1,(batchSize,Noise_dim))
            gLoss=gan.train_on_batch(noise,np.ones([batchSize,1])) if e % 20 == 0:
           print("epoch: %d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (e, dLoss[0], 100 * dLoss[1], gLoss)) dLossReal.append([e,dLoss[0]])
        dLossFake.append([e,dLoss[1]])
        gLossLogs.append([e,gLoss]) if e % plotInternal == 0 and e!=0:
            show_imgs(generator, e)

        dLossRealArr= np.array(dLossReal)
        dLossFakeArr = np.array(dLossFake)
        gLossLogsArr = np.array(gLossLogs)

        chk = e while chk > 50:
            chk = chk - 51 if chk == 0:
            discriminator.save_weights('/content/gdrive/My Drive/discriminator_DCGAN_lr=0.0001,proportion2,deepgenerator_Fake.h5')
            gan.save_weights('/content/gdrive/My Drive/gan_DCGAN_lr=0.0001,proportion2,deepgenerator_Fake.h5')
            generator.save_weights('/content/gdrive/My Drive/generator_DCGAN_lr=0.0001,proportion2,deepgenerator_Fake.h5')
        # At the end of training plot the losses vs epochs
    plt.plot(dLossRealArr[:, 0], dLossRealArr[:, 1], label="Discriminator Loss - Real")
    plt.plot(dLossFakeArr[:, 0], dLossFakeArr[:, 1], label="Discriminator Loss - Fake")
    plt.plot(gLossLogsArr[:, 0], gLossLogsArr[:, 1], label="Generator Loss")
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.legend()
    plt.title('GAN')
    plt.grid(True)
    plt.show()

    return gan, generator, discriminatorgan, generator, discriminator = DCGAN(Noise_dim)
train(epochs=4000, batchSize=128, plotInternal=200)

让我们比较一下这两个网络的输出。通过运行该行:

show_imgs(Generator)

网络将从生成器输出一些图像(这是我们之前定义的函数之一)。

Generated images from 1:1 training of discriminator vs. generator.

现在让我们检查第二个模型。

Generated images from the second network with different training times for the discriminator and generator.

我们可以看到,生成的图像的细节得到了改善,它们的纹理稍微更加详细。然而,与训练图像相比,它们仍然是不合格的。

Training images from Anime dataset.

也许 VAE-甘会表现得更好?

动漫数据集上的甘

重申一下我之前说过的关于 VAE-甘的话,术语 VAE-甘首先是由 Larsen 等人使用的。al 在他们的论文“使用学习的相似性度量进行像素以外的自动编码”。VAE-甘模型与甘模型的区别在于它们的生成器是变异自动编码器

VAE-GAN architecture. Source: https://arxiv.org/abs/1512.09300

首先,我们需要创建并编译 VAE-GAN,并对每个网络进行总结(这是简单检查架构的好方法)。

# Create and compile a VAE-GAN, and make a summary for themfrom keras.models import Sequential, Model
from keras.layers import Input, Dense, Dropout, Activation, \
    Flatten, LeakyReLU, BatchNormalization, Conv2DTranspose, Conv2D, Reshape,MaxPooling2D,UpSampling2D,InputLayer, Lambda
from keras.layers.advanced_activations import LeakyReLU
from keras.layers.convolutional import UpSampling2D
from keras.optimizers import Adam, RMSprop,SGD
from keras.initializers import RandomNormal
import numpy as np
import matplotlib.pyplot as plt
import os, glob
from PIL import Image
import pandas as pd
from scipy.stats import norm
import keras
from keras.utils import np_utils, to_categorical
from keras import backend as K
import random
from keras import metrics
from tqdm import tqdm # plotInternal
plotInternal = 50#######
latent_dim = 256
batch_size = 256
rows = 64
columns = 64
channel = 3
epochs = 4000
# datasize = len(dataset)# optimizers
SGDop = SGD(lr=0.0003)
ADAMop = Adam(lr=0.0002)
# filters
filter_of_dis = 16
filter_of_decgen = 16
filter_of_encoder = 16 def sampling(args):
    mean, logsigma = args
    epsilon = K.random_normal(shape=(K.shape(mean)[0], latent_dim), mean=0., stddev=1.0)
    return mean + K.exp(logsigma / 2) * epsilondef vae_loss(X , output , E_mean, E_logsigma):
	# compute the average MSE error, then scale it up, ie. simply sum on all axes
  reconstruction_loss = 2 * metrics.mse(K.flatten(X), K.flatten(output))

	# compute the KL loss
  kl_loss = - 0.5 * K.sum(1 + E_logsigma - K.square(E_mean) - K.exp(E_logsigma), axis=-1) total_loss = K.mean(reconstruction_loss + kl_loss)    

  return total_loss def encoder(kernel, filter, rows, columns, channel):
    X = Input(shape=(rows, columns, channel))
    model = Conv2D(filters=filter, kernel_size=kernel, strides=2, padding='same')(X)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = LeakyReLU(alpha=0.2)(model) model = Conv2D(filters=filter*2, kernel_size=kernel, strides=2, padding='same')(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = LeakyReLU(alpha=0.2)(model) model = Conv2D(filters=filter*4, kernel_size=kernel, strides=2, padding='same')(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = LeakyReLU(alpha=0.2)(model) model = Conv2D(filters=filter*8, kernel_size=kernel, strides=2, padding='same')(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = LeakyReLU(alpha=0.2)(model) model = Flatten()(model) mean = Dense(latent_dim)(model)
    logsigma = Dense(latent_dim, activation='tanh')(model)
    latent = Lambda(sampling, output_shape=(latent_dim,))([mean, logsigma])
    meansigma = Model([X], [mean, logsigma, latent])
    meansigma.compile(optimizer=SGDop, loss='mse')
    return meansigma def decgen(kernel, filter, rows, columns, channel):
    X = Input(shape=(latent_dim,)) model = Dense(2*2*256)(X)
    model = Reshape((2, 2, 256))(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = Activation('relu')(model) model = Conv2DTranspose(filters=filter*8, kernel_size=kernel, strides=2, padding='same')(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = Activation('relu')(model)

    model = Conv2DTranspose(filters=filter*4, kernel_size=kernel, strides=2, padding='same')(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = Activation('relu')(model) model = Conv2DTranspose(filters=filter*2, kernel_size=kernel, strides=2, padding='same')(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = Activation('relu')(model) model = Conv2DTranspose(filters=filter, kernel_size=kernel, strides=2, padding='same')(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = Activation('relu')(model) model = Conv2DTranspose(filters=channel, kernel_size=kernel, strides=2, padding='same')(model)
    model = Activation('tanh')(model) model = Model(X, model)
    model.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0001, beta_1=0.5), metrics=['accuracy'])
    return model def discriminator(kernel, filter, rows, columns, channel):
    X = Input(shape=(rows, columns, channel)) model = Conv2D(filters=filter*2, kernel_size=kernel, strides=2, padding='same')(X)
    model = LeakyReLU(alpha=0.2)(model) model = Conv2D(filters=filter*4, kernel_size=kernel, strides=2, padding='same')(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = LeakyReLU(alpha=0.2)(model) model = Conv2D(filters=filter*8, kernel_size=kernel, strides=2, padding='same')(model)
    model = BatchNormalization(epsilon=1e-5)(model)
    model = LeakyReLU(alpha=0.2)(model) model = Conv2D(filters=filter*8, kernel_size=kernel, strides=2, padding='same')(model) dec = BatchNormalization(epsilon=1e-5)(model)
    dec = LeakyReLU(alpha=0.2)(dec)
    dec = Flatten()(dec)
    dec = Dense(1, activation='sigmoid')(dec) output = Model(X, dec)
    output.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002, beta_1=0.5), metrics=['accuracy'])

    return output def VAEGAN(decgen,discriminator):
    # generator
    g = decgen # discriminator
    d = discriminator
    d.trainable = False
    # GAN
    gan = Sequential([g, d])

#     sgd=SGD()
    gan.compile(optimizer=Adam(lr=0.0001, beta_1=0.5), loss='binary_crossentropy')
    return g, d, gan

我们再次定义了一些函数,这样我们就可以打印来自生成器的图像。

def get_image(image_path, width, height, mode):
    image = Image.open(image_path)
    #print(image.size)

    return np.array(image.convert(mode))

def show_imgs(generator):
    row=3
    col = 5
    noise = np.random.normal(0, 1, (row*col, latent_dim))
    gen_imgs = generator.predict(noise)

    # Rescale images 0 - 1
    gen_imgs = 0.5 * gen_imgs + 0.5

    fig, axs = plt.subplots(row, col)
    #fig.suptitle("DCGAN: Generated digits", fontsize=12)
    cnt = 0

    for i in range(row):
        for j in range(col):
            axs[i, j].imshow(gen_imgs[cnt, :, :, :])
            axs[i, j].axis('off')
            cnt += 1

    #plt.close()
    plt.show()

发生器的参数将受到 GAN 和 VAE 训练的影响。

# note: The parameters of the generator will be affected by both the GAN and VAE training

G, D, GAN = VAEGAN(decgen(5, filter_of_decgen, rows, columns, channel),discriminator(5, filter_of_dis, rows, columns, channel))

# encoder
E = encoder(5, filter_of_encoder, rows, columns, channel)
print("This is the summary for encoder:")
E.summary()

# generator/decoder
# G = decgen(5, filter_of_decgen, rows, columns, channel)
print("This is the summary for dencoder/generator:")
G.summary()

# discriminator
# D = discriminator(5, filter_of_dis, rows, columns, channel)
print("This is the summary for discriminator:")
D.summary()

D_fixed = discriminator(5, filter_of_dis, rows, columns, channel)
D_fixed.compile(optimizer=SGDop, loss='mse')

# gan
print("This is the summary for GAN:")
GAN.summary()

# VAE
X = Input(shape=(rows, columns, channel))

E_mean, E_logsigma, Z = E(X)

output = G(Z)
# G_dec = G(E_mean + E_logsigma)
# D_fake, F_fake = D(output)
# D_fromGen, F_fromGen = D(G_dec)
# D_true, F_true = D(X)

# print("type(E)",type(E))
# print("type(output)",type(output))
# print("type(D_fake)",type(D_fake))

VAE = Model(X, output)
VAE.add_loss(vae_loss(X, output, E_mean, E_logsigma))
VAE.compile(optimizer=SGDop)

print("This is the summary for vae:")
VAE.summary()

在下面的单元格中,我们开始训练我们的模型。注意,我们使用前面的方法来训练鉴频器以及 GAN 和 VAE 不同的时间长度。我们在训练过程的前半部分强调鉴别器的训练,在后半部分我们更多地训练发生器,因为我们想提高输出图像的质量。

# We train our model in this cell

dLoss=[]
gLoss=[]
GLoss = 1
GlossEnc = 1
GlossGen = 1
Eloss = 1

halfbatch_size = int(batch_size*0.5)

for epoch in tqdm(range(epochs)):
    if epoch < int(epochs*0.5):
        noise = np.random.normal(0, 1, (halfbatch_size, latent_dim))
        index = np.random.randint(0,dataset.shape[0], halfbatch_size)
        images = dataset[index]  

        latent_vect = E.predict(images)[0]
        encImg = G.predict(latent_vect)
        fakeImg = G.predict(noise)

        D.Trainable = True
        DlossTrue = D.train_on_batch(images, np.ones((halfbatch_size, 1)))
        DlossEnc = D.train_on_batch(encImg, np.ones((halfbatch_size, 1)))       
        DlossFake = D.train_on_batch(fakeImg, np.zeros((halfbatch_size, 1)))

#         DLoss=np.add(DlossTrue,DlossFake)*0.5

        DLoss=np.add(DlossTrue,DlossEnc)
        DLoss=np.add(DLoss,DlossFake)*0.33
        D.Trainable = False

        cnt = epoch

        while cnt > 3:
            cnt = cnt - 4

        if cnt == 0:
            noise = np.random.normal(0, 1, (batch_size, latent_dim))
            index = np.random.randint(0,dataset.shape[0], batch_size)
            images = dataset[index]  
            latent_vect = E.predict(images)[0]     

            GlossEnc = GAN.train_on_batch(latent_vect, np.ones((batch_size, 1)))
            GlossGen = GAN.train_on_batch(noise, np.ones((batch_size, 1)))
            Eloss = VAE.train_on_batch(images, None)   
            GLoss=np.add(GlossEnc,GlossGen)
            GLoss=np.add(GLoss,Eloss)*0.33
        dLoss.append([epoch,DLoss[0]]) 
        gLoss.append([epoch,GLoss])

    elif epoch >= int(epochs*0.5):
        cnt = epoch
        while cnt > 3:
            cnt = cnt - 4

        if cnt == 0:
            noise = np.random.normal(0, 1, (halfbatch_size, latent_dim))
            index = np.random.randint(0,dataset.shape[0], halfbatch_size)
            images = dataset[index]  

            latent_vect = E.predict(images)[0]
            encImg = G.predict(latent_vect)
            fakeImg = G.predict(noise)

            D.Trainable = True
            DlossTrue = D.train_on_batch(images, np.ones((halfbatch_size, 1)))
        #     DlossEnc = D.train_on_batch(encImg, np.ones((halfbatch_size, 1)))       
            DlossFake = D.train_on_batch(fakeImg, np.zeros((halfbatch_size, 1)))

            DLoss=np.add(DlossTrue,DlossFake)*0.5

#             DLoss=np.add(DlossTrue,DlossEnc)
#             DLoss=np.add(DLoss,DlossFake)*0.33
            D.Trainable = False

        noise = np.random.normal(0, 1, (batch_size, latent_dim))
        index = np.random.randint(0,dataset.shape[0], batch_size)
        images = dataset[index]  
        latent_vect = E.predict(images)[0]

        GlossEnc = GAN.train_on_batch(latent_vect, np.ones((batch_size, 1)))
        GlossGen = GAN.train_on_batch(noise, np.ones((batch_size, 1)))
        Eloss = VAE.train_on_batch(images, None)   
        GLoss=np.add(GlossEnc,GlossGen)
        GLoss=np.add(GLoss,Eloss)*0.33

        dLoss.append([epoch,DLoss[0]]) 
        gLoss.append([epoch,GLoss])

    if epoch % plotInternal == 0 and epoch!=0:
        show_imgs(G)

    dLossArr= np.array(dLoss)
    gLossArr = np.array(gLoss)

#     print("dLossArr.shape:",dLossArr.shape)
#     print("gLossArr.shape:",gLossArr.shape)

    chk = epoch

    while chk > 50:
        chk = chk - 51

    if chk == 0:
        D.save_weights('/content/gdrive/My Drive/VAE discriminator_kernalsize5_proportion_32.h5')
        G.save_weights('/content/gdrive/My Drive/VAE generator_kernalsize5_proportion_32.h5')
        E.save_weights('/content/gdrive/My Drive/VAE encoder_kernalsize5_proportion_32.h5')

    if epoch%20 == 0:    
        print("epoch:", epoch + 1,"  ", "DislossTrue loss:",DlossTrue[0],"D accuracy:",100* DlossTrue[1], "DlossFake loss:", DlossFake[0],"GlossEnc loss:",
          GlossEnc, "GlossGen loss:",GlossGen, "Eloss loss:",Eloss)
#     print("loss:")
#     print("D:", DlossTrue, DlossEnc, DlossFake)
#     print("G:", GlossEnc, GlossGen)
#     print("VAE:", Eloss)

print('Training done,saving weights')
D.save_weights('/content/gdrive/My Drive/VAE discriminator_kernalsize5_proportion_32.h5')
G.save_weights('/content/gdrive/My Drive/VAE generator_kernalsize5_proportion_32.h5')
E.save_weights('/content/gdrive/My Drive/VAE encoder_kernalsize5_proportion_32.h5')

print('painting losses')
# At the end of training plot the losses vs epochs
plt.plot(dLossArr[:, 0], dLossArr[:, 1], label="Discriminator Loss")
plt.plot(gLossArr[:, 0], gLossArr[:, 1], label="Generator Loss")
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.title('GAN')
plt.grid(True)
plt.show()
print('end')

如果你计划运行这个网络,请注意培训过程需要很长时间。我不会尝试这样做,除非你有一些强大的图形处理器,或者愿意运行一整天的模型。

现在我们的 VAE-GAN 训练已经完成,我们可以检查看看我们的输出图像看起来如何,并与我们以前的 GAN 进行比较。

# In this cell, we generate and visualize 15 images. 

show_imgs(G)

我们可以看到,在 VAE-甘的实现中,我们得到了一个很好的模型,它可以生成清晰的图像,并且具有与原始图像相似的风格。我们的 VAE-甘可以创建更健壮的图像,这可以在没有额外的动画脸噪声的情况下完成。然而,我们模型的概括能力不是很好,它很少改变角色的方式或性别,所以这是我们可以尝试改进的一点。

最终点评

不一定清楚哪个模型比其他模型更好,而且这些方法都没有经过适当的优化,因此很难进行比较。

这仍然是一个活跃的研究领域,所以如果你感兴趣,我建议你投入进去,在你自己的工作中尝试使用 GANs,看看你能想出什么。

我希望你喜欢这个关于 GANs 的文章三部曲,并且现在对它们是什么、它们能做什么以及如何制作你自己的有了更好的了解。

感谢您的阅读!

时事通讯

关于新博客文章和额外内容的更新,请注册我的时事通讯。

[## 时事通讯订阅

丰富您的学术之旅,加入一个由科学家,研究人员和行业专业人士组成的社区,以获得…

mailchi.mp](https://mailchi.mp/6304809e49e7/matthew-stewart)

进一步阅读

在 COLAB 中运行 BigGAN:

  • https://colab . research . Google . com/github/tensor flow/hub/blob/master/examples/colab/biggan _ generation _ with _ TF _ hub . ipynb

更多代码帮助+示例:

  • https://www . jessicayung . com/explaining-tensor flow-code-for-a-卷积神经网络/
  • https://lilian Weng . github . io/lil-log/2017/08/20/from-GAN-to-wgan . html
  • https://py torch . org/tutorials/初学者/dcgan_faces_tutorial.html
  • https://github.com/tensorlayer/srgan
  • https://junyanz.github.io/CycleGAN/https://affinelayer.com/pixsrv/
  • https://tcwang0509.github.io/pix2pixHD/

有影响力的论文:

  • https://arxiv.org/pdf/1511.06434v2.pdf
  • 瓦瑟斯坦甘https://arxiv.org/pdf/1701.07875.pdf
  • 条件生成对抗网(CGAN)https://arxiv.org/pdf/1411.1784v1.pdf
  • 使用对抗网络的拉普拉斯金字塔的深度生成图像模型(拉普根)https://arxiv.org/pdf/1506.05751.pdf
  • 使用生成式对抗网络(SRGAN)的照片级单幅图像超分辨率https://arxiv.org/pdf/1609.04802.pdf
  • 使用循环一致对抗网络的不成对图像到图像翻译https://arxiv.org/pdf/1703.10593.pdf
  • InfoGAN:通过信息最大化生成对抗网络的可解释表示学习https://arxiv.org/pdf/1606.03657
  • https://arxiv.org/pdf/1704.00028.pdf 的 DCGAN
  • 瓦瑟斯坦·甘斯的强化训练(WGAN-GP)【https://arxiv.org/pdf/1701.07875.pdf T4
  • 基于能量的生成对抗网络(EBGAN)https://arxiv.org/pdf/1609.03126.pdf
  • 使用学习的相似性度量(VAE-甘)对像素之外的内容进行自动编码https://arxiv.org/pdf/1512.09300.pdf
  • 对抗性特征学习(https://arxiv.org/pdf/1605.09782v6.pdf甘比
  • 堆叠生成敌对网络(SGAN)https://arxiv.org/pdf/1612.04357.pdf
  • StackGAN++使用堆叠式生成对抗网络进行现实图像合成https://arxiv.org/pdf/1710.10916.pdf
  • 通过对抗训练(SimGAN)从模拟和无监督图像中学习https://arxiv.org/pdf/1612.07828v1.pdf

“GANs”vs“ODEs”:数学建模的终结?

原文:https://towardsdatascience.com/gans-vs-odes-the-end-of-mathematical-modeling-ec158f04acb9?source=collection_archive---------2-----------------------

Disentangling neural networks representations [source]

大家好!在这篇文章中,我想在我们在学校、大学学习的经典数学建模和机器学习之间建立一种联系,机器学习也以完全不同的方式对我们周围的对象和过程进行建模。虽然数学家基于他们的专业知识和对世界的理解创建模型,但机器学习算法以某种隐藏的方式描述世界,不完全可以理解,但在大多数情况下,甚至比人类专家开发的数学模型更准确。然而,在许多应用中(如医疗保健、金融、军事),我们需要清晰和可解释的决策,而机器学习算法,特别是深度学习模型,并没有设计来提供这些决策。

本博客将回顾我们期望从任何模型中获得的主要特征,以及“经典”数学建模和机器学习建模的优缺点,并将展示一个结合了这两个世界的候选者— 解开表征学习

此外,如果你想尝试在你自己的数据上应用解开的表示,请查看来自 Google Research 的我在 GitHub 上的实现和这个库。

深度学习有什么问题?

自从深度学习革命以来,我们试图将神经网络应用到各个领域。在许多重要的领域,它确实有意义,并有助于实现最先进的结果:在计算机视觉,自然语言处理,语音分析和信号处理。最终,所有这些深度学习宣传都是关于从复杂数据中自动提取特征,结合神经网络中的线性和非线性转换,以一些“向量”结束,我们也称之为“嵌入”,它表示关于输入对象的所有需要的信息,并允许对其进行分类或回归:

这些“嵌入”在特征提取和准确性方面确实非常好,但它们在许多方面都失败了:

  • 解释:大小为 N 的向量没有告诉我为什么要做出某个特定的决定,只有逆向工程方法可以突出输入数据中的“感兴趣的对象”。
  • 需要大量数据:深度学习实际上对 10–100 个样本不起作用。
  • 无监督学习:现在大部分应用都需要标注训练数据
  • 零触发重用:这是当今一个非常重要的问题:在一个数据集上训练的神经网络很少能够直接应用于另一个类似的数据集,而无需重新训练。
  • 对象生成:我能从这个嵌入中生成一个真实的对象吗?可能是和甘斯——是的。
  • 对象操作:我可以用这个嵌入操作输入对象的特定属性吗?不完全是。
  • 理论基础:嗯,我们得到了普适近似理论。不多。

看起来这些问题真的很难在现代机器学习框架内解决。但是我们最近都在处理它们!

数学建模有什么好?

关于上面提到的所有这些问题,20 年、50 年甚至 100 年前的大多数数学家根本没有遇到过。为什么?因为他们忙于数学建模,即使用数学抽象描述现实世界中的对象和过程,例如,分布、公式或微分方程(这就是为什么我们在标题中有“ODE”,即常微分方程)。让我们再检查一下“问题清单”,但是想想科学家们从零开始创造的数学模型。这里我仍将使用术语“嵌入”,但它将表示数学模型的参数,即微分方程中的一组自由度。

  • 解释:每一个数学模型都是基于科学家对物体的描述而创建的——带有明确的动机和理解。例如,为了描述物理运动,我们的嵌入将由物体质量、运动速度和坐标空间组成——没有抽象矢量!
  • 需要大量数据:今天的大多数科学突破都不是在“图像网络大小”的数据集上完成的。
  • 无监督学习:嗯,数学建模也不尽然:)
  • 零炮重用:比如说,几何布朗运动的同一个随机微分方程可以应用于金融、生物或物理——只需重命名参数名称。
  • 对象生成:开箱即用,只是采样参数。
  • 对象操纵:开箱即用,只是操纵参数。
  • 理论基础:几百年的科学。

那么为什么我们不把微分方程用于所有的事情呢?事实证明,对于大规模的复杂数据,它们的表现要差得多。这就是为什么我们今天正在驾驭深度学习的浪潮。但是,我们仍然希望从人类开发的模型中获得好的属性。

结合机器学习和基于人类的建模

如果我们仍然可以使用神经网络,在分析复杂数据时如此准确,而且还具有我们上面描述的属性,会怎么样?可解释性,生成和操纵对象的能力,无监督的特征学习和不同环境下的零拍重用,你在哪?例如,作为面部图像的特征提取器,我希望看到这样的内容:

Almost unsupervised disentanglement

它处理对于微分方程或其他模型来说过于复杂的图像,允许生成和操作对象,是可解释的,并且最有可能的是,也可以在另一个数据集上完成所有这些。这项工作的唯一问题是不能完全无人监督。操纵的另一个重要问题是,当我改变“胡子”特征时,它会自动使一张脸变得更有男子气概,这意味着,习得的特征虽然可以解释,但彼此相关,或者换句话说,纠缠在一起

β -VAE

然而,有一种方法可以帮助我们获得解开的表示,换句话说,一种嵌入,其中每个元素负责一个单独的因素,并且这种嵌入可以用于新数据的分类、生成或操作任务(以零触发的方式)。该算法由 DeepMind 实验室开发,基于变分自动编码器,但更强调潜在分布和选择的先验分布之间的 KL 散度,而不是恢复损失。要了解更多细节,我希望你参考下面的视频,它很好地解释了贝塔 VAE 背后的想法,它在监督学习和强化学习中的应用。

beta-VAE applications to machine learning and reinforcement learning

看完这个视频后,你可以看到,beta-VAEs 真的能够提取输入数据的变化因素:物理运动方向、对象大小、颜色和方向,它们能够在强化学习应用中分离感兴趣的对象和背景,以及在现实环境中的模拟中训练的代理的零触发重用。

我自己的实验

由于我经常处理医疗和金融应用,在这些应用中,分离可以真正解决许多与模型的可解释性、人工数据生成和零触发学习相关的实际问题,因此我尝试将 beta-VAEs 用于 ECG 数据和 BTC 价格数据。你可以在我的 GitHub 里找到训练模型的代码。首先,我将β-VAE(实际上非常简单的 MLP 网络)应用于来自 PTB 诊断数据集的心电图,该数据集实际上有三个变化因素:心电图的不同导联/形式、因人而异的脉搏、以及诊断,即梗塞或其缺失。我用瓶颈大小= 10,学习速率 5e-4,容量 C = 25 训练了 VAE 50 个纪元(详见本作)。输入总是一个心跳。正如我所料,我的模型了解到了数据集中变化的真实因素。在下面的图片上,你可以看到,我是如何操作输入(黑线)心跳的,将一个单一的特性从瓶颈的-3 变为 3,同时保持所有其他特性不变。你可以看到,第 5 个特征负责改变心跳的形式,第 8 个特征代表心脏状况(蓝色心电图有梗塞症状,而红色心电图试图“相反”),第 10 个特征轻微改变脉搏。

Disentangling ECG beats

关于财务数据,一切都不那么明朗(这并不奇怪)。训练参数相对相似,但输入是 2017 年收集的 180 分钟 BTC 价格样本。我期望从 beta-VAE 中学习一些“标准的”金融时间序列模型,如均值回复时间序列,但是解释获得的表示相对困难。好吧,我可以告诉你,特征 5 改变了输入时间序列的趋势,但是特征 2、4 和 6 在时间序列的不同部分添加/移除曲线,或者使其更“不稳定”。

Disentangling BTC close prices

多个对象解开

当几个物体出现在图像上,我们想为每个物体找到不同的因素时,该怎么办呢?同样,DeepMind 让我们对他们的结果感到满意。我不会深究细节,只需查看下面两张 gif,获得动力并阅读推文中相应的论文。值得:)

摘要

让我们像描述“正常的”深度学习和数学建模一样,得出描述贝塔-VAE 方法的结论。

  • 解释:完全可解释的特性,我们只需要验证每个特定的嵌入元素。
  • 需要大量数据:嗯,仍然如此,因为我们正在深度学习领域运营。
  • 无监督学习 : 100%无监督。
  • 零镜头重用:视频《为自己说话》中的强化学习实例
  • 对象生成:像一般 VAE 一样简单采样。
  • 物体操作:你想要的任何变化因素都很好很容易。
  • 理论基础:进行中的工作:/

我们几乎拥有数学建模的所有良好特性,同时具备深度学习能力,能够以高精度分析复杂的数据类型。因此,一个非常自然的问题出现了:如果我能以完全无监督的方式从复杂数据中学习如此好的表示,这是否意味着“经典”数学建模的终结?如果一个 ML 模型可以做到,我们真的需要考虑复杂的模型吗,我们只需要分析它的特征?由我们决定:)

P.S.
如果你觉得这个内容有用,有观点,可以在 Bitclout 上支持我。关注我还可以在脸书上看到太短的人工智能文章,在 Instagram 上看到个人资料,在 Linkedin 上看到!如果你想在可解释的人工智能应用或其他人工智能项目上合作,请联系我。

使用 GARCH & Monte-Carlo 模拟的波动性度量

原文:https://towardsdatascience.com/garch-processes-monte-carlo-simulations-for-analytical-forecast-27edf77b2787?source=collection_archive---------7-----------------------

风险度量是资金管理的关键

如何对波动性建模以衡量风险

Image by author

风险措施是投资组合基金管理的主要因素。波动性和风险是相互关联的。高波动性的投资容易产生高风险,因此不利于短期风险。传统上,波动性在度量风险中起着重要的作用,然而,波动性并不跟随市场的变化。为了估计波动性,有必要开发一个考虑到时间序列中波动性变动的模型,例如非对称 Garch 模型,如 Tarch 和 Egarch 模型。

在这里,我们将探讨如何使用 GARCH、e GARCH 和 GJR-GARCH 模型结合蒙特卡罗模拟来建立 VaR 模型。金融时间序列的尖峰值、聚集波动性和杠杆效应特征证明了 GARCH 建模方法的正确性。时间序列的非线性特性将被用来检验布朗运动和研究时间演化模式。

因此,在 GARCH 建模方法之前,我们将采用涉及分形维数(FD)、重标极差和递归量化分析(RQA)的数据建模技术来总结数据的非线性动力学行为并实现研究目标。

方法:

赫斯特系数 (H) 是长程相关性的特征,与 FD ( FD + H = 2 )相关。重定标(R/S) 分析是分形数据建模的核心工具。经验研究(1)表明,与该类别中的其他方法相比,如自相关分析、方差比和光谱分解,R/S 会带来更好的结果。它是表征时间序列散度的度量,定义为给定持续时间 (T) 的以平均值为中心的值的范围除以该持续时间的标准偏差[R/S = k * T(H)*]; k 是依赖于时间序列的常数。h 测量时间序列的长期记忆,将其描述为均值回复、趋势或随机游走。

H < 0.5 indicating mean reversion

H > 0.5 表示趋势时间序列,以及

H = 0.5 表示随机游走。

递归量化分析(RQA)将用于通过计算 REC、DET、TT 和 LAM 等测量值对动态系统进行量化,从而从数据中提取有价值的见解。

我们将探讨如何使用 GARCH 模型进行风险评估。

GARCH 模型的一个关键限制是对其参数施加非负约束,以确保条件方差的正定性。这种限制会给估计 GARCH 模型带来困难。因此,非对称 GARCH 模型,俗称 GJR-GARCH 模型,可以用来处理对称 GARCH 模型的局限性。此外,指数 GARCH (EGARCH)将被引入,对传统 GARCH 模型进行潜在的改进(4)。

数据挖掘:

让我们看看数据中存储了什么。

在过去的几十年里,原油价格呈现大幅波动,尤其是在 2008 年前后。可以看出,随着多次断崖式的涨跌,价格保持在相对较低的水平。从自相关图中可以看到原始数据中显著的序列自相关的明显证据。QQ 和概率图的形状表明该过程接近正态,但尾部很重。

简单收益常用的形式是:r(t) = {p(t) — p(t-1)}/p(t-1)对数收益= ln(pt/p(t-1),pt 每日原油价格,r(t)是每日收益。

日志返回在这里被认为是每日返回。原始价格和对数收益的直观显示清楚地证明了使用接近常数均值的对数收益的合理性。

回归序列图显示了高和低可变性的周期。在图中可以看到一个以零为中心的随机过程。正负收益的大幅波动增加了风险投资和管理的难度。石油日收益率的均值基本上在零水平附近,具有明显的波动聚类,表明存在异方差。ACF 很小,串行不相关,但高度依赖。QQ 和概率图的形状没有明显变化。正负收益的大幅波动增加了风险投资和管理的难度。

*sns.distplot(df.returns, color=’blue’) #density plot
plt.title(“2000–2019 Crude Oil return frequency”)
plt.xlabel(‘Possible range of data values’)
# Pull up summary statistics
print(df.returns.describe())*

收益的偏度(-0.119)和向右偏离表明正收益比负收益更强烈,峰度(7.042)反映了石油波动的大范围。

标准正态分布的偏度和峰度分别为 0 和 3。

Jarque-Bera 检验的值表明,传统的正态分布假设并不适合原油收益的真实分布。

*ADF = ADF(df.returns)
print(ADF.summary().as_text())**kpss = KPSS(df.returns)
print(kpss.summary().as_text())**dfgls = DFGLS(df.returns)
print(dfgls.summary().as_text())**pp = PhillipsPerron(df.returns)
print(pp.summary().as_text())**za = ZivotAndrews(df.returns)
print(za.summary().as_text())**vr = VarianceRatio(df.returns, 12)
print(vr.summary().as_text())*

进行虚拟现实测试是为了测试收益序列是否是纯粹的随机游走,而不是具有一定的可预测性。我们在这里比较了 1 个月和 12 个月的回报。用负检验统计量 VA(-11.07)拒绝零表示时间序列中存在序列相关性。ADF、KPSS、DFGLS、PP 和 ZA 统计量的单位根和平稳性检验都显示出显著性,表明应用 GARCH 型模型拟合收益率序列是合适的。

自从 Mandelbrot 发表了他的关于 R/S 分析在时间序列的长记忆依赖性中的应用的著作(Mandelbrot,Wallis,1969;Mandelbrot,1972)和自从 Peters 提出了他的分形市场假说(Peters,1991)作为公认的有效市场假说的替代,这种方法正在关于金融时间序列被检查。

非线性动力学:

我们现在将使用 H 扩展对平稳性的研究。 H 提供了一种方法来衡量金融时间序列偏离随机游走的程度。

*closes_recent = df.Price[-2000:]
plot(closes_recent); show()
# calculate Hurst of recent prices
lag1 = 2
lags = range(lag1, 20)
tau = [sqrt(std(subtract(closes_recent[lag:], closes_recent[:-lag]))) for lag in lags]
plot(log(lags), log(tau)); show()
m = polyfit(log(lags), log(tau), 1)
hurst = m[0]*2
print (‘hurst = ‘,hurst)*

H (0.531)表示具有长期相关性的随机运动时间序列。对数收益的长记忆性证明了本研究中给定系列的 GARCH 模型的合理性。

*time_series = TimeSeries(df.Price, embedding_dimension=2, time_delay=2)
settings = Settings(time_series, computing_type=ComputingType.Classic, neighbourhood=FixedRadius(0.65), similarity_measure=EuclideanMetric,
theiler_corrector=1)
computation = RQAComputation.create(settings, verbose=True)
result = computation.run()
result.min_diagonal_line_length = 2
result.min_vertical_line_length = 2
result.min_white_vertical_line_lelngth = 2
print(result)*

这里,低 RR 表示较低程度的周期性和随机行为;此外,低的 DET 值表明较少的确定性。 LAM 值表示过程中的层次性,是明显周期性和混沌动力学的阶段交替。虽然来自 RQA 的发现也证明了分形建模的含义,但是,通过显示自动回归行为,非线性动力学拒绝了有效市场假说,证明了使用 GARCH 方法的合理性。

GARCH 模型:

在估计 GARCH 型模型之前,将回报率放大 100 倍总是一个好主意。这有助于优化器转换,因为波动率截距的范围更接近模型中其他参数的范围。

X = 100* df.returns

让我们拟合一个 ARCH 模型,并绘制平方残差来检验自相关性。

*gam = arch_model(Model.resid, p=2, o=0, q=2, dist=’StudentsT’)
gres = gam.fit(update_freq=5, disp=’off’)
print(gres.summary())**tsplot(gres.resid**2, lags=30)*

我们可以在平方残差中看到自相关的明显证据。让我们拟合一个 GARCH 模型,看看它的表现如何。我们将应用如下程序:

  • 迭代 ARIMA(p,d,q)模型的组合,以最佳拟合时间序列。
  • 根据 AIC 最低的 ARIMA 模型选择 GARCH 模型订单。
  • 用 GARCH(p,q)模型拟合时间序列。
  • 检查自相关的模型残差和残差平方
*def _get_best_model(TS):
 best_aic = np.inf 
 best_order = None
 best_mdl = None
 pq_rng = range(5) # [0,1,2,3,4,5]
 d_rng = range(2) # [0,1]
 for i in pq_rng:
 for d in d_rng:
 for j in pq_rng:
 try:
 tmp_mdl = smt.ARIMA(TS, order=(i,d,j)).fit(
 method=’mle’, trend=’nc’
 )
 tmp_aic = tmp_mdl.aic
 if tmp_aic < best_aic:
 best_aic = tmp_aic
 best_order = (i, d, j)
 best_mdl = tmp_mdl
 except: continue
 print(‘aic: {:6.2f} | order: {}’.format(best_aic, best_order)) 
 return best_aic, best_order, best_mdl

TS = X
res_tup = _get_best_model(TS)*

aic: 22462.01 |顺序:(2,0,2)

所以,我们在这里发现,最佳模型是 ARIMA(2,0,2)。现在我们绘制残差来决定它们是否拥有条件异方差行为的证据。

*am = arch_model(X, p=2, q=2, o=1,power=2.0, vol=’Garch’, dist=’StudentsT’)
res = am.fit(update_freq=5)
print(res.summary())*

*am = arch_model(X, p=2, q=2, o=1,power=2.0, vol=’Garch’, dist=’StudentsT’)
res = am.fit(update_freq=5)
print(res.summary())**eam = arch_model(X, p=2,q=2, o=1, power=2.0, vol=’EGARCH’, dist=’StudentsT’)
eres = eam.fit(update_freq=5)
print(res.summary())**gjam = arch_model(X, p=2, o=1, q=2, power=2.0, dist=’StudentsT’)
gjres = gjam.fit(update_freq=5, disp=’off’)
print(gjres.summary())*

所有 3 个 GARCH 模型的输出都以表格形式显示。ω是白噪声,α和β是模型的参数。此外,α [1] + β [1] < 1 表示稳定模型。EGARCH 模型似乎是三个模型中最好的,然而,GARCH 和 EGARCH 之间的差别很小。

尽管我已经用所有可用的数据进行了实验;然而,在训练/测试中分割数据并获得 MSE/MAE/RMSE 结果来比较最佳模型拟合是一个好主意。

标准化残差的计算方法是将残差除以条件波动率。

*std_resid = res_normal.resid / res_normal.conditional_volatility
unit_var_resid = res_normal.resid / res_normal.resid.std()*

标准化残差和条件波动率图显示了一些误差,但幅度不大。

*plt.xlim(-2, 2)
sns.kdeplot(squared_resid, shade=True)
sns.kdeplot(std_resid, shade=True)
sns.kdeplot(unit_var_resid, shade=True)
plt.legend([‘Squared Residual’, “Unit variance residual”, “Std Residual”], loc=’best’)
plt.show()*

标准化残差也与非标准化但成比例的残差一起绘制。平方残差在中心更突出,表明该分布比标准化残差的分布具有更重的尾部。让我们检查一下 ACF 图。

*plot_acf(std_resid)
plt.title(‘Standardized residuals’)
pyplot.show()*

看起来有些尖峰超出了阴影置信区域。让我们来看看残差的平方。

*plot_acf(squared_resid)
plt.title(‘Squared residuals’)
pyplot.show()*

残差平方显示数据点位于蓝色阴影置信区域(95%)内,表明模型拟合度良好。

*am = arch_model(X,mean=’HAR’,lags=[1,5,22],vol=’Constant’) 
sim_data = am.simulate([0.1,0.4,0.3,0.2,1.0], 250)
sim_data.index = pd.date_range(‘2019–01–01’,periods=250) 
am = arch_model(sim_data[‘data’],mean=’HAR’,lags=[1,5,22], vol=’Constant’) 
res = am.fit()
fig = res.hedgehog_plot(type=’mean’)*

刺猬图显示了 2019 年的预测方法。橙色线表示不同时间间隔的预测。

基于模拟的预测:

基于模拟的方法用于从这里模拟的 EGARCH 中获得预测波动率的置信区间。这个过程被重复了很多次,以获得波动性预测的集合。预测点通过对模拟进行平均来计算,95%置信区间分别使用模拟分布的 2.5%和 97.5%分位数来计算。考虑到平均收益输入(mu)为 0.0292,年波动率输入(vol)为(26.48) * sqrt 252 = 37.37%。

*vol = df.returns.std()*sqrt(252)
print (“Annual Volatility =”, str(round(vol,4)*100)+”%”)**#Define Variables
S = df.Price[-1] #starting stock price (i.e. last available real stock price)
T = 252 #Number of trading days
mu = 0.0622 #Return
vol = 0.3737 #Volatility**daily_returns=np.random.normal((1+mu)**(1/T),vol/sqrt(T),T)**price_list = [S]
 price_list.append(price_list[-1]*x)**#Generate Plots — price series and histogram of daily returns
plt.plot(price_list)
plt.show()
plt.hist(daily_returns-1, 100) 
plt.show()*

最上面的图显示了一个交易年度(252 天)内潜在价格序列演变的单一模拟,基于遵循正态分布的随机每日回报。第二个图是一年中这些随机日收益率的直方图。然而,真正的洞察力可以从运行成千上万的模拟中获得,每次运行都基于相同的股票特征(mu 和 vol)产生不同系列的潜在价格演变。

*#set up empty list to hold our ending values for each simulated price series
result = []**S = df.Price[-1] #starting stock price (i.e. last available real stock price)
T = 252 #Number of trading days
mu = 0.0622 #Return
vol = 0.3737 #Volatility**#choose number of runs to simulate — I have chosen 10,000
for i in range(10000):
 #create list of daily returns using random normal distribution
 daily_returns= np.random.normal((1+mu)**(1/T),vol/sqrt(T),T)

 #set starting price and create price series generated by above random daily returns
 price_list = [S]

 for x in daily_returns:
 price_list.append(price_list[-1]*x)**#append the ending value of each simulated run to the empty list we created at the beginning
 result.append(price_list[-1])**plt.figure(figsize=(10,6))
plt.hist(result,bins= 100)
plt.axvline(np.percentile(result,5), color=’r’, linestyle=’dashed’, linewidth=2)
plt.axvline(np.percentile(result,95), color=’r’, linestyle=’dashed’, linewidth=2)
plt.figtext(0.6,0.8,s=”Start price: $%.2f” %S)
plt.figtext(0.6,0.7,”Mean final price: $58.44")
plt.figtext(0.6,0.6,”5% quantile: $29.72")
plt.figtext(0.15,0.6, “95% quantile: $101.75”)
plt.title(u”Final price distribution for Crude stock”, weight=’bold’, fontsize=12)
plt.show()*

这里的结果会略有不同,因为这些是模拟随机的每日收益抽取。由于每个模拟中包含的路径,平均值越倾向于“mu”输入中使用的平均回报。下面的直方图显示了潜在价格分布的几个分位数,以了解非常高或非常低的回报的可能性。

很明显,原油价格有 5%的可能会低于 29.72 美元,有 5%的可能会高于 101.75 美元。

关键要点:

在这里,我们研究并提出了一个基于混合时变长记忆 GARCH 和模拟的波动模型。经验证据表明,具有布朗运动的原油数据往往在其时间动态中表现出一定程度的可预测性。

虽然风险值可以用分析方法和模拟方法来衡量;我们使用蒙特卡罗模拟来检验结果的稳健性。蒙特卡洛模拟的输出表明,即使在控制了外来因素之后,结果仍然是稳健的。因此,研究结果提供了一个很好的混合 EGARCH 和 Monte-Carlo 模拟模型,该模型考虑了诸如波动聚集性和不对称性、时变风险和重尾分布等波动特征来衡量原油价格。

可以到达 这里

参考文献:

(1)曼德尔布罗,b . b .&沃利斯,J. R. (1969)。分数高斯噪声的计算机实验:第 2 部分,重新标度的范围和光谱。水资源研究,5(1),242–259

(2)杜塔,A. (2014)。波动性建模:对称或非对称 garch 模型。统计学杂志:理论与应用进展,12(2),99–108。

(3) Glosten,l .,Jagannathan,r .和 Runkle,D. (1993)关于股票预期收益之间的关系,金融杂志,48,1779–801。

(4) Nelson,D. (1991)资产回报的条件异方差:一种新的方法,计量经济学,59,349–70。

(5)彼得斯,E. E. (1991),资本市场的混乱和秩序:周期、价格和市场波动的新观点,威利,纽约。

Gartner 2019 新兴技术炒作周期。人工智能领导者有什么好处?

原文:https://towardsdatascience.com/gartner-2019-hype-cycle-for-emerging-technologies-whats-in-it-for-ai-leaders-3d54ad6ffc53?source=collection_archive---------13-----------------------

https://www.gartner.com/smarterwithgartner/5-trends-appear-on-the-gartner-hype-cycle-for-emerging-technologies-2019/

Gartner 2019 年对新兴技术的炒作周期已经结束,因此这是一个很好的时机来深入研究这份报告并反思我们作为一家公司的人工智能战略。你可以在这里找到完整报告的简要总结。

首先,在详细介绍报告的内容及其对公司人工智能战略的影响之前,我想谈谈最近几天我在社交网络上看到的一个反复出现的评论。许多人惊讶地看到,某些技术尽管在前几年出现过,却完全从报告中消失了。正如 Gartner 在其研究中解释的那样,其炒作周期涵盖了非常广泛的主题,因此如果某项特定技术没有被报道,并不一定意味着它们不重要,恰恰相反一些技术从炒作周期中消失的一个原因可能是它们不再是“新兴的”,而是业务和 IT 的关键。

因此,让我们从实际回顾与人工智能相关的基础技术开始,这些技术已从今年的报告中排除,但对业务仍然至关重要:

  • 深度神经网络。事实上,Gartner 认为 DNNs 是炒作周期中许多其他新兴技术的基础。
  • 对话人工智能平台。 Gartner 不再考虑对话式人工智能平台新兴技术,而是坚持其业务相关性。
  • 虚拟助手。Gartner 不再认为虚拟助理是新兴技术,而是坚持其业务相关性。
  • 人工通用智能(AGI) 。在我看来,Gartner 的呼吁很好,主张围绕人工智能的务实愿景,远离炒作。正如 Gartner 提到的,AGI 几十年内都不会成熟。

根据 Gartner 的说法,哪些应该是公司人工智能领导者的重点领域?根据其 2019 年新兴技术优先矩阵,这些技术应该是:

  • 增强智能。Gartner 将这一新兴技术视为新业务解决方案设计方法的关键,平衡短期自动化与中长期方法,确保不仅通过自动化手段,而且通过放大人才来提高质量。
  • 边缘 AI 。在那些通信成本、延迟或大容量摄入可能是关键的场景中。当然,这意味着确保我们用例(如深度学习)的足够的人工智能开发和技术可用于我们想要部署的物联网基础设施,以及其他条件。

最后,2019 炒作周期中与 AI 相关的新兴技术有哪些:

  • 适应性 ML。定义为可以在相同评分环境下再培训的一类 ML。
  • 情感 AI。定义为使用计算机视觉或语音分析等人工智能技术来适应用户的情绪状态并改善整体体验。
  • 可解释的人工智能。在确保道德和法规合规性的同时,可解释性是深度学习面临的主要挑战之一。可解释的人工智能包括不同的方法和技术,能够解释人工智能算法考虑基于提供的数据产生其输出的推理。
  • 生成对抗网络(GANs)。最初由 Ian Goodfellow 和 al。,GANs 使用两种不同的神经网络(生成型和判别型)。虽然判别网络的目标是改善其对输入数据的分类方式,但生成网络试图通过创建旨在欺骗算法的合成数据来使其失败。虽然这种网络可以用来改善人工智能训练,但它们正被用来按照特定的模式或风格生成视频、音频或文本等合成内容。
  • 迁移学习。定义为重用先前训练的人工智能模型作为在不同背景下训练它们的起点,一些人工智能专家声称迁移学习是未来实现人工一般智能的关键。

综上所述,基于我的个人经验,人工智能领导者应该:

  • 拥抱像 DNN 这样的人工智能核心技术不是作为一项创新举措,而是作为公司核心战略的一部分。公司应该从实验室概念验证转向可扩展的人工智能方法,包括如何组织人工智能人才、应用方法以及在整个公司范围内实施通用平台。
  • 考虑人工智能如何帮助他们的公司与物联网或 5G 等其他创新技术一起解决业务挑战。虽然 Gartner 专注于边缘 AI 的影响,但 5G 也可以在不久的将来使解决有趣的用例变得可行。此外,区块链(顺便说一下,它也从炒作周期中消失了)和人工智能非常适合解决非常有趣的用例。
  • 最后,关注技术的人性一面。从如何让我们的数字人才从自动化中受益,到考虑人工智能对员工工作、客户体验和整个社会的影响。

如果你喜欢读这篇文章,请 考虑成为会员 以获得每个故事的完整访问权,同时支持我和媒体上的其他作者。

用矩阵解释门控循环单位:第 1 部分

原文:https://towardsdatascience.com/gate-recurrent-units-explained-using-matrices-part-1-3c781469fc18?source=collection_archive---------7-----------------------

由:闪耀的拉塞尔-普勒里和道林-普勒里

很多时候,我们都在使用深度学习框架,这些框架执行构建模型所需的所有操作。然而,首先理解一些基本的矩阵运算是有价值的。在本教程中,我们将带您完成理解 GRU 工作原理所需的简单矩阵运算。

详细的笔记本可以在 https://github.com/sparalic/GRUs-internals-with-matrices或 https://github.com/DPuleriNY/GRUs-with-matrices找到

什么是门控循环单元(GRU)?

门控递归单元(如下图所示)是一种递归神经网络,它解决了长期依赖性问题,这可能导致梯度消失更大的香草 RNN 网络体验。GRUs 通过存储前一时间点的“记忆”来帮助通知网络未来的预测,从而解决了这个问题。乍一看,人们可能认为这个图相当复杂,但事实恰恰相反。本教程的目的是揭穿使用线性代数基础的 GRUs 的困难。

GRUs 的控制方程为:

Governing equations of a GRU

其中 z 和 r 分别代表更新门和复位门。而 h_tilde 和 h 分别表示中间存储器和输出。

GRUs vs 长期短期记忆(LSTM) RNNs

GRUs 和流行的lstm(由 Chris Olah 很好地解释)之间的主要区别是门的数量和单元状态的维护。与 GRUs 不同,LSTMs 有 3 个门(输入、遗忘、输出),并保持内部存储单元状态,这使其更加灵活,但在存储和时间方面效率较低。然而,由于这两种网络都擅长解决有效跟踪长期相关性所需的消失梯度问题。通常使用以下经验法则在它们之间做出选择。当在这两者之间做出决定时,建议您首先训练 LSTM,因为它有更多的参数,更灵活一些,然后是 GRU,如果两者的性能之间没有相当大的差异,那么使用更简单有效的 GRU

方法

为了进一步说明 RNNs 的优雅,我们将带您了解理解 GRU 内部工作所需的线性代数基础知识。为此,我们将使用一小段字母来说明我们认为理所当然的矩阵计算是如何使用预打包的包装函数创建许多常见的 DL 框架的。本教程的目的不是让我们倒退,而是帮助我们更深入地理解 rnn 如何使用线性代数工作。

示例使用以下示例字符串作为输入数据:

` text =数学数学数学数学'

然而,算法本质上是某种数学方程,因此我们的原始文本在提交给 GRU 层之前必须用数字形式表示。这在下面的预处理步骤中完成。

数据预处理

第一步,创建一个包含所有唯一字符的字典,将每个字母映射到一个唯一的整数:

字符字典:{'h': 0,' a': 1,' t': 2,' M': 3}

我们的编码输入现在变成:
数学数学= [3,1,2,0,3,1,2,0]

第一步:创建数据批次 这一步是通过用户指定我们想要创建多少批次(B),或者给定我们的词汇表(V)的序列长度(S)来实现的。下图演示了如何创建和编码批处理。

假设我们需要以下参数:
1。批量大小(B) = 2
2。序列长度(S) = 3
3。词汇(V) = 4
4。输出(O) = 4

那么什么是时间序列呢?
如果您对 RNN 进行基本搜索,您将会找到下图。这个图像是展开形式中发生的事情的概括视图。然而,x(t-1)、x(t)和 x(t+1)(以红色突出显示)在我们的批次中意味着什么?

Vanilla RNN architecture

在我们的小批量中,时间序列代表每个序列,信息从左到右流动,如下图所示。

Schematic of data flow for each one-hot encoded batch

数据集的维度

Batch anatomy

步骤 1:用代码演示

整形后,如果你检查 X 的形状,你会发现你得到一个形状的秩为 3 的张量:3 x 3 x 2 x 4。这是什么意思?

Dimensions of the dataset

会演示什么?

数据现在已经准备好进行建模了。然而,我们想强调本教程的流程。我们将演示为批次 1 中的第一个序列(以红色突出显示)执行的矩阵运算(如下所示)。这个想法是为了理解第一个序列的信息是如何传递给第二个序列的,以此类推。

Sequence used for walk through (Sequence 1 batch 1)

为此,我们需要首先回忆一下这些批次是如何被输入算法的。

Schematic of batch one being ingested into the RNN

更具体地说,我们将遍历序列 1 在 GRU 单元中完成的所有矩阵运算,并将在该过程中计算结果输出 y_(t-1)和 h_t(如下所示):

First time step of of batch 1

步骤 2:定义我们的权重矩阵和偏差向量

在这一步中,我们将带您完成用于计算 z 门的矩阵运算,因为其余三个方程的计算完全相同。为了帮助理解这一点,我们将通过将内部等式分解为三部分来遍历复位门 z 的点积,最后我们将对输出应用 sigmoid 激活函数,以挤压 0 和 1 之间的值:

Reset gate

但首先让我们定义网络参数:

什么是隐藏尺寸?

上面定义的隐藏大小是学习参数的数量,或者简单地说,是网络内存。该参数通常由用户根据手头的问题来定义,因为使用更多的单元可能会使训练数据过拟合。在我们的例子中,我们选择了隐藏大小 2,以便更容易说明这一点。这些值通常被初始化为来自正态分布的随机数,它们是可训练的,并且在我们执行反向传播时被更新。

Anatomy of the Weight matrix

我们体重的大小

我们将使用第一批遍历所有矩阵运算,因为对于所有其他批来说,这是完全相同的过程。然而,在我们开始任何上述矩阵运算之前,让我们讨论一个叫做广播的重要概念。如果我们看 batch 1 (3 x 2 x 4)的形状和 Wz (4 x 2)的形状,首先想到的可能是,我们将如何对这两个形状不同的张量执行元素式矩阵乘法?

答案是我们使用一个叫做“广播”的过程。广播被用来使这两个张量的形状兼容,这样我们可以执行我们的元素矩阵运算。这意味着 Wz 将被广播到一个非矩阵维度,在我们的例子中是我们的序列长度 3。这意味着更新等式 z 中的所有其他项也将被广播。因此,我们的最终等式将是这样的:

Equation for z with weight matrices broadcasted

在我们执行实际的矩阵运算之前,让我们想象一下第一批中的序列 1 是什么样子的:

Illustration of matrix operations and dimensions for the first sequence in batch 1

更新门:z

更新门决定了过去的信息对当前状态的有用程度。这里,sigmoid 函数的使用导致更新门值在 0 和 1 之间。因此,该值越接近 1,我们包含的过去的信息就越多,而值越接近 0,则意味着只保留新信息。

现在让我们开始数学… 第一项:注意,当这两个矩阵用点积相乘时,我们是每行乘以每列。这里,第一个矩阵(x_t)的每一行(用黄色突出显示)都要乘以第二个矩阵(Wz)的每一列(用蓝色突出显示)。

术语 1:应用于输入的权重

Dot product of the first term in the update gate equation

术语 2:隐藏权重

Dot product of the second term in the update gate equation

术语 3:偏差向量

Bias vector

将所有这些放在一起:z_inner

Inner linear equation of the reset gate

然后,使用 sigmoid 激活函数将结果矩阵中的值压缩在 0 和 1 之间:

Sigmoid equation

复位门:r

重置门允许模型忽略可能与未来时间步不相关的过去信息。在每一批中,复位门将重新评估先前和新输入的综合性能,并根据新输入的需要进行复位。再次因为 sigmoid 激活函数,更接近 0 的值将意味着我们将继续忽略先前的隐藏状态,并且对于更接近 1 的值,情况相反。

Reset gate

中间内存:波形符

中间存储单元或候选隐藏状态将来自先前隐藏状态的信息与输入相结合。因为第一项和第三项所需的矩阵运算与我们在 z 中所做的相同,所以我们将只给出结果。

Intermediate/candidate hidden state

第二学期:

Second term matrix operations

将所有内容放在一起:颚化符

Inner linear equation calculation

然后,使用 tanh 激活函数将结果矩阵中的值压缩在-1 和 1 之间:

Tanh activation function

最后:

Candidate hidden state output

在时间步长 t:h(t-1)输出隐藏层

Hidden state for the first time step

Resulting matrix for hidden state at time step 1

批次 1 中的第二个序列(时间步长 x_t)如何从这种隐藏状态中获取信息?

回想一下,h(t-n)首先被初始化为零(在本教程中使用)或随机噪声,以开始训练,之后网络将学习和适应。但是在第一次迭代之后,新的隐藏状态 h_t 现在将被用作我们的新的隐藏状态,并且在时间步长(x_t)对序列 2 重复上述计算。下图演示了这是如何做到的。

Illustration of the new hidden state calculated in the above matrix operations

这个新的隐藏状态 h(t-1)将不用于计算批量中第二个时间步的输出(y(t+1))和隐藏状态 h(t),以此类推。

Passing of hidden states from sequence1 to sequence 2

下面我们演示如何使用新的隐藏状态 h(t-1)来计算后续的隐藏状态。这通常使用循环来完成。该循环迭代每个给定批次中的所有元素,以计算 h_(t-1)。

代码实现:第 1 批输出:h(t1)、h(t)和 h(t+1)

第二批的隐藏状态是什么?

如果你是一个视觉的人,它可以被看作是一个系列,在 h(t+1)的输出,然后将被送到下一批,整个过程再次开始。

Passing of hidden states across batches

步骤 3:计算每个时间步的输出预测

为了获得我们对每个时间步长的预测,我们首先必须使用线性层来转换我们的输出。回想一下隐藏状态下的列的维数 h(t+n)本质上是网络尺寸/隐藏尺寸的维数。然而,我们有 4 个唯一的输入,我们希望我们的输出也有 4 个。因此,我们使用所谓的密集层或全连接层将输出转换回所需的维度。然后,根据所需的输出,将这个完全连接的层传递给一个激活函数(对于本教程为 Softmax)。

Fully connected/Linear layer

最后,我们应用 Softmax 激活函数将我们的输出归一化为一个概率分布,其总和为 1。Softmax 函数:

Softmax equation

根据教科书的不同,您可能会看到不同风格的 softmax,特别是使用 softmax max 技巧,它会减去整个数据集的最大值,以防止大型 y _ linear y/full _ connected 的值爆炸。在我们的情况下,这意味着我们的最大值 0.9021 将首先从 y_linear 中减去,然后应用于 softmax 方程。

让我们分解一下,请注意,我们不能像前面那样对序列进行子集划分,因为求和需要整批中的所有元素。

  1. 从完全连接的图层中的所有元素中减去整个数据集的最大值:

Applying the Max trick for Softmax equation

2.求指数矩阵中所有元素的和

Sum of the exponents for each row

Final Softmax output for the first sequence in batch 1

最后,训练我们的网络(仅向前)

这里,我们通过在网络中多次运行每个批次来训练输入批次的网络,这被称为一个时期。这允许网络多次学习序列。随后进行损失计算和反向传播,以最大限度地减少我们的损失。在本节中,我们将一次性实现上面显示的所有代码片段。鉴于输入尺寸较小,我们将仅演示正向传递,因为损失函数和反向传播的计算将在后续教程中详细介绍。

这个函数将向网络输入一系列字母,帮助创建一个初始状态,避免胡乱猜测。如下所示,生成的前几个字符串有点不稳定,但是经过几次处理后,至少接下来的两个字符是正确的。然而,考虑到词汇量很小,这个网络很可能会过度适应。

最后的话

本教程的目的是通过演示简单的矩阵运算如何组合成如此强大的算法,提供 GRUs 内部工作的一个演示。

接下来:用矩阵解释的门递归单元:第 2 部分训练和损失函数

参考资料:

  1. 递归神经网络的不合理有效性
  2. 使用 Pytorch 的 Udacity 深度学习
  3. 面向编码人员的 fastai 深度学习
  4. 深度学习——直接的兴奋剂
  5. 深度学习书籍
  6. http://colah.github.io/posts/2015-08-Understanding-LSTMs/

数据科学中的看门人和精英主义

原文:https://towardsdatascience.com/gatekeeping-and-elitism-in-data-science-74cf19cd5744?source=collection_archive---------11-----------------------

Photo by Court Prather on Unsplash

老实说,我经常觉得我需要证明我比其他人更优秀。当涉及到我所建立的身份,我引以为豪的事情,给我提供自我价值感的事情时,我可能会特别自私,不管这些事情多么肤浅。因此,当我在数据科学领域遇到精英主义和势利的知识分子守门人时,我完全理解。

当我听到那些大部分时间都在使用 Microsoft Excel 工作、对数学或统计学知之甚少的人将他们的工作称为数据科学或分析时,我经常感到愤怒。当我看到有人在网上论坛问“理解统计学对数据科学真的有必要吗?”或者“我正试图从社交媒体经理转型为数据科学家,从哪里开始学习线性代数最好?”,我有时会觉得自己被冒犯了。见鬼,即使人们习惯于在真实数据集上天真地运行 svm.fit()和 svm.predict(),而不试图理解凸优化的理论细微差别,我的不安全感也会迫使我嘲笑自己,就好像我是一个被农民邀请参加舞会的法国贵族妇女。

当然,这样的反应是幼稚和自恋的。试图阻止有抱负的学习者,并假设一些错误的优越感或道德制高点,不仅是不成熟和自私的。不积极鼓励其他人参与数据科学领域,不赞扬在线教育资源的扩展,就会成为数据科学领域进步的阻碍。许多人对人类知识所能做出的最重要的贡献是激励和鼓励他人。

充当数据科学的看门人是对求知欲的背叛,是对可获取知识、技术颠覆以及数据和经验证据的民主本质的新范式的冒犯。

另一方面,我也相信在某种程度上,这种守门本能至少是部分有效的反应。尽管自我和饥荒思维——认为在数据科学中只有固定数量的机会,因此一个人的成功对另一个人是有害的——可以解释大量的这些反应,但我确实相信这里还有其他因素在起作用。

在试图对这种精英主义、排外主义的心态提供一种宽容的理解之前,我想澄清一下我所说的数据科学中的守门人是什么意思。我所指的守门人通常采取既定的数据科学家和其他“内部人士”的形式,试图劝阻或阻止人们(通常是来自非常规或非技术学术和职业背景的人)追求他们的神圣领域。一种类似的精英主义倾向贯穿于许多清晰区分“真正的数据科学家”和假货的尝试中,以澄清“商业/报告分析师”不是真正在做分析,或者声称一个人“必须拥有 STEM 领域的研究生学位”才能成为一名有价值的数据科学家。

现在,我想谈谈我们应该同情看门人的几个原因。为了理解他们的观点,我们需要对其中的一些问题进行批判性的审视。最终,这让我们更好地理解了鼓励来自许多不同背景的不同人群进行合作、组建社区以及在所有数据科学领域寻求各种机会的必要性。

在为 techcrunch.com 撰写的题为“软件开发人员日益增长的精英主义问题”的文章中,卡兰·夏普指出,推动程序员精英主义的因素之一是年轻一代的新兴程序员有机会获得老一辈没有的机会和捷径。老一代的守卫者感到被这种感知的不公平所欺骗,并被新程序员所拥有的巨大潜力所威胁。我感觉这种相同的动态在数据科学中很普遍。

想象一下,你是几十年来一直使用统计编程和构建模型的职业统计学家之一,或者你是第一批行业数据科学家中的一员。在过去十年左右围绕数据科学的炒作爆发之前,拥有研究生学位和定量领域正式教育经验的人成为数据科学家可能更常见。物理学、计算机科学、生物学和其他 STEM 领域的博士可能在应用科学研究的背景下学习编程和数据分析,然后过渡到工业界作为数据科学家工作。

不难看出,拥有 STEM 研究生学位的早期数据科学家和如今的新兴数据科学家之间存在巨大差异。后者将获得精心策划的在线数据科学项目,可以在世界任何地方免费访问,以及特定的职业指导和新的分析软件。这位 2000 年代中期的资深数据科学家可能会觉得受到了欺骗,因为他错过了“Python 中的数据科学入门”或“R 编程入门”的所有在线课程,以及 Kaggle 等在线数据科学社区,此外还有专门提供数据科学和机器学习方面的本科生和研究生课程的大学。

让我们假定我们的看门人是无辜的。让我们假设他们的反应不仅仅是觉得被新一代人享有的额外优势欺骗了。让我们假设他们的担忧是更真实的:他们认为这一代人的教育水平在下降。此外,假设他们真的担心越来越多的人仅仅为了诱人的薪水和社会声望而追求数据科学。最后,让我们补充一个事实,即不得不应对“数据科学家”这一宽泛且往往无益的标签是可以理解的恼人。在某些方面,也许精英主义仅仅是为了拒绝媒体围绕数据科学的讨论。

这一论点,即使是以最慈善的形式,也远远不能证明精英主义是正当的。哀叹教育质量的下降并不是阻止他人获取知识并声称自己是真理的唯一来源的理由。如果有什么不同的话,劣质教育内容的普及应该激励人们传播更高质量的教育内容来取代它。

寻租的涌入可能是试图保护该领域免受其腐败影响的更有力的理由。然而,守门人的回应似乎实际上依赖于这样一种心态,即新来者将侵占老一辈人本应享有的利润。这不是一场零和游戏,像数据科学这样基础而广泛的领域本身不会腐败,就像数学不会腐败一样。

在数据科学和一般技术领域,定义松散的术语肯定存在问题,但将如此多的重量放在一个标题上,并让它偏离炒作背后非常真实的实质,这是非常琐碎的。

随着社会变革开始影响各种行业、学科、艺术家、音乐流派等。试图保护自己的区域不受外界影响是人类非常自然的反应。在历史上,臭名昭著的勒德分子对纺织机械的抵制,摇滚乐会撕裂社会道德结构的呼声,以及对伽利略提出的日心说的暴力反对,都可以看到这样的例子。然而,在数据科学的情况下,更合适的做法是,该领域开始避免这些情绪冲动,转而支持更理性、更有计算能力的评估,这种评估自然会否定精英主义,拥抱颠覆。

高斯混合模型(GMM)

原文:https://towardsdatascience.com/gaussian-mixture-modelling-gmm-833c88587c7f?source=collection_archive---------0-----------------------

内部 AI

使用无监督学习理解文本数据

在之前的帖子中,我讨论了 k-means 聚类作为总结文本数据的一种方式。我还谈到了 k-means 的一些局限性,以及在什么情况下它可能不是最合适的解决方案。可能最大的限制是每个聚类都有相同的对角协方差矩阵。这就产生了球形集群,就它们能够建模的分布类型而言,球形集群是相当不灵活的。在这篇文章中,我想解决其中的一些限制,并特别谈谈一种可以避免这些问题的方法,【GMM】。这篇文章的格式将与上一篇非常相似,在上一篇文章中,我解释了 GMM 背后的理论以及它是如何工作的。然后,我想深入研究用 Python 编写算法,我们可以看到结果与 k-means 有何不同,以及为什么使用 GMM 可能是一个很好的替代方案。

GMM 变得简单了

最简单地说,GMM 也是一种聚类算法。顾名思义,每个聚类都是根据不同的高斯分布建模的。这种灵活的概率数据建模方法意味着,我们有软分配,而不是像 k-means 那样将硬分配到聚类中。这意味着每个数据点可能是由具有相应概率的任何分布生成的。实际上,每个分布对于生成特定的数据点都有一些“责任”。

我们如何评估这种类型的模型?嗯,我们可以做的一件事是为每个数据点引入一个 潜变量 𝛾 (伽马)。这假设每个数据点都是通过使用潜在变量 𝛾 的一些信息生成的。换句话说,它告诉我们哪个高斯函数生成了一个特定的数据点。然而,在实践中,我们没有观察到这些潜在的变量,所以我们需要估计它们。我们该怎么做?对我们来说幸运的是,已经有一种算法可以在这种情况下使用,即 期望最大化(EM)算法 ,这是我们接下来要讨论的。

EM 算法

EM 算法由两个步骤组成,E 步骤或期望步骤和 M 步骤或最大化步骤。假设我们有一些潜在变量 𝛾 (它们未被观察到,用下面的向量 z 表示)和我们的数据点 X 。我们的目标是在给定参数的情况下最大化 X 的边际可能性(由向量 θ 表示)。本质上,我们可以找到作为 X 和 Z 的结合点的边际分布,并对所有 Z 求和(概率求和规则)。

Equation 1: Marginal Likelihood with Latent variables

上述等式通常会产生一个难以最大化的复杂函数。在这种情况下我们能做的就是用 简森斯不等式构造一个下界函数这样就更容易优化了。如果我们通过最小化两个分布之间的 KL 散度(间隙)来优化这一点,我们可以近似原始函数。这个过程如下图 1 所示。我也在上面提供了一个视频链接,展示了 KL 散度的推导,给那些想要更严格的数学解释的人。**

为了从本质上评估我们的模型,我们只需要执行两个步骤。在第一步(E-step)中,我们希望根据我们的权重(π)均值()和高斯分布的协方差(σ)来估计我们的潜在变量𝛾的后验分布。参数向量在图 1 中表示为θ。估计 E-step 需要首先初始化这些值,我们可以用 k-means 来完成,这通常是一个很好的起点(在下面的代码中有更多的介绍)。然后,我们可以进入第二步(m 步),使用𝛾使参数θ的可能性最大化。重复这个过程,直到算法收敛(损失函数不变)。

可视化 EM 算法

为什么我们不试着用图 1 来形象化这个过程呢?我们在第一步中计算𝛾的后验分布,它相当于我们通过最小化两个分布之间的 KL 散度得到的值。然后,我们将后验概率设为 q(我知道这是一个令人困惑的符号,但这只是𝛾),并最大化关于参数θ的函数。从图中我们可以看到,当我们迭代和执行这些计算时,我们向最优(或者至少是局部最优)移动。

Note: Theta is a vector of all parameters, Source: Bayesian Methods for Machine Learning

GMM 的 EM 算法

电子步骤

好了,现在我们已经看到了 EM 算法在做什么,我想概述并解释一下我们需要在 E 步和 M 步中计算的方程。在编写代码的时候,这些真的很重要。我们可以将高斯混合分布写成权重等于π的高斯分布的组合,如下所示。其中 K 是我们要建模的高斯数。

Equation 2: Gaussian Mixture Distribution

采用上述结果,我们可以使用下面的公式计算每个高斯函数对于每个数据点的责任的后验分布。这个等式就是贝叶斯规则,其中π是先验权重,并且似然性是正态的。

Equation 3: Posterior Responsibilities using Bayes Rule

M 步

在计算后验概率之后,我们需要做的就是得到由下面的等式定义的每个高斯参数的估计,然后评估对数似然。然后重复这两个步骤,直到收敛。

Equation 4: Mean of the Gaussians

Equation 5: Covariance of the Gaussians

Equation 6: weights

Equation 7: Sum of responsibilities in each Gaussian k

Equation 8: Marginal Likelihood: This is what we want to maximise

请记住,我们已经以这样的方式设置了问题,我们可以最大化下限(或最小化分布之间的距离),这将近似于上面的等式 8。我们可以把我们的下界写成如下,其中 z 是我们的潜在变量。请注意,我们的求和现在出现在对数之外,而不是对数之内,这导致表达式比等式 8 简单得多。

Equation 9: Variational Lower Bound, Source: Bishop equation 9.74

Python 代码

既然我们已经解释了建模背后的理论,我想用 Python 来编写这个算法。像我之前的帖子一样,我将使用相同的数据集,这样我们可以比较 k-means 和 GMM 的结果。预处理步骤与前一篇文章中的步骤完全相同,我在这篇文章的结尾提供了完整代码的链接。

k 均值估计

正如我之前提到的,为了开始算法(执行第一步),我们需要参数的初始值。与其随机设置这些值,不如使用 k-means 来估计它们。这通常会给我们一个好的起点,并可以帮助我们的模型更快地收敛。在我们估计 GMM 之前,让我们快速看一下 k-means 给出了什么样的聚类。

sklearn k-means

使用来自 sklearn 的估计,我们可以创建一个很好的集群可视化(图 2)。请注意,这些集群都是球形的,大小相同。球形聚类似乎没有很好地模拟数据的分布,这表明在这种特定情况下 k-means 可能不是最佳方法。这说明了 k 均值的局限性之一,因为所有协方差矩阵都是单位方差的对角矩阵。这个限制意味着该模型不是特别灵活。记住这一点,让我们试试 GMM,看看会给我们带来什么样的结果。

Source: Python for Data Science Handbook

Figure 2: k-means spherical Gaussians

GMM 估计

下面的图 3 展示了 GMM 正在做的事情。它清楚地显示了由三种不同的高斯分布建模的三个集群。我在这里用了一个玩具数据集来清楚地说明这一点,因为安然的数据集不太清楚。如你所见,与图 2 中使用球状星团建模相比,GMM 更加灵活,使我们能够生成更好的拟合分布。

Figure 3: GMM example: simple data set: Full Covariance

GMM Python 类

好了,现在我们将直接用 Python 来编写我们的 GMM 类。和往常一样,我们从一个 init 方法开始。我在这里初始化的唯一的东西是我们想要运行我们的算法的次数和我们想要建模的集群的数量。这段代码中最有趣的方法是calculate _ mean _ 协方差*** 。这有助于我们计算初始参数的值。它接受我们的数据以及来自 k-means 的预测,并计算每个聚类的权重、均值和协方差矩阵。***

下一段代码实现了我们的 initialise _ parameters 方法,该方法使用 sklearn 库中的 k-means 来计算我们的聚类。注意,这个函数实际上调用了上面定义的 calculate _ mean _ 协方差方法。我们可能已经使用了一种方法来计算我们的集群和初始参数,但是如果每种方法只执行一个特定的任务,通常会更容易调试和避免错误。

是时候进入我们班上最重要的方法了。算法的 E-step 在下面定义,并接受我们的参数和数据,这对于我们上面定义的方程来说是非常有意义的。记住,这一步的目的是计算我们责任的后验分布(𝞬).)这里要注意的主要问题是,我们循环遍历每个 C 高斯函数(在我们的例子中是 3 个),并使用 scipy 中的函数计算后验概率,以计算多元正态 pdf。

**from scipy.stats import multivariate_normal as mvn**

在我们为每个高斯计算了这个值之后,我们只需要归一化伽马(𝞬),对应于等式 3 中的分母。这是为了确保我们的伽玛是有效概率。如果我们对每个数据点的聚类值求和,它们应该等于 1。

在我们计算出职责(𝞬)的值后,我们可以将这些值输入到 M-step 中。 同样,M 步的目的是使用 E 步的结果计算我们的新参数值,对应于等式 4、5 和 6。为了使调试更容易,我在下面的代码中分离了 m_step 方法和compute _ loss _ function方法。compute_loss_function 正如其名称所暗示的那样。它接受 E-step 和 M-step 返回的责任和参数,并使用这些来计算等式 9 中定义的下限损失函数。

我们所有最重要的方法现在都被编码了。与 sklearn 保持一致,我将定义一个 fit 方法,它将调用我们刚刚定义的方法。特别是,我们从初始化参数值开始。在此之后,我们执行 EM 算法中概述的步骤,以选择迭代次数。请注意,实际上并不需要大量的迭代来收敛,特别是当您使用 k-means 来获得初始参数的值时(我认为我的算法在大约 30 次迭代中就收敛了)。

因为我们可能也对使用这个模型来预测高斯新数据可能属于什么感兴趣,所以我们可以实现一个 预测预测 _proba 方法。predict_proba 方法将接受新的数据点,并预测每个高斯函数的责任。换句话说,这个数据点来自每个分布的概率。这就是我在文章开头提到的软任务的本质。predict 方法基本上做同样的事情,但是使用 np.argmax 来分配具有最高概率的聚类。

符合我们的模型

解释完之后,我认为是时候评估我们的模型了,看看我们会得到什么。希望上面的 GMM 视觉化提供了一个关于模型正在做什么的很好的直觉。我们将对我们的安然数据集做完全相同的事情。下面的代码只是使用 3 种不同的高斯模型在我们的数据集上估计我们的 GMM 模型。为了绘图的目的,我还计算了每个分布的最高密度点,对应于中心,这有助于可视化。最后,我们还使用模型参数来绘制图 4 中每个分布的形状。

该图的主要结论是,分布显然不再是球形的。GMM 允许我们放松对协方差矩阵的限制,使分布更好地符合数据。考虑到我们的数据显然不是球形的,这一点特别有用。现在,这可能不是一个完美的解决方案,有一些数据点不适合任何分布,但它是对 k 均值的改进。

Figure 4: GMM with Full covariance

GMM sklearn 实施

现在,为了确保我们没有在代码中做任何完全疯狂的事情,我将使用 sklearn 重新做这个估计,看看我的解决方案是否相同。下面的代码与上面的代码几乎完全相同,所以我不会详细介绍。看起来我们和 sklearn 的结果非常相似。唯一不同的是,我们的一个集群中心似乎是不同的。在 sklearn 实现中,中心接近 0.4,而在我们的实现中,中心接近 0.6。或许这是由于 sklearn 中的初始化略有不同?

sklearn GMM

Figure 5: GMM sklearn

好了,伙计们,这是这篇文章。我希望这是对高斯混合模型的一个有用且非常直观的解释。如果你们中的任何人想要更深入地理解这些材料,我推荐 Coursera 课程 机器学习的贝叶斯方法 我从本课程中获取了大量资料,我认为它对我在这里提出的概念进行了非常好和深入的解释。我还要推荐主教模式识别与机器学习这本书。这本书是你在机器学习中会遇到的大多数经典算法的绝佳参考。下面我提供了帖子中概述的 GMM 类的完整代码,以及一个到 Kaggle 内核的链接,我在那里做了所有的分析。一如既往,欢迎反馈。

GMM 类的完整 Python 代码

链接完整代码:https://www.kaggle.com/dfoly1/gaussian-mixture-model

来源:Christopher m . Bishop 2006,模式识别与机器学习

来源: 机器学习的贝叶斯方法:Coursera 课程

来源:Python for Data Science Handbook

请注意,上面的一些链接是附属链接。

高斯混合模型聚类算法讲解

原文:https://towardsdatascience.com/gaussian-mixture-models-d13a5e915c8e?source=collection_archive---------0-----------------------

https://www.pexels.com/photo/macbook-pro-beside-spiral-notebook-669616/

高斯混合模型可以像 k-means 一样用于聚类未标记的数据。然而,与 k-均值相比,使用高斯混合模型有几个优点。

首先,k 均值不考虑方差。方差是指钟形曲线的宽度。

在二维中,方差(确切地说是协方差)决定了分布的形状。

思考k-均值模型的一种方式是,它在每个集群的中心放置一个圆(或者,在更高维度中,一个超球体),半径由集群中最远的点定义。

当你的数据是循环的时候,这很好。然而,当您的数据呈现不同的形状时,您最终会得到这样的结果。

相比之下,高斯混合模型甚至可以处理非常长方形的集群。

k-means 和高斯混合模型之间的第二个区别是前者执行硬分类,而后者执行软分类。换句话说,k-means 告诉我们什么数据点属于哪个聚类,但不会给我们提供给定数据点属于每个可能的聚类的概率。

在调用predict函数时,模型会将每个数据点分配给其中一个聚类。

gmm.predict(X)

另一方面,我们可以调用predict_proba函数来返回一个数据点属于每个 K 聚类的概率。

gmm.predict_proba(X)

高斯混合模型一览

顾名思义,高斯混合模型涉及多个高斯分布的混合(即叠加)。为了便于解释,假设我们有三个由三个不同类别的样本组成的分布。

蓝色高斯表示构成下层阶级的人的教育水平。红高斯表示构成中产阶级的人的教育水平,绿高斯表示构成上层阶级的人的教育水平。

在不知道哪些样本来自哪个类的情况下,我们的目标是使用高斯混合模型将数据点分配到适当的聚类中。

训练完模型后,我们理想的结果是在同一轴上有三个分布。然后,根据给定样本的教育水平(它在轴上的位置),我们将它放在三个类别中的一个。

每个分布都乘以一个权重π,以说明我们在每个类别中没有相同数量的样本。换句话说,我们可能只包括了 1000 名来自上层阶级的人和 10 万名来自中产阶级的人。

因为我们处理的是概率,所以权重加起来应该是 1。

如果我们决定添加另一个维度,比如孩子的数量,那么,它可能看起来像这样。

高斯混合模型算法

对于那些对数学不感兴趣的人,我提前向你们道歉,因为下一节很重。

假设我们想知道第 I 个样本来自高斯k概率是多少。我们可以这样表达:

其中θ代表每个高斯的平均值、协方差和权重。

你也可能会碰到写成π的方程。这不要和每个高斯相关的权重混淆(我知道的混淆)。

接下来,我们将观察到来自高斯 K 的数据点的可能性表示为:

后者有时候是这样写的(我相信 N 来源于 N 正规分布):

假设我们有一个高斯分布,横轴是一个人可能得到的不同智商分数,从最低到最高。我们可以通过从沿着 x 轴的位置到曲线画一条垂直线,然后查看 y 轴上相应的值,来找出个人智商为 120 的可能性有多大。任意一点的 y 值都等于上面的等式。

如果我们想知道在考虑所有不同分布的情况下观察样本 i 的可能性,我们只需对观察样本的可能性求和,假设样本来自每个可能的高斯分布。

换句话说,我们从数据集中选取一个样本(行),查看单个特征(即教育水平),在 x 轴上绘制其位置,并对每个分布的相应 y 值(可能性)求和。

为了将此扩展到我们数据集中的所有样本。我们假设观察一个样本的可能性独立于所有其他样本,然后我们可以简单地将它们相乘。

我们可以使用之前看到的命名法重写该等式,如下所示:

通常情况下,我们采用可能性的对数,因为对数中两个数字的乘积等于其组成部分的对数之和,并且数字相加比相乘更容易。

期望最大化算法

我们还需要解决这样一个事实,即我们需要每个高斯的参数(即方差、均值和权重)以便对我们的数据进行聚类,但是我们需要知道哪个样本属于哪个高斯,以便估计那些完全相同的参数。

这就是期望最大化发挥作用的地方。在高层次上,期望值最大化算法可以描述如下:

  1. 从随机高斯参数(θ)开始
  2. 重复以下步骤,直到我们收敛:

a) 期望步骤:计算 p(zi = k | xi,θ)。换句话说,样本 i 看起来像是来自聚类 k 吗?

b) 最大化步骤:更新高斯参数(θ) 以适合分配给它们的点。

最大化步骤

在最大化步骤中,我们希望最大化每个样本来自分布的可能性。回想一下,可能性是曲线在 x 轴某一点的高度。因此,我们希望修改分布的方差和均值,以使每个数据点的图形高度最大化。

这就带来了一个问题,“我们应该如何着手选择方差和均值的最优值。”使用期望最大化的一般形式,我们可以推导出均值、方差和权重的一组方程。

我们可以遵循相同的过程来获得协方差和权重的方程。

一旦我们有了方程,我们只需在最大化步骤中应用它们。也就是说,我们在每个方程中插入数字,以确定最佳均值、协方差、权重,然后相应地设置高斯参数。

让我们来看看数学在起作用。最初,我们不知道哪些点与哪个分布相关联。

我们从具有随机均值、方差和权重的 K 个高斯分布(在这种情况下,K=2)开始。

然后,我们重复期望和最大化步骤,直到θ几乎没有变化。

值得注意的是,该算法易受局部极大值的影响。

密码

现在,我们已经掌握了高斯混合模型的工作原理,让我们来看看如何实现它们。首先,导入以下库。

import numpy as np
from sklearn.datasets.samples_generator import make_blobs
from sklearn.mixture import GaussianMixture
from matplotlib import pyplot as plt
import seaborn as sns
sns.set()

我们随机生成 4 个集群。

X, y = make_blobs(n_samples=300, centers=4, cluster_std=0.60, random_state=0)
plt.scatter(X[:,0], X[:,1])

最佳聚类数(K)是最小化赤池信息准则(AIC) 或贝叶斯信息准则(BIC) 的值。

n_components = np.arange(1, 21)
models = [GaussianMixture(n, covariance_type='full', random_state=0).fit(X) for n in n_components]plt.plot(n_components, [m.bic(X) for m in models], label='BIC')
plt.plot(n_components, [m.aic(X) for m in models], label='AIC')
plt.legend(loc='best')
plt.xlabel('n_components');

我们使用最佳数量的聚类(在本例中为 4)来训练我们的模型。

gmm = GaussianMixture(n_components=4)gmm.fit(X)

我们使用predict方法来获得一系列的点和它们各自的集群。

labels = gmm.predict(X)plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis');

最后的想法

与 k-means 不同,高斯混合模型考虑了方差并返回数据点属于每个 K 聚类的概率。

高斯混合模型解释

原文:https://towardsdatascience.com/gaussian-mixture-models-explained-6986aaf5a95?source=collection_archive---------0-----------------------

从直觉到实施

在机器学习领域,我们可以区分两个主要领域:监督学习和非监督学习。两者的主要区别在于数据的性质以及处理数据的方法。聚类是一个无监督的学习问题,我们希望在数据集中找到具有一些共同特征的点的聚类。假设我们有一个类似这样的数据集:

我们的工作是找到看起来很接近的几组点。在这种情况下,我们可以清楚地识别出两组点,我们将分别将它们着色为蓝色和红色:

请注意,我们现在引入了一些额外的符号。这里,μ1 和μ2 是每个聚类的质心,并且是识别每个聚类的参数。一种流行的聚类算法被称为 K-means,它将遵循迭代方法来更新每个聚类的参数。更具体地说,它要做的是计算每个聚类的均值(或质心),然后计算它们到每个数据点的距离。后者随后被标记为由其最近质心识别的聚类的一部分。重复该过程,直到满足某种收敛标准,例如当我们看不到集群分配中的进一步变化时。

K-means 的一个重要特点是它是一个硬聚类方法,也就是说它会将每个点关联到一个且仅一个聚类。这种方法的一个局限是没有不确定性度量或概率来告诉我们一个数据点与一个特定的聚类有多少关联。那么,使用软集群而不是硬集群怎么样呢?这正是高斯混合模型(简称 GMM)试图做的事情。现在让我们进一步讨论这个方法。

定义

一个高斯混合是一个由几个高斯组成的函数,每个高斯由 k ∈ {1,…, K }标识,其中 K 是我们数据集的聚类数。混合物中的每个高斯 k 由以下参数组成:

  • 定义其中心的平均值μ。
  • 定义其宽度的协方差σ。这相当于多变量场景中椭球体的维度。
  • 定义高斯函数大小的混合概率π。

现在让我们用图表来说明这些参数:

在这里,我们可以看到有三个高斯函数,因此 K = 3。每个高斯解释了三个可用分类中包含的数据。混合系数本身是概率,必须满足以下条件:

现在,我们如何确定这些参数的最佳值呢?为了实现这一点,我们必须确保每个高斯拟合属于每个聚类的数据点。这正是最大似然法的作用。

通常,高斯密度函数由下式给出:

其中 x 代表我们的数据点, D 是每个数据点的维数。μ和σ分别是均值和协方差。如果我们有一个由 N = 1000 个三维点( D = 3)组成的数据集,那么 x 将是一个 1000 × 3 的矩阵。μ将是 1 × 3 的向量,σ将是 3 × 3 的矩阵。为了后面的目的,我们还会发现取这个等式的对数是有用的,它由下式给出:

如果我们对该方程的均值和协方差进行微分,然后使其等于零,那么我们将能够找到这些参数的最优值,并且解将对应于该设置的最大似然估计(MLE)。然而,因为我们处理的不是一个,而是许多个高斯函数,当我们找到整个混合物的参数时,事情会变得有点复杂。在这方面,我们需要引入一些额外的方面,我们将在下一节中讨论。

初始导数

我们现在要引入一些额外的符号。只是一句警告。数学来了!别担心。为了更好地理解推导,我将尽量保持符号的简洁。首先假设我们想知道一个数据点xn 来自高斯 k 的概率是多少。我们可以这样表达:

上面写着“给定一个数据点 x ,它来自高斯 k 的概率是多少?”在这种情况下, z 是一个潜在变量,它只取两个可能的值。当 x 来自高斯 k 时为 1,否则为零。实际上,我们在现实中看不到这个 z 变量,但是知道它出现的概率将有助于我们确定高斯混合参数,正如我们稍后讨论的。

同样,我们可以陈述如下:

这意味着观察到来自高斯 k 的点的总概率实际上等于该高斯的混合系数。这是有意义的,因为高斯越大,我们期望的概率就越高。现在让 z 成为所有可能的潜在变量 z 的集合,因此:

我们预先知道每个 z 独立于其他出现,并且当 k 等于该点来自的集群时,它们只能取值 1。因此:

现在,假设我们的数据来自高斯函数 k ,那么如何找到观察数据的概率呢?原来它其实就是高斯函数本身!遵循我们用来定义 p ( z )的相同逻辑,我们可以声明:

好吧,现在你可能会问,我们为什么要做这些?还记得我们最初的目标是确定给定我们的观测值 xz 的概率吗?事实证明,我们刚刚推导出的方程,以及贝叶斯法则,将帮助我们确定这个概率。根据概率的乘积法则,我们知道

嗯,看起来我们现在有所进展了。右边的操作数是我们刚刚找到的。也许你们中的一些人会预料到,我们会用贝叶斯法则来得到我们最终需要的概率。但是,首先我们会需要p(xn),而不是p(xnz) 。那么我们这里怎么去掉 z 呢?是的,你猜对了。边缘化!我们只需要总结一下 z 轴上的术语,因此

这是定义高斯混合的方程,你可以清楚地看到,它取决于我们之前提到的所有参数!为了确定这些的最优值,我们需要确定模型的最大似然。我们可以找到所有观测值的联合概率xn 的可能性,定义如下:

就像我们对原始高斯密度函数所做的那样,让我们将对数应用于等式的每一侧:

太好了!现在为了找到高斯混合的最佳参数,我们要做的就是对这个方程的参数求导,这样就完成了,对吗?等等!没那么快。我们这里有一个问题。我们可以看到,有一个对数正在影响第二次求和。计算这个表达式的导数,然后求解参数,会非常困难!

我们能做什么?嗯,我们需要用迭代法来估计参数。但是首先,记住我们应该找到给定 xz 的概率?好,让我们这样做,因为在这一点上,我们已经有了定义这个概率的一切。

根据贝叶斯法则,我们知道

从我们之前的推导中,我们了解到:

现在让我们将这些代入上一个等式:

这就是我们一直在寻找的!接下来,我们会经常看到这个表达。接下来,我们将继续讨论一种方法,这种方法将帮助我们容易地确定高斯混合的参数。

期望值最大化算法

好了,在这一点上,我们已经得到了一些概率的表达式,我们会发现这些表达式对确定模型的参数很有用。然而,在上一节中,我们可以看到,简单地评估(3)来找到这样的参数将被证明是非常困难的。幸运的是,我们可以使用一种迭代方法来达到这个目的。它被称为期望——最大化,或者简称为 EM 算法。它广泛用于目标函数复杂的优化问题,比如我们刚刚遇到的 GMM 问题。

让我们的模型的参数

现在让我们定义一般 EM 算法将遵循的步骤。

步骤 1: 相应地初始化 θ 。例如,我们可以使用前一次 K-Means 运行获得的结果作为我们算法的良好起点。

第二步(期望步骤):评估

嗯,其实我们已经找到了 p ( Z | X, θ )。还记得上一节我们最后用的γ表达式吗?为了更好地理解,让我们将之前的等式(4)放在这里:

对于高斯混合模型,期望步骤归结为通过使用旧的参数值来计算(4)中γ的值。现在,如果我们将(4)替换为(5),我们将得到:

听起来不错,但是我们还缺少 p ( XZ | θ* )。怎么才能找到呢?嗯,实际上并没有那么难。就是模型的完全似然,既包括 X 又包括 Z ,我们可以用下面的表达式求出:

这是计算所有观测值和潜在变量的联合概率的结果,是我们对 p ( x )的初始推导的扩展。该表达式的对数由下式给出

不错!我们终于摆脱了影响(3)中求和的这个麻烦的对数。有了所有这些,我们通过最大化关于参数的 Q 来估计参数就容易多了,但是我们将在最大化步骤中处理这个问题。此外,请记住,每次求和时,潜在变量 z为 1。有了这些知识,我们就可以根据推导的需要轻松地去掉它。

最后,我们可以将(6)中的(7)替换为:

在最大化步骤中,我们将找到混合物的修正参数。出于这个目的,我们将需要使 Q 成为一个受限的最大化问题,因此我们将向(8)添加一个拉格朗日乘数。现在让我们回顾一下最大化步骤。

步骤 3(最大化步骤):使用以下公式找到修正参数 θ *

在哪里

这就是我们上一步的结果。但是,Q 还应考虑所有π值总和应为 1 的限制。为此,我们需要添加一个合适的拉格朗日乘数。因此,我们应该这样重写(8):

现在我们可以很容易地用最大似然法来确定参数。现在让我们对π求 Q 的导数,并将其设为 0:

然后,通过重新排列各项,并对等式两边的 k 求和,我们得到:

从(1)中,我们知道所有混合系数的总和π等于 1。此外,我们知道,将概率γ与 k 相加也会得到 1。因此我们得到 λ = N 。利用这个结果,我们可以求解 π :

类似地,如果我们将 Q 对μ和σ求导,使导数等于零,然后利用我们定义的对数似然方程(2)求解参数,我们得到:

就是这样!然后,我们将在下一次 EM 迭代中使用这些修正值来确定γ,以此类推,直到我们看到似然值有所收敛。我们可以使用等式(3)来监控每一步中的对数似然,并且我们总是保证达到局部最大值。

如果能看到我们如何用编程语言实现这个算法就好了,不是吗?接下来,我们将看到我提供的 Jupyter 笔记本的一部分,这样您就可以看到 GMMs 在 Python 中的工作实现。

用 Python 实现

顺便提一下,完整的实现可以在 https://bit.ly/2MpiZp4 的 Jupyter 笔记本上获得

我在这个练习中使用了 Iris 数据集,主要是为了简单和快速训练。根据我们之前的推导,我们说明了 EM 算法遵循迭代方法来寻找高斯混合模型的参数。我们的第一步是初始化我们的参数。在这种情况下,我们可以使用 K-means 的值来满足这个目的。这方面的 Python 代码如下所示:

接下来,我们执行期望步骤。我们在这里计算

相应的 Python 代码如下所示:

请注意,为了计算总和,我们只需利用分子中的项,然后进行相应的除法运算。

然后是最大化步骤,我们计算

相应的 Python 代码如下所示:

请注意,为了稍微简化计算,我们使用了:

最后,我们还有对数似然计算,由下式给出

这方面的 Python 代码应该是

我们已经在期望步骤中预先计算了第二个求和的值,所以我们在这里只是利用它。此外,创建图表来查看可能性的进展情况总是很有用的。

我们可以清楚地看到,算法在大约 20 个历元后收敛。EM 保证在过程的给定迭代次数之后将达到局部最大值。

最后,作为实现的一部分,我们还生成一个动画,向我们展示每次迭代后集群设置是如何改进的。

注意 GMM 是如何改进 K-means 估计的质心的。当我们收敛时,每个集群的参数值不再改变。

结束语

高斯混合模型是一种非常强大的工具,广泛用于涉及数据聚类的各种任务。我希望这篇文章对你有用!请随意提出问题或评论。我也强烈建议您亲自尝试这些派生,并深入研究代码。我期待着尽快创作出更多这样的材料。

尽情享受吧!

[1] Bishop,Christopher M. 模式识别和机器学习 (2006)施普林格出版社柏林,海德堡。

[2]墨菲,凯文·p .机器学习:一种概率视角 (2012) 麻省理工学院出版社,剑桥,麻省,

高斯过程:预测纽约气温

原文:https://towardsdatascience.com/gaussian-processes-predicting-new-york-temperatures-d80906eb006?source=collection_archive---------18-----------------------

在我们开始之前,我想澄清一下,这篇文章并不完整,也不一定正确。当我试图学习更多关于高斯过程的知识时,把它看作是我的想法的笔记本,如果你看到错误或需要进一步澄清的部分,请突出显示并评论它们,以帮助我和其他读者。

数学中最著名的形状之一一定是不起眼的钟形曲线。卡尔·弗里德里希·高斯首先提出了这个函数,许多人都知道这个函数,而且由于它被用作正态分布随机变量的概率密度函数,现在学生们必须在高中以上学习。它广泛存在于我们的自然世界,这在很大程度上归功于中心极限定理。

The Guassian Curve for a random variable with mean 0 and standard deviation 1 i.e. the probability density function for such a random variable

由于我们试图了解更多关于高斯人以及这一切背后的数学和计算机科学,上面的曲线是以一种比使用图书馆更 DIY 的方式生成的。我觉得这是最好的学习方式之一,尤其是涉及数据科学及其他领域的编程技能。

A verbose Guassian function

现在我们对正态分布和定义其概率密度函数的高斯函数有了更好的理解,你可能会问,如果我不是只有一个变量呢?现代世界中的许多系统,无论是生物学、物理学还是气候科学,都是复杂的,涉及许多干扰变量。你的健康不仅仅取决于你的年龄,就像气候变化不仅仅与二氧化碳排放有关一样。

我们能把这个想法纳入我们的正态分布吗?简短的回答是:是的!但是首先,我们需要了解更多关于描述这些被称为协变量的干扰变量。

通常在科学和数学中,当我们想要理解多个元素时,我们会求助于向量和矩阵,因为它们将所有这些东西捆绑在一起,使得应用变换更加容易。以你的健康为例,它可以(不完全)表达为你的年龄、身高和体重的向量。我们可能需要计算哪些东西?首先是每一个的意思,这很简单。如果我们考虑一个大型电子表格,其中每个人都有行,向量中的每个元素都有列,我们可以很容易地计算出每列的平均值,因此健康向量的平均值是包含这些组件的单个向量。

更有趣的是协方差矩阵。这个想法很简单,我们想了解一个变量相对于另一个变量是如何变化的。凭直觉,你可以开始做预测:年龄越大,你会越高(在一定程度上),你越高,你越有可能重。显然,事情没那么简单。

A Covariance Formula

呀!好吧,让我们稍微分解一下。协方差在这里有很多详细的描述。在某种意义上,我们正在寻找两个随机变量偏离其平均值的乘积的平均值。需要注意的一点是,如果随机变量是独立的,那么它们的协方差是零。在这种情况下,它们的联合分布就是它们两个分布的乘积。

让我们看一个具体的例子,多元高斯分布。下面是两个随机变量 X 和 Y,都以零为中心,但具有不同的标准偏差。我们假设它们是独立的,我们看 Z,它们的联合分布,就是它们的概率密度函数的乘积。

有趣的是,通过联合分布,我们可以计算边际和条件概率分布,就像反向工作一样,以发现有趣的模式和对数据的洞察。事实上,我们可以从联合正态分布p(x_1, x_2)到条件概率p(x_1 | x_2),因为我们已经了解了第二个变量。

这就是我们如何开始对看不见的数据进行预测!我们可以将我们观察到的数据和我们想要预测的数据视为一个联合分布,然后将其转换为一个条件分布,其中我们以我们标记的数据为条件。这种转换的数学问题超出了本文的范围,所以我们将只应用公式。下面公式中的xy分别与训练和测试数据有关。

在开始举例之前,这个难题还有一个额外的部分。乔莱斯基分解。这听起来很可怕,但事实并非如此,如果你从未听说过它,那么希望你能从这篇文章中学到一些数学知识。直观上就像是求一个矩阵的平方根。如果我有一些矩阵A,那么乔莱斯基分解会给我一个新的矩阵L,这样LL* = A。所有这些矩阵都需要有一些特殊的属性,例如A必须是正定的并且L必须是下三角矩阵。这里有一个例子:

让我们用一个例子来使它更加真实。我们将尝试用高斯过程来拟合来自纽约市(T2)的温度数据。

The earliest twenty data points for New York City temperatures

在实际数据中,我们将在尝试进行任何类型的拟合之前对其进行归一化——这是数据科学中使用的一种常用技术,可以使梯度下降等事情更好地工作(见最后我关于这一点的问题)。

在这里,我们只是初始化数据,并将其规范化。下一步是使用我们的核函数进行计算——在这个例子中,我选择使用径向基函数。我们用核函数来度量变量的协方差。不同的函数有不同的属性,选择正确的函数似乎既是一门科学,也是一门艺术。但首先,让我们在没有任何数据的情况下,通过逐步完成这个过程来感受一下我们在做什么。

这将产生不同采样函数的下图。

现在,我们将做同样的事情,只是这一次,我们将对一些观察到的数据进行处理,以更好地猜测数据中的潜在模式。

请注意,我重新调整了所有的数据,使其回到此时的原始温度。拟合度显然不是很好,改善的一种方法是改变alpha值(称为长度比例),这可以控制曲线中的摆动量,考虑到季节性波动引起的数据周期性,将其设置为 6 可能是有意义的。

我希望这篇文章已经帮助你掌握了高斯过程的一些关键数学特征。正如我在开始时提到的,它绝不是完整的,甚至是正确的,所以请指出任何错误或有用的指示。我发现这是一个学习和展开讨论的好方法。

问题

我对高斯过程相当陌生,实际上我自己也有不少问题,如果有人读到这里,觉得他们可以启发我,并为其他人提供更多内容,请评论。

  1. 当我试图拟合温度,然后绘制它们顶部的标准偏差时,最初我没有将数据标准化。在我看来,标准偏差需要进行缩放,是这样吗?
  2. 在我看来,高斯过程更适合填补数据点之间的空白,而不是推断遥远的未来,这是正确的吗?

资源

  • 凯瑟琳·贝利关于 GPs 的一篇精彩的帖子
  • Neil Lawrence 在 MLSS 的演讲记录
  • Chris Fonnesbeck 的另一篇好文章,代码清晰示例
  • 牛津大学工程科学和天体物理学系的详尽的课程笔记。

GCNet:非局域网络与压缩激励网络相遇及超越综述

原文:https://towardsdatascience.com/gcnet-non-local-network-meets-squeeze-excitation-network-and-beyond-review-f3f3e4035e4d?source=collection_archive---------29-----------------------

在进入 GCNet 之前,我们首先需要了解两个网络:非局域网络压缩-激发网络。我们不会得到太多关于这些网络的细节。一旦我们有了基本的概念,我们就可以进入主要的话题,GCNet。

非局部神经网络

该网络受非局部均值滤波器的启发。该滤波器用于随机降噪任务。图像中的这些噪声可以通过取具有随机噪声的其他多幅图像的像素平均值来减少。然而,在真实世界场景中,获取具有随机噪声的多个图像是困难的。我们通常得到的是带有随机噪声的单幅图像。

为了解决这个问题,采用了非局部均值滤波。代替具有随机噪声的多个图像,可以使用位于不同区域的类似补片来计算平均值。如上图所示,图像补丁 p 与其他图像补丁( q1q2) 类似。这些补丁可以用来去除补丁 p 中的噪声。

受这个想法的启发,NLNet 的作者提出了一个非本地块。该块计算像素之间的所有相互作用,为此,网络执行多次权重整形和乘法以产生嵌入的特征表示。

如图所示,如果块获得 T x H x W x 1024 作为输入(T 代表时间戳,因为原始论文的目标是视频分类),它会产生相同大小的特征图。执行矩阵整形、乘法和逐元素加法来捕捉像素之间的全局依赖性。

要了解更多关于这篇论文的信息,请阅读原文这里。

挤压激励网络

与 NLNet 相比,压缩激励网络解决了一个不同的问题。NLNet 试图捕获像素之间的全局相关性,而 SENet 试图捕获通道间的相关性。SENet 背后的主要思想是在每个特征映射通道中添加参数。通过这样做,网络自适应地学习特征图中通道的权重。

挤压激励模块将特征图作为输入。首先减少特征图的空间维度(W x H x C ),以应用两个完全连接的层。与输入要素通道大小相同的最终矢量被转换为 s 形图层,以根据其重要性缩放每个通道。

要了解更多关于这篇论文的信息,请阅读原文这里。

GCNet

全球背景网络有三个主要想法。

简化的非局部块:作者提出了非局部块的简化版本。简化版本计算全局(独立于查询的)注意力图,并共享所有查询位置的注意力图。这种变化是在观察不同查询位置产生的相似注意力图后做出的。

此外,块中的 W_v 被移出注意池以减少计算成本。在遵循关系网络论文中的结果之后,权重 W_z 也被移除。

全局上下文建模框架:全局上下文网络中使用的主块(上图中的 a)可以分为三个过程:首先,全局注意力池,采用 1x1 卷积和 softmax 函数来获得注意力权重。然后应用注意力池来获取全局上下文特征。一旦应用了注意力集中,输出特征通过 1x1 卷积被转换,并且它们被聚集以将全局上下文特征添加到每个位置的特征。

全局上下文块:如上图所示,全局上下文块与挤压激励块一起使用了一个简化的非局部块。对模型进行了一些调整,以减少参数的数量。例如,在图中所示的挤压激励块中,1x1 卷积被瓶颈变换模块代替。而不是有 CxC 参数,数量减少到 2CC/ r ,其中 r 是瓶颈比,C/ r 是瓶颈的隐藏表示维度。

结果

实验在目标检测和分割任务中进行。上表比较了不同的架构设计。作者观察到,添加全局上下文块明显提高了模型的性能。

此外,需要注意的一点是,参数/触发器的数量不会急剧增加。这可能是因为 NL 数据块和 SE 数据块都设计了轻量级体系结构。

结论

该论文成功地结合了两种思想,并提出了一个优于现有基线网络的模型。作者通过提出 NL/SE 块的简化版本来解决长程相关性问题。通过仅添加少量参数,该模型在对象检测和识别任务上优于现有模型。

参考

[## GCNet:非局域网络与压缩激励网络相遇及超越

非本地网络(NLNet)提出了一种开创性的方法,通过聚集…

arxiv.org](https://arxiv.org/abs/1904.11492) [## 非局部神经网络

卷积运算和递归运算都是一次处理一个局部邻域的构建块。在这个…

arxiv.org](https://arxiv.org/abs/1711.07971) [## 压缩和激励网络

卷积神经网络(CNN)的核心构件是卷积算子,它使网络能够…

arxiv.org](https://arxiv.org/abs/1709.01507) [## 非局部神经网络

이번포스트에서는한동안·arxiv-sanity.com·에서상위권에머물었던·明凯·he의2017년11월에공개된논문,“非本地神经 Networks'를 소개 드리도록 하겠습니다…”

博客. lunit.io](https://blog.lunit.io/2018/01/19/non-local-neural-networks/) [## 用于对象检测的关系网络

尽管多年来人们普遍认为对物体之间的关系进行建模有助于物体识别,但目前仍存在一些问题

arxiv.org](https://arxiv.org/abs/1711.11575)

极客女孩崛起:神话还是现实

原文:https://towardsdatascience.com/geek-girls-rising-myth-or-reality-81e1897433c8?source=collection_archive---------16-----------------------

2019 年 Kaggle ML 和 DS 关于机器学习和数据科学领域女性代表性的调查分析

Designed by rawpixel.com / Freepik

巴拉克·奥巴马:在女性充分参与国家政治或经济的地方,社会更有可能成功

最近参加了 2019 Kaggle ML & DS 调查 挑战赛。这是第三年的调查,旨在提供数据科学和机器学习状况的全面视图。这项挑战面向所有人,讲述数据科学社区独特而有创意的故事的笔记本电脑将获得奖励。挑战描述说-: " 挑战是(通过数据)深入探索数据科学和机器学习实践者的特定群体的影响、优先事项或关注点

这对我来说是一个绝佳的机会,让我可以参与挑战,探索 w.r.t 全球女性参与调查的情况。笔记本的目的是分析调查数据以回答一个重要问题: 女性参与 STEM 的情况真的有所改善,还是只是一种炒作?我运用我的分析技巧来调查事情是否有所改善,或者是否还有很多事情要做。

我还获得了 2019 年 11 月 19 日之前发布的所有笔记本的最佳笔记本奖。

这篇文章是我在分析数据集时获得的结果和见解的总结。点击可以查看 Kaggle 笔记本原文。

方法学

我在六个不同类别下分析了女性参与调查的情况,即:

分析这些不同类别下的妇女代表情况,让我对妇女代表在 ML 和 DS 领域的性质有了一个公平的想法。

我首先分析了 2019 年调查的数据集,以了解整体情况。

2019 年受访者最多的国家

  • 大多数受访者(男性和女性)来自印度,事实上紧随其后的是美国;这些国家加起来占总人口的 50%以上。

请注意,如果某个国家或地区收到的调查对象少于 50 人,他们将被分组到名为“其他”的匿名组中。

历年答卷人数比较

  • 尽管 2018 年的回复数量远高于 2017 年,但 2019 年有所下降。

现在让我们看看从六个关键领域的分析中获得的见解——性别、国家、年龄、教育、职业经验和工资。

1.性别

PC: rudall30

巨大的性别差异

  • 在调查中,男性和女性受访者之间有着惊人的差异。大约 82%的受访者是男性,只有 16%是女性。

历年性别分布情况

与过去两年相比,2019 年的性别分布情况。

  • 嗯,模式差不多。多年来,女性受访者的参与率一直很低。

2.国家

PC: Freepic.com

现在让我们看看女性受访者来自哪些国家。这些数据将有助于我们了解反应最大和最小的国家。

女性受访者所在国家

  • 2019 年大多数女性受访者来自印度和美国。
  • 来自中非的参与比例令人震惊,尽管像尼日利亚这样的国家确实在世界地图上显示了它们的存在。
  • 来自土耳其、尼日利亚和巴基斯坦的女性也对调查做出了回应,尽管她们所占的比例很小。

这些年来印度和美国的女性受访者

由于印度和美国的受访者比例最高,我也分析了这些数据,看看过去几年是否也观察到了类似的趋势。

  • 2017 年和 2018 年,美国女性受访者的数量远高于印度。然而,2019 年印度女性受访者有所增长,其比例超过了美国女性。

非洲仍然存在巨大的障碍

  • 与前几年相比,2019 年回答调查的非洲女性人数有所增加。2019 年,约有 150 名女性回答了调查,而在此前几年,这一数字甚至不到 100 人。
  • 探究 2019 年非洲次大陆参与度增加的原因很有意思。首先,很少有阿尔及利亚女性在 2019 年首次参加调查。其次,与前两年相比,2019 年观察到尼日利亚女性受访者人数激增。这两个因素都促使非洲女性在 2019 年的调查中表现更好。

3.年龄分布

PC: www.freepik.com

年龄是任何人口统计分析的一个重要属性,在分析年龄变量时获得了一些有趣的结果。

年轻的旅在 2019 年占据主导地位

2019 年女性受访者的年龄分布。

  • 大多数女性受访者属于 (25 -29) 年龄组,紧随其后的是(22-24)年龄组。因此,大多数女性处于(20-30)年龄段。
  • (20–30)年龄组可以包括学生(本科生和研究生)和专业人士。
  • 有趣的是,60 岁和 70 岁以上的女性也对调查做出了回应。嗯,正如人们所说——年龄只是一个数字。

历年的年龄分布模式

  • 没有观察到模式的显著变化。总的来说,20-30 岁的群体在调查中占主导地位。

国别年龄分布

  • 印度大多数女性受访者是 20 多岁的女性,这一比例也高于其他任何国家。因此,来自印度的女性受访者主要是年轻人。
  • 此外,印度有相当数量的 18 至 21 岁的女性受访者。这个年龄组通常由学生组成,看到他们参与调查令人振奋。
  • 对于美国女性来说,学生受访者的比例相对较低。至于其他国家,各年龄组的分布几乎相同。

4.教育

PC: www.freepik.com

有人说得对,受过教育的女性是社会的支柱。以下是对女性受访者资格状况的分析。

2019 年女性受访者的学历

  • 女性的教育状况令人印象深刻,大多数人(~46%)拥有硕士学位,紧随其后的是学士学位(27%)。16%的博士回答了调查。
  • 分析还显示,有一定比例的人高中毕业后没有接受过正规教育。尽管如此,他们还是参加了调查,这本身就是一件值得称赞的事情。

按国家分列的女性受访者的教育资格

  • 美国 T1 拥有最多的 T2 硕士学位,T4 T3 和 T5 拥有博士学位,紧随其后。然而,应该记住的是,印度和其他国家的许多女性一般都是为了获得硕士和博士学位而移民到美国的。
  • 印度拥有最多的学士学位。这一点非常明显,因为大多数女性受访者都是 20 多岁的学生。
  • 除了专业学位出现率较高的日本之外,所有国家的硕士学位普遍高于其他学位。

5.专业经验

PC: www.freepik.com

让我们看看女性在行业中所扮演的各种职业角色。

多年来女性受访者的角色

  • 自 2017 年以来,数据科学家似乎是女性受访者的主要角色,其次是数据分析师。开发人员、研究人员和项目经理等其他角色也可以在人群中看到。

2019 年女性受访者的 20 大角色

  • 如果我们从结果中排除学生,数据科学家(约 19.5%)构成了参加调查的大部分人口。紧随其后的是从事数据分析师工作的女性(约 11%)。
  • 有趣的是,一些妇女没有工作,但对调查做出了回应。这些妇女不可能选择工作,也不可能寻找工作。我们可以联系这些女性,了解她们是否愿意工作,并帮助她们。

女性受访者目前的角色

我结合了一些角色来创建更广泛的群体。例如,数据工程师和 DBA/数据库工程师与数据分析师和业务分析师混在一起。

  • 同样,排除学生,美国参与调查的数据科学家和数据分析师人数最多,其次是印度。
  • 印度参与调查的软件工程师人数最多。有趣的是,失业女性受访者的比例(~<2%) was also the highest in India.

Female Data Scientists distribution over the years

  • Even though the percentage of female respondents had decreased in 2019, the percentage of Data Scientists who took the survey was more significant than in 2018.

6. Salary

Even though someresearch相反,薪酬是留住和获得新人才的一个重要激励因素。让我们看看我们的女士在数据科学领域的薪酬有多高。我分析了 2019 年女性受访者工资的大致趋势,然后将趋势与 2018 年的工资进行了对比。

2019 年女性受访者薪资范围

  • 大多数女性受访者不愿意透露自己的年薪。剩下的人中,有 10%的人年薪不到 1000 美元。这是有道理的,因为其中很大一部分人是目前可能没有固定工作的学生。
  • 也有一小部分女性年收入超过 20 万到 30 万美元。

2018 年和 2019 年女性受访者薪资对比。

为了了解这种工资模式是 2019 年独有的,还是一种反复出现的现象,我将它与 2018 年的工资范围进行了比较。我没有包括 2017 年的工资数据,因为它有十多种不同的货币。

  • 2018 年和 2019 年,薪酬分布的总体模式似乎相同。2019 年的年度薪酬比 2018 年略有改善,这很好。
  • 另一个关键点是,与 2018 年不同,2019 年确实有一些女性收入超过 50 万美元。

2019 年男女薪酬对比。

  • 男女工资的总体趋势保持不变。大多数人收入低于 1000 美元。然而,收入低于 1000 美元的女性比例高于男性。此外,与男性不同,没有女性受访者的收入高于 50 万美元

2019 年男女数据科学家薪酬对比

  • 与男性同行相比,收入低于 1000 美元的女性数据科学家的比例要高得多。女性数据科学家在高工资范围内的薪酬似乎也较低。收入超过 20 万美元的女性数据科学家的比例非常低。

全球女性数据科学家的薪水一览

  • 美国数据科学家的薪酬相对高于其他国家。

关键要点和建议

从整个练习中获得的一些重要收获可以总结为六个要点:

  • 妇女在这项调查中的参与率很低,而且这些年来没有显示出多大的改善。我们需要了解参与率如此之低背后的原因,以及我们如何才能鼓励女性变得更加积极参与。
  • 美国和印度女性的反应令人振奋,尽管与男性相比仍然很低。随着尼日利亚和阿尔及利亚等国家加快步伐,非洲显示出一线希望。组织应该与非洲政府和非政府组织合作,为这些妇女提供更好的学习和研究机会。
  • 数据科学领域的年轻女性人数正在上升,其中大多数来自印度。这并不奇怪,因为印度拥有世界上最年轻的军队之一。应该通过改革现有的印度教育模式并在当前课程中引入高质量的数据科学课程来有效利用这一人口红利。
  • 科学领域的女性素质很高,大多数拥有硕士学位。
  • 大多数女性数据科学家位于美国和印度。一些没有工作的妇女也对调查做出了回应。这可能有多种原因。他们可能是学生或女性,希望在休息后重新开始他们的职业生涯。后者可以通过参加聚会或社区活动得到帮助。对于学生来说,导师是一个很好的选择。
  • 薪酬分配多年来保持不变,但与美国同行相比,印度女性数据科学家的薪酬相对较低

结论

所以让我们回到最初的问题——极客女孩崛起了吗?真是百感交集。一些领域有所改善,但其他领域仍有大量工作要做。总的来说,事情似乎很有希望。

数据科学本身是不同科学学科的结合。让不同性别、背景和种族的人加入进来更有意义,他们可以带来更多的创造力,让知识、发现和创新蓬勃发展。

这需要社会的共同努力,使多样性和包容性成为生态系统的重要组成部分。作为女性,我们应该确保创建一个积极的支持小组来帮助数据科学领域的其他女性。毕竟,被赋予权力的女性赋予了女性权力。

GPT 的性别偏见-2

原文:https://towardsdatascience.com/gender-bias-in-gpt-2-acf65dc84bd8?source=collection_archive---------32-----------------------

一名男子和他的儿子遭遇了一场严重的事故,被紧急送往医院抢救。医生看着这个男孩,大声说道:“我不能给这个男孩做手术,他是我的儿子!”。这怎么可能?

答案?医生是男孩的母亲

我的回答…在为此纠结了一分钟后,我得出结论,这个男孩有两个爸爸。虽然我并不完全不喜欢我的答案(我们对异性关系有偏见),但我得出这个结论只是因为我的大脑无法计算医生是女性的想法。更糟糕的是,我研究算法偏差……这个问题是在“像我这样的女人”活动中提出的。

在社会中,偏见无处不在,存在于我们每一个人身上。当我们构建人工智能时,我们冒着做出反映这些偏见的东西的风险,并根据我们与技术互动的方式,加强或放大这些偏见。

OpenAI 在二月份发布了 GPT-2,这是一个生成语言模型,在互联网上掀起了风暴,部分是因为它创造了令人信服的合成文本,但也因为这种模型的安全性令人担忧。一个问题是偏见。

“我们预计安全和安保问题将在未来减少我们的传统出版,同时增加共享安全、政策和标准研究的重要性,” OpenAI Charter

九个月过去了,OpenAI 稳步遵循分阶段发布策略,仔细监控模型的使用,在他们的 6 个月更新中发布关于模型偏差的初步结果,现在(仅仅一周前!)发布完整型号。

在这篇博客中,我们将深入探讨 GPT 新协议中的偏见。具体来说,我们将着眼于职业性别偏见,如何与社会中预先存在的偏见进行比较,并讨论为什么语言模型中的偏见很重要。

这不是我第一次写 GPT-2。我写这篇博客是关于我用 GPT-2 写小说的经历。我觉得挺好的,但我可能有偏见。

结果

我们实验的目的是测量 GPT-2 中的职业性别偏见,观察这种偏见如何随着不同规模的模型而变化,并将这种偏见与我们社会中的偏见进行比较。我们的实验从“单词嵌入事实关联测试” (Caliskan 等人)中获得了一些灵感,这是一种类似于“隐含关联测试”的测试,但针对事实数据进行测量,即“事实关联”。我们的事实数据来自“国家统计局”(ONS)和他们的英国职业数据:一个大约 500 个工作类别的列表,每个列出了该职业的男女雇员人数和平均工资。

我们通过各种 GPT-2 模型(124 米、355 米、774 米和 15 亿个参数)运行了一系列提示,以衡量每个模型给国家统计局职业数据中各种职位的性别关联。

为了帮助你理解我们的实验,我想让你想象你在一个学校集市上。在集市上,其中一个摊位有一个装满软糖的罐子。上百个!几千,也许?无论如何都数不过来。你猜一猜,写在一张纸上,放在一个小盒子里,然后祈祷好运。

一天结束时,负责摊位的两个学生浏览了所有的猜测,他们注意到一些奇怪的事情。虽然这些人都不知道罐子里软糖的确切数量,而且每个猜出来的人对罐子里有多少颗软糖都有自己的偏见,但是如果你把所有的猜测加在一起并取平均值,你会得到一个非常接近罐子里软糖数量的数字。

就像果冻豆游戏的参与者一样,GPT-2 无法获得果冻豆的确切数量(或者说,它没有从国家统计局的数据中了解到社会偏见)。相反,我们正在观察 GPT-2 是否通过从很多人那里学习语言来反映社会偏见。

这是我们发现的!

图表中的 X 轴显示了英国不同工作的薪水。在 Y 轴上,我们测量性别偏见,大于 0 的数字表示男性偏见,小于 0 的数字表示女性偏见。就国家统计局的数据而言,它描绘了从事各种职业的实际人数及其工资。对于 GPT-2,我们正在研究 GPT-2 与同样的工作相关的性别偏见的强度。

GPT-2 的所有 4 个模型和社会数据显示,随着工作薪水的增加,男性倾向越来越大,这意味着职位越高,薪水越多,GPT-2 就越有可能表明男人在那个位置工作。国家统计局的数据还显示,在英国就业市场,这种对从事高薪工作的男性的职业性别偏见甚至比 GPT-2 更强烈。

随着我们给 GPT-2 增加更多的参数,这个趋势真的很有希望。我们在 GPT-2 中加入的参数越多,模型就越接近中性零线。该模型的 15 亿参数版本既最接近零,也具有最弱的梯度,表明随着工作薪水的增加,偏向男性的趋势最小。根据国家统计局的数据,在所有趋势线中,我们可以看到英国社会最偏向男性,并且随着工资的增加,表现出最明显的偏向男性的趋势。

通常,我们会期望一种算法通过输入更多数据或训练更长时间来更接近事实,但 GPT-2 似乎正相反。那么,这是为什么呢?

记得糖豆!GPT-2 从来没有得到国家统计局的数据来训练。相反,它已经从数百万在线用户的语言中学习。虽然每个人都有自己的偏见,这可能与社会真相有一定的距离,但总的来说,GPT-2 发现自己接近社会偏见是令人惊讶的。

GPT-2 不仅从个人偏见的平均值中学习,而且还从他们的语言偏见中学习。理解了这一点,我们可能会认为性别陈规定型的工作表现出不同的趋势。所以让我们试试…

在这张图表中,我们可以看到全部结果的一个子集,从中挑选出一些典型的与女性相关的工作。社会偏见的趋势比我们在上图中看到的更加接近。我们发现 776m 模型惊人地接近社会偏见,在模型中,像“护理助理”这样的角色与女性代词的联系比男性代词多 77.4%,在社会中多 77.3%。即使有这些老套的例子,15 亿参数模型仍然显示出性别中立的趋势。

一个公平的批评是,我们挑选了刻板的女性工作来支持一个假设。为“性别刻板印象工作”找到一个标准的分类器并不容易,网上的清单大体上是由其他人的判断组成的。为了尽可能公平起见,我们的选择是基于论文中的一个列表:男人对于电脑程序员就像女人对于家庭主妇一样?去偏置词嵌入' T1 '。我们从他们的“极端 she 职业”列表中选取了职位,排除了那些缺乏完整的 ons 统计数据的职位。基于我们团队的判断和我们所经历的刻板印象,我们还增加了一些职位名称(例如助产士和幼儿园老师)。

我们对男性刻板印象的工作重复了这一过程,再次发现 15 亿参数模型最接近中性。然而,在所有型号的模特中,这些角色几乎普遍存在男性偏见。

我们学到了什么?

你在提示中使用的词语真的很重要!

我们的第一课受到了我们在为模型创建可访问的职位时所面临的挑战的启发。为了帮助解释这一点,请和我一起快速玩一轮“单词联想游戏”。当你听到这些英国国家统计局的工作类别时,你首先想到的是什么?

学校午间过马路警卫?

邮政工人?

货车司机?

如果你和我一样,你会发现“学校午间交警”变成了“棒棒糖女士”,“邮政工人”变成了“邮递员”,“货车司机”变成了“开货车的人”。我们修改了许多英国国家统计局的职位名称,从那些明确但极不寻常的职位名称,改为我们期望在社会上听到的对等名称。国家统计局的分类太不寻常了,不能在新 GPT 协议中发挥作用,我们必须非常小心,不要在修改它们的过程中添加不必要的性别偏见。在我描述的三个“真实世界”的标题中,每一个都包含了对性别的明确提及,并将 GPT-2 推向了性别偏见。

有些情况下,每个职位都有男性/女性相关的工作,比如服务员和女服务员。国家统计局包含“服务员”类别的统计数据,女性比男性多 55.8%。当我们通过模型的 774m 参数版本运行时,我们发现服务员有 15%的男性偏见,而女服务员有 83.6%的女性偏见。总的来说,我们得到平均 34.3%的女性偏见,非常接近社会偏见。

解决办法?

考虑每个工作类别的中性词。我们不应该在招聘广告上登“场地管理员”,而应该登“场地人员”的广告。与其称某人为“绘图员”,不如称他们为“绘图员”或“制图员”。这同样适用于我们使用 GPT-2 的方式和我们自己写的东西。下面你可以看到“穿越守卫”的结果,它最清楚地证明了这一点。点击此处查看更多示例。

展望未来

虽然新 GPT 协议通常反映了现有的社会偏见,但我们对该技术的应用有可能加剧社会偏见。虽然随着模型尺寸的增加,性别中立的趋势是有希望的,但所有模型尺寸都继续显示出一定程度的性别偏见,这很重要,因为 GPT-2 可以以前所未有的速度生成可信的文本,可能没有人的监督。这不一定会增加社会偏见,反而会增加惰性,减缓朝着减少偏见社会的积极进展。在最坏的情况下,它可能会放大我们的偏见,使其对社会的影响更加极端。GPT-2 的偏见对我们社会的影响将取决于谁能获得这项技术以及如何应用它。这使得 OpenAI 分阶段发布并在公开发布之前分析其效果的决定尤其有价值。

自 2011 年 Siri 发布以来,数字助理大受欢迎,这为科技领域的性别偏见提供了一个严酷的教训。在联合国教科文组织的报告《如果我能,我会脸红》中,我们经历了数字助理性别偏见的现实。在 Siri、Alexa、Cortana 和谷歌助手中,我们看到数字助手被描绘成女性,她们屈从于用户对她们咆哮的命令,甚至把性挑逗当作笑话不予理睬。在数字助理表现不佳的地方(他们经常表现不佳),我们会在心理上将这种不佳表现与这些数字助理模仿的声音和角色的女性联系起来。我们现在刚刚开始看到数字助理中男性/女性选项的趋势,远离默认的女性,并逐渐增加性别中立选项的可用性。

联合国教科文组织的报告建议开发者和其他利益相关者监控数字助理对用户行为的影响,特别关注“儿童和年轻人的社会化”。正如我们可能希望限制儿童与女性数字助理的接触,以避免他们在女性和从属关系之间建立不健康的联系,我们也可能希望更加关注 GPT-2 和其他生成性语言模型的使用。GPT-2 本身没有角色,也不认同性别,但这只是微调模型并将其作为网站上的对话代理来实现的一小步,例如,以达到相同的结果。即使 GPT-2 没有表明性别,使用带有性别偏见的语言仍然会对我们的行为和年轻人的思想产生同样的影响。相反,联合国教科文组织的报告建议我们建立人工智能,以性别中立的方式回应查询。

在某些特殊情况下,我们应该限制 GPT 新协议的使用,例如在写招聘广告时,性别语言会影响申请者的多样性。带有性别偏见的语言模式可能会减缓缩小性别薪酬差距的进程,并放大我们在国家统计局数据中看到的男性在高薪工作中的主导地位。

在他们 6 个月的更新中,OpenAI 分享了一个积极的信息:自发布以来,他们几乎没有看到恶意使用他们技术的证据。虽然这肯定是一件好事,但我们仍然需要小心这项技术的善意使用。体验负面影响不需要有任何恶意,但只要小心,GPT-2 可以对我们的社会产生积极影响。

感谢让这一切成为可能的人们

没有一些伟人的贡献,这个实验是不可能的。我的 Sopra Steria 同事 Mark Claydon 提出了实验方法,管理所有后端集成并帮助处理数据。还要感谢艾莉森·加德纳和索克拉蒂斯·卡卡拉斯帮助构思实验并回顾我们的结果。

如果您想了解更多关于我们方法的信息,请点击此处。

I spent about 30 seconds making this because I figure some cover photo is better than nothing. Sorry!

男人之于医生,如同女人之于护士:词语嵌入的性别偏见

原文:https://towardsdatascience.com/gender-bias-word-embeddings-76d9806a0e17?source=collection_archive---------5-----------------------

为什么我们应该担心自然语言处理技术中的性别不平等

[© CalArts]

文化和语言,语言和机器

电梯里的性别

我想象你正和两个人一起走进医院的电梯:一男一女。他们穿着同样的白大褂,但他们的徽章被遮住了,所以你看不出他们在医院里是什么角色。在某个时刻,电梯门打开了,一位年轻女士跳出来说:“早上好,史密斯医生!”。你觉得哪个会去迎接她回来?

常识告诉我们两人都有可能成为史密斯医生,但是几项实验表明个人更有可能将女性与护理联系在一起,将男性与医生联系在一起。也就是说,你可能最终会把头转向那个穿白大褂的人,期待他说点什么。

If you are a sci-fi lover, you probably know that doctor Smith’s gender can’t be established without knowing which version of Lost in Space you’re referring to. [© Netflix, CBS]

语言反映了(不良)文化

性别陈规定型观念在我们的社会中仍然根深蒂固,由于有意识和无意识的性别偏见,女性在成长和生活中受到与男性截然不同的对待。

语言是性别歧视和性别歧视得以实施和复制的最强有力的手段之一。词汇选择和日常交流不断反映出这种长期存在的偏见,以至于语言本身被设计成反映社会不对称。例如,语法和句法规则是以这样一种方式构建的,即阴性术语通常源自其对应的阳性形式(例如 princ- ess ,god- dess 等)。)【梅内加蒂等人,2017 。同样,阳性名词和代词也经常与一个通用功能一起使用,既指男人也指女人(如 man- kind,states- men 等)。),经常被人认为是歧视女性。这些问题对大多数语言来说都是常见的,凸显了性别歧视是如何在全世界蔓延的,涉及到整个社会。

由于语言和文化是如此紧密地联系在一起,很容易理解对基于理解和处理人类语言的自动任务的危险暗示,从网络浏览器的自动补全到人工智能机器人(还记得微软的人工智能聊天机器人完全纳粹化的时候吗?)和查询结果排名。

让我们用一些技术性的细节来更深入一点(不涉及数学!).

Surprisingly (?) biased Google Search’s autocomplete suggestions from a 2013 query [© UN Women]

自然语言处理中的性别偏见:垃圾进,垃圾出

什么是自然语言处理?

自然语言处理(NLP)是人工智能(AI)的一个分支,它帮助计算机理解、解释和处理自然语言。
将 NLP 驱动的机器想象成能够理解和评估输入文档(即单词集合)的上下文的黑盒,输出有意义的结果,这些结果取决于机器被设计用于的任务。

Documents are fed into magic NLP model capable to get, for instance, the sentiment of the original content

就像任何其他机器学习算法一样,有偏见的数据导致有偏见的结果。就像任何其他算法一样,结果去偏置是非常恼人的,以至于去偏置社会本身可能更简单。

亲爱的人类:请停止性别歧视。
真诚的,你友好的邻居数据科学家。

现在,让我们看看性别偏见是如何通过 NLP 模型传播的。

大事:单词嵌入

W ords 必须表示为数值向量才能馈入机器学习算法。最强大(也是最流行)的方法之一是通过单词嵌入。在单词嵌入模型中,给定语言中的每个单词被分配给一个高维向量,使得向量的几何形状捕获单词之间的关系。例如,单词 king 的向量表示之间的余弦相似度将更接近单词 queen 而不是 potato。记住,余弦相似度就是两个向量之间角度的余弦,可以定义为:

因此,余弦相似度越高,向量方向越接近。让我们试着把它变成一个简单的 R 脚本,使用一个预训练的手套单词嵌入(你可以在这里找到它)。

> word_vec = read.csv('./glove.6B.300d.csv')> cosine_sim = function(v1,v2){
+    return(dot(v1, v2) / (sqrt(sum(v1^2)) * sqrt(sum(v1^2)))
+}> cosine_sim(word_vec["**king**",],word_vec["**queen**",])
[1] **0.67**> cosine_sim(word_vec["**king**",],word_vec["**potato**",])
[1] **0.23**

这些惊人的结果可以通过学习单词嵌入的方式来实现:遵循分布假设,嵌入以无监督的方式评估每个目标单词及其上下文(即出现在目标单词之前和之后的一组单词),建立和处理共现矩阵(手套)或输入巧妙设计的神经网络来解决单词预测任务( Word2Vec 和 FastText )。

为了完整地保留自然语言的语义,单词嵌入通常在大规模文本数据库上进行训练,如维基百科转储(600 万个英文页面)或谷歌新闻(约 1000 亿个单词),继承了我们之前指出的所有偏见。当然,特定于上下文的嵌入总是可以使用较小的数据集来学习。

国王和王后:单词嵌入实际上发挥了魔力

L et 的贴有国王王后字样。作为人类,我们知道国王是统治国家的皇家男性人物,而我们用单词 queen 来描述一个嫁给国王或独自领导一个王国的女人(queens 统治 king-doms…你能看到吗?).围绕国王和王后的语义关系对我们来说相当直接,但是对于一台不能理解字里行间含义的机器来说可能很难理解。单词嵌入允许机器捕捉(部分)这些类比和关系,包括性别。****

既然我们在谈论数字向量,我们可以简单地通过取 kingman 的向量表示之间的差来估计语义关系方向如果我们试图将女人向量投射到同一个方向,会发生什么?惊喜:我们得到了单词 queen
关于女王国王的女性的信息从未被直接输入到模型中,但模型无论如何都能捕捉到这种关系

2D representation of the semantic analogies between king, queen, man and woman

此时,你大概会猜到这件事会在哪里结束:如果我们试着对——比如说——职业——做同样的事情会怎么样?不出所料,这就是性别刻板印象真正出现的地方。

> get_analogy = function(v1,v2,v3){
+   x = v2-v1+v3
+   return(names(get_closest(x,word_vec))[1])
+}> get_analogy(word_vec["man",],
+              word_vec["doctor",],
+              word_vec["woman",])
[1] **"nurse"**

该死的。显然,我们的算法也经历了医院电梯的情况。

许多不同的职业都可以得到类似的结果。举个例子,如果我们试图得到男人:程序员* = 女人 : X 的类比,我们会不可思议地以 X = 家庭主妇告终。当然,单词程序员(以及单词家庭主妇)根据其定义是中性的,但是在新闻语料库上训练的嵌入模型倾向于认为程序员更接近,因为我们对这份工作的社会认知,这反映在我们使用的语言中。[ Bolukbasi 等人,2016 年 ]*

通过词云的性别偏见

当我们观察男人女人K-最近嵌入邻居时,更容易发现 S 存在。即使不看描述也能猜出两朵云的目标性别。

Word clouds for the nearest neighbours of “man” (L) and “woman” (R). Topic observed: “occupations”

子群中,我们可以找到像暴徒商人机械师、中尉屠夫警察这样的词。在女性子群中最相关的词中,我们看到的是助产士、护士、接待员、女服务员和……妓女这样的词。可怕。

甚至更可怕的结果可以被检索到将感兴趣的领域从职业切换到形容词。按照嵌入方式,男人有趾高气扬正派奸诈聪明绝顶谦逊。不出所料,女性反而被描述为时髦的性感的有品味的迷人的华丽的。**

我们真的只能用这个来形容一个女人吗?

Considering the first 200 closest adjectives to man or woman, 76% of them are referred to “man”. Within the remaining 14%, more than 50% are beauty-related terms.

你可以用这个令人难以置信的可视化工具亲自尝试一下,这个工具是在 2017 年微软新英格兰研究&开发中心举办的黑客歧视黑客马拉松上制作的。

性别偏见的人工智能在现实生活中的影响

鉴于自然语言处理中的性别偏见确实存在,即使只是出于伦理原因也应该避免,那么受刻板印象影响的人工智能对人类日常生活的影响是什么?换句话说,我们为什么要在乎呢?

在自动化系统的所有优点中,廉洁、敬业和尽职尽责的工作狂可能是最重要的优点之一。机器学习系统可以确定贷款资格而不受申请人种族的影响,它们可以提供信息 和服务而没有性别歧视,它们可以为公司招聘最佳候选人而不受他/她的性取向等的影响。
然而,当机器学习系统开始在预测中变得更像人类时,它们也可能开始延续人类行为,失去它们对人类的主要优势之一:不是人类

让我们考虑工作招聘的例子。我们希望设计一个 NLP 驱动的自动系统,根据候选人的动机信生成工作适合度分数。假设公司 HR 的数据库不够大,不足以训练自己的嵌入,我们决定使用维基百科上预先训练的 300 维手套词嵌入。
在激励函中找到积极形容词的几率很高,如
狡猾的聪明的聪明的,但是我们观察到,在预训练的嵌入空间中,这些术语更接近于男人而不是女人。此外,假设我们正在评估初级程序员职位的候选人,我们知道我们的嵌入不会被认为是性别中立的。
在这种情况下,如果模型成功检索到候选人的性别,它将在候选人选择过程中受到很大影响。

结论

G 安德不等式在我们的社会中仍然根深蒂固,机器学习算法的盲目应用有传播和放大原始上下文中存在的所有偏见的风险。实施这种令人不快的人类行为不仅非常不道德,而且可能在许多不同的决策场景中产生令人担忧的后果

如今,数据科学家正在努力解决这个问题,最终找到了非常聪明的去偏置策略 [ Bolukbasi 等人,2016 ][ Chakraborty 等人,2016 ],在保留嵌入的有用属性的同时,减少了性别极化。然而,我们应该非常小心地在每一个社会偏见不应该造成差异的环境中应用 NLP 技术。这样做将提高我们模型的效率,最终提高我们作为人类的自身。

参考资料和进一步讲座

在这里你可以找到我的主要资料,以及一些非常有趣的读物,如果你有兴趣深入研究单词嵌入和偏差消除,我建议你看一看。

  • 学习中性词嵌入
  • 单词嵌入量化了 100 年来的性别和种族刻板印象
  • 检查两百个情感分析系统中的性别和种族偏见
  • 男人对于电脑程序员就像女人对于家庭主妇一样?去偏置词嵌入
  • 男医生、女护士:潜意识成见难改
  • 哦,你是护士吗?医师性别偏见
  • 神经自然语言处理中的性别偏见
  • 语言中的性别偏见和性别歧视
  • 自然语言处理的简单介绍
  • 为什么你的 AI 可能是种族主义者

希望这篇博文能够强调李颖社会中的性别不平等,以及为什么我们应该担心 NLP 中的性别陈规定型观念。如果你觉得有帮助,请在评论区留下你的想法并分享!

*[## Tommaso Buonocore - Scrittore -走向数据科学| LinkedIn

查看世界上最大的职业社区 LinkedIn 上 Tommaso Buonocore 的个人资料。托马索有 3 份工作列在…

www.linkedin.com](https://www.linkedin.com/in/tbuonocore/)*

深度学习的性别推断

原文:https://towardsdatascience.com/gender-identification-with-deep-learning-ac379f85a790?source=collection_archive---------19-----------------------

名人的微调预训练卷积神经网络

Photo by Alex Holyoake on Unsplash

总结

我想建立一个从图像中推断性别的模型。通过微调预训练的卷积神经网络 VGG16,并在名人图像上训练它,我能够在测试集上获得超过 98%的准确性。该练习展示了设计预训练模型的架构以补充数据集特征的效用。

任务

通常情况下,人类可以很容易地分辨出上面照片中的男人和女人,但很难准确描述我们为什么会做出这样的决定。没有定义的特征,这种区分对于传统的机器学习方法来说变得非常困难。此外,与任务相关的特征并不是每次都以完全相同的方式表达,每个人看起来都有点不同。深度学习算法提供了一种在没有预定义特征的情况下处理信息的方法,并且尽管特征表达方式存在差异,但仍能做出准确的预测。在本文中,我们将把卷积神经网络应用于名人的图像,目的是预测性别。(免责声明:作者理解外貌与性别没有因果关系)

工具

卷积神经网络(ConvNets)提供了一种从原始图像进行预测的方法。该算法的一个特点是能够通过使用识别区别特征的过滤器序列来降低图像的维度。模型中的附加层帮助我们强调由过滤器识别的特征和分配给图像的标签之间的非线性关系的强度。我们可以调整与过滤器和附加层相关联的权重,以最小化预测分类和观察分类之间的误差。Sumit Saha 提供了一个更深入的解释:https://towardsdatascience . com/a-comprehensive-guide-to-convolutionary-neural-networks-the-Eli 5-way-3bd2b 1164 a53

有许多预训练的神经网络已经被训练来对从飞机到柯基犬的一系列图像进行分类。通过使用预训练模型的权重并根据我们的目的对它们进行微调,我们可以节省计算时间并克服一些采样不足。

资料组

CelebA 数据集包含超过 200,000 张名人的照片,这些照片标有包括性别在内的 20 个属性。图像是从肩膀以上开始的,所以大部分信息都在面部特征和发型上。

Example image available from CelebA

建模

特征抽出

我们将使用 VGG16 预训练模型,并对其进行微调,以最好地从名人图像中识别性别。

vgg=VGG16(include_top=False, pooling=’avg’, weights=’imagenet’,
input_shape=(178, 218, 3))

我们使用“include_top=False”来移除为识别 VGG16 被训练识别的一系列对象(例如,苹果、柯基犬、剪刀)而设计的全连接层,并且我们下载与 ImageNet 竞赛相关联的权重。

下表 1 显示了 VGG16 的卷积架构;对于所有的卷积,有数百万个权重,我们可以选择训练或保持冻结在预训练值。通过冻结模型的所有权重,我们有欠拟合的风险,因为预训练的权重不是为我们的特定任务专门估计的。相比之下,通过训练所有的权重,我们冒着过度拟合的风险,因为模型将开始“记忆”训练图像,这是由于高参数化的灵活性。我们将通过训练最后一个卷积块来尝试折衷:

# Freeze the layers except the last 5
for layer in vgg.layers[:-5]:
 layer.trainable = False# Check the trainable status of the individual layers
for layer in vgg.layers:
 print(layer, layer.trainable)

Table 1: Architecture of VGG16 model after turning final layers on

VGG16 模型中的第一个卷积块识别更一般的特征,如线条或斑点,因此我们希望保留相关的权重。最后的块识别更精细的尺度特征(例如,与飞机翼尖相关的角度),所以我们将训练那些给定名人图像的权重。

模型编译

在卷积提取特征之后,我们将在模型中添加两个密集层,使我们能够根据识别的特征对图像进行预测。您可以使用单个密集图层,但是附加的隐藏图层允许在对要素进行更复杂的解释的情况下做出预测。过多的密集层可能会导致过度拟合。

# Create the model
model = models.Sequential()# Add the VGG16 convolutional base model
model.add(vgg)

# Add new layers
model.add(layers.Dense(128, activation=’relu’))
model.add(layers.BatchNormalization())
model.add(layers.Dense(2, activation=’sigmoid’))

我们添加了一个批处理规范化层,它将缩放我们的隐藏层激活值,以减少过度拟合和计算时间。最后一个密集层对性别进行预测(表 2)。

Table 2: Custom Model Architecture

因为我们允许模型训练卷积层和密集层,所以我们将估计数百万个权重(表 3)。给定我们构建的网络的深度,为像随机梯度下降这样的优化器选择最佳的恒定学习速率将是棘手的;相反,我们将使用 ADAM 优化器,它可以调整学习速度,在训练中迈出更小的步伐。

model.compile(optimizer=’adam’, loss=’binary_crossentropy’, metrics=[‘accuracy’])

使用 Keras,我们将设置我们的数据生成器来支持我们的模型,并使网络适合我们的训练集。

data_generator = ImageDataGenerator(preprocessing_function=preprocess_input)train_generator = data_generator.flow_from_directory(
 ‘C:/Users/w10007346/Pictures/Celeb_sets/train’,
 target_size=(178, 218),
 batch_size=12,
 class_mode=’categorical’)validation_generator = data_generator.flow_from_directory(
 ‘C:/Users/w10007346/Pictures/Celeb_sets/valid’,
 target_size=(178, 218),
 batch_size=12,
 class_mode=’categorical’)model.fit_generator(
 train_generator,
 epochs=20,
 steps_per_epoch=2667,
 validation_data=validation_generator,
 validation_steps=667, callbacks=cb_list)

经过 6 个时期后,模型达到了 98% 的最大验证精度。现在应用于测试集。

测试

我们有一个每个性别 500 张图片的测试集。该模型将通过网络为我们提供每张图像的预测概率,我们可以简单地将这些概率的最大值作为预测的性别。

# obtain predicted activation values for the last dense layer
pred = saved_model.predict_generator(test_generator, verbose=1, steps=1000)# determine the maximum activation value for each sample
predicted_class_indices=np.argmax(pred,axis=1)

我们的模型预测名人性别的准确率高达 98.2%!这相当于人类的能力。

这个模型适用于非名人吗?让我们试试作者。这个模型在作者的近照上表现很好。

上面这张图片的预测概率是 99.8%是男性。

这位模特在作者年轻、头发蓬乱的过去也做得很好;它预测 98.6%是男性。

结论

这个练习展示了微调预训练 ConvNets 的强大功能。每个应用程序都需要不同的方法来优化建模过程。具体来说,模型的架构需要以补充数据集特征的方式进行设计。佩德罗·马塞利诺对调整微调过程以适应任何数据集的一般规则做了很好的解释:https://towardsdatascience . com/transfer-learning-from-pre-trained-models-f 2393 f 124751

我感谢对这项工作的任何反馈和建设性的批评。与分析相关的代码可以在 github.com/njermain 的找到

Kaggle 上数据科学家的性别薪酬差距

原文:https://towardsdatascience.com/gender-pay-gap-among-data-scientists-on-kaggle-87b393aa21fe?source=collection_archive---------14-----------------------

美国和印度的性别薪酬差距一样吗?

Pixabay.com

2012 年,数据科学家被《哈佛商业评论》评为 21 世纪最性感的工作。从那以后,数据科学领域发展了很多,也发生了很多变化。但是,这份如此现代的工作避免了困扰许多传统工作的性别薪酬不平等吗?

数据科学平台 Kaggle 最近在 2018 年机器学习和数据科学调查中对其全球用户群进行了调查。近 24,000 个回复让我们对这个问题有了深入的了解。

谁是调查对象?

调查答复主要来自美国和印度,中国远远排在第三位:

这三个国家的大多数受访者都是男性。大约 23%的美国受访者是女性,而印度和中国的女性受访者比例分别为 15%和 16%。

进一步研究不同国家男性和女性受访者的年龄差异显示:

  • 在美国,25-29 岁是男性和女性最常见的年龄范围,平均年龄为 33 岁。
  • 50 岁及以上的受访者大多是美国男性——这一年龄范围在美国女性中的代表性不足。
  • 中国受访者的平均年龄为 26.4 岁,略低于印度 26.6 岁的平均年龄。
  • 印度男性受访者的年龄分布显示,最年轻的年龄组(18-21 岁)比任何其他年龄组都更常见,而对于印度女性来说,22-24 岁的年龄范围更普遍。

按国家和性别划分的收入水平如何?

调查参与者报告了他们的收入,用美元表示了一个范围。

一些受访者报告的年薪超过 20 万美元,但特别是在印度和中国,年薪大多低于 5 万美元。美国的平均年收入为 10 万美元,印度和中国的平均年收入约为 2.2 万美元(由于括号中的数据为工资,因此每个受访者的括号中均为中间值)。如果将非常高的工资从样本中剔除,那么中国和印度的平均工资将比美国还要低。

Note that the amounts below zero are an artifact from trying to plot a smooth curve. The lowest reported salary range was 0–10,000 USD and that range was encoded as 5,000 USD.

将每个国家的数据按性别分类显示:

  • 中国女性的薪酬分布比男性更窄,平均水平似乎也更低。
  • 印度男性受访者的收入分布范围比女性受访者窄。
  • 美国男性调查者的薪酬分布显示了一个较高的中心点,约为 10 万美元,范围超过 20 万美元,而美国女性的薪酬分布在 10 万美元以上急剧下降。

按国家和性别划分的工资分布似乎表明,男性收入高于女性。这种性别薪酬差距与其他地方的研究结果一致。

女性数据科学家的工资比男性低吗?

到目前为止,我们已经查看了所有对调查的回复。调查受访者报告了各种各样的职称、教育程度、工作经验年限和使用的工具。我们需要更仔细地剖析这些数据,这样我们就不会将一位 50 多岁的印度男性首席执行官与一位印度女数学系学生进行比较,然后得出他比她挣得多的结论(他很可能会这么做)。

Kaggle 调查中有一个问题可以帮助我们关注数据科学家。Kaggle 问每个参与者“你认为自己是数据科学家吗?”。

印度女性在“可能是”群体中有所下降,但除此之外,我们还有数百人认为自己在“是”群体中属于美国和印度。每一组中中国女性的数量都要少得多,因此我们未来将专注于美国和印度。

现在,我们有了尝试回答男女之间是否存在薪酬差距这一问题的所有要素——我们将研究将自己列为数据科学家的个人,并比较他们的薪酬、年龄、性别和国家。在一个可视化中包含了很多维度:

  • 下面您会看到四个图表(左栏是美国,右栏是印度,最上面一行是将自己列为“可能”“肯定”是数据科学家的个人,底部显示只是是“肯定”数据科学家的个人)。
  • 每张图表都以等高线图的形式显示了年龄与收入分布的关系——“峰值”是大部分值所在的位置。
  • 为了便于比较,男性和女性的回答重叠在一起,女性的回答用蓝色轮廓线表示,而男性的回答用橙色实线表示。
  • 要比较男性和女性,只需比较每个图中橙色和蓝色的“峰值”,并注意分布如何不同。

请注意,平滑的线条给人以极其详细和丰富的数据的印象,但我们已经进入了数据集的一些相当稀疏的区域(例如,在 45-50 岁的年龄组中,只有三名印度女性认为自己“绝对”是数据科学家)。尽管如此,等高线图的总体形状应能让我们对数据有所了解:

Each chart is showing the most relevant ranges on Age and Pay — ie some of the highest incomes are not shown but they were included in the analysis. Number of respondents in each chart quadrant: upper left: 1,242 men and 352 women, lower left: 669 men and 172 women, upper right: 908 men and 117 women, lower right: 435 men and 79 women.

很难估计受访者在将自己归类为“可能”或“肯定”数据科学家时的自信程度。性别之间和国家之间也可能存在文化差异。在本次分析中,我们将重点关注那些有信心认为自己“绝对”是数据科学家的人,因此,让我们试着理解我们可能从最下面一行的图表中推断出什么:

来自美国的 20 多岁的女性数据科学家回应了 Kaggle 的调查,似乎比他们的男性同行挣得多一点。但是对于年龄较大的男性来说,工资似乎高于女性(30-35 岁年龄组的工资范围更高,扩展到 15 万美元以上)。

来自印度的男性和女性自我分类数据科学家之间的薪酬差距似乎很小(分布的总体形状相当相似)。在相同的薪酬范围内,大多数男性印度数据科学家似乎比女性年轻几岁(男性和女性的高峰期相差 2-3 岁)。

包装它

我们研究了一个包含近 24,000 份调查反馈的丰富数据集。一旦我们将数据按国家、作为数据科学家的自我分类和性别进行了划分,我们就能够按年龄对男性和女性的自我报告的薪酬数据进行比较。

对数据的分析表明,回答 Kaggle 调查的美国老年男性数据科学家比他们的女性同行挣得更多,收入范围更广。印度男性和女性数据科学家之间的薪酬差距似乎不那么明显。

我们能从这里去哪里?关于美国和印度之间更大的社会经济趋势和差异,这告诉了我们什么?薪酬差距在成熟经济体或行业更明显吗?

查看这些文章了解更多:https://www . aauw . org/research/the-simple-truth-about-the-gender-pay-gap/和https://www.payscale.com/data/gender-pay-gap

如果你喜欢这个帖子,请鼓掌。这篇文章也发表在我的网站上:http://flo lytice . com/blog/gender-pay-gap-in-data-scientists-on-ka ggle。

这篇文章的分析和图形是用 Python 制作的。

你可以在这里找到 Github 上的完整项目:https://github.com/Lindstaedt/Kaggle-2018-Survey-Analysis

来自 Kaggle 的原始数据集在这里:https://www.kaggle.com/kaggle/kaggle-survey-2018/

泛化界限:依赖你的深度学习模型

原文:https://towardsdatascience.com/generalization-bounds-rely-on-your-deep-learning-models-4842ed4bcb2a?source=collection_archive---------12-----------------------

你的深度学习系统对新数据会有怎样的表现(泛化)?它的性能能差到什么程度?评估算法的概括能力是建立信任和依赖人工智能系统所必需的。

Can you trust your AI? Will your AI go binge drinking or try to destroy the world once it goes live? (image source: https://unsplash.com/photos/0E_vhMVqL9g)

TL;DR —传统方法(VC 维、Rademacher 复杂性)无法提供可靠、有用(足够紧密)的泛化界限。如果网络压缩与泛化边界的估计齐头并进会怎样?那是一张中奖彩票!

为什么统计学习理论很重要?

确保一个算法一旦上线就能按预期执行是必要的:人工智能系统需要安全可靠。证明人工智能算法的性能对于推动采用和信任是必要的[5]

此外,理解算法的泛化属性是政策制定者的要求,正如欧盟委员会发布的可信人工智能(AI)道德准则所强调的[0]。

尽管如此,不幸的是,模型的泛化特性(泛化理论)的研究仍然是一个投资不足的研究领域。在训练、验证和测试集中拆分数据已经成为进行的标准方式,并且通常被认为是进行的唯一方式。然而,对于我们无法量化算法的泛化能力来说,在测试(保留)集上估计算法的泛化属性的想法可能只是一个聪明的变通办法;这是一个棘手的过程,使我们暴露在泄漏的风险中,并需要额外的独立性假设(参数从维持集独立选择),这已被 p-hacking [20] 等实践所混淆

什么是泛化?

我们的主要工作假设是,数据是由一个潜在的、未知的分布 D 产生的。统计学习不是直接访问分布,而是假设给我们一个训练样本 S ,其中 S 的每个元素都是 i.i.d .并根据 D 生成。学习算法从函数空间(假设类) H 中选择一个函数(假设 H),其中 H = {f(x,α)}其中α是参数向量。

然后,我们可以将假设的泛化误差定义为从分布 D 中选取的样本 x 的误差期望值与经验损失(给定样本 S 的损失)【4,11】之差

我们的工作是给泛化误差上界:它能有多坏?

传统方法:模型容量

在一般化理论的传统方法中,一般化的能力由假设类 h 的复杂性(容量)来建模。粗略地说,类的“容量”是它可以(似乎)很好地适合多少不同的数据集。高容量模型类更灵活,但也更容易过度拟合。[..产能控制是一门艺术,它使用足够灵活的模型以获得良好的适应性,而不使用过于灵活以至于过度适应的模型

我们如何定义一个假设类的复杂性 H ?传统的泛化理论概念包括 VC 维、Rademacher 复杂度和 PAC-Bayes 界。

VC 维与死亡神经元

VAP Nik–Chervonenkis(VC)维度是一种通过评估其成员的波动程度来衡量一类函数的复杂性的方法:类 H 的 VC 维度被定义为可以被 H 的成员分解的最大点数。如果一组点被一类函数分解,不管我们如何给每个点分配一个二元标号,这个类中的一个成员可以完美地分离它们。[5]

Figure 1 — Ballooning number of parameters — yet the test error does not explode [1]

张等人【7】的实验表明,20 多年前 Bartlett 的 VC 计算(节点数 #层数)*【2】对基于现实数据训练的深度网络的真实“参数复杂性”(当然现在没人知道)。

这可能并不令人惊讶,例如,根据 死神经元 : 当网络的规模足够大并且非线性被选择为 ReLU 时,许多权重为零【13】。

那么,我们如何估算一个模型的风险值呢?

PAC 可学习性和 Rademacher 复杂性

大概近似正确(PAC)可学习性的定义很简单:有一个算法,对于每个分布 d 和є,δ > 0,找到一个概率为 1-δ的“є-optimal”假设。每个分布都有一个算法是一个很强的要求:Rademacher 复杂度是为一个特定的未知分布定义的 D

A sketched derivation of the Rademacher complexity based on [23]

简而言之,Rademacher 复杂度测量假设类 H 适合随机 1 二进制标签的能力。如果与 VC 维相比,Rademacher 复杂度是分布相关的,并且是为任何一类实值函数(不仅仅是离散值函数)定义的。

正如 Bartlett 的 VC 计算的情况一样,Rademacher 复杂性没有为深度学习提供有用的泛化界限。实证测试表明,事实上,许多神经网络与随机标签的训练集完美匹配,我们期望对应的模型类 h 具有几乎完美的 Rademacher 复杂性。当然,这是 Rademacher 复杂性的一个微不足道的上限,在现实设置中不会导致有用的泛化界限【7】。

换句话说,事情在理论上并不可行,我们只剩下“炼金术”和一些最佳实践:实际上降低如此复杂的学习架构的 Rademacher 复杂性的唯一方法是尝试训练一个分类器,并通过一个保留的集合来检测一般化的缺乏。世界上的每一个实践者都已经这样做了(没有意识到),张等人(【7】)强调理论目前没有提供更好的东西【2】值得称赞

走向新颖的方法

一般化理论的经典方法很难计算出今天复杂的 ML 模型,更不用说在设计学习系统时用作指南【2】。一般化理论的经典方法只是描述性的:换句话说,如果一般化没有发生,我们可以通过利用复杂性的度量来证明这一经验发现(VC 维度,Rademacher),但我们没有任何可以指导我们的规定性原则[2]。

此外,经验证据证明,假设类具有高,甚至无限的能力,可能在实践中工作得很好。这是真的,不仅对于深度学习模型如此,对于其他机器学习方法论也是如此:例如,具有某些核(例如:径向基函数)的 SVM 的特征在于无限的 VC 维。甚至更简单的线性模型也可以欺骗我们:过参数化线性模型的假设空间可以记忆任何训练数据,并在参数范数任意大的情况下,将训练和测试误差降低到任意接近于零(包括零),即使参数距离地面真实参数任意远【12】

深度学习将泛化理论的传统方法强调到了极致:**深度网络的一个主要难题围绕着没有过拟合,尽管存在大的过参数化,尽管随机标记数据上的零训练误差证明了大容量【1】。

复杂性的整体概念正在被重新审视。专注于深度学习,有许多新颖的概括方法。

基于规范的能力度量

一种方法是查看基于通过差值归一化的权重矩阵的范数度量的容量度量。数据样本的输出分类容限是模型分配给正确类别的值减去所有其他类别的最大值的差值。

Figure 2 — Note that path norms, sum over all possible paths going from the input to the output of the network, passing through one single neuron in each layer [14]

基于范数的度量并不明确依赖于模型中的参数数量,因此更有可能代表其能力 [14]: 基于范数的度量可以解释深度神经网络(DNNs)的泛化,因为在随机标签上训练的模型的复杂性总是高于在真实标签上训练的模型的复杂性,对应于后者的良好泛化能力 [14]

Figure 3 — Different complexity measures of a VGG network (a Convolutional Neural Network architecture) on CIFAR10 data. In all experiments, the training error of the learned network is zero. The plots indicate that these measures can explain the generalization as the complexity of model learned with random labels is always higher than the one learned with true labels. Furthermore, the gap between the complexity of models learned with true and random labels increases as we increase the size of the training set [22]

与基于范数的方法相关的另一个有趣的容量度量是网络的 Lipschitz 常数。Lipschitz 常数是权重矩阵的谱范数的乘积。谱范数是矩阵的最大奇异值:一个矩阵可以拉伸一个向量多少[9]。

经验证据表明,李普希茨常数与超额风险(测试误差减去训练误差)相关。然而,这一指标随着时间的推移而增长,尽管超额风险处于平稳状态[4];再一次,通过边缘的 Lipschitz 常数进行归一化,可以中和的增长(见图 4)

Figure 4 — AlexNet trained with SGD on cifar10 [4]

压缩方法

一般化的基本定理陈述了如果训练集具有 m 个 样本,则定义为训练数据和测试数据上的误差之差的一般化误差的顺序为 sqrt(N’/m)其中N’

取一个矩阵 C N 可训练参数并尽量压缩成另一个带较少参数的矩阵【C’(【N】)并且训练误差与*****大致相同)确实概括得好。【23,24】***

我发现压缩方法非常有吸引力。一方面,我们确定了 DNNs 的推广范围。另一方面,我们获得了广泛的实际和操作优势:

  1. 将较小的(经过训练的)模型部署到生产中有很多好处:较小的模型速度更快,消耗的能量更少(这在移动和嵌入式应用中很重要),占用的内存也更少。
  2. 最近的研究提供了一些被称为“彩票假说”的经验证据:随机初始化的密集神经网络包含一个子网络(中奖彩票),该子网络被初始化为当被隔离训练时,它可以在最多相同次数的迭代训练后匹配原始网络的测试精度 [16]。采用能够识别中奖彩票的训练策略意味着 a)更快的学习 b)更高的测试准确度 c) …)

除了“彩票方法”,还有许多其他有趣的网络压缩方法。我发现一个特别吸引人的想法是受张量网络的启发:这个想法“张量训练”DNN 的全连接层的权重矩阵已经显示了有希望的实证结果[17]。

[25]提供了网络压缩方法的调查,尽管这种压缩通常涉及重新训练压缩的网络,这是基于基本定理和[23,24]提供的压缩的一般化理论的方法没有考虑的。

结论

为了能够确保深度学习算法的可靠性,我们需要能够估计有用的(紧密的)泛化边界。这是一个开放的问题,传统的方法(VC dimension,Rademacher)无法提供答案,而新的方法正在开发中。

免责声明

这篇博文中所表达的观点是我的,并且仅是我的。错误和不准确也是如此。

参考

[0]https://EC . Europa . eu/futurium/en/ai-alliance-consultation/guidelines/1 # Robustness

[1] Poggio,Tomaso,等,“深度学习理论 III:解释非过度拟合难题。”arXiv 预印本 arXiv:1801.00173 (2017)。[ 链接 ]

[2]桑吉夫·阿罗拉(Sanjeev Arora),《一般化理论与深度网络导论》(2017) [ 链接 ]

[3] Desh Raj,学习理论导论—第 1 部分[ 链接 ]

[4]巴特利特、彼得·l、迪伦·j·福斯特和马图斯·j·特尔加斯基。"神经网络的光谱标准化边界界限."神经信息处理系统进展。2017.

[5]成长的烦恼——2018 年全球 CEO 展望[ 链接

6 Jordan Boyd-Graber,分类:Rademacher 复杂性,机器学习,第 6 讲,[ 链接 ]

[7]张、等,“理解深度学习需要反思概括。”arXiv 预印本 arXiv:1611.03530 (2016)。

[8]科斯马·罗希拉·沙莉兹,本科生能力控制,2012,[ 链接

[9]吉田、雄一和宫藤健。"谱范数正则化用于提高深度学习的泛化能力."arXiv 预印本 arXiv:1705.10941 (2017)。

[10] Boyd,s .,EE263 讲义(2015),奇异值分解[ 链接 ]

[11] Shawe-Taylor,j .和 Rivasplata,o .,“统计学习理论:搭便车指南”,2012 年,[ 链接 ]

[12] Kawaguchi,Kenji,Leslie Pack Kaelbling 和 Yoshua Bengio。“深度学习中的泛化。”arXiv 预印本 arXiv:1710.05468 (2017)。[ 链接

[13]维达尔、雷内等,《深度学习的数学》arXiv 预印本 arXiv:1712.04741 (2017)。[ 链接

[14] Jakubovitz,Daniel,Raja Giryes 和 Miguel RD Rodrigues。“深度学习中的泛化错误。”arXiv 预印本 arXiv:1808.01174 (2018)。[ 链接

[15] Rob Schapire,COS 511:理论机器学习讲义,第 09 讲,[ 链接 ]

[16]弗兰克、乔纳森和迈克尔·卡宾。"彩票假说:寻找稀疏的、可训练的神经网络."arXiv 预印本 arXiv:1803.03635 (2018)。

[17]诺维科夫,亚历山大等,“张量化神经网络”神经信息处理系统进展。2015.

[18]周、哈蒂等:“解构彩票:零、符号与超级市场”。优步工程博客帖子。2019.[ 链接

[20]巴格纳尔、亚历山大和戈登·斯图尔特。"证明真正的错误:Coq 中的机器学习与验证的泛化保证."(2019).【链接

[21] Neyshabur,Behnam,Ryota Tomioka 和 Nathan Srebro。"神经网络中基于规范的容量控制."学习理论会议。2015.[ 链接

[22] Neyshabur,Behnam 等人,“探索深度学习中的泛化”神经信息处理系统的进展。2017.

[23] Belkin,Mikhail 等人,“调和现代机器学习和偏差-方差权衡” arXiv 预印本 arXiv:1812.11118 (2018)。[ 链接

[23]巴斯卡拉,CS 5966/6966:机器学习理论,第 6 讲[ 链接 ]

[23] Arora,Sanjeev 等人,“通过压缩方法对深度网络进行更强的推广” arXiv 预印本 arXiv:1802.05296 (2018)。[ 链接

[24] Arora,Sanjeev,通过压缩证明深度网络的一般化(2018) [ 链接

[25]程,于等.深度神经网络模型压缩与加速综述 arXiv 预印本 arXiv:1710.09282 (2017)。[ 链接

深度强化学习中的泛化

原文:https://towardsdatascience.com/generalization-in-deep-reinforcement-learning-a14a240b155b?source=collection_archive---------9-----------------------

source

监督学习中的过拟合

机器学习是一门学科,在这门学科中,给定一些训练数据\环境,我们希望找到一个优化某些目标的模型,,但目的是在训练期间模型从未见过的数据上表现良好。这通常被称为概括,或者学习超出培训环境细节的有用知识的能力。

为了做到这一点,我们通常要求训练数据分布能够代表真实的数据分布,我们确实希望在这些数据分布上表现良好。我们将数据分为训练集和测试集,并尝试确保这两个集代表相同的分布。这在监督学习环境中很容易看到:

source

我们可以看到,虽然训练样本和测试样本不同,但它们是由相同的底层过程生成的。如果不是这样,监督学习中泛化的标准概念就不成立,并且很难证明我们的期望,即在训练集上的学习也应该在测试集上产生良好的结果。

机器学习中的一个常见挑战是避免过度拟合,这是一种我们的模型“太好”适应训练数据的细节和细微差别的情况,这种方式对它在测试数据上的性能是有害的。

在上面的例子中,我们可以看到一个正弦曲线(黑色曲线)给出了一个体面的近似数据。当我们将数据分为训练集(蓝色)和测试集(红色)时,我们看到试图“太好地”拟合训练集会导致橙色曲线,该曲线显然与黑色曲线非常不同,并且在测试集上表现不佳。

RL 中的过拟合

在强化学习中,事情有些不同。当考虑尽可能最好地玩一个 Atari 游戏的任务时,我们似乎不清楚如何区分一些训练环境和一个测试环境。如果我训练我的代理玩“突破”并且表现良好,这不就是我的目标吗?直到最近,RL 研究中一直是这种情况,大多数研究论文报告的结果都是在相同的环境下进行的。

第一个登上头版的 RL 作品是关于使用 ALE 环境学习玩 Atari 游戏的原始 DeepMind 论文。ALE 是确定性的,2015 年一篇名为的论文《街机学习环境:总代理评估平台表明,使用一种名为“Brute”的天真的轨迹优化算法,可以在一些游戏上产生最先进的结果。该算法甚至不知道在任何给定时刻的当前状态,但是它利用环境中的确定性来记忆成功的动作序列。这引起了人们的关注,一些习得的智能体可能在某种意义上“记忆”动作序列,并利用状态的细微差别来记住要采取的动作。**

神经网络策略记忆动作意味着什么?当学习玩一些游戏时,我们可能喜欢我们的策略来学习避开敌人,跳过障碍和抓住宝藏。具体来说,我们希望我们的策略跳过一个敌人,因为附近有一个敌人,并且爬上梯子到平台,因为它看到了平台上的宝藏。在完全确定的环境中,情况可能不是这样。我们的策略可能会了解到,由于背景墙上的某些视觉特征(如独特的瓷砖纹理或绘画),它需要在某个点跳跃,并且当它在某个遥远的平台上的某个位置看到敌人时,它会学习爬梯子。

这些特征与期望的特征同时出现完全是巧合,但是因为环境是决定性的,它们可能提供比我们希望我们的政策基于其决策的那些特征更强的学习信号。

source

随后的论文开始探索将随机性引入游戏的方法,以阻止代理记住动作序列,而是学习更有意义的行为。其他几篇论文表明,RL 策略对于它们学习的环境和它们预期部署的环境之间非常小的不匹配可能是脆弱的,这使得在现实世界中采用 RL 非常困难。我们希望我们的策略能够像在监督学习中一样一般化,但是这在 RL 环境中意味着什么呢?

RL 中的概括

RL 的目标通常被描述为学习马尔可夫决策过程(MDP)的策略,该策略使一些目标函数最大化,例如期望的奖励的折扣和。MDP 由一组状态 S、一组动作 A、一个转移函数 P 和一个奖励函数 r 来表征。当我们讨论一般化时,我们可以提出不同的表述,其中我们希望我们的策略在 MDP 的分布上表现良好。使用这样的设置,我们现在可以让代理在一组 MDP 上训练,并保留一些其他 MDP 作为测试集。

这些 MDP 在哪些方面有所不同?我认为有三个关键的不同点:

1.MDP 之间的状态在某些方面有所不同,但转换函数是相同的。例如,玩不同版本的视频游戏,游戏中的颜色和纹理可能会改变,但策略的行为不应因此而改变。

2.即使状态看起来相似,MDP 之间的基本转换函数也是不同的。这方面的一个例子是一些机器人操纵任务,其中各种物理参数(如摩擦系数和质量)可能会发生变化,但我们希望我们的策略能够适应这些变化,或者在可能的情况下保持稳健。

3.MDP 在大小和表面复杂性上各不相同,但是有一些基本的原则可以推广到不同大小的问题。这方面的例子可能是某些类型的组合优化问题,如旅行推销员问题,我们希望有一个策略可以解决不同大小的实例。(我之前写过关于组合优化的 RL

在我看来,这些代表了一般化挑战的主要来源,但是当然也有可能产生结合多个这样的来源的问题。接下来,我将集中讨论第一种类型。

最近,研究人员已经开始通过开发新的模拟环境来系统地探索 RL 中的泛化,这些模拟环境能够创建 MDP 的分布并拆分独特的训练和测试实例。这种环境的一个例子就是 CoinRun ,OpenAI 在论文中介绍了强化学习。这种环境可以产生大量具有不同布局和视觉外观的关卡,因此可以作为通用化的良好基准。**

source

在本文中,作者检查了几个变量对学习策略的泛化能力的影响:

训练集的规模:作者已经证明,增加训练 MDP 的数量可以提高泛化能力,这可以从以下方面看出:

source

正如监督学习中的情况一样,我们可以看到,增加训练“数据”的数量会使策略更难在训练集上成功,但会增加其推广到看不见的实例的能力。

神经网络的规模:这篇论文的另一个与监督学习的当前实践相呼应的发现是,较大的神经网络通常比较小的神经网络获得更好的泛化性能。作者使用了 DeepMind DQN 论文(他们将其命名为“自然-CNN”)中的“标准”卷积架构,并将其与 DeepMind 的 IMPALA 论文中提出的架构进行了比较。使用更大的模型结果明显更好。

source

正则化:监督学习中用来提高泛化能力的最常见的一套技术是 L2 正则化、剔除和批量归一化。这些技术通过添加噪声和减小权重的大小来限制神经网络的过拟合能力,并且已经成为监督学习中的标准。有趣的是,它们在深度 RL 文献中并不常见,因为它们的帮助并不总是显而易见。然而,在本文中,作者证明了这些技术确实有助于提高泛化性能。

总的来说,本文展示了一个很好的基准环境,并考察了监督学习的常见实践。但是我们能进一步提高泛化能力吗?

随机网络泛化

一篇名为深度强化学习中泛化的简单随机化技术的非常有趣的论文提出了一种比之前显示的标准正则化改进泛化的好方法。他们建议在输入图像和神经网络策略之间添加一个卷积层,以转换输入图像。这个卷积层在每集被随机初始化,并且它的权重被归一化,使得它不会过多地改变图像。这有点像数据扩充技术,自动生成更多种类的训练数据。****

source

神经网络策略被馈入该增强图像,并输出动作的概率,这在 RL 中是常见的。拥有各种视觉上不同的输入应该有助于模型学习更通用的特征,并且不太可能过度适应环境的视觉细微差别。这通常被称为域随机化,经常被用来帮助在 RL 的机器人应用中弥合模拟和现实之间的差距(我在另一篇文章中写过)。不幸的是,众所周知,域随机化会遭受高样本复杂性和策略性能的高变化。**

为了减轻这些影响,作者增加了另一项损失;特征匹配。这意味着我们给我们的模型一个原始图像和一个增强图像(使用随机层),并通过将它们之间的均方误差添加到损失中来鼓励它具有相似的特征。**

作为概念的证明,作者首先在一个玩具监督学习问题上尝试他们的方法;给猫和狗分类。为了使问题在泛化方面具有挑战性,他们用白狗和黑猫创建了一个训练数据集,并用黑猫和白猫创建了一个测试集。他们针对上一节提到的常见正则化方法以及图像处理文献中的一些其他数据增强技术测试了他们的方法。结果相当有趣:

source

在 RL 设置中,他们在几个问题中针对这些基线测试了他们的方法,包括 CoinRun,并在泛化方面取得了优异的结果。

他们进行了一项有趣的实验,以检查他们的技术是否确实创造了对视觉外观差异不变的特征,方法是在几个视觉上不同的变化中取一个样本轨迹,并将其馈送给未经他们的方法训练的模型和用他们的方法训练的模型。然后,他们使用维度缩减来可视化这些轨迹在不同模型中的嵌入:

source

数字代表轨迹中的阶段,颜色代表状态的视觉变化。很明显,使用新技术,状态在嵌入空间中更好地聚集在一起,这表明该模型确实已经学习了对这些令人分心的视觉变化更加不变的特征。

我认为这是一个非常有趣的研究方向,对于深度强化学习在工业中的广泛应用至关重要。希望看到更多这方面的研究。

理解机器学习中的泛化、正则化、过拟合、偏差和方差

原文:https://towardsdatascience.com/generalization-regularization-overfitting-bias-and-variance-in-machine-learning-aa942886b870?source=collection_archive---------6-----------------------

这五个术语如何定义机器学习中的“学习”

Photo by Scott Webb on Unsplash

如何知道机器学习模型是否真的在学习有用的东西?它不像看起来那么简单,绝对值得仔细研究。首先,这篇文章是关于机器学习的,例如,在经典书籍【T2 统计学习元素】中有解释。这些模型通常通过计算损失函数的导数并逐步向正确的方向移动其参数来学习,或一些类似的统计学习的想法。在这种情况下,“学习”实际上与人类的学习毫无关系。即使一些算法是受人脑的启发,它们的工作方式也非常不同。做出这一区分非常重要,因为“学习”一词可能会错误地暗示这种模型真的可以像人类一样“学习理解”它正在处理的数据——但事实并非如此。它唯一可以学习的是统计模式,不多也不少。

一般化

机器学习的最终目标是在训练集中找到统计模式,这些模式可以推广到训练集之外的数据。以下面这个简单的 NLP 问题为例:假设你想要预测一个序列中的一个单词,给定它前面的单词。

例如,序列“猫 __”之后可能是睡觉享受、想要。你的训练序列大概包括很多这样的名动组合,其他的可能是“她”、“一个专家”、“它好像”等等。注意,所有这些动词都有第三人称- s ,因为它们指的是序列的主语。一个好的语言模型确实可以获得这种模式,甚至可以对未经训练的序列做出正确的预测。例如,给定输入“飞机 __ ”,我们会期望模型预测离开的概率比离开的概率高,并且离开的概率比离开的概率高。在这种情况下,模型已经学习了一种更普遍适用的模式。竖起大拇指。然而这个模型不理解单词的意思,更不用说一般的语言了。例如,如果我们提供“theee plaaaane __”作为模型的输入,它将完全出错。

到底是学习吗?

规划学习过程通常是个好主意。首先,看一下培训损失。它应该接近零,或者至少是一个合理的低值(见下图)。如果不是,您的模型可能不是很合适,不够灵活,或者——这一点经常被忘记——输出不是输入数据的函数,因此没有要学习的关系。例如,想想一个句子是否真的是单词的函数。它可能不是无条件成立的,但在某些方面仍然是有用的。

Training loss should decrease with the number of training iterations (but not necessarily to 0)

什么是泛化 n?

如果训练损失确实如预期的那样减少了,这并不自动意味着无论模型学到了什么都是有用的。这就是验证损失发挥作用的地方。如果验证损失随着训练损失一起减少,情况看起来会好一些。在这种情况下,学习到的模式似乎会推广到看不见的验证数据。但是,验证损失通常会高于训练损失,因为并非所有模式都会泛化,如下图所示。

If validation loss decreases as well, the learned patterns seem to generalize.

偏见

偏差被定义为预测值和真实值之间的均方差。这是衡量模型与数据吻合程度的标准。零偏差意味着模型完美地捕捉了真实的数据生成过程。您的培训和验证损失都将为零。然而,这是不现实的,因为数据在现实中几乎总是有噪音的,所以一些偏差是不可避免的——称为不可约误差

无论如何,如果损失没有像预期的那样减少,这可能表明该模型不太适合数据。例如,如果您试图用线性模型来拟合指数关系,就会出现这种情况——它根本无法充分捕捉这种关系。在这种情况下,尝试不同的、更灵活的模型。

你也可以称之为不合身,尽管内涵略有不同。与偏差不同,拟合不足意味着模型仍有学习能力,因此您只需为更多迭代进行训练或收集更多数据。

重要的是,偏见也可能隐藏在训练数据中——这很容易被忽略。在那种情况下,你的训练损失可能会像往常一样减少。只有对真实数据的测试才能揭示这种偏差。

差异

如果一个模型的预测对输入的微小变化很敏感,则称该模型具有高方差。换句话说,你可以把它想象成数据点之间的曲面不是平滑的,而是非常起伏的。这通常不是你想要的。高方差通常意味着过度拟合,因为模型似乎捕捉到了随机噪声或异常值。

像高偏差和拟合不足一样,高方差和过度拟合也是相关的,但在意义上仍然不完全等同。见下文。

过度拟合

在模型训练期间的某个时间点,验证损失通常趋于平稳(有时甚至开始再次增加),而训练损失继续减少。这是过度拟合的信号。换句话说,模型仍在学习模式,但它们不会泛化到训练集之外(见下图)。过度拟合对于具有大量参数的模型尤其典型,例如深度神经网络。

Overfitting can happen after a certain number of training iterations.

训练和验证损失之间的巨大差距暗示模型不能很好地概括,您可能想要尝试缩小差距(下图)。解决过度拟合的最简单方法是提前停止,也就是说,一旦验证损失开始趋于平稳,就停止训练循环。或者,正规化可能会有所帮助(见下文)。另一方面,如果你过早停止,可能会出现不适应。

Generalization is low if there is large gap between training and validation loss.

正规化

正则化是一种避免高方差和过拟合以及提高泛化能力的方法。不涉及细节,正则化旨在保持系数接近于零。直观地说,模型所代表的函数更简单,不太不稳定。因此预测更加平滑,过度拟合的可能性更小(下图)。正则化可以简单到缩小或惩罚大系数——通常称为权重衰减。L1 和 L2 正则化是两种广泛使用的方法。但是你也可能遇到不同的形式,比如神经网络中的辍学正则化。

Regularization can help avoid high variance and overfitting.

综上所述,学习固然很好,但泛化才是我们真正想要的。就此而言,一个好的模型应该同时具有低偏差和低方差。过度拟合和欠拟合都应该避免。正规化可能是解决所有这些问题的一部分。

如果真实的情节与这里呈现的非常不同,不要感到惊讶。他们只是应该将概念形象化,并帮助理解它们。真实的损失曲线有时会以某种方式偏离。然而,知道在训练机器学习模型时要注意什么是很好的。

广义 Huber 回归

原文:https://towardsdatascience.com/generalized-huber-regression-505afaff24c?source=collection_archive---------13-----------------------

在这篇文章中,我们提出了一个广义的 Huber 损失函数,它可以与广义线性模型(GLM)结合,非常适合异方差回归问题。我们将讨论如何使用梯度提升树优化损失函数,并在人工数据集上将结果与经典损失函数进行比较。

让我们首先简要回顾一下休伯损失函数和广义线性模型(GLM)的基础知识。

Huber 损失和广义线性模型

Huber 损失[ Huber ]是回归问题的稳健损失函数,定义为

其中 y 是目标变量, ŷ 是相应的预测值, α ∈ ℝ⁺是超参数。人们很容易将这种损失视为潜在重尾误差分布的对数似然函数。事实上,对于小于 α 的绝对误差,相应的分布类似于正态分布,在该区域之外,它与更重尾的拉普拉斯分布一致。这正是这种损失对异常值稳健的原因。

这就是我们现在需要知道的关于 Huber 损失的全部情况。因此,让我们直接跳到 GLMs,通过首先记住线性回归的假设,可以最好地理解 GLMs。在线性回归中,人们通常假设因变量 Y 和某个特征向量 X 之间的线性关系中的误差项正态分布,均值为零,方差为常数σ,即y|x~x^⊤β+ε,ε ∈ 𝓝(0,σ)和β是一组变分参数。人们感兴趣的是找到最小化二次成本函数(对应于ε分布的对数似然)的最佳估计 β^hat 。对于给定的 X 的估计 ŷ 就是简单的ŷ(x)= e[y|x]=x*⊤*β*帽子*。请注意(在最大似然解释中), Huber 回归用一个更重尾的分布代替了正态分布,但仍然假设方差不变。

另一方面,GLM 方法以下列方式放松了线性回归的假设:

  1. 随机分量的非正态性:

2.由链接功能 g 引入的非线性:

指数族包含各种分布,尤其是方差是平均值的函数的分布,如泊松或伽马分布。这一特性特别适用于异方差问题,在这种情况下,误差项的恒定方差假设不再成立,例如,目标变量的范围跨越几个数量级的情况就很常见。链接功能通过贡献非线性效果额外地增强了模型的复杂性。还要注意的是,链接函数永远不会应用于 y。这与将模型拟合到转换后的目标变量的常见做法形成对比,后者通常会导致在预测被反向转换后低估平均值。这可以从詹森不等式中看出,该不等式陈述对于任何凹函数 g ,E[g(Y)|Xg(E[Y|X),对于对数或 Box-Cox 函数也是如此。还可以导出 GLM 似然函数的封闭形式的表达式,这导致了一大类损失函数,例如参见 P. Rigollet 对 GLMs 的精彩介绍[ MIT 。但是,在指数族内似乎不存在负支持度且方差非常数的连续分布。

因此,是否有可能将连接函数的概念与 Huber 损失结合起来,同时仍然具有非常数方差?下一节试图回答这个问题。

广义 Huber 损失函数

对于任何可逆函数 g : ℝ ↦ ℝ,我们将广义 Huber 损失(GHL)函数定义为

α ∈ ℝ⁺, y 目标变量和 ŷ 一些预测模型的连续输出。这里最重要的观察是,大小写的区分是在由 g (y)定义的“链接标度”上进行的,而范围是在原始标度上进行的。该损失函数不能转化为单变量问题[如等式(1)的情况]。然而,在固定的 ŷ_ 0 处,人们可能会将𝓛( yŷ_ 0)视为误差分布的对数似然函数𝓟( yŷ_0)~ exp(-𝓛(yŷ_ 0)。下面我们将进一步说明𝓟( yŷ_ 0)的方差是 ŷ_ 0 的(单调)增函数。

现在让我们讨论如果我们在等式(2)的右边取 g ( y )而不是 g ⁻ ( ŷ )会发生什么。这将简单地对应于首先转换目标变量,从而估计 E[g(Y)|X]。然而,由于 E[g(Y)|Xg(E[Y|X)对于任何凹函数 g ( y ),我们最终会低估均值。

第二种选择是在等式(2)的右边取 g ⁻ ( ŷ ),从而在原始标度上应用案例区分,这也不会有多大帮助。请记住,我们希望解决的问题是 y 的范围可以在几个数量级内变化。在这种情况下,我们通常无法找到合适的 α 值来保证对于 y 的所有范围,两种情况都适用。换句话说,只有通过等式(2)中的选择,我们才能得到非常数方差的分布。

然而,等式(2)中的损失函数在线|g(y)-ŷ| =α处具有跳跃不连续性,这可以用一种或另一种方法消除。等式(2)的以下平滑版本在实践中证明工作良好

其中∓= SGN(g(y)-ŷ)。
如图[1]所示,对于固定的 y _0,函数𝓛_s( y _0, ŷ )没有局部最小值,但也不是凸的。此外,𝓛_s( y _0, ŷ )展示了一个小斜率区域,这可能导致基于梯度的优化例程中的收敛问题。然而,这些问题通常可以通过选择一个好的起始向量来克服。我们将在下面用一个例子进一步讨论这个问题。

Figure 1: Left: Smoothed generalized Huber function with y_0 = 100 and α =1. Right: Smoothed generalized Huber function for different values of α at y_0 = 100. Both with link function g(x) = sgn(x) log(1+|x|).

在图[2]中,我们说明了前面提到的𝓟( yŷ_ 0)的比例随着 ŷ_ 0 的增加而增加。正是这一特点使得 GHL 函数稳健并适用于异方差问题。注意,𝓟( yŷ_ 0)的比例也随着 α 的增加而增加,如图【2】右侧所示。注意,我们没有将 𝓟( yŷ_ 0)规格化。相应的归一化因子将取决于 ŷ_ 0,研究是否可以导出封闭形式的表达式将是有趣的。

Figure 2: Left: (Unnormalized) Error distribution for different values of ŷ_0 at α = 1. Right: (Unnormalized) Error distribution at ŷ_0 = 1 for different values of α. Both with link function g(x) = sgn(x) log(1+|x|).

为了用梯度法优化𝓛_s( yŷ ,我们需要这个函数的梯度和海森。然而,这些表述相当冗长,因此可以在下文的附录中找到。相反,现在让我们来看最后一个例子。

例子

让我们考虑一个简单的一维问题,具有非常数方差的偏斜正态误差分布,即y=x+ε_ skew normal。我们使用了具有偏斜度参数 a =100, loc = 0 和 scale = 1 + | x |的 SciPy skewnorm 对象,并从区间[-500,500]创建了一个线性间隔的网格,网格中有 N = 10⁶个示例。此外,我们训练了三个 LightGBM 模型。一个在 g ( y )上的均方根误差(RMSE)模型,一个在 g( y )上的平均绝对误差(MAE)模型,还有一个 GHL 模型,都带有链接函数g(x)= SGN(xlog(1+|x|)。通过使用三重交叉验证方法,基于 R -score 度量,通过早期停止来训练模型。GHL 函数中的自由参数也被交叉验证并被选择为 α = 0.67。LightGBM 中的所有采样参数都设置为 1,num_leaves = 31,而所有其他参数都保留为默认值。

一般来说,为了收敛到 GHL 损失函数的最小值,需要一个好的起始向量。这里我们首先用经典的 Huber 目标函数(Huber 参数 α = 2)在 g ( y )上训练了一个只有 20 棵树的小型 LightGBM 模型。该模型的输出然后被用作 GHL 模型的起始向量(init_score)。

图[3]显示了所有三个模型的测试集(0.7/0.3 分流比)预测的散点图,其中预测最接近来自 GHL 模型的趋势线。下表还总结了一些指标,并举例说明了 GHL 模型在测试集上取得了明显更好的结果,同时比其他两个模型需要更少的树。

这个例子的 Jupyter 笔记本以及线性估计器包可以在这里找到【GIT】。线性估计器也可以与 pip 一起安装:

pip 安装 ghlestimator

Comparison of RMSE, MAE and (smoothed) Generalized Huber. Predictions are partitioned into 150 equally sized bins and within each bin the mean is plotted against the true mean of that partition. Black dots show a trend line of 45 degrees.

最后,我要感谢我的同事塞巴斯蒂安·霍弗就这个话题进行了富有成效的讨论。

附录

𝓛_s( yŷ 的梯度由下式给出

黑森被发现

这里我们定义了a=(g⁻(ŷ**α)-g⁻(ŷ))和b=(y-g⁻(g(y)α)用∓ = sgn()

广义线性模型

原文:https://towardsdatascience.com/generalized-linear-models-9cbf848bb8ab?source=collection_archive---------0-----------------------

高级统计建模简介

在本文中,我想解释广义线性模型(GLM),这是学习更高级的统计建模的一个很好的起点。学习 GLM 让你了解我们如何使用概率分布作为建模的基础。我假设你熟悉线性回归和正态分布。

Image by Semevent from Pixabay

线性回归再探

线性回归是通过解释变量 X 的线性组合来预测连续变量 y 的值。

在单变量情况下,线性回归可以表示如下:

Linear regression

这里, i 表示每个样本的指数。请注意,该模型假设噪声项呈正态分布。该模型可以说明如下:

Linear regression illustrated

通过三个正态 PDF(概率密度函数)图,我试图说明数据遵循具有固定方差的正态分布。

泊松回归

所以你只需要知道线性回归?肯定不是。如果你想在实际问题中应用统计建模,你必须知道更多。

例如,假设您需要用传感器值( x )作为解释变量来预测缺陷产品的数量( Y )。散点图看起来像这样。

Do you use linear regression for this data?

如果你试图对这类数据应用线性回归,会有几个问题。

  1. X 和 Y 之间的关系看起来不是线性的。更有可能是指数级的。
  2. 相对于 X,Y 的方差看起来不恒定。这里,当 X 增加时,Y 的方差似乎也增加。
  3. 因为 Y 代表产品的数量,所以它必须是正整数。换句话说,Y 是一个离散变量。然而,用于线性回归的正态分布假定变量是连续的。这也意味着通过线性回归的预测可能是负的。它不适合这种计数数据。

在这里,你能想到的更合适的模型是泊松回归模型。泊松回归是广义线性模型(GLM) 的一个例子。

广义线性模型有三个组成部分。

  1. 线性预测器
  2. 链接功能
  3. 概率分布

在泊松回归的情况下,公式是这样的。

Poisson regression

线性预测器只是参数( b )和解释变量( x )的线性组合。

链接功能字面上“链接”线性预测值和概率分布参数。在泊松回归的情况下,典型的连接函数是对数连接函数。这是因为泊松回归的参数必须是正的(稍后解释)。

最后一个部分是概率分布,它产生观察变量 y 。当我们在这里使用泊松分布时,该模型被称为泊松回归。

泊松分布用于模拟计数数据。它只有一个代表分布的均值和标准差的参数。这意味着平均值越大,标准差越大。见下文。

Poisson distribution with mean=1, 5, 10

现在,让我们将泊松回归应用于我们的数据。结果应该是这样的。

Poisson regression illustrated

品红色曲线是通过泊松回归的预测。我添加了泊松分布的概率质量函数的条形图,以明确与线性回归的区别。

预测曲线是指数曲线,因为对数连接函数的倒数是指数函数。由此也可以清楚地看出,由线性预测器计算的泊松回归参数保证为正。

Inverse of log link function

如果使用 Python, statsmodels 库可以用于 GLM。泊松回归的代码非常简单。

# Poisson regression code
import statsmodels.api as sm
exog, endog = sm.add_constant(x), y
mod = sm.GLM(endog, exog,
             family=sm.families.Poisson(link=sm.families.links.log))
res = mod.fit()

endog(内生)和 exog(外生)就是你在 statsmodels 中怎么称呼 yX 。请注意,您需要将常数项添加到 X 中。没有这个,你的线性预测器就只是 b_1x_i* 。

实际上,您不需要在这里提供 link 参数,因为 log link 是 Poisson 系列的缺省值。

我用来创建所有图形的完整代码在我的 Github 库中。

其他典型的 GLM

线性回归也是 GLM 的一个例子。它只是使用恒等连接函数(线性预测器和概率分布的参数是相同的)和正态分布作为概率分布。

Linear regression

如果用 logit 函数作为连接函数,用二项式/伯努利分布作为概率分布,那么这个模型就叫做 logistic 回归

logistic regression

如果用 z 表示线性预测器,上面的等式等价于下面的。

Logistic function

第二个方程的右边称为逻辑函数。因此,这个模型被称为逻辑回归。

由于逻辑函数对任意输入返回值介于 0 和 1 之间,因此它是二项式分布的合适链接函数。

逻辑回归主要用于二元分类问题。下面是一个用逻辑回归拟合一些数据的例子。

Logistic regression illustrated

自定义 GLM

到目前为止,我解释的模型使用了概率分布和链接函数的典型组合。换句话说,上面所有的模型都使用了规范链接函数。

这是概率分布及其规范链接函数的列表。

  • 正态分布:身份函数
  • 泊松分布:对数函数
  • 二项式分布:logit 函数

但是,您不一定要使用规范链接函数。更确切地说,统计建模的优势在于,您可以创建任何类型的模型来很好地适应您的数据。

例如,让我们考虑以下数据。

这看起来类似于我为泊松回归准备的数据。然而,如果你仔细观察数据,似乎 y 相对于 X 的方差是恒定的。况且 y 是连续的,不是离散的。

因此,这里使用正态分布是合适的。由于 Xy 之间的关系看起来是指数关系,你最好选择对数链接函数。

GLM with non-canonical link function

使用 statsmodels,您可以像这样编码。

mod = sm.GLM(endog, exog,
             family=sm.families.Gaussian(sm.families.links.log))
res = mod.fit()

请注意,您需要在这里指定链接函数,因为高斯分布的默认链接是身份链接函数。模型的预测结果是这样的。

statsmodels 中实现了各种链接功能。但是,如果您需要使用更复杂的链接函数,您必须自己编写模型。

为此,Stan、PyMC3 和 TensorFlow Probability 等概率编程框架将是一个不错的选择。这可能是我未来工作的主题。

广义线性模型—简介

原文:https://towardsdatascience.com/generalized-linear-models-introduction-1b4af2a11759?source=collection_archive---------23-----------------------

本文探讨了线性模型的背景,它们的局限性和广义线性模型背后的思想,以及是什么使它们广义化。

Photo by Markus Spiske on Unsplash

什么是机器学习中的线性模型?

为了举例说明这个主题,我采用了这个数据集的,它有一个预测器/特征/自变量/解释变量,即Brain Weight和一个响应/目标/因变量,即Body Weight

Index Brain Weight Body Weight
 1          3.385     44.500
 2          0.480     15.500
 3          1.350      8.100
 4        465.000    423.000
 5         36.330    119.500
 6         27.660    115.000
...

响应变量Body Wight 具有连续分布。我们可以将该分布建模为预测值的线性组合— Brain Weight,(在该数据集中仅有一个)和截距项。这里,模型本质上是试图学习与每个特征相关联的权重/参数。在数学上,我们必须建立以下线性方程的模型—

y = Body Weight [Response]
X = Brain Weight [Predictor]
We are interested to model the following equation ***y_hat***
 **y_hat = W1*X1 + W0
     y = y_hat + e**

上式中,**W1****W0**统称为模型参数。在线性模型的上下文中,**W1****W0** 分别称为系数和截距。**W0** 代表所有**X1**预测值为零的情况,**W0**是我们的模型将预测的值。****

**e**称为误差项。这是不能从预测者的知识中预测的误差。这是观察到的结果(即**y**)与我们的模型预测的结果(即**W1*X1 + W0**)之间的差异。

回归函数告诉我们,对于X1值的单位变化(增加或减少),响应变量y平均变化多少。**

下面的图是符合数据的超平面(在这种情况下是直线)。

Figure 1: Linear Regression Example

Figure 2: Learned Parameter of the Linear Model

我们将再举一个例子来更具体地说明线性模型的思想。
在这个例子中,我们有这个数据集,它包含两个预测值和一个连续响应变量。在这种情况下,我们有以下情况—

Figure 3: Fish Length Data

**y = Fish Length [Response]
X1 = Age [Predictor]
X2 = Water Temperature[Predictor]We are interested to model the following equation ***y_hat***
 **y_hat = W1*X1 + W2*X2 + W0**     **y = y_hat + e****

下面的超平面(在这种情况下是平面)是使用模型学习的参数,即W1, W2, W0绘制的。虽然它不是数据的最佳拟合,但我们的重点是线性模型的基本概念,而不是模型的预测能力。

Figure 5: Linear Model with two Predictors

Figure 5: Learned Parameter of the Linear Model

我们可以通过将学习到的参数放入方程y_hat = W1*X1 + W2*X2 + W0来比较和交叉检查方程y = y_hat + e。为了简洁起见,我取了数据集的前十行。

Figure 6: Error which cannot be predicted by the model

Figure 7: Comparison between y and y_hat

我们可以清楚地看到,y非常接近等于y_hat和误差项e的总和。

根据上述讨论,我们可以得出结论,线性模型意味着随机变量的分布被建模为特征/预测值的线性组合。**

线性模型中的‘线性’是什么?

当我们说“特征的线性组合”时,意思是模型参数Wi是线性的,阶数为 1,而不是特征。我们估计线性参数,而不是在线性模型中估计类似于W1², W1*W2的东西。此外,特性可以有不同种类的术语,如— X1, X1*X2, X2²等。

现在我们可以为线性模型写一个通用方程如下—

**y = W0 + W1*X1 + W2*X2 + W3*X3 + ... + Wn*Xn + e**

但是,当我们进行线性回归时,我们做出某些假设,例如:1。响应变量的分布为正态分布,即*Y_i ~ N(* μ_i,σ *)* 2。预测因子/解释变量Xi的功能W0 + Wi*Xi3。解释变量和Yi 分布之间的连接/联系是响应变量的平均值。
每个数据点的预测值将以方差 σ分布在平均值周围。

*****μ_i = E(Y_i) = W0 + Wi*Xi*****

线性模型的局限性-
1。常态假设并不总是成立的,我们可能有自己的分类特征,如性别、职业类型等。或者我们可能有非正态分布的时间序列数据。
2。线性模型无法拟合具有分类响应变量的数据,如鸢尾花数据集、MNIST 数据集等。

Figure 8: Distribution of Categorical Target Variable

3.即使响应变量是连续的随机变量,但是其取值在诸如 0 和 1 之间的概率的范围内。
传统的线性模型将无法预测 0 到 1 之间的值,因为我们的特征可以取范围(-∞,∞)内的任何值。

现在我们已经知道,线性模型并不总是正确的选择,因为它与连续响应数据不同,可能会提供相当奇怪的结果。现在我们要做的是推广这个模型来克服这样的问题。这就产生了 GLMs,它提供了一个统一的框架,用于对源自概率分布指数族(如正态分布、二项式分布、泊松分布等)的数据进行建模。

GLM 有三个组成部分。

  1. 随机分量— 定义响应变量 y 及其概率分布。一个重要的假设是从y1yn的响应是相互独立的。
  2. 系统组件— 定义我们希望在模型中包含哪些解释变量。它还允许解释变量之间的相互作用,例如— X1*X2X1² etc.这是我们建模的部分。它也被称为协变量的线性预测器,即X1, X2, … , Xn和系数的线性预测器,即W1, W2, … , Wn.
  3. 链接组件— 连接随机组件和系统组件。响应变量期望值的函数,即E(Y),使参数呈线性,并允许E(Y)与解释变量呈非线性关系。链接函数概括了线性模型。****

Figure 9: Components of GLM

注意,连接函数的选择与随机分量的选择是分开的。

现在我们可以说,简单线性回归模型是 GLM 的一个特例,其中随机分量具有正态分布,并且取范围(-∞,∞)内的连续值。系统组件是X.链接功能是标识功能。

 ***Y ~ N(**μ, σ²**)
                        E(Y) = μ
                        g(E(Y)) = μ = W1*X1 + e***

我们在 GLMs 中概括了什么?

  1. 我们推广了响应变量的分布,即y,可以取。
  2. 我们在解释变量Xi和响应变量Yi之间推广了链接函数

下表包含了常用的链接功能。

Figure 10: Types of Link Functions

让我们总结一下到目前为止我们所讨论的内容——T4。线性模型适合于模拟连续响应变量,但它们有一定的局限性。
2。广义线性模型统一了许多不同类型的属于指数密度族的响应变量分布。
3。链接函数是 GLM 中实现参数线性的关键组件,并且是概括线性模型的组件。

参考文献:
【1】b . Caffo, 03 01 第 1 部分共 1 部分广义线性模型(2015)
【2】r . Cooksey,一般线性模型的逻辑(GLM)(2013)
【3】精算教育, CT6 广义线性模型导论(GLMs) (2012)

生成包含感兴趣的主题/关键词的公共“tweets”语料库

原文:https://towardsdatascience.com/generate-a-corpus-of-public-tweets-containing-a-subject-keyword-of-interest-da86bc90259f?source=collection_archive---------22-----------------------

通常很难对人们的兴趣进行研究,民意测验和调查结果经常是有偏差的,或者有无意中加载的问题。因此,这意味着理解人们兴趣的最真实的 T2 方法在于他们想要分享或谈论什么,而不受任何外部影响。最简单的方法是在网上搜索包含某些特征的 twitter 帖子。

Twitter API

最初,最直观的方法是查看 twitter API。要使用它,你首先必须在 https://developer.twitter.com/en/apply-for-access 注册一个开发者账户(免费)

这里为您分配了一组凭证,您可以将它们保存为以下格式的 JSON 文件:

{
 “twitter”: {
 “auth”: {
     “consumer_key”: “xxxx”,
     “consumer_secret”: “xxx”,
     “access_token_key”: “xxx”,
     “access_token_secret”: “xxx”
 },
  “token”: “xxx”,
  “secret”: “xxx”
 }
}

接下来,我们需要安装 Twython 库pip install twython(不幸的是 python 3),之后我们可以根据需要定制下面的脚本。

# Import the Twython class
from twython import Twython
import json# Load credentials from json file
with open("twitter_credentials.json", "r") as file:
    creds = json.load(file)['twitter']['auth']# Instantiate an object
python_tweets = Twython(creds['consumer_key'], creds['consumer_secret'])
# Create our query
query = {'q': 'air quality',
        'result_type': 'popular',  # other options 'mixed'
        'count': 100,   # max 100
         # 'until':"2019-02-01",
        }import pandas as pd
# Search tweets
dict_ = {'user': [], 'date': [], 'text': [], 'favorite_count': []}
for status in python_tweets.search(**query)['statuses']:
    dict_['user'].append(status['user']['screen_name'])
    dict_['date'].append(status['created_at'])
    dict_['text'].append(status['text'])
    dict_['favorite_count'].append(status['favorite_count'])# Structure data in a pandas DataFrame for easier manipulation
df = pd.DataFrame(dict_)

这种方法的缺点是结果仅限于过去 7 天,并且最多只能返回 100 条推文。

访问两个日期之间的所有推文

相反,如果我们希望获得更久以前日期之间的所有推文,我们需要依靠其他方法。要做到这一点,我们可以依赖 GetTweetsFrom 库;https://github.com/Jefferson-Henrique/GetOldTweets-python

这是在 python 2 上设计的,尽管有一个 python 3 的实验接口,它可能工作也可能不工作。

因为我希望只提取每条 tweet 的文本,并将其保存在新的一行上进行文本处理(word2vec),所以对库提供的原始示例代码进行了轻微的调整。这里,我对查询、开始和结束日期以及输出文件名进行了硬编码。

下面的脚本遍历两个日期之间的每一天,并下载它找到的与查询匹配的前 1000 条 tweets。这可以适应用户的需求。

# -*- coding: utf-8 -*-
import sys,getopt,datetime,codecs
from datetime import date, timedeltaedate = date(2019, 10, 1)   # start date
sdate = date(2018, 10, 1)   # end datequery = 'atmospheric chemistry'
maxtweets = 1000
toptweet=False
outputFileName = 'myoutput.csv'delta = edate - sdate       # as timedelta
dates = [(sdate + timedelta(days=i)) for i in range(delta.days + 1)]if sys.version_info[0] < 3:
    import got
else:
    import got3 as gotdef main():try:tweetCriteria = got.manager.TweetCriteria()tweetCriteria.querySearch = query
        tweetCriteria.topTweets = toptweet
        tweetCriteria.maxTweets = maxtweetsoutputFile = codecs.open(outputFileName, "w+", "utf-8")def receiveBuffer(tweets):
            for t in tweets:
                outputFile.write('\n%s'% t.text)
            outputFile.flush()for dt in dates:
            print (dt)
            tweetCriteria.since = str(dt)
            tweetCriteria.until = str(dt + timedelta(days=1))got.manager.TweetManager.getTweets(tweetCriteria, receiveBuffer)except arg:
        print('Arguments parser error, try -h' + arg)
   finally:
        outputFile.close()
        print('Done. Output file generated "%s".' % outputFileName)if __name__ == '__main__':
   main()

结论

  • Twitter API 仅用于收集过去 7 天的推文。
  • 如果您需要历史数据,GetOldTweets 库非常有用
  • 然后,生成的输出文件可以用作基于 NLP 的机器学习和预测的语料库,或者关于该主题的公众观点的样本。
  • 这两种方法都非常容易使用,而且几乎是即插即用的(一旦您使用了正确版本的 python)。

使用 DCGAN 生成动漫风格人脸并探索其潜在特征表示

原文:https://towardsdatascience.com/generate-anime-style-face-using-dcgan-and-explore-its-latent-feature-representation-ae0e905f3974?source=collection_archive---------1-----------------------

逐步试验 DCGAN 并可视化其结果

各位,好久不见了!今天,我想写一下我学习和实验另一种深度学习技术的结果,这种技术是生成对抗网络(GAN)。最近研究了解了一下。我想如果把我的实验分享给每个人会很好。

Photo by Hitesh Choudhary on Unsplash

“干”主要是指产生某种东西。在这篇文章中,我想分享关于生成动漫人物面部的实验。不仅仅是生成,我还实验了图像可以通过潜在变量(一个用于生成人脸的向量)的线性代数运算来操作。我还看到生成的人脸遵循统计分布,这真的很棒。

这篇文章将集中在教程如何做 GAN 的每个步骤解释(与源代码)。它将针对任何对人工智能感兴趣的人,特别是想练习使用深度学习的人。它也针对每个人谁想学习如何做甘第一次。我会尽可能简单易懂地写这篇文章。我希望读者通过阅读这篇文章,了解甘将军是如何工作的。

如果你想在阅读这篇文章时有更好的理解,我建议你至少了解神经网络和卷积神经网络(CNN)。

如果您想了解完整的源代码,本文末尾有一个 GitHub 链接。现在,我将给出存储库中的 python 笔记本和协作链接。

图片 0 是生成的动漫人物脸之一,我们将使用模型形成的图片来创建。左起第一张和第二张图由 GAN 生成。第三是第一面和第二面的相加(你可以称之为第一面和第二面的融合)。

Images 0 : Example of generated faces and the fusion of their face. G + D = GAN

概述

  1. 技术
  2. 介绍
  3. 甘简介
  4. 履行
  5. 结果
  6. 吸取的教训
  7. 结论
  8. 编后记
  9. 贮藏室ˌ仓库
  10. 来源

技术和数据

  1. Python 3.7
  2. 合作实验室:免费的 Jupyter 笔记本环境,无需设置,完全在云中运行。有 GPU 特斯拉 K80 甚至 TPU!遗憾的是,在撰写本文时,Tensorflow v2.0 alpha 仍不支持 TPU。遗憾的是,DCGAN 不能通过 TPU 训练。
  3. Keras:用于深度学习的 Python 库。
  4. 数据取自这里

介绍

深度学习领域的研究热点之一是生成对抗网络。由 Ian Goodfellow 等人介绍。,它可以在无人监督的情况下从零开始生成东西。在计算机视觉领域。有许多研究人员在研究和改进它。例如,NVIDIA 通过使用 GAN 创建了逼真的人脸生成器。音乐领域也有一些关于使用甘的研究。我之前的一篇文章展示了如何使用 GAN 来生成音乐。

Image 1 : HoloGAN paper

研究人员开发了许多不同类型的氮化镓。最新的一个(在我写这篇文章的时候)是可以从自然图像生成 3D 表示的 HoloGAN 。如果你看看它是如何做到的,它真的很神奇。实际上,这些高级 GAN 遵循 GAN 工作的基本原理。每个 GAN 都有两个代理作为它的学习器、鉴别器和生成器(我们将在后面深入讨论这些术语)。要了解更多高级 GAN 技术,必须了解基本 GAN 的工作原理。

本文将重点介绍深度卷积 GAN (DCGAN)的实现,它是拉德福德等人提出的 GAN 的变体之一。基本上就是一个有很多卷积层的 GAN。它是流行的 GAN 神经网络之一。我们将构建一个与他们论文中提出的架构不同的架构。尽管有所不同,但它仍然产生了一些好结果。

关于 GAN 的一个有趣的事情是,它将建立它的潜在变量(一个长度为任何长度的一维向量),可以用线性代数运算。图像 0 上的例子就是其中之一。第一个面的向量(从左边开始)被添加到第二个面的向量。然后,它产生了第三张脸。

它还产生了一些有趣数据分布。分布中的每一点都有不同的面。例如,以平均值-0.7 为中心的数据将具有黄色头发的脸。

我们将从了解一个关于甘的简要描述开始。

简介

那么,甘是什么呢?

更简单地说,这是一种用于从头生成一些新数据的深度学习技术。它以无人监管的方式运行,这意味着它可以在没有人为标记的情况下运行。它会根据学习到的模式生成数据。

甘是一个生成性的模型,他有以下几个方面的特点:

  • 学习联合概率 P(x,y) 其中 x 是输入, y 是输出。它将基于 P(x|y) 进行推断,给定输出 y,它将推断出 x. 你可以说 y 是 GAN 中的真实数据。
  • 当模型被给予训练真实数据 y 时,它将学习真实数据的特征。它将通过识别真实数据潜在特征表示变量来学习。更简单地说,它学习真实数据中图像的基本构造函数特性。例如,模型可以学习由眼睛和头发的颜色构成的脸。这两个将是产生面的基础之一。通过调整它的变量,它也可以改变生成的面。比如提高眼睛的变量,眼睛会更黑。降低它将产生相反的结果。
  • 它可以建立概率分布,例如正态分布,其可以用于避免异常值。由于异常值通常在分布中非常罕见,所以生成它的几率将非常小。因此,GAN 在有异常值的真实数据上运行良好。

那么,它是如何工作的呢?

GAN 组成两个神经网络,鉴别器发生器。甘将使这两个网络在一个零和博弈框架(博弈论)上相互争斗。这是这些代理(网络)之间的游戏。《甘》中的名就来源于这个概念。

Image 2 : Illustration of Discriminator vs Generator . Image modified and taken from here

发生器将产生一些假数据,而鉴别器将识别出几个数据,这些数据包含由发生器产生的假数据和从真实数据中采样的数据。发生器的目的主要是产生一些与真实数据相似的虚假数据,并欺骗鉴别器识别哪些数据是真实的,哪些是虚假的。鉴别器的目的是让它更智能地识别真假数据。每个代理将交替移动。通过与这些代理决斗,我们希望这些代理会变得更强,尤其是发电机。

你可以说他们是命中注定的对手。主角是发电机,它通过从对手的战斗中学习,力求更好地实现我们的目标。****

好的,换句话说,发生器将通过对学习到的分布进行采样来模拟真实数据,并打算与真实数据相同的分布。它会训练自己的神经网络来生成它。鉴于此,鉴别器将在监督技术中训练其神经网络来检测虚假和真实数据。每个网络将交替训练其网络。

Image 3 : Illustration GAN on learning data distribution. Picture taken from here.

以下是 GAN 工作原理的大致步骤:

  1. 以概率分布如正态分布产生随机噪声。
  2. 将其作为发电机神经网络的输入。它将输出生成的 假数据 。这些步骤也意味着我们从生成器学习的分布中抽取一些数据。我们将噪声记为**z_n**,生成的数据记为**G(z_n**)**G(z_n)**指发电机 G 处理噪声的结果。
  3. 我们将生成的假数据与从数据集采样的数据(真实数据)结合起来。使它们成为我们的鉴别器的输入。我们将其记为 D.** 鉴别器将通过预测数据是否为假来尝试学习。通过前向传递和后向传播来训练神经网络。更新 D 权重。**
  4. 然后,我们需要训练发电机。我们需要将**G(z_n)**或者随机噪声产生的伪数据作为 D 的输入注意,这个步骤只是将伪数据输入到鉴别器中。正向传递【d】中的**G(z_n)** 通过使用鉴别器神经网络,在做正向传递时,预测假数据是否为假数据**(D(G(z_n)))**。然后进行反向传播,我们将只更新 G 权重。
  5. 重复这些步骤,直到我们可以看到生成器提供良好的伪数据或者已经达到最大迭代。

图示如下:

Image 4 : How GAN Works. Picture taken from [here](http://Image 3 : Illustration GAN on learning data distribution. Picture taken from here.).

通过更新生成器的分布来匹配鉴别器。这和最小化 JS 散度是一样的。要了解更多信息,您可以阅读这篇文章。

为了让我们的代理学习,一定要让鉴别器发生器互相支配。使它们尽可能平衡,并使鉴别器发生器同时学习。当鉴别器太强(能 100%区分真假)时,发生器变得什么也学不会。如果在训练过程中我们达到这一点,最好结束它。在发生器比鉴别器强的情况下,相反的情况也有影响。它会导致模式崩溃,我们的模型对任何随机噪声都会预测相同的结果。这是 GAN 中最难和最难的部分之一,它会让人感到沮丧。

如果你想了解更多,我建议看一看这篇很棒的文章。

履行

那么,鉴别器和生成器的架构如何呢?

这取决于我们将开发的 GAN 的变体。由于我们将使用 DCGAN,我们将使用一系列的 CNN 层。

我们将使用不同于原始论文的自定义架构。我沿用了《用 Python 进行深度学习》一书中使用的架构。****

我们用于构建 DCGAN 的配置如下:

*latent_dim = 64
height = 64
width = 64
channels = 3*

这意味着我们将有一个 64 维的潜在变量。我们的图像的高度和宽度是 64。每个图像有 3 个通道(R,G,B)

以下是导入的库以及如何准备数据:

这里是架构:

发电机

它由卷积层组成,其中一层是卷积转置层。为了增加图像(32 -> 62)的大小,我们将在卷积层中使用步长参数。这样做是为了避免 GAN 的不稳定训练。

代码

鉴别器

它还由卷积层组成,我们使用步长进行缩减采样。

代码

开始

为了使生成器的反向传播成为可能,我们在 Keras 中创建新的网络,它是生成器后跟鉴别器。在这个网络中,我们冻结了所有的权重,这样它的权重就不会改变。****

这是网络:

培养

培训的配置如下:

*iterations = 15000 
batch_size = 32*

该配置意味着我们将进行 15000 次迭代。每次迭代我们处理 32 批真实数据和虚假数据(总共 64 批用于训练鉴别器)。

按照我上面解释的粗略步骤,下面是我们如何一步一步地训练 DCGAN:

  1. 重复以下步骤直到最大迭代次数
*for step in tqdm_notebook(range(iterations)):*

2。以概率分布如正态分布产生随机噪声。

*random_latent_vectors = np.random.normal(size = (batch_size, latent_dim))
generated_images = generator.predict(random_latent_vectors)*

3。将生成的假数据与从数据集中采样的数据结合起来。

*stop = start + batch_size
real_images = x_train[start: stop]
combined_images = np.concatenate([generated_images, real_images])
labels = np.concatenate([np.ones((batch_size,1)), 
                                    np.zeros((batch_size, 1))])*

请注意,我们使用顺序采样器,每个数据将被顺序采样,直到数据结束。将被抽样的数量等于批量大小。

4。向输入标签添加噪声

*labels += 0.05 * np.random.random(labels.shape)*

这是训练甘的重要一招。

5。训练鉴别器

*d_loss = discriminator.train_on_batch(combined_images, labels)*

6。训练发电机

*random_latent_vectors = np.random.normal(size=(batch_size, 
                                                 latent_dim))
misleading_targets = np.zeros((batch_size, 1))
a_loss = gan.train_on_batch(random_latent_vectors, 
                              misleading_targets)*

注意,我们创建了一个新的潜在向量。别忘了我们需要交换标签。请记住,我们要尽量减少因鉴别者未能预测到假货而造成的损失。misleading_targets的标签应该是 1。

7。更新真实数据集的起始索引

*start += batch_size

  if start > len(x_train) - batch_size:
    start = 0*

就这样,下面是训练 DCGAN 的完整代码:

结果

好了,好戏开始了!我们将开始在不同的平均点上可视化生成的图像。在我们这样做之前,让我告诉你,这是上述模型的结果,该模型训练了 20000 步(迭代)和 30000 步。该模型被训练大约 7 小时(大约每小时 4300 步)。我将较少步骤的模型命名为模型-A* ,另一个命名为模型-B 。***

开始了。

如何阅读

N ~ (x,y) :遵循正态分布随机生成的潜在向量,具有均值 x 和标准差 y

模型-AN ~ (0,0.4) 的潜在向量结果:

Image 5 : Generated Face Model-A N ~ (0, 0.4)

不错吧,虽然有一些照片中的人有不对称的脸。

模型-AN ~ (0,1) 的潜在向量结果:

Image 6 : Generated Face Model-A N ~ (0, 1)

看看它..这个模型产生了一些令人厌恶的面孔。事实证明,这个模型并没有真正掌握真实数据的分布。当标准差较低时,它可以做得更好。我训练的 DCGAN 还没有掌握如何表示不太接近均值点的数据点。我认为,它需要更多的训练或更强大的架构。

让我们将架构更改为模型-B****

模型 B:N ~ (0,0.4) 的潜在向量结果

Image 7 : Generated Face Model-B N ~ (0, 0.4)

还好,但是脸变得更黑了。我想知道发电机怎么了。

模型-B* 上的 N ~ (0,1) 上的潜在向量结果:***

Image 8 : Generated Face Model-A N ~ (0, 1)

嗯,好吧..其中大部分仍然包含着可憎的面孔。他们中的一些人表情很好。质量还是和 a 型差不多。好的..对于下一批图像,让我们尽可能地改变标准偏差。0.4 最好。**

让我们检查一下,我们的潜在向量是否是使用相同的标准偏差,以-0.3 和 0.3 为中心平均值生成的。

模型-AN ~ (-0.3,0.4) 的潜在向量结果:

Image 9 : Generated Face Model-A N ~ (0.3, 0.4)

模型-AN ~ (0.3,0.4) 的潜在向量结果:

Image 10: Generated Face Model-A N ~ (-0.3, 0.4)

B 型N ~ (-0.3,0.4) 的潜在向量结果:

Image 11: Generated Face Model-B N ~ (-0.3, 0.4)

Model-BN ~ (0.3,0.4) 上的潜在向量结果:

Image 12: Generated Face Model-B N ~ (0.3, 0.4)

看出区别了吗?

是的,看他们的头发。平均值为 0.3 时,头发大部分是黑色的(其中一些是棕色的)。相反,在平均值为-0.3 时,毛发大多是黄色的。是的,我们的模型可以把脸放在相应的点上。模型 B 也生成比 a 更暗的面。

从上面我们所做的,我们可以直观地了解我们的模型是如何学习数据分布的。

让我们绘制它:

Image 13: Data distribution of the generator

从上面显示的结果来看,我认为潜在向量越小,脸的头发越亮,潜在向量越大,脸的头发越红。

为了确定这一点,让我们来看看每个平均点中的平均面:

我们画出这些潜在向量,它们的平均值是:

*[-1, -0.8, -0.6, -0.4, -0.2, 0, 0.2 0.4, 0.6, 0.8 ]*

Image 14: Average faces from different mean points

第一行是模型 A,第二行是模型 b。通过处理潜在向量的平均值,我们可以看到它在该点生成的脸。我们可以看到:

  • 向量的点越低,头发越黄。
  • 它的脸中间比较黑。这意味着数据集中的平均人脸具有这些风格。
  • 向量的点越正,头发越蓝。正面潜在向量在微笑上也有更多的开口。

基本线性代数运算

很神奇吧?

还没有,我们可以对潜向量做线性代数运算。方程的结果也可以生成,并有有趣的结果。在介绍部分之前,从我们的第一张面孔中提取一个结果:

G + D

Images 15 : G + D = GAN

甘脸是 G 和 d 相加的结果。你可以看到头发变得有点棕色。右边的头发是 D 型,左边的是 G 型。

以下是其他人操作的结果:

G — D(绝对)

Images 16 : G-D

按分量相乘(G,D)

Images 17 :Component-Wise multiplied (G, D)

操纵潜在向量

如果我们在潜向量中操作一个维度,我们将会看到生成的图像是怎样的。正如我前面所说,模型将学习潜在的特征表示。所以,潜在向量中的每一个元素都有生成图像的目的。

为了进行可视化,我们将冻结 vectors 中的所有元素,并更改要检查的所选维度。

Images 18 : Illustration on what we do in this section

例如,我们想要检查潜在向量中的第一个元素,我们改变该维度并保持其他维度不变。

我们将生成一些具有以下意义的面:

*[-0.6, -0.3, 0.1, 0.3, 0.6]*

对于每个平均点,我们将生成其潜在向量中的维度随着这些值迭代地改变的面:

*[-1.08031934, -0.69714143, -0.39691713, -0.12927146,  0.12927146, 0.39691713,  0.69714143,  1.08031934]*

让我们在选择的维度上可视化: (本节将只使用模型-A)

第 28 次元:

Image 19 : Result on Changing 28th latent variable in different mean points.

第 28 个潜变量的目的是什么?

我认为,它使头发变得更亮,改变左眼的形状,也改变右眼的小变化。由于它将特征压缩成 64 长度的潜在向量,一个维度可以有多种用途。

让我们看另一个!

第五维度

Image 20 : Result on changing 5th latent variables in different means

这个潜在变量的目的是什么?

我认为这与左眼有关,尽管每个穴位对左眼的治疗不同。它也使头发颜色变深。你怎么想呢?

第 11 维

Image 21 : Result on changing the 11th latent variables in different means

我想,这个维度关心的是嘴巴和右眼。

另一个例子是通过调整一个潜在变量从一个平均点生成的面:

Image 22 : Result on faces by changing a latent variable

就是这样。我们可以画出潜在向量的任何维度,看看它的目的是什么。尽管有时很难看出潜在变量的目的是什么。

与真实数据比较

让我们从数据集中抽取 8 个真实的人脸样本:

Image 22 : Real Faces from dataset

型号 A 和 B 的发电机 N ~ (0,1)的样本 8:

Image 23 : Fake faces generated by generator

那么,如果我们充当鉴别者,我们能区分真脸和假脸吗?

毫无疑问,我们仍然可以区分哪些面孔是假的,哪些是真的。这种模式需要更多训练或强大的架构来实现。即便如此,我们的模型仍然可以生成动漫风格的人脸形状,这很棒。

吸取的教训

以下是我研究 DCGAN 后学到的经验:

  • 训练甘很难。如果没有经验者的提示和技巧,很难做出一个稳定的架构。尤其是在平衡鉴频器和发生器的功率方面。使 GAN 不崩溃也是一个挑战。

Photo by Pablo Merchán Montes on Unsplash

  • 实际上,这些模型仍然不擅长生成假图像。然而,它可以建立一些好的面孔,虽然没有真正的好。我们仍然可以区分假图像和真实图像。这是因为模型还没有掌握真实数据的数据分布。
  • 该模型在 26000 步左右降低其质量。在我的实验中,这是发电机变弱的地方。这是 GAN 中的不稳定性。我需要寻找一个更好的架构来做这件事。我们可以看到模型 B 上的结果变得更暗。
  • 因此,我开发了另一个具有批处理规范化甚至是丢弃层的架构。你猜怎么着?在调整架构的过程中,我有两个结果。模型崩溃和鉴别器优势。我猜开发 GAN 架构并不容易。
  • 然而,有许多关于开发一个好的 GAN 的提示和技巧我还没有实现。也许遵循这些提示可以减少模型的不稳定性。
  • 有许多更稳定 GAN 变体,例如 WGAN-DC 和 DRAGAN,以及 SAGAN。我需要使用可能比 DCGAN 做得更好的不同架构。

结论

这篇文章告诉了我们甘在做什么,并一步一步地告诉我们如何去做。之后,它告诉我们一个有趣的特征,它的潜在向量显示了数据分布的发电机学习。它向我们展示了它可以形成一个数据分布。

潜在向量可以进行线性代数运算。它可以向我们展示一些有趣的事情,例如两个潜在向量的相加将组合这些面孔中每一个的特征。它还可以被操纵以基于潜在向量中的改变的元素来改变面部。

即便如此,我们的模型仍然无法做出一张能让我们怀疑那张脸是不是假的脸。它仍然可以形成一个动漫风格的面孔。

编后记

Photo by Lemuel Butler on Unsplash

就是这样,我第一次做 GAN 的经验。我越来越了解甘在做什么。我也想探究一下我对甘到底学到了什么的好奇心。它们就在那里,它实际上做的事情真的很神奇。生成器可以将正常随机噪声生成的随机向量映射到数据分布中。它将人脸聚集成指定的数据点。

在做甘,我实际上运行几个模型,我手工制作的。好吧,他们悲惨地失败了。有一次,我认为模型可以成功,但它进入模式崩溃(预测的脸将是相同的,不管潜在向量)。我找到了关于 DCGAN 的 fchollet 存储库,并遵循了它的架构。

由于这是我第一次设计 GAN,我希望每个人都对此有很多反馈。请指出我犯的错误,因为这是我第一次做。如果结果没那么好请见谅。我只想分享我做甘的兴奋。并分享如何做到。

即便如此,这真的很有趣,我想尝试另一种 GAN 变体,如 WGAN-GP、DRAGAN 或 SAGAN。我只是略读了一点,并想尝试一下。期待一篇做这些实验的文章😃。

这个迷因实际上描绘了这个实验😆。

Images 24 : Image taken from neuralnetmemes Instagram

我欢迎任何可以提高我自己和这篇文章的反馈。我正在学习写作和深度学习。我感谢能让我变得更好的反馈。确保以适当的方式给出反馈😄。

在我的下一篇文章中再见!

Source : https://cdn.pixabay.com/photo/2017/07/10/16/07/thank-you-2490552_1280.png

贮藏室ˌ仓库

查看这个 GitHub 资源库:

*** [## haryoa/DCGAN-Anime

使用 DCGAN 制作动漫脸的个人项目。通过在…上创建一个帐户,为哈里亚海/DCGAN-Anime 的发展做出贡献

github.com](https://github.com/haryoa/DCGAN-Anime)

目前,我只提供 IPython 笔记本来从头开始训练 GAN。请注意,如果模型在大约 200 次迭代后没有输出人脸形状的图像,请重新开始训练(从“创建模型部分开始运行)。

稍后,我将创建一个操场笔记本来实验操纵潜在变量。

来源

[## 深度学习——生成对抗网络

在这篇文章中,我们将了解生成性敌对网络(GAN)。我们将比较生成性和辨别力…

medium.com](https://medium.com/datadriveninvestor/deep-learning-generative-adversarial-network-gan-34abb43c0644)

感谢雷努·汉德尔瓦尔的精彩文章。

https://www . cs . Toronto . edu/~ duvenaud/courses/CSC 2541/slides/gan-foundations . pdf

https://github . com/fchollet/用 python 深度学习笔记本

[## 从 GAN 到 WGAN

这篇文章解释了生成性对抗网络(GAN)模型背后的数学原理,以及为什么它很难被训练…

lilianweng.github.io](https://lilianweng.github.io/lil-log/2017/08/20/from-GAN-to-WGAN.html)

https://arxiv.org/pdf/1511.06434.pdf

[## 甘——为什么生成性对抗网络这么难训练!

认出莫奈的画比画一幅容易。生成模型(创建数据)被认为是非常…

medium.com](https://medium.com/@jonathan_hui/gan-why-it-is-so-hard-to-train-generative-advisory-networks-819a86b3750b)

感谢 Jonathan Hui 的精彩文章。***

使用 python 成为视频分析专家

原文:https://towardsdatascience.com/generate-any-sport-highlights-using-python-3695c98baead?source=collection_archive---------17-----------------------

Courtesy: pixabay

如果告诉你这不是用机器学习或者深度学习生成的呢!

为任何运动生成精彩场面的任务都是相当乏味和困难的。它涉及许多技术和其他软件、硬件需求。你也需要投入大量的时间去做。如果你对这样的视频公司或部门感兴趣,那就没问题,但如果你是像我一样的普通用户,你就不会想这么做。我将使用 python 在几个步骤中完成这项工作。不会涉及任何外部软件。只是纯粹的 python,而且,我们不必依赖机器学习或深度学习技术来做到这一点。我们将使用语音分析来完成这项任务。

当比赛中发生令人兴奋的事情时,解说员的声音就会提高。让我们以板球为例。每当击球手击球或投球手击球时,解说员的声音就会提高。在那场比赛中,观众和解说员的音调都很高。我们可以利用音频的这些变化从视频中捕捉有趣的瞬间。

我们将遵循的流程补充如下:

  • 输入视频文件
  • 提取音频
  • 将音频分成几块
  • 计算每个块的短时能量
  • 将每个块分类为兴奋或不兴奋(基于阈值)
  • 合并所有精彩片段,形成视频集锦
  • 生成最终的视频集锦

记住,我们不会在这里使用任何外部软件。

1。下载视频输入:https://bit.ly/2lKfVa6

你也可以选择你最喜欢的运动的任何其他视频。

2。提取音频:

为了提取音频和对视频文件进行其他操作,我们将使用一个名为 moviepy 的包。

a.安装软件包。

pip install moviepy

b.在此代码中输入文件路径。

# AudioExtract.pyimport moviepy.editor as mpclip = mp.VideoFileClip("filepath//videoplayback.mp4").subclip(1, 1380)
clip.audio.write_audiofile("filepath//audio.wav")

在上面的代码中, mp 视频文件剪辑是我们输入视频文件的地方。

子剪辑,我们指定我们需要音频的时间限制。如果您想要完整的剪辑音频,则不需要**

audio.write_audiofile ,我们在这里指定输出路径和文件名。

就这样,我们通过两个简单的步骤提取了音频。

3。将音频分成几块:

我们将使用刚刚在步骤 2 中提取的音频。

librosa 是一个用于音乐和音频分析的 python 包。

import librosa
import IPython.display as ipdfilename = "filepath\\audio.wav"# loading the file with a sampling rate
x, sr = librosa.load(filename, sr=16000)# To get duration of the audio clip in minutes
int(librosa.get_duration(x, sr) / 60)# Dividing into chunks of 5 seconds 
max_slice = 10
window_length = max_slice * sr# Playing the audio chunk
a = x[21 * window_length:22 * window_length]
ipd.Audio(a, rate=sr)

在这里,我将采样率设置为 16000,您可以根据自己的方便和需要进行设置。现在,我已经将音频分成每个 10 秒的块,因为我们想要找出特定的音频块是否包含音频声音的上升。您可以根据自己的选择设置时间限制,对不同的输出尝试不同的时间限制。此外,我们将播放音频块只是为了检查。

4。计算每个组块的短时能量:

import numpy as np
s_energy = np.array([sum(abs(x[i:i + window_length] ** 2)) for i in range(0, len(x), window_length)])

音频信号的能量或功率是指声音的响度。它是通过时域中音频信号幅度的平方和来计算的。当对整个音频信号的块计算能量时,它被称为短时能量

让我们画出来:

import matplotlib.pyplot as plt
plt.hist(s_energy)
plt.show()

5。将每个组块分类为兴奋与否(基于阈值):

import pandas as pd
df = pd.DataFrame(columns=['energy', 'start', 'end'])
thresh = 180
row_index = 0
for i in range(len(s_energy)):
    value = energy[i]
    if value >= thresh:
        i = np.where(s_energy == value)[0]
        df.loc[row_index, 'energy'] = value
        df.loc[row_index, 'start'] = i[0] * 10
        df.loc[row_index, 'end'] = (i[0] + 1) * 10
        row_index = row_index + 1

我正在根据能源数据创建一个数据框架。我选择的阈值是 180,你可以根据自己的选择来选择,也可以看上面的图表。然后将音频剪辑的连续时间间隔合并成一个:

temp = []
i = 0
j = 0
n = len(df) - 2
m = len(df) - 1
while (i <= n):
    j = i + 1
    while (j <= m):
        if (df['end'][i] == df['start'][j]):
            df.loc[i, 'end'] = df.loc[j, 'end']
            temp.append(j)
            j = j + 1
        else:
            i = j
            break
df.drop(temp, axis=0, inplace=True)
print(df)

6。合并所有精彩片段,形成视频集锦

start = np.array(df['start'])
end = np.array(df['end'])
for i in range(len(df)):
    if i != 0:
        start_lim = start[i] - 10
    else:
        start_lim = start[i]
    end_lim = end[i]
    filename = "highlight" + str(i + 1) + ".mp4"
    ffmpeg_extract_subclip("filepath//videofile.mp4", start_lim, end_lim, targetname=filename)

这段代码将根据振幅从每个块中生成突出显示,然后将这些文件保存到您的系统中。你还没有完成,你必须将所有的 14 文件合并成一个文件来创建高光。

7。生成最终的视频集锦

# Final_joined.pyfrom moviepy.editor import VideoFileClip, concatenate_videoclipsclip1 = VideoFileClip("filename\\highlight1.mp4")
clip2 = VideoFileClip("filename\\highlight2.mp4")
clip3 = VideoFileClip("filename\\highlight3.mp4")
clip4 = VideoFileClip("filename\\highlight5.mp4")
clip5 = VideoFileClip("filename\\highlight6.mp4")
clip6 = VideoFileClip("filename\\highlight7.mp4")
clip7 = VideoFileClip("filename\\highlight8.mp4")
clip8 = VideoFileClip("filename\\highlight9.mp4")
clip9 = VideoFileClip("filename\\highlight10.mp4")
clip10 = VideoFileClip("filename\\highlight11.mp4")
clip11= VideoFileClip("filename\\highlight12.mp4")
clip12 = VideoFileClip("filename\\highlight13.mp4")
clip13= VideoFileClip("filename\\highlight14.mp4")
clip14= VideoFileClip("filename\\highlight4.mp4")final_clip = concatenate_videoclips([clip1,clip2,clip3,clip4,clip5,clip6,clip7,clip8,clip9,clip9,clip10,clip11,clip12,clip13,clip14])
final_clip.write_videofile("filepath\\Final_Highlights.mp4")

我们使用 concatenate 将所有文件合并成一个文件。在此之后,将生成最终文件。

完整代码:https://bit.ly/2lE55mi

你可以在这里获得【https://bit.ly/2lDEd5V】视频演示:

如果您遇到任何错误或需要任何帮助,您可以随时在 LinkedIn 上评论或 ping 我。

LinkedIn:https://bit.ly/2u4YPoF

**参考:https://bit.ly/2kry0tB

我希望这有助于增强你的知识基础:】

关注我了解更多!

感谢您的阅读和宝贵时间!

使用 stylecloud 生成现代时尚的 Wordcloud

原文:https://towardsdatascience.com/generate-modern-stylish-wordcloud-with-stylecloud-9cbb059696d2?source=collection_archive---------17-----------------------

几乎每个需要从文本语料库中寻找见解的文本分析项目都会包含一个词云。但正如你们中的许多人所记得的,在数据科学家的脑海中,单词云有一个非常无聊的图像和感知,我们总是试图美化它们——最终在这个过程中放弃——除了少数人会选择一些掩蔽图像,然后试图让单词云变成那个形状。这是我们大多数人使用单词云的最高水平。

但在内心深处,我们所有人都一直希望有现代时尚美丽的文字云。这个愿望在 Max Woolf(以[minimaxir](https://github.com/minimaxir/)闻名)的新 python 包[stylecloud](https://github.com/minimaxir/stylecloud)中实现了

78%的数据营折扣

关于 styelcloud

stylecloud是一个 Python 包,它利用了流行的 word_cloud 包,添加了有用的功能来创建真正独特的单词云,包括渐变和图标形状。

stylecloud 安装

stylecloud仅一个pip之遥

pip3 install stylecloud

样式云—基础知识

stylecloud提供了两种方式来生成 style-wordcloud:

  • 作为一个 CLI 命令,可以从您的终端/Shell/Cmd 提示符调用来生成 wordcloud(快速而时尚)
  • 导入stylecloud包并在代码中使用stylecloud()创建 wordcloud 的典型 pythonic 方式

示例文本文件

对于本文,我们将考虑美国前总统巴拉克·奥巴马在 2008 年当选为总统时的标志性就职演说。

从这里下载文件2009–01–20-inaugural-address.txt

样式云— CLI

简单地说,打开你的TerminalCommand Prompt并尝试下面的命令stylecloud指向我们上面下载的文件

stylecloud --file_path 2009-01-20-inaugural-address.txt

来自stylecloud的这个简单命令产生了这个美丽的图(自动保存在与stylecloud.png相同的当前目录中)

这是简单,快速和美丽的不是吗?⚑

样式云-在 Python 脚本中

CLI 中的 stylecloud 是针对普通人类的,而我们是喜欢用Python编码的coders。所以让我们用下面两行代码在 Python 中构建同样的东西。

import stylecloudstylecloud.gen_stylecloud(file_path = "2009-01-20-inaugural-address.txt")

样式云—定制

现在,假设我们不希望它是国旗的形状,而是 twitter 标志的形式。毕竟这是互联网时代,不是吗?代码中的一点点变化——只需一个新的参数来给特定的字体图标命名,就能让我们得到奥巴马演讲的 twitter 形状的风格云。

stylecloud.gen_stylecloud(file_path = "2009-01-20-inaugural-address.txt", icon_name= "fab fa-twitter")

现在,让我们改变一点调色板,也是一个黑暗的主题(这是每个人都喜欢这些天)

stylecloud.gen_stylecloud(file_path = "2009-01-20-inaugural-address.txt", icon_name= "fab fa-twitter", palette="cartocolors.diverging.TealRose_7", background_color="black")

那是真正的黑暗!如果你是 Linkedin(而不是 Twitter)的粉丝,不要离开你——这是你的 Linkedin 图标形状的风格——word cloud

摘要

感谢 Max Woolf ,我们被赋予了这个神奇的库 stylecloud 。我们很快就学会了如何使用这个时髦的 wordcloud 生成器,既可以作为 CLI 工具,也可以使用 Python 脚本。PNG 文件和笔记本可以在这里找到。

当您没有足够的数据时,生成更多的训练数据

原文:https://towardsdatascience.com/generate-more-training-data-when-you-dont-have-enough-db7d8dcde90e?source=collection_archive---------11-----------------------

找出可以用来增加你的训练数据的技巧。

Photo album (Photo by True Agency on Unsplash)

计算机在图像和物体识别方面胜过人类。

像谷歌和微软这样的大公司已经在图像识别方面击败了人类基准[1,2]。平均而言,人类在图像识别任务中犯错误的概率约为 5%。截至 2015 年,微软的图像识别软件达到了 4.94%的错误率,而大约在同一时间,谷歌宣布其软件实现了 4.8%的降低错误率[3]。

这怎么可能呢?

这是通过在包含数百个对象类别的 ImageNet 数据集的数百万个训练样本上训练深度卷积神经网络而实现的[1]。

一百万训练数据!

German 1 million mark stamp (Image by Hebi B. from Pixabay)

“例如,要教会一台计算机从多个角度识别一只猫,可能需要覆盖各种视角的数千张照片。”- 汤姆·西蒙尼特

Image of a cat (Photo by Mikhail Vasilyev on Unsplash)

为了成功地训练用于计算机视觉任务的深度卷积神经网络,需要大量的数据。这是因为这些神经网络有多个隐藏的处理层,随着层数的增加,它需要学习的样本数量也增加。如果没有足够的训练数据可用,模型往往会学习训练数据太好。这叫做过度拟合。如果一个模型过拟合,它的概括能力就很差,因此它对看不见的数据的表现就很差。

但是如果没有庞大的训练数据呢?

对于我们手头的所有图像识别任务来说,没有必要有数百万个训练样本。对于某些任务,收集成千上万的示例图像甚至是一个挑战。这通常是医学图像的情况,例如用于乳腺癌检测和定位的乳房 x 线照相术、用于肺癌检测的胸部 x 射线或用于定位脑瘤的 MRI 扫描。

归结为一个问题。

当我们只有有限的数据时,我们如何训练一个模型来很好地执行这些任务?

通过使用增强生成更多的训练数据

当我们只有少量的图像数据来训练深度卷积神经网络时,我们可以使用数据增强技术从我们已经拥有的数据中生成更多的训练数据。

Multiple images of a person

数据扩充是一种为原始图像生成多个图像的技术。有几种不同的数据增强技术,Mikolajczyk 和 Grochowski 在他们的论文[4]中将这些技术分为两个子类别:使用基本图像处理的数据增强和使用深度学习方法的数据增强。

Data augmentation techniques [4]

几何变换

诸如翻转、裁剪、旋转和平移等几何变换是一些常用的数据扩充技术。我们将在本帖中简要讨论它们。

轻弹

Original image of a dog on the left, horizontally flipped image about centre on the right 6

翻转是拍摄任何给定图像的镜像。这是最简单的增强技术之一。图像可以水平或垂直翻转。然而,水平翻转在两者中更为常见。

种植

Orignal and random cropped image of a cat [7]

裁剪是一种数据扩充技术,通过裁剪边界像素来减小原始图像的大小。裁剪时不会保留空间维度。在这种类型的数据扩充中,不能保证转换后的图像与原始图像属于相同的输出标签。

在上面的图像中,通过从左和右裁剪像素,从原始图像生成了四个图像。裁剪后的图像尺寸从 256x256 缩小到 227x277。

旋转

Orignal and rotated image of a cat [8]

图像可以在 1 到 359 度之间的轴上向左或向右旋转。1 到 20 度之间的旋转被称为轻微旋转,并且可以是用于扩充原始图像的有用技术。随着旋转角度的增加,转换后的数据可能无法保留其原始标签。

翻译

Original and translated images of a tennis ball [8]

翻译是一种将图像向左、向右、向上或向下移动的技术。这是一种非常有用的转换技术,可以避免数据中的位置偏差。当图像被移动时,剩余的空间或者被 0、255 填充,或者被随机噪声填充,从而保持图像的原始大小。

基于 GAN 的数据增强

生成性对抗网络(GAN)也称为 GAN,是一种生成性建模技术,其中从数据集创建人工实例,其方式是保留原始集的相似特征[9]。

GAN 由两个相互竞争的人工神经网络(ann)组成,即生成器和鉴别器。第一个创建新的数据实例,而第二个评估它们的真实性[10]。

这是由 GAN 生成的人脸图像,它是在人脸上训练的。请注意,这些是合成的脸,而不是真人。

Synthetic faces generated by GAN trained on human images [10]

这些是为了从有限的数据集中生成更多的数据,从而可以训练更有效的卷积神经网络而通常使用的一些数据扩充技术。

Olaf 和他的团队使用显微图像上的移位、旋转和随机弹性变形等数据增强技术来训练 U-net 架构模型,同时只有有限的训练数据,并在这些类别中以较大优势赢得了 2015 年 ISBI 细胞追踪挑战赛[11]。

因此,下次你在训练卷积神经网络时对数据进行排序时,使用这些技术来创建更多的数据。

您使用过哪些数据增强技术?在下面的评论中分享你的想法。

来源:

[1]https://www.eetimes.com/document.asp?doc_id=1325712

[2]https://venturebeat . com/2017/12/08/6-人工神经网络胜过人类的领域/

[3]https://www . the guardian . com/global/2015/may/13/Baidu-minwa-super computer-better-human-recogning-images

[4] Mikolajczyk,a .,& Grochowski,M. (2018 年)。图像分类问题中改进深度学习的数据增强。 2018 国际跨学科博士研讨会(Iiphdw) 。doi:10.1109/iiphdw。56686.88868888666

[5]佩雷斯,l .,&王,J. (2017)。使用深度学习的图像分类中数据扩充的有效性。斯坦福大学研究报告

https://snow.dog/blog/data-augmentation-for-small-datasets

https://www.learnopencv.com/understanding-alexnet/

[8]https://nano nets . com/blog/data-augmentation-how-to-use-deep-learning-when-you-have-limited-data-part-2/

[9]肖滕,c .,& Khoshgoftaar,T. (2019 年)。面向深度学习的图像数据增强综述。大数据期刊6 (1)。doi:10.1186/s 40537–019–0197–0

[10]亨里克,f .,&阿拉尼亚,C. (2019 年)。使用 GANs 的数据扩充。机器学习研究论文集

[11] Ronneberger,o .,Fischer,p .,& Brox,T. (2015 年)。生物医学图像分割的卷积网络。

利用深度学习生成钢琴器乐

原文:https://towardsdatascience.com/generate-piano-instrumental-music-by-using-deep-learning-80ac35cdbd2e?source=collection_archive---------1-----------------------

通过试验 Tensorflow v2.0 Alpha 逐步生成钢琴音乐

Photo by Marius Masalar on Unsplash

大家好!终于可以在我的介质上再次写作,有空闲时间做一些人工智能(AI)的实验了。这一次,我将写下并分享如何利用深度学习生成音符。与我的上一篇关于生成歌词的文章不同,这次我们将生成音乐的音符并生成文件(MIDI 格式)。

Photo by Malte Wingen on Unsplash

音乐的主题是钢琴。本文将使用递归神经网络(RNN)、门控递归单元(GRU)的变体,在自我注意的帮助下生成钢琴音符。这篇文章不仅将告诉如何生成音符,这篇文章还将告诉如何生成一个适当的 MIDI 文件,也可以在电脑上播放。

这篇文章的目标读者是对人工智能感兴趣的人,尤其是想练习使用深度学习的人。我希望通过发表这篇文章来提高我的写作技巧,并且内容对你有益😃。

如果您想了解完整的源代码,本文末尾有一个 Github 链接。现在,我将给出 python 笔记本和资源库中的协作链接。

下面是开场音乐

Sound 1 : Opening Piano 😃

(音乐是由我们将在本文中创建的模型生成的)

概述

  1. 介绍
  2. 技术和数据
  3. 管道
  4. 预处理 MIDI 文件
  5. 火车模型
  6. 推理并生成 MIDI 文件
  7. 结果
  8. 结论
  9. 编后记

介绍

当前人工智能领域的一个热门话题是如何仅使用数据(无监督的)来生成东西。在计算机视觉领域,有许多研究人员正在研究利用生成式 Advesarial Network (GAN)生成图像的先进技术。例如,NVIDIA 通过使用 GAN 创建了逼真的人脸生成器。还有一些利用甘生成音乐的研究。

Photo by Akshar Dave on Unsplash

如果我们谈论音乐生成器的,它可以用来帮助音乐家创作他们的音乐。它能增强人的创造力。我认为在未来,如果在这个领域有很多高关注度,大多数音乐人将在人工智能的帮助下创作音乐。

这篇文章将集中在如何通过在音乐中生成连续的音符来生成音乐。我们将知道如何对数据进行预处理,并将其转换为神经网络的输入来生成音乐。

实验还将使用 Tensorflow v2.0 (仍在 alpha 阶段)作为深度学习框架。我想展示的是通过遵循他们的一些最佳实践来测试和使用 Tensorflow v2.0。Tensorflow v2.0 中我喜欢的一个特性是,通过使用他们的亲笔签名,它确实加速了模型的训练。可以通过使用@tf.function定义我们的函数来使用。此外,不再有“tf.session ”,也没有全局初始化。这些特点是我从 Tensorflow 转到 PyTorch 的原因之一。Tensorflow 的可用性对我来说并不好。然而,在我看来 Tensorflow v2.0 改变了这一切,增加了它们的可用性,使做一些实验变得更舒适。

这个实验还使用了自我关注层。自我注意层会告诉我们,给定一个连续的实例(例如在音乐音符“C D E F G”中),每个记号会学习到那个记号对其他记号的影响有多大。以下是一些示例(针对 NLP 任务):

Image 1 : Visualization of attention. Taken from : http://jalammar.github.io/illustrated-transformer/

关于自我关注的进一步信息,尤其是关于变形金刚的,你可以看这篇牛逼的文章。

事不宜迟,让我们继续创作音乐

技术和数据

本实验将使用:

  1. Tensorflow v2.0:深度学习框架,Tensorflow 的新版本,仍处于 alpha 开发阶段。
  2. Python 3.7
  3. 合作实验室:免费的 Jupyter 笔记本环境,无需设置,完全在云中运行。有 GPU 特斯拉 K80 甚至 TPU!遗憾的是,在撰写本文时,Tensorflow v2.0 alpha 仍不支持 TPU。
  4. Python 库 pretty_midi :操作和创建 midi 文件的库

对于数据,我们使用 Magenta 的 MAESTRO (为同步轨道和组织编辑的 MIDI 和音频)作为数据集。该数据集仅包含钢琴乐器。我们将从大约 1000 首音乐中随机抽取 100 首,以加快我们的训练时间。

管道

下面是我们的音乐生成器将如何工作的管道:

Image 2 : Pipeline

我们将看到每一个过程。为简单起见,我们将每个流程划分如下:

  1. 预处理待输入神经网络的 MIDI 文件
  2. 培训过程
  3. 生成 MIDI 文件

预处理 MIDI 文件

在我们进入如何预处理 midi 文件之前,我们需要知道什么是 Midi 格式文件。

pcmag中,MIDI 的定义:

乐器、合成器和计算机之间交换音乐信息的标准协议。开发 MIDI 是为了允许一个合成器的键盘演奏另一个合成器产生的音符。它定义了音符以及按钮、拨号盘和踏板调整的代码,MIDI 控制信息可以编排一系列合成器,每个合成器演奏乐谱的一部分。MIDI 版本 1.0 于 1983 年推出。

总之,MIDI 文件包含一系列带有音符的乐器。比如钢琴和吉他的结合。每种乐器通常有不同的音符来演奏。

对于 MIDI 文件的预处理,Python 中有一些库可以用来完成。其中一个就是[*pretty_midi*](https://github.com/craffel/pretty-midi)。它可以操作 MIDI 文件,也可以创建一个新的。在本文中,我们将使用这个库。

对于pretty_midi, midi 文件的格式如下:

Image 3 : PrettyMidi format

****开始是以秒为单位弹奏的音符的开始。结束是一个音符在一秒钟内演奏完毕。一次可以有多个音符重叠。 Pitch 是弹奏的音符的 MIDI 编号。力度是弹奏音符的力度。

关于 MIDI 编号和音符名称之间的关系,可以参考下图:

Image 4 : Midi Number with the Note Name. Taken from https://newt.phys.unsw.edu.au/jw/notes.html

读取 Midi 文件

我们将成批读取 midi 文件。这是我们如何使用 pretty_midi 读取它:

midi_pretty_format = pretty_midi.PrettyMIDI('song.mid')

我们会得到PrettyMidi的对象。

钢琴卷帘窗阵列预处理

Image 5 : PrettyMidi to Piano Roll Array

对于本文,我们需要从乐器中提取音乐的所有音符。许多 MIDI 文件的音乐中有多种乐器。在我们的数据集中,MIDI 文件只包含一种乐器,即钢琴。我们将从钢琴乐器中提取音符。为了使它更容易,我们将提取每秒所需帧的笔记。pretty_midi有一个方便的函数get_piano_roll来获取(notes, time)维数组中二进制 2D numpy.array 的注释。notes长度为 128,time跟随音乐的持续时间除以 FPS。

源代码我们是如何做到的:

midi_pretty_format = pretty_midi.PrettyMIDI(midi_file_name)
piano_midi = midi_pretty_format.instruments[0] # Get the piano channels
piano_roll = piano_midi.get_piano_roll(fs=fs)

对时间和笔记字典进行预处理

Image 6 : Piano Roll Array to Dictionary

当我们得到钢琴卷首的数组后,我们把它们转换成字典。字典将从弹奏音符的时间开始。例如,在上面的图片中,我们从 28 开始(如果我们转换到第二,假设我们以 5 fps 转换到 piano_roll,音乐在 5.6 秒开始播放它的音符,这可以通过 28 除以 5 得到)。

创建字典后,我们将把字典的值转换成字符串。例如:

array([49,68]) => '49,68'

为此,我们应该循环字典的所有键并更改其值:

for key in dict_note:
    dict_note[key] = ','.join(dict_note[key])

对待输入音符列表和神经网络目标进行预处理

Image 7 : Dictionary to List of Sequences

在我们得到字典后,我们将把它转换成音符序列,作为神经网络的输入。然后我们得到下一个时间步长作为神经网络的输入目标。

Image 8 : Sliding window, taken from : https://towardsdatascience.com/generating-drake-rap-lyrics-using-language-models-and-lstms-8725d71b1b12

在本文中,序列表的长度为 50。这意味着如果我们的 fps 是 5,我们将得到一个包含 10 (50 / 5)秒播放时间的序列。****

列表中的“e”表示在这段时间内没有音符被演奏。因为有时在每个弹奏音符之间会有跳跃或者没有弹奏音符。在图 7** 的例子中,我们可以看到从 43 到 46 有一个跳跃。如果我们转换序列,序列列表将是:**

[ ... '61,77', '61,77', 'e', 'e', '73' , ...]

我们怎么做?我们将在一批音乐中处理音符。

我们使用一个 50 长的推拉窗。对于音乐中的第一个音符,我们将在列表中添加“e”49 次。然后将开始时间设置为字典中的第一个时间步长。在图 7** 中的例子中,是 28 。然后,我们添加音乐中的第一个音符(例如“77”)。**

然后,对于下一个实例,我们将窗口滑动一次,将“e”追加到列表中 48 次,追加在时间步长 28 中播放的音符,在时间步长 29 中追加音符,并重复,直到音乐结束。****

对于下一首音乐,我们重复上述过程。

这是源代码:

创建笔记标记器

在我们深入研究神经网络之前,我们必须创建标记化器,将顺序笔记转换为笔记的顺序索引。首先,我们应该将票据映射到一个表示票据 id 的索引中。

例如:

{
'61,77' : 1, # 61,77 will be identified as 1
'e' : 2,
'73' : 3,
.
.
}

因此,如果我们之前的输入如下:

[ ... , '61,77', '61,77', 'e', 'e', '73' , ...]

我们将其转换为:

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

这是我们的做法。

总结我们的预处理函数,下面是我们将使用的函数:

火车模型

在我们了解如何使用 Tensorflow v2.0 的新功能进行训练之前,我们将看到如下架构:

神经网络体系结构

Image 9 : Our Neural Network Architecture

因此,深度学习架构将使用 3 层门控递归单元(GRU,递归神经网络的一种变体)和一些自我关注层。使用丢弃是为了使神经网络不会过拟合得太快。

对于自我关注层,我们将使用这个存储库并稍加编辑,以便我们可以在 Tensorflow v2.0 上使用它。

代码:

培养

我们将通过迭代数据集中的一些音乐来更新模型的权重,并如上所述对数据进行预处理。然后,我们将一批实例中的一些实例作为神经网络的输入和目标。

我们将使用GradientTape来更新神经网络的权重。首先,我们计算损耗,并使用apply_gradients 对其进行反向传播。如果你熟悉 PyTorch 的使用,这就是 Pytorch 训练神经网络模型的方法。

确保在功能上使用@tf.function。这样可以把功能转换成亲笔签名,让我们的训练更快。tf.function的一个缺点是不能使用不同大小的批次作为神经网络的输入。例如,我们的批量是 64。如果数据集的大小是 70,最后一批将包含 6 个实例。这将向程序抛出异常,因为图形将具有与初始图形不同大小的输入。也许它的工作原理是通过使用函数时看到第一个输入来创建占位符。

在本文中,我们将使用 16 个BATCH_SONG 和 96 个BATCH_NNET_SIZE。这意味着我们将从所有音乐列表中选取 16 首音乐,然后提取其序列。然后对于神经网络中的每一步,我们从提取的序列实例中取 96 个序列作为神经网络的输入和目标。

代码如下所示:

推理并生成 MIDI 文件

Image 10 : Inference and Generate MIDI files

使用我们训练过的神经网络模型,有两种方法生成 MIDI 文件:

我们需要从一开始就做出选择:

  1. 我们随机生成 50 个音符作为音乐的开始。
  2. 我们使用 49 个空注释(' e '),后跟我们选择的开始注释(例如' 72 ',确保注释在 NoteTokenizer 中)。

Image 11 : Visualization on how the generator works

在我们选择了音乐生成器的种子之后,我们使用训练好的模型根据 50 个随机音符预测下一个音符。我们用预测值作为随机选择音符的概率分布。我们这样做,直到指定我们想要的最大序列长度。然后我们放下前 50 个音符。

在我们生成一个音符序列列表后,我们将再次将其转换为钢琴卷帘窗数组。然后将其转换为 PrettyMidi 对象。

之后,我们调整音乐的速度和节奏,最终生成 MIDI 文件。

代码:

这是如何从生成的音符编写 midi 文件:

结果

当我做的时候,训练花了 1 个小时 1 个纪元。当我这样做的时候,我决定运行 4 个纪元(4 小时)的训练。

根据经过 4 个时期训练的模型,以下是结果:

随机生成 50 张纸币

Sound 2

Sound 3

从一个音符生成

Sound 4

Sound 5

(注意,这些是从 MIDI 文件转换而来的 mp3 文件。我用在线转换器做到这一点。这份笔记似乎有点与原作不符。如果你想听的话,我会上传原始的 MIDI。)

这些生成的音符之间存在明显的差异。如果我们从一个音符生成它,它将在演奏音符时有一个缓慢的速度开始。它不同于我们从 50 张随机纸币中产生的。它没有一个缓慢的开始。

这是选择从随机的 50 个音符开始的音乐的最后一个序列上的自我注意块的可视化:

首先关注

Image 12 : First Self Attention

第二注意

Image 13 : Second Self Attention

正如你所看到的,第一个自我注意块学习序列实例中的每个音符要关注什么音符。然而,对于第二个注意块应该关注什么还没有结果。我们还可以看出,如果其他音符的位置离当前音符很远,它将不会聚焦到当前音符(图像 12 和图像 13 中的黑色)。

结论

我们已经建立了一个工具来生成包含钢琴音乐的 MAESTRO 数据集的音乐。我们对它进行预处理,训练我们的神经网络模型,然后用它生成音乐。这些音乐是 MIDI 格式的。我们用 Tensorflow v2.0 来做。我认为 Tensorflow v2.0)的用户体验比之前的版本更好。

我们的模型生成的音乐也很连贯,很好听。它可以调整如何弹奏音符。例如:当发生器从一个音符(意味着它是音乐的开始)开始时,它以慢节奏开始。

我们可以为音乐生成器尝试一些东西。在本文中,我们对生成单个乐器进行了实验。如果音乐有多种乐器会怎样?需要有一个更好的架构来做这件事。我们可以尝试多种方法来试验音乐数据。

编后记

Photo by Alan Chen on Unsplash

这就是这篇关于生成钢琴音乐音符的文章。事实上,我写这篇文章的灵感来自于我的第一篇关于深度学习的文章,深度学习是生成音乐的歌词。"生成音乐笔记怎么样?"。我试验了一下,很好……它工作了。

对我来说,做这个实验有些困难。首先,我需要搜索什么样的文件格式便于预处理和作为神经网络的输入。我发现 MIDI 很简单,文件也很小。然后,我需要知道在 Python 中有没有可以预处理文件的库。我找到了两个,有music21pretty_midi ,它们的存储库没有过期。我选择pretty_midi。也许是因为它的名字里有“漂亮”😝。最后,我需要思考如何对笔记进行预处理。谢天谢地,pretty_midi有一个方便的功能get_piano_roll让它变得更容易。

我也没看过多少关于音乐的研究论文。也许有研究论文可以被复制,可以在实验室里看到。

我很抱歉缺乏对自我关注层的可视化。

我欢迎任何可以提高我自己和这篇文章的反馈。我正在学习写作和深度学习。我感激能让我变得更好的反馈。确保以适当的方式给出反馈😄。

在我的下一篇文章中再见!

Source : https://cdn.pixabay.com/photo/2017/07/10/16/07/thank-you-2490552_1280.png

贮藏室ˌ仓库

** [## haryoa/note_music_generator

在 GitHub 上创建一个帐户,为 haryoa/note_music_generator 的开发做出贡献。

github.com](https://github.com/haryoa/note_music_generator)

来源

[## 百科全书

(乐器数字接口)一种标准协议,用于在音乐…

www.pcmag.com](https://www.pcmag.com/encyclopedia/term/47014/midi) [## 记下名称、MIDI 编号和频率

记下名称、MIDI 编号和频率

音符名称、MIDI 编号和频率 new . phys . UNSW . edu . au](https://newt.phys.unsw.edu.au/jw/notes.html) [## 图示的变压器

在之前的帖子中,我们研究了注意力——现代深度学习模型中普遍存在的方法。注意力是一种…

jalammar.github.io](http://jalammar.github.io/illustrated-transformer/) [## 斯库尔杜尔/古典钢琴作曲家

在 GitHub 上创建一个帐户,为 Skuldur/古典钢琴作曲家的发展做出贡献。

github.com](https://github.com/Skuldur/Classical-Piano-Composer) [## 品红

一个探索机器学习在艺术和音乐创作过程中的作用的研究项目。

magenta.tensorflow.org](https://magenta.tensorflow.org/)

https://cs224d.stanford.edu/reports/allenh.pdf

[## 有效张量流 2.0 |张量流|张量流

TensorFlow 1 中常见的使用模式。x 是“厨房水槽”策略,所有可能的计算…

www.tensorflow.org](https://www.tensorflow.org/alpha/guide/effective_tf2)**

利用数据科学生成体育排名

原文:https://towardsdatascience.com/generate-sports-rankings-with-data-science-4dd1979571da?source=collection_archive---------9-----------------------

在本教程中,我们将介绍一种非常流行的算法,用于为运动队生成排名。我们将要学习的方法叫做科利评级。

在深入研究之前,让我们先了解为什么需要这些排名系统。简单的输赢比会不会不够?要回答这个,我们先来看一个例子。假设有一个有 4 支球队参加的锦标赛,以下是结果,以及到目前为止锦标赛的最终排名。

正如你所看到的,曼联赢得了他们的所有 6 场比赛,轻松地坐在首位,利物浦输掉了他们所有的比赛,躺在积分榜的底部。阿森纳和切尔西分享战利品,两轮都被曼联击败,两轮都击败了利物浦,然后他们平分秋色,阿森纳在第一轮获胜,切尔西在反向比赛中回敬。

现在想象我们开始第三轮比赛,前几场比赛的结果如下。第一场:阿森纳击败曼联第二场:切尔西击败利物浦
更新后的表格如下。

等等,切尔西和阿森纳真的应该得到同样的排名吗?这不是很明显吗?阿森纳击败了曼联,他们是目前为止在锦标赛中占主导地位的球队,而切尔西击败了利物浦,反正他们输掉了所有的比赛。毫无疑问,阿森纳应该得到更多的信任,排名应该高于切尔西。但是我们怎么做呢?如果我们只是用一个简单的输赢比,就没有办法区分它们。更进一步,如果你考虑净胜球之类的问题,考虑到所有比赛都是以 2 比 1 的比分获胜,我们再次陷入僵局。那么我们应该如何考虑阿森纳击败了一支比切尔西强大得多的球队,因此应该得到更高的排名。这就是排名系统发挥作用的地方。正如我们将看到的,科利排名能够理解强队被击败的事件,并相应地调整他们的排名。所以不要再拖延了,让我们开始吧。

科利排名

Wesley N. Colley 先生建议,不要像;收视率=[总胜场数]/[总游戏数],收视率应根据以下公式计算

评级= [1 +总胜场数] / [2 +总游戏数]。如果你看看这个公式,在任何锦标赛开始之前,所有球队都将以 0.5 的评分开始,因为“总胜场数”和“总游戏数”都将为零。记住这一点(事实上所有的团队都是从 0.5 分开始的),它以后会派上用场的。事实上,在所有时间内,所有团队的评分在科利算法中的平均值将始终保持在 0.5。
我们可以写出如下所示的总胜率。

仔细观察单个团队的* [总游戏数]项,我们可以说[总游戏数] = * [1+1+1…1],其中“1”代表与每个对手进行的游戏。这反过来可以写成[总游戏数] = [1/2 + +..].如果你还记得,就像开始时所说的,所有团队的评分都在 0.5 左右,因此所有团队的平均评分加起来也是 0.5。考虑到这一点,我们可以说[1/2 + +..]~ =[对手评分总和]。以此改写总胜率的方程式。

重写评分公式,

扩展总胜率并写下单个团队的评分,我们可以写为。

其中,rᵢ、wᵢ、lᵢ和 ti 代表感兴趣的球队的评分、胜场、负场和总场次,而∑rj 是对手评分的总和。这可以进一步重新安排为

现在,正如我的大多数其他教程一样,让我们使用一个玩具示例来更好地理解数学方程。考虑两个团队的情况。如上所述,在开始之前,它们都将具有 0.5 的评级。现在让我们假设他们互相打了一场比赛。让 rW 和 rL 分别代表赢队和输队的新评级。如果您为两个团队输入 tᵢ(等于 1),并考虑他们的 wᵢ和 lᵢ值,我们将从等式(a)获得以下结果

这代表一个简单的两变量线性系统,当求解时,我们得到新的额定值 rw = 5/8 和 rL = 3/8。对于 2 个团队,方程(A)导致两个变量的线性系统,对于 N 个团队,它将导致 N 个变量的线性系统。在编程世界中,每当我们想要解 N 个变量的线性方程时,我们总是把它们写成矩阵的形式。因此,将矩阵形式的等式(A)改写为

其中向量 r 表示所有评级 rᵢ的列向量,而向量 b 是等式(a)右侧的列向量。矩阵 C 被定义为科利矩阵,只是稍微复杂一些。想象一下,我们最喜欢的四支英超球队排成 4x4 的行列,如下图所示

科利矩阵中的对角线元素应由相应球队的数字= (2 +总游戏数)填充。因此,第一个蓝色单元格的值应该是 2 +曼联的比赛次数。同样的,切尔西、阿森纳和利物浦的比赛也将被填满。由绿色单元格表示的对角线外的元素应该具有由该单元格的行和列表示的团队之间进行的游戏次数的负值。因此,例如,与曼联行和切尔西列相交的单元格应该有一个等于曼联对切尔西比赛次数负值的数字。就这样,我们将填充科利矩阵中的剩余单元。一旦我们解了这个 N 变量线性方程 Cr = b,我们将得到' r '的向量值,它代表每个单独团队的评级。

有了对理论背景的清晰理解,让我们继续编写一个 Python 代码来计算本文开头介绍的 toy example 的 Colley 排名。Python 代码文件以及一些支持文件可以在我的 github repo 这里找到。

在开始编码之前,让我解释一下两个支持文件的结构,即“分数”和“团队”,它们都是“逗号分隔值”格式。“团队”文件包含团队列表,旁边有一个“号码”。这个“号码”将用于在“分数”文件中代表该队。下面的截图显示了“团队”文件的内容。

所以从现在开始,无论何时我们想代表曼联,我们都会用 1 号代表他们。同样,对于切尔西、阿森纳和利物浦,我们将分别使用数字 2、3 和 4 来代表他们的分数。现在让我们在下面截图的帮助下看看分数的文件。

“分数”文件中的每一行对应一场比赛。我稍后会解释为什么这个文件有如此特殊的顺序。“分数”文件中的列表示= >列 1 =从 1/1/0000 开始玩这个特定游戏的天数。第 2 列=今天的日期。第 3 列=团队 1 号。第 4 列=球队 1‘主场’值(1 =主场,-1 =客场,0 =中立)。第 5 列=团队 1 得分。第 6 列=团队 2 号。第 7 列=球队 2‘主场’值(1 =主场,-1 =客场,0 =中立)。第 8 列=团队 2 得分。

因为在本练习中我们不会使用第 1、2、4 和 7 列的值,所以我为它们设置了虚拟数字。此外,为了方便起见,我将分数(第 5 列表示团队 1 的分数,第 8 列表示团队 2 的分数)分别记为 2 和 1,因为在本例中我们也不会查看分数。我们将用它来决定每场比赛的赢家。

让我们以第一排为例。表示比赛日期的列 1 和 2 分别具有虚拟值“1”。第 3 列的值为“1”。交叉检查我们的“团队”文件,我们可以看到值“1”是用来代表曼联。第 4 列有“-1”,表示这场比赛是曼联的客场比赛。第 5 列的值为“2 ”,表示曼联进了 2 个球。第 6 列数值代表第 2 队的号码,其中 2 号表示第 2 队是切尔西,这是一场曼联对切尔西的比赛。第 7 列的值为“1 ”,表示这是切尔西的主场比赛,最后一列的值为“1 ”,表示切尔西的进球数。

最后,让我们开始编码这个算法。编码 Colley 算法相对简单,并且相当容易理解。与任何 Python 文件一样,我们将导入所需的包,即本例中的 numpy 和 pandas。

# Importing packages
import numpy as np
import pandas as pd

然后我们去读“团队”和“分数”文件。

# Reading 'teams' and 'scores' data
teams = pd.read_csv('teams.txt', header = None)
num_of_teams = len(teams.index)data = pd.read_csv('scores.txt', header = None)

我们用所需维数中的所有 0 来初始化 Colley 矩阵和向量 b。

# Initializing Colley Matrix 'c'and vector 'b'
c = np.zeros([num_of_teams, num_of_teams])
b = np.zeros(num_of_teams)

然后,逐行迭代“分数”文件,我们根据哪个队在比赛以及每场比赛的获胜者来填充 Colley 矩阵和向量“b”。

# Iterating through rows and populating Colley matrix values
for index, row in data.iterrows():
    t1 = row[2]
    t2 = row[5]

    c[(t1-1)][(t1-1)] = c[(t1-1)][(t1-1)] + 1 # Updating diagonal element
    c[(t2-1)][(t2-1)] = c[(t2-1)][(t2-1)] + 1 # Updating diagonal element
    c[(t1-1)][(t2-1)] = c[(t1-1)][(t2-1)] - 1 # Updating off - diagonal element
    c[(t2-1)][(t1-1)] = c[(t2-1)][(t1-1)] - 1 # Updating off - diagonal element

    # Updating vecotr b based on result of each game
    if row[4] > row[7]:
        b[(t1-1)] += 1
        b[(t2-1)] -= 1
    elif row[4] < row[7]:
        b[(t1-1)] -= 1
        b[(t2-1)] += 1

一旦完成,我们按照等式(A)进行调整,将 2 加到 Colley 矩阵的对角元素,并将 1 除以向量 b 的每个元素。

# Adding 2 to diagonal elements (total number of games) of Colley matrix
diag = c.diagonal() + 2
np.fill_diagonal(c, diag)# Dividing by 2 and adding one to vector b
for i, value in enumerate(b):
    b[i] = b[i] / 2
    b[i] += 1

然后,我们使用 numpy 的 linalg.solve()求解这个 N 变量线性方程。

# Solving N variable linear equation
r = np.linalg.solve(c, b)

一旦我们在“r”中得到结果,我们通过使用 argsort()方法显示前 4 个团队。

# Displaying ranking for top 4 teams
top_teams = r.argsort()[-4:][::-1]
for i in top_teams:
    print (str(r[i]) + " " + str(teams.iloc[i][1]))

这样,如果您成功下载了 repo 并运行了这段代码,您应该会看到下面的输出。

现在,为了检查这个算法的真正实力,我们将通过插入下面几行来在我们的“分数”文件中增加两个游戏。
第一场:阿森纳击败曼联= > 1,1,1,-1,1,3,1,2
第二场:切尔西击败利物浦= > 1,1,2,-1,2,4,1,1
在‘scores’中做了上述修改后再次运行 Python 文件,会得到如下结果。

正如你所看到的,即使阿森纳和切尔西打了,赢了和输了同样多的比赛,科利算法也能够认识到这样一个事实,即阿森纳击败了比被切尔西击败的利物浦更强大的曼联队。

状态良好的团队

回到“分数”文件的格式,让我们再看一个用例。假设锦标赛有 3 轮,结果如下图所示。

曼联在第一轮赢得所有比赛,切尔西在第二轮赢得所有比赛,阿森纳在第三轮。尽管三支球队在胜利数量上打成平手,但任何有见识的体育人士都会告诉你,在第一轮赢得所有比赛后,曼联已经失败了。另一方面,阿森纳在最近一轮的比赛中连胜,切尔西位于两者之间。考虑到这一点,即使曼联,阿森纳和切尔西的总积分相同,一个好的排名系统应该提供一个区分旧表现和最近表现的条款。

为了将这种“动量”或“形式”因素考虑在内,引入了一个称为“权重”的新变量。借助一个简单的“if else”条件语句,我们给不同的游戏赋予不同的权重。

# Iterating through rows and populating Colley matrix values
for index, row in data.iterrows():
    t1 = row[2]
    t2 = row[5]

    if row[0] <= 6: #For first round matches
        weight = 0.9
    elif row[0] > 6 and row[0] <=12: #For second round matches
        weight = 1.0
    else:
        weight = 1.1 #For third round matches

    c[(t1-1)][(t1-1)] = c[(t1-1)][(t1-1)] + 1 * weight # Updating diagonal element
    c[(t2-1)][(t2-1)] = c[(t2-1)][(t2-1)] + 1 * weight # Updating diagonal element
    c[(t1-1)][(t2-1)] = c[(t1-1)][(t2-1)] - 1 * weight # Updating off - diagonal element
    c[(t2-1)][(t1-1)] = c[(t2-1)][(t1-1)] - 1 * weight # Updating off - diagonal element

    # Updating vecotr b based on result of each game
    if row[4] > row[7]:
        b[(t1-1)] += 1 * weight
        b[(t2-1)] -= 1 * weight
    elif row[4] < row[7]:
        b[(t1-1)] -= 1 * weight
        b[(t2-1)] += 1 * weight

随着锦标赛的进行,旧游戏的比重越来越小。而与前两轮相比,最新一轮的装置被给予更高的权重。通过以上修改,如果我们再次运行我们的 Colley 算法,我们将得到以下结果。

不出所料,在最近的比赛中赢得所有比赛的阿森纳排名第一,而曼联排名第三,尽管他们与阿森纳和切尔西积分相同。

就这样,我将结束这篇文章。希望你这个体育迷和数据科学家能够欣赏科利方法的美丽和简单。

像往常一样,如果你喜欢这篇文章,在 Twitter 上关注,转发,或者鼓掌,媒体上的赞将鼓励我继续我的博客世界之旅。

直到下一次…干杯!!

用 MapBox GL 和 Python 生成 logo。

原文:https://towardsdatascience.com/generating-a-logo-with-mapbox-gl-and-python-2c44a357f462?source=collection_archive---------14-----------------------

建筑足迹总是有一种令人愉悦的美感。视觉设计通常源于自然和人造的隐喻——这两种事物都包含在制图领域中。拓扑特征和水路为我们呈现了柔和的曲线特征,与道路设计的线性和对称形状形成了直接对比。

在这里,我们将建筑物的占地面积绘制成类似 Tron 的图像,有点像印刷电路板(PCB)。

第一步:选择你的位置

就我个人而言,我发现河流与城市结合的地方效果最好。这就是为什么我选择使用威斯敏斯特划船基地的位置,这是伦敦市中心的一个小型水上运动中心。

使用快速谷歌地图搜索,可以从 url 获得经度和纬度:

51 29 ' 06.6 " N+0 08 ' 04.9 " W

步骤 2:获取建筑造型文件

获取一个国家建筑物的形状文件有很多来源。美国的足迹可以在这里找到,英国的足迹可以通过英国国家测绘局的开放地图项目(链接如下)找到。

* [## 英国的所有建筑

此页面包含为整个英国构建 shapefile 数据的链接,以及指向单个地理包的链接…

ajrae.staff.shef.ac.uk](http://ajrae.staff.shef.ac.uk/buildings/)

步骤 3:只提取你需要的数据

这个过程涉及到 Python 的使用,结合 geopandas 库pip install geopandas

我们用geopandas.read_file读取文件,然后过滤掉任何不想要的结果。因为我们希望绘制的区域包括三个不同的行政区,所以我们只在NAME列包含其中一个行政区名称的地方提取数据:

selection = all_data[ (all_data.NAME == 'Westminster') ^     
                      (all_data.NAME == 'Wandsworth' ) ^ 
                      (all_data.NAME == 'Lambeth'    )    ]

然后,我们确保我们的单位是经度和纬度的单位:

selection = selection.to_crs(epsg=4326).reset_index()

第四步:只获取我们位置一定半径范围内的建筑

现在我们有了所有的数据,我们希望过滤掉一定距离以外的所有建筑。

为此,我们可以使用 shapley 几何图形并定义我们的位置。然后,我们可以遍历 GeoPandas 数据框中的所有项目,并且只追加距离所选点一定距离的项目。

point = Point(lon,lat)
thresh = 0.01
keep=[]**for** r **in** selection.iterrows(): dst = point.distance(r[1].geometry) **if** abs(dst) < thresh:
        x,y = r[1].geometry.exterior.coords.xy
        keep.append([list(x),list(y)])

最后,我们将所有数据写入一个文本文件:

**import** **json**
json.dump( [[list(i) **for** i **in** zip(x,y)] **for** x,y **in** keep] , 
                                 open('keep_footprint.json','w') 

可选:在 python 中预先绘制

fig = plt.figure()
ax = fig.add_subplot(111)

**for** poly **in** keep:
    x,y = poly
    ax.plot(x, y, color='red', alpha=0.7,
        linewidth=1, solid_capstyle='round', zorder=2)

ax.set_title('test')
plt.show()

步骤 5:设计创建地图框样式

现在我们注册了一个免费的地图框账户,用提供的工作室应用【https://studio.mapbox.com 创建我们自己的定制风格

我个人是从“暗”布局开始的,把所有的街道都变暗,把所有的标签的不透明度设置为 0,去掉所有的标签。生产出来的款式可以在这里找到。

Mapbox Studio

步骤 6:简单的地图框布局

最后,我们可以使用带有我们的 latlon 值的自定义样式的 Mapbox 示例脚本来生成我们位置的预览。(下面链接中的代码)

[## 以自定义样式显示地图

使用自定义地图框托管样式。

docs.mapbox.com](https://docs.mapbox.com/mapbox-gl-js/example/custom-style-id/)

然后,我们通过添加一个椭圆形的剪辑路径来扩展它,样式为“map”元素:

<style>#map{
   width:600px;
   height:600px;
   clip-path:ellipse(300px 300px at 300px 300px);
}</style>

为我们的位置添加一个标记:

// marker
new mapboxgl.Marker({"color":'#33ff00'})
    .setLngLat([ -0.134605,51.484575])
    .addTo(map);

步骤 6:加载我们的足迹数据

最后,剩下的就是在文本文件中读取。我发现使用 GitHub 的 raw 格式,结合 d3 库最简单:d3js.org

d3.json(“[https://raw.githubusercontent.com/wolfiex/GeoLogo/master/polyfoot.txt](https://raw.githubusercontent.com/wolfiex/GeoLogo/master/polyfoot.txt)", run)

现在,我们需要做的就是在加载的数据集中绘制每个建筑物的轮廓:

data.forEach((polygon, i) => {map.addLayer({
        'id': 'poly' + i,
        'type': 'line',
        'source': {
            'type': 'geojson',
            'data': {
                'type': 'Feature',
                'geometry': {
                    'type': 'Polygon',
                    'coordinates': [polygon]
                }
            }
        },
        'layout': {},
        'paint': {
            'line-color': '#088',
            'line-opacity': 0.8
        }
    });
}
})

如果我们希望每个形状都被填充而不是描边,我们可以将“类型”设置为fill而不是line,并相应地更改line-colorline-opacity

第七步:享受!

我们有了它,一个围绕我们感兴趣的区域的漂亮标志。

注意:由于可能有许多多边形要绘制,此过程可能需要一段时间才能完成。明智地选择你的门槛距离!

*

用 Python 生成简历

原文:https://towardsdatascience.com/generating-a-resume-in-python-1480a4d6a399?source=collection_archive---------5-----------------------

我正沿着“自学”的道路向数据科学领域过渡。因此,当我坐下来开始写简历时,我努力思考如何在简历这种静态和传统的东西上表达我学到的新技能。老实说,我觉得写简历很吓人。

当我没有能让你眼前一亮的学历或经验时,我如何才能吸引招聘经理的目光呢?

在思考这个问题的时候,我想起了一件重要的事情。虽然数据科学对我来说是一个相对较新的尝试,但我非常精通通信和创造性故事的世界。因此,戴上我的创意帽子,我开始寻找一种新的方式来创建一份简历,它可以以一种自然而清晰的方式快速展示技术数据可视化技能。

而这就是结果…

这非常简单,但是我使用 Python 中的 matplotlib 库编译了整个简历。它基本上是一个 8.5 x 11 的图表,没有轴和信息,但有一些图形线条和许多注释。

它很容易编译,但是它展示了对 Python 的熟练程度和创造性交流的能力。或许更重要的是,它让写简历变得更有趣,也不那么令人生畏。

源代码在下面,或者你可以在我的 GitHub 库找到。希望你喜欢它,如果你有任何意见或建议让我知道!

# Text Variables
Header = '>>>This resume was generated entirely in Python. For full sourcecode, view my portfolio.'
Name = 'EDDIE KIRKLAND'
Title = 'Data Science & Analytics'
Contact = 'Atlanta, GA\n404-XXX-XXXX\nwekrklndATgmailDOTcom\nlinkedin.com/in/ekirkland\ngithub.com/e-kirkland'
ProjectsHeader = 'PROJECTS/PUBLICATIONS'
ProjectOneTitle = 'Increasing Kaggle Revenue'
ProjectOneDesc = '- Published by Towards Data Science\n- Analyzed user survey to recommend most profitable future revenue source\n- Cleaned/visualized data using pandas/matplotlib libraries in Python'
ProjectTwoTitle = 'NYC School Data Cleaning & Analysis'
ProjectTwoDesc = '- Cleaned and combined several tables using pandas library in Python\n- Used PDE and visualization to determine correlations for future study'
ProjectThreeTitle = 'Pandas Cleaning and Visualization'
ProjectThreeDesc = '- Cleaned data for analysis using pandas library in Python\n- Used pandas and matplotlib to explore which cars hold the most value over time'
Portfolio = 'Portfolio: rebrand.ly/ekirkland'
WorkHeader = 'EXPERIENCE'
WorkOneTitle = 'Example Company / Example Position'
WorkOneTime = '8/2013-Present'
WorkOneDesc = '- Raised $350k in startup funds, recruited/organized launch team\n- Coordinated branding and communication strategy\n- Led team of 80 volunteer and staff leaders'
WorkTwoTitle = 'Second Company / Second Position'
WorkTwoTime = '2/2007-8/2013'
WorkTwoDesc = '- Led team of over 100 full-time and contract staff\n- Helped create branding and messaging for weekly content\n- Created/directed musical elements at weekly events for up to 10,000 people'
WorkThreeTitle = 'Third Company / Third Position'
WorkThreeTime = '6/2004-2/2007'
WorkThreeDesc = '- Planned/Coordianted Toronto arena event and South Africa speaking tour\n- Oversaw research for published products'
EduHeader = 'EDUCATION'
EduOneTitle = 'Example University, Bachelor of Business Administration'
EduOneTime = '2000-2004'
EduOneDesc = '- Major: Management, Minor: Statistics'
EduTwoTitle = 'Example University, Master of Arts'
EduTwoTime = '2013-2017'
SkillsHeader = 'Skills'
SkillsDesc = '- Python\n- Pandas\n- NumPy\n- Data Visualization\n- Data Cleaning\n- Command Line\n- Git and Version Control\n- SQL\n- APIs\n- Probability/Statistics\n- Data Manipulation\n- Excel'
ExtrasTitle = 'DataQuest\nData Scientist Path'
ExtrasDesc = 'Learned popular data science\nlanguages, data cleaning and\nmanipulation, machine learning \nand statistical analysis'
CodeTitle = 'View Portfolio'# Setting style for bar graphs
import matplotlib.pyplot as plt
%matplotlib inline# set font
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['font.sans-serif'] = 'STIXGeneral'fig, ax = plt.subplots(figsize=(8.5, 11))# Decorative Lines
ax.axvline(x=.5, ymin=0, ymax=1, color='#007ACC', alpha=0.0, linewidth=50)
plt.axvline(x=.99, color='#000000', alpha=0.5, linewidth=300)
plt.axhline(y=.88, xmin=0, xmax=1, color='#ffffff', linewidth=3)# set background color
ax.set_facecolor('white')# remove axes
plt.axis('off')# add text
plt.annotate(Header, (.02,.98), weight='regular', fontsize=8, alpha=.75)
plt.annotate(Name, (.02,.94), weight='bold', fontsize=20)
plt.annotate(Title, (.02,.91), weight='regular', fontsize=14)
plt.annotate(Contact, (.7,.906), weight='regular', fontsize=8, color='#ffffff')
plt.annotate(ProjectsHeader, (.02,.86), weight='bold', fontsize=10, color='#58C1B2')
plt.annotate(ProjectOneTitle, (.02,.832), weight='bold', fontsize=10)
plt.annotate(ProjectOneDesc, (.04,.78), weight='regular', fontsize=9)
plt.annotate(ProjectTwoTitle, (.02,.745), weight='bold', fontsize=10)
plt.annotate(ProjectTwoDesc, (.04,.71), weight='regular', fontsize=9)
plt.annotate(ProjectThreeTitle, (.02,.672), weight='bold', fontsize=10)
plt.annotate(ProjectThreeDesc, (.04,.638), weight='regular', fontsize=9)
plt.annotate(Portfolio, (.02,.6), weight='bold', fontsize=10)
plt.annotate(WorkHeader, (.02,.54), weight='bold', fontsize=10, color='#58C1B2')
plt.annotate(WorkOneTitle, (.02,.508), weight='bold', fontsize=10)
plt.annotate(WorkOneTime, (.02,.493), weight='regular', fontsize=9, alpha=.6)
plt.annotate(WorkOneDesc, (.04,.445), weight='regular', fontsize=9)
plt.annotate(WorkTwoTitle, (.02,.4), weight='bold', fontsize=10)
plt.annotate(WorkTwoTime, (.02,.385), weight='regular', fontsize=9, alpha=.6)
plt.annotate(WorkTwoDesc, (.04,.337), weight='regular', fontsize=9)
plt.annotate(WorkThreeTitle, (.02,.295), weight='bold', fontsize=10)
plt.annotate(WorkThreeTime, (.02,.28), weight='regular', fontsize=9, alpha=.6)
plt.annotate(WorkThreeDesc, (.04,.247), weight='regular', fontsize=9)
plt.annotate(EduHeader, (.02,.185), weight='bold', fontsize=10, color='#58C1B2')
plt.annotate(EduOneTitle, (.02,.155), weight='bold', fontsize=10)
plt.annotate(EduOneTime, (.02,.14), weight='regular', fontsize=9, alpha=.6)
plt.annotate(EduOneDesc, (.04,.125), weight='regular', fontsize=9)
plt.annotate(EduTwoTitle, (.02,.08), weight='bold', fontsize=10)
plt.annotate(EduTwoTime, (.02,.065), weight='regular', fontsize=9, alpha=.6)
plt.annotate(SkillsHeader, (.7,.8), weight='bold', fontsize=10, color='#ffffff')
plt.annotate(SkillsDesc, (.7,.56), weight='regular', fontsize=10, color='#ffffff')
plt.annotate(ExtrasTitle, (.7,.43), weight='bold', fontsize=10, color='#ffffff')
plt.annotate(ExtrasDesc, (.7,.345), weight='regular', fontsize=10, color='#ffffff')
plt.annotate(CodeTitle, (.7,.2), weight='bold', fontsize=10, color='#ffffff')#add qr code
from matplotlib.offsetbox import TextArea, DrawingArea, OffsetImage, AnnotationBbox
import matplotlib.image as mpimg
arr_code = mpimg.imread('ekresumecode.png')
imagebox = OffsetImage(arr_code, zoom=0.5)
ab = AnnotationBbox(imagebox, (0.84, 0.12))
ax.add_artist(ab)plt.savefig('resumeexample.png', dpi=300, bbox_inches='tight')

用机器学习生成披头士歌词

原文:https://towardsdatascience.com/generating-beatles-lyrics-with-machine-learning-1355635d5c4e?source=collection_archive---------6-----------------------

(source)

语言模型和 OpenAI 的 GPT-2 的高级入门

甲壳虫乐队是一个巨大的文化现象。他们永恒的音乐至今仍在年轻人和老年人中引起共鸣。我个人是个超级粉丝。依我拙见,他们是有史以来最伟大的乐队。他们的歌曲充满了有趣的歌词和深刻的思想。以这些酒吧为例:

当你超越自己时,你会发现内心的平静在那里等着你

强大的东西。然而,甲壳虫乐队的伟大之处在于他们的多才多艺。他们的一些歌曲深刻而有思想,而另一些则有趣而轻松。不出所料,贯穿他们歌词的最大主题是爱情。这里有一段这样的诗句:

我亲爱的小宝贝,你难道看不出,当你属于我时是多么美好。要是我能永远做你的爱人就好了,我永远得不到我的心,我得不到我的思想。

事实上,这些歌词不是你可能认识的任何一个甲壳虫乐队成员写的。不是列侬,或麦卡特尼,或哈里森,甚至,上帝保佑,林哥·斯塔尔(只是开玩笑,林戈是好的)。它们实际上是由一个机器学习模型生成的,即 OpenAI 的 GPT-2 [1]。虽然这使用了他们最小的模型,但结果是相当惊人的。

但是在我们走得太远之前,让我们后退一步,看看这一切是如何工作的。和往常一样,我的 Github 上有完整的工作代码。

语言建模

语言模型试图学习一种语言的结构(例如英语或披头士的歌词)。它们是使用监督学习训练的生成模型。像其他监督学习任务一样,语言模型试图预测给定一些特征的标签。然而,与大多数监督学习任务不同,没有明确的标签,而是语言本身既充当特征又充当标签。

在高层次上,语言模型试图做的是,在给定一系列前一个单词的情况下,预测下一个单词。例如,一个好的语言模型可能预测到“milk”是短语“购买一加仑 ____”的逻辑结论

通过尝试猜测下一个单词,我们真正做的是学习词汇的概率分布,这取决于我们到目前为止看到的单词。也就是说,我们想要学习

我们的词汇表中的单词在哪里?

因为我们显式地对这个分布建模,所以我们可以用它做一些很酷的事情,比如用它来生成我们以前没有见过的单词。我们可以通过重复地从这个分布中抽取下一个单词,然后当我们抽取下一个单词时,用它作为条件,以此类推。具体来说,让我们看看这在 Python 中可能是什么样子。如果我们有一个带有sample方法的model对象,那么我们可以通过如下方式生成新的样本:

How we might generate sentences from a language model.

当然,我跳过了一些细节,但希望随着我们的继续,这些会变得更加清晰。现在,让我们考虑世界上最简单的语言模型,unigram。

unigram 模型忽略任何条件作用,只是从训练数据中随机选择下一个单词。这相当于把我们的训练数据扔进搅拌机,在高空搅拌 10 分钟后把里面的东西洒出来。可以说,我们不会产生任何类似英语的东西(当然,除非我们有一万亿只猴子和一万亿台搅拌机,或者是打字机)。

二元模型

一元模型之上的一步是二元模型。正如你可能已经从名字中猜到的,二元模型学习一个分布,这个分布只取决于前一个单词,即

因为它非常简单,所以二元模型很容易在 Python 中实现,并且会让我们更深入地理解语言模型是如何工作的。

收集数据

在实现之前,我们首先需要一些数据。我们的最终目标是创作出让披头士感到自豪的歌曲,所以让我们从收集他们所有已知的歌词开始吧。

我发现这个网站把他们发行的每首歌的歌词分类。它也有一个有用的索引页面,上面有我们可以用来抓取网站的单首歌曲的链接。我编写了一个简单的脚本来迭代页面上的每个链接,解析它的 HTML 来提取歌词,并将歌词转储到一个文件中,每行一首歌。如果你打算继续下去,或者只是自己想要披头士的歌词,我强烈推荐使用它,因为抓取 HTML 是相当乏味和烦人的,即使使用像 Beautiful Soup 这样的工具。

一旦我们有了一个好的、干净的格式的数据,剩下的就容易了。但是不要只相信我的话,从这张图表中来看:

Data cleaning and organizing accounts for the biggest chunk of data science projects (source).

构建模型

如上所述,二元模型只是在前一个词的条件下对下一个词进行采样。我们可以做到这一点的一个简单方法是跟踪哪些单词跟随当前单词,以及出现的频率。也就是说,我们为训练数据中的每个单词current_word保留一个字典,然后每当我们看到一个next_word,我们就更新current_word[next_word] += 1。然后,为了生成单词,我们只需在current_word字典中查找所有单词和计数,并以与其计数成比例的概率对单词进行采样。下面是 Python 中完整模型的草图:

A sketch of the bigram language model.

最后要注意的是,我们可能想通过添加一些特殊的标记来表示歌词和歌曲的开始/结束,从而对歌词进行预处理。这是为了迫使我们的模型在生成新歌词时保持歌曲的一些结构,否则模型将会不断地吐出大块的文本。在我的代码中,我用XXSL, XXEL, XXSS,XXES分别表示开始行、结束行、开始歌曲和结束歌曲。

最后,为了生成歌曲,我们可以从XXSS标记开始,并一直调用model.predict(),直到我们达到一个XXES标记。

Generating a song with the bigram model.

理论上,一旦循环停止,我们将生成一首前所未见的披头士歌曲。但是这有什么好处吗?

一首前所未见的披头士歌曲

这是 bigram 模型生成的一首歌曲的一小段:

她是如此的我爱她的心。
他们很好;他们说我这么多,
她一点也不惊讶
当你是我的时候
悲伤和阿姆斯特丹的希尔顿
他们让我走,
是的我等一个男孩生下来就和一个有钱人在一起,
大家一起分享

生成的样本听起来像一个疯子的胡言乱语,只有在我们非常幸运的情况下才有意义。

我们可以继续扩展二元模型来考虑前面的两个词。这就是所谓的三元模型。你可能会发现三元模型实际上会产生更好听的歌词。这是因为少了三个单词组合,所以模型在每一步都有较少的选择,在某些步骤中只有一个选择。一般来说,我们可以通过考虑前面的 n 个单词来创建一个任意的 n-gram 模型。当 n 等于一首完整歌曲的长度时,你可能会发现这个模型非常适合生成披头士的歌曲。不幸的是,它生成的歌曲已经存在。

走向更好的模式

二元模型的一个最明显的问题是,它将只使用它在训练数据中看到的单词和短语。虽然我们希望生成听起来像是披头士写的歌词,但我们不想只局限于他们使用的词。例如,如果甲壳虫乐队从未使用过“游行”这个词,那么 bigram 模型将不会生成任何关于“游行”的歌曲。当然,由于我们只训练披头士的歌词,我们不可能指望我们的模型使用从未见过的词。我们需要的是在巨大的语料库上进行训练,比如维基百科或者 Reddit 。

然而,即使我们在所有的维基百科上训练,并且看到英语中的每一个单词,我们的二元模型仍然太死板了。比如说“高个子”这个短语。每一个对英语有基本了解的人都会意识到“高”只是“人”的修饰词,与“人”无关。相反,“高”可以用来修饰无数其他事物,如“女人”、“男孩”、“建筑物”、“长颈鹿”等。然而,我们的二元模型无法了解这一点,而是必须在使用“tall”之前至少看到它的一次使用。所以如果模特只见过“高个子”、“高个子男生”、“高个子女生”,而没有见过“高个子女生”,就它而言,“高个子女生”这个词组甚至不存在。

因此,我们想要的是一个具有更丰富的词汇表和对词汇表中单词之间关系的更深入理解的模型。幸运的是,聪明的研究人员已经发明了如此强大的模型,我们可以用它们来创作更好的歌曲。

GPT-2 模型

OpenAI 的 GPT-2 模型[1]最近因为“太危险而不能发布”而成为头条新闻该模型生成了如此令人信服的文本,以至于作者认为它可能被用于恶意 purposes⁴.相反,他们发布了两个较小的版本供人们玩和试验。我们将使用两者中最小的一个来生成披头士的歌词。

GPT-2 是一个基于变形金刚的模型,它是在数百个 GPU 小时的海量 Reddit 数据上训练的。在训练期间,它能够学习一种非常好的英语语言模型(或者至少是 Reddit 上使用的英语版本)。这意味着它能够理解“高”可以用于人类、建筑物或长颈鹿。此外,因为它在 Reddit 的很大一部分上进行了训练,所以它可能看到了英语中 99.9%的单词和短语。这对我们来说是个好消息,因为这正是我们想要的:丰富的词汇和对如何使用这些词汇的深刻理解。

然而,如果我们打开模型,让它生成一些东西,它极不可能得出类似披头士的歌词(即使r/披头士存在)。这是因为模型不知道我们关心的是生成披头士的歌词,毕竟这不是它被训练要做的。相反,我们需要推动模型做我们想让它做的事情。我们可以做到这一点的一个方法是通过迁移学习。

迁移学习

迁移学习是指我们可以通过做一件事来利用我们所学的信息,并应用它来解决一件相关的事情。例如,当你开始阅读这篇文章时,你不必重新学习什么是单词,哪些单词跟随哪些其他单词,或者它们如何组合在一起构成句子。想象一下那会有多乏味。相反,你利用花在阅读 AP 文学书籍上的所有时间来理解我现在在说什么(我猜哈克芬终究派上了用场)。

以类似的方式,我们可以利用 GPT 2 号通过数百小时阅读 Reddit 帖子学到的知识,并将其转移到我们生成披头士歌词的任务中。高层次的想法是采取预先训练的模型,并继续训练它一段时间。然而,代替 Reddit 的帖子,我们将只使用刮掉的披头士的歌词。这将使模型严重偏向于生成类似披头士的歌曲。

我将在这里跳过具体如何做,因为这将需要另一个类似长度的帖子来解释一切。相反,如果你对确切的细节感兴趣,我会让你参考[2]。这是一篇很棒的博文,一步一步地指导你如何将 GPT-2 模型应用到你关心的任何语言任务中。这也是我得到这里显示的结果所遵循的。

新甲壳虫乐队

像所有好的深度学习结果一样,我在简介中发布的歌词是经过精心挑选的。生成的歌曲并不都一样好,它们的质量取决于你在微调阶段的位置。当模型仍然严重不符合训练数据时,在对大约 100 个小批量进行微调后,您可能会得到以下结果:

我永远爱你,列侬,麦卡特尼,你永远爱我。你永远爱我,你也永远爱我。我永远都是

这样又持续了 10-15 行。至少比 Lil' Pump 要好。

玩笑归玩笑,我最感兴趣的是前两行。在训练数据中,每首歌曲的第一行是标题,第二行是作者,后面几行是实际的歌词。即使在这个早期阶段,模型已经设法学习我们的数据结构:第一行和第二行是特殊的;在第二行中,可能出现的单词组合很少,最有可能是 Lennon & McCartney。

如果我们对大约 350 个小批量进行微调,该模型就会开始生成更加可信的歌词,比如介绍中的这首,或者这首:

黑衣女人
列侬&麦卡特尼
我要大吵大闹
如果你不想让我出现
你最好离我远点。
我濒临死亡,我恋爱了

不完美,但还不错。最后,如果我们长时间保持微调(大约 2800 分钟一批),就会发生这种情况:

回来(回来)
列侬&麦卡特尼
黄色潜水艇
列侬&麦卡特尼
在一个周六的夜晚,当太阳照在我身上的时候
太阳出来了,船帆清晰
太阳出来了,船帆清晰
哦——嘿

模型开始过度拟合,并且生成的样本是很可能出现在训练数据中的东西,例如重复的“Lennon & McCartney”线、“黄色潜水艇”等。我发现微调 300-500 步可以产生最好的歌词。

结论

希望您现在对语言模型如何工作以及我们如何利用最先进的模型来极大地改进下游任务有了更好的了解。

也就是说,GPT-2 模型还有很多值得探索的地方。我生成的样本使用了默认的(可能)次优超参数。如果花更多的时间进行微调,看看生成的歌词会有多好,这将是一件有趣的事情。我也只使用了最小的型号,因为我是用我的笔记本电脑来训练的。我相信更大的模型会产生更壮观的结果。最后,OpenAI 最近发布了 MuseNet ,它能够生成非常逼真的声音音乐。将 GPT-2 和 MuseNet 放在一起(它们基本上是同一个模型)并生成歌词和伴奏音乐会有多神奇?如果我有更多的时间、金钱或任何关于我在做什么的想法,我想用机器学习来创作一首成熟的歌曲,然后让真正有才华的人来演奏它。

感谢阅读!

Eugen Hotaj,
2019 年 6 月 30 日

附言:如果你喜欢这篇文章,那就关注我,让我通知你有新的帖子!一如既往,所有代码和数据都可以在 my GitHub 上获得。

脚注

尽管我认为最佳独唱音乐家必须是另一个 60 年代的传奇人物,鲍勃·迪伦。他的单曲像滚石,可能是有史以来写得最好的歌曲,这是不仅仅是我的看法。

来自 无你之内 我最喜欢的披头士专辑里我最喜欢的披头士的歌。很奇怪,但又很好。

为了简洁起见,我跳过了一些次要的细节。你可以在我的 GitHub 上看到所有血淋淋的细节。

⁴有些人认为这只是一个巨大的宣传噱头,但那是无关紧要的。

参考

[1] A .拉德福德等人,语言模型是无监督的多任务学习器 (2019)

[2] S .托多洛夫,根据 Facebook Messenger 的数据微调 OpenAI 的 GPT-2,产生虚假对话 (2019)

使用异常检测生成关键场景

原文:https://towardsdatascience.com/generating-critical-scenarios-using-anomaly-detection-f25e67e0553b?source=collection_archive---------21-----------------------

概观

假设你正在开发一辆自动驾驶汽车或软件(我同意这是一个相当大的假设),你的第一个原型已经准备好,你想彻底测试。一种方法是运行大量测试车,检查系统如何响应其环境,这就是所谓的系统验证。但这可能是非常资本密集型的,虽然你应该这样做,但有一种更容易或更便宜的方式来做,那就是通过模拟,可以非常快速地生成大量数据。在这两种情况下,你都有大量的场景可以测试你的系统,但让自动驾驶软件承受大量的常规条件有意义吗?我们需要在关键场景下测试软件,这是对自治系统的真正测试,但关键场景的生成率不到 1%。在这里,我提出了一种称为异常检测的技术,它可以用来从大量数据中过滤关键场景。

Anomaly Detection

首先,让我们从总体上讨论异常或异常值检测。根据维基百科的说法,异常检测(也称异常检测)是对罕见项目、事件或观察结果的识别,这些项目、事件或观察结果通过与大多数数据显著不同而引起怀疑。那么,如何在数据集上实现异常检测呢?有几种方法可以执行异常检测,例如基于密度的异常检测、基于聚类的异常检测和基于支持向量机的异常检测。这里,我们将讨论一种基于移动平均线的简单方法,该方法将超出移动平均线固定标准偏差的点检测为时间序列数据中的异常值。遍历时间序列数据的平均值并不简单,因为它不是静态的。您需要一个滚动窗口来计算数据点的平均值。从技术上来说,这被称为滚动平均线或移动平均线,它的目的是平滑短期波动,突出长期波动。数学上,n 周期简单移动平均线也可以定义为“低通滤波器”。这里你可以找到一个非常直观的解释。让我们来看看算法:

  1. 首先,我们定义一个函数,使用离散线性卷积计算固定窗口大小的时间序列数据的移动平均值。卷积是一种数学运算,可以描述为两个函数的乘积在一个函数反转和移位后的积分。在这种情况下,该操作计算每个滑动窗口的平均值。
  2. 计算移动平均值后,我们计算 y 值和相应平均值之间的差值,我们称之为残差。接下来,我们计算这些残差的标准差。
  3. 我们将异常值定义为相应残差大于移动平均值加三个标准差或小于移动平均值减三个标准差的点。我们将三个标准偏差作为任意选择,它可以根据数据的分布和我们的用例而变化。

让我们来看看 python 中的实现:

在这里,我试图在加速度与时间的样本数据中找到异常,这将给我们带来车辆加速度的异常行为。这可能意味着突然刹车或加速度增加,这可能是由于可能的障碍物、碰撞或急转弯等。以下结果是使用 20 的滚动窗口在样本数据集上获得的:

红点是异常值,绿线是移动窗口的平均值。现在,必须进一步分析这些异常值,以了解它们是否仅对应于我们感兴趣的噪声或关键事件。这种算法为我们提供了整个时间序列数据中的兴趣点,从而缩小了我们的搜索范围。我们可以从我们可能从客户/测试汽车中收集的大量数据中挖掘所有这些关键事件,并将它们输入到我们的自动驾驶汽车系统中,看看它们如何应对这些事件。这对于验证自动驾驶汽车非常有用,因为在我们收集的数据中,只有不到 1%的数据发生了关键事件。

干杯!

用可变自动编码器和张量流生成假的 FIFA 19 足球运动员

原文:https://towardsdatascience.com/generating-fake-fifa-19-football-players-with-variational-autoencoders-and-tensorflow-aff6c10016ae?source=collection_archive---------13-----------------------

更新 25/01/2021:我会很快更新这些帖子,在 Twitter 上关注我以获得更多信息https://twitter.com/mmeendez8

这是我的第三篇关于可变自动编码器的文章。如果你想赶上数学,我推荐你查看我的第一篇文章。如果你想跳过这一部分,直接用 VAEs 做一些简单的实验,那就来看看我在的第二篇文章,在那里我展示了这些网络有多有用。如果你只是想看看神经网络如何创造足球运动员的假脸,那么你来对地方了!阅读更多 …

使用深度自回归模型生成高分辨率图像

原文:https://towardsdatascience.com/generating-high-resolution-images-using-autoregressive-models-3683f9af0db4?source=collection_archive---------11-----------------------

超越 GANs,捕捉真实数据分布的多样性

Figure 1. High-resolution (256x256 pixels) 8-bit celebrity images generated using a deep autoregressive model trained on the CelebA-HQ dataset.

介绍

图 1 中的名人面孔并不存在。它们是使用深度自回归模型生成的,该模型是由谷歌 Deepmind 和谷歌大脑的研究人员在一篇题为“用亚尺度像素网络和多维尺度放大生成高保真图像”的论文中引入的。这项工作特别重要,因为它朝着生成高分辨率、高保真度的自然图像迈出了一大步,同时支持整个数据分布并保证模型的概化能力。不用担心这里介绍的不熟悉的术语。在这篇文章中,我将带你浏览这篇文章,并解释所有的术语。最近我也在 AISC 展示并讨论了这项工作。你可以在 YouTube 上找到完整的演示。

在我们深入阅读本文之前,让我先概述一下我们的目标:

  1. 文件概述:其目标和贡献;
  2. 图像生成的深度生成模型与该领域最新趋势的比较:
  3. 图像生成的深度自回归模型概述:它们是什么,为什么我们对它们感兴趣,以及以前方法的主要挑战;和
  4. 深入探究子尺度像素网络和多尺度放大:它们是什么,它们为什么工作,以及它们如何与以前的深度自回归模型进行比较。

本文的目标是构建一个深度自回归(AR)解码器,它可以无条件地生成高保真图像。保真度是指模型生成真实图像的程度,这项工作能够使用深度 AR 模型在高分辨率下生成高度逼真的图像。我们将讨论与使用深度 AR 模型生成高分辨率、高保真度图像相关的主要挑战,并且我们将解释在这项工作中引入的用于解决这些问题的解决方案。

这里将简单介绍的 pixelRNN、pixelCNN 等深度 AR 模型就是成功利用深度 AR 模型进行图像生成的例子;但是,它们只能生成分辨率相对较低的图像(32x32 和 64x64 像素图像)。使用深度 AR 模型生成高分辨率图像具有挑战性,因为网络的大小随着图像大小线性增加,这是不可持续的。然而,该论文生成最大尺寸为 256x256 的图像,并且网络的尺寸不依赖于图像尺寸。他们使用在受欢迎的 CelebA-HQ 数据集上训练的模型生成 256x256 张名人脸。他们还使用在著名的 ImageNet 数据集上训练的模型,生成各种类别的 32x32 到 256x256 图像。

图像的深层生成模型

生成模型旨在学习训练数据的经验分布,并通过对学习的分布进行采样来生成图像,在样本质量和样本多样性之间进行权衡。图像的深度生成模型可以分为三个主要类别:

  1. 可变自动编码器(VAEs),
  2. 生成对抗网络(GANs),以及
  3. 自回归(AR)模型。

变分推理模型(各种类型的变分自动编码器)逼近潜在空间,并通过对所学习的潜在空间进行采样来生成一组不同的图像;然而,生成的图像往往是模糊的。对抗图像生成模型(各种类型的生成对抗网络)生成清晰、高分辨率的图像;但是,不能保证这些模型以有意义的方式学习整个数据分布,并且生成的样本可能不会覆盖整个数据分布。最后,自回归模型捕捉整个数据分布,保证生成一组不同的样本;然而,AR 模型往往局限于低分辨率图像,因为内存和计算要求随着图像的大小而增长。这是本文试图解决的问题。

比较这些模式时要考虑的其他要点是它们的训练过程和有效采样,即快速生成新样本的能力。变分推理和对抗模型在采样时相对有效;然而,这是自回归模型研究的一个开放领域,因为它们在采样过程中往往效率低下。AR 方法是具有稳定训练过程的简单模型,而对抗性方法通常在训练期间不稳定并且难以训练。

图像深度生成建模的最新趋势

谷歌 Deepmind 的研究人员最近发表了许多突破性的研究论文,都专注于图像的深度生成模型(见图 2)。这些论文的中心主题是,可以生成高保真度和高分辨率的样本,而不会遭受 GAN 的缺点,如模式崩溃和缺乏多样性。这些结果非常重要,因为它们显示了在探索除 GANs 之外的方法中的价值,例如用于图像生成任务的变分推断方法和自回归方法。他们还引入了一个新的度量标准来衡量模型对数据分布的了解程度。这个想法是,如果一个模型已经学习了整个数据分布,那么它生成的样本可以成功地用于下游任务,如分类。他们表明,对抗方法比变分推断和自回归模型获得更低的分数,表明对抗方法不一定学习整个数据分布,尽管它们能够生成高保真图像。本文成功使用自回归模型生成高分辨率、高保真图像,同时保证学习整个数据分布。

Figure 2. Recent papers published by researchers at Google Deepmind with a common theme.

自回归模型

AR 模型将图像视为一系列像素,并将其概率表示为所有像素的条件概率的乘积。如下式所示,每个像素强度的概率取决于所有先前生成的像素。

换句话说,为了生成图 3 中的像素 xi ,我们需要之前生成的所有蓝色像素的亮度值。

Figure 3. Generating individual image pixels using an autoregressive model

对抗模型的挑战之一是没有内在的概括措施。在文献中已经提出了不同的度量,但是没有关于单个度量的共识,使得比较不同图像生成模型的性能具有挑战性。另一方面,AR 模型由于其目标函数而被迫捕捉整个数据分布。它们是基于似然的模型,通过最大似然估计来训练。这允许直接计算负对数似然(NLL)分数,这是对模型在保留数据上进行良好概括的能力的一种测量,并可用作测量生成样本的视觉保真度的代理。一个成功的生成模型能产生高保真的样本,并能很好地概括保留的数据。虽然对抗方法产生高保真图像,但不能保证捕捉到整个数据分布。

以前的尝试

在过去的几年中,人们已经做出了许多努力来使用深度 AR 模型来顺序预测图像中的像素。最著名的型号是 PixelRNN 和 PixelCNN 。PixelRNN 使用 LSTM 层从先前生成的像素中捕获信息,而 PixelCNN 对先前生成的像素使用掩蔽卷积。最近的门控 PixelCNN 架构通过对 LSTM 门使用掩蔽卷积,结合了 pixelRNN 和 PixelCNN 的思想,实现了与 PixelRNN 相当的性能,同时训练速度与 pixelCNN 一样快。最近, PixelSNAIL 架构结合了掩蔽卷积和自关注,利用卷积在有限上下文大小上的高带宽访问和自关注在无限大上下文上的访问来生成图像。本文中描述的基线解码器使用类似 PixelSNAIL 的架构。

尽管做出了这些努力,AR 模型仍然需要生成高分辨率的样本,并捕捉长程结构和语义一致性。此外,由于 AR 模型被迫支持整个数据分布,它们倾向于将容量用于与保真度无关的部分分布。

亚比例像素网络

本文中描述的论文旨在通过引入亚尺度像素网络(SPN)以及将大图像划分为一系列大小相等的切片的替代排序,来生成捕捉细节和全局一致性的高分辨率、高保真图像。如图 4 所示,从原始图像每隔 n 个像素对图像切片进行二次采样。这种架构将模型大小与图像分辨率/大小分离,从而保持内存和计算需求不变。它还可以轻松地对大图像中许多像素之间的长程相关性进行压缩编码。

Figure 4. Subsampling 4 image slices from the original image

SPN 是一种条件解码器,它将图像生成为一系列大小相等的子图像。这些子图像随后在尺寸和深度上增长,以在称为多维放大的过程中生成全分辨率、全深度图像。这个过程如图 5 所示,可以描述为引导模型首先关注分布中视觉上更显著的位,然后关注视觉上不太显著的位。该文件确定了两个视觉突出的子集:大小和深度。尺寸是指生成初始切片(子图像),然后通过以编码丰富空间结构的方式基于先前生成的切片一次生成一个切片来对原始图像进行上采样。深度是指用于分别生成每个 RGB 通道的最高和最低有效位的不同网络。

Figure 5. Three networks working together to generate the final full-size full-depth image

因此,训练了 3 个具有相似架构的独立网络:

(a)在小尺寸、低深度图像切片上训练的解码器;

(b)尺寸放大解码器,其生成以初始图像切片为条件的大尺寸、低深度图像,即小尺寸、低深度图像;和

(c)深度提升解码器,其以大尺寸、低深度图像为条件生成大尺寸、高深度图像。

图 6 (i)示出了网络(a)和(b)一起工作以生成全尺寸、低深度图像,而图 6 (ii)示出了用于生成大尺寸、高深度图像的所有三个网络。最初的小尺寸、低深度图像切片(白色像素)是使用网络(a)生成的。然后,网络(b)用于通过生成蓝色像素来生成大尺寸、低深度的图像。最后,网络(c)用于生成紫色像素,该紫色像素代表大尺寸图像的每个 RGB 通道的剩余位。

Figure 6. Distinct colors correspond to distinct neural networks used to generates various pixels of an image

SPN 架构如图 7 所示。该网络具有编码器或切片嵌入器和屏蔽解码器。编码器将先前生成的沿深度维度连接的切片作为输入,并将先前切片的上下文编码在单个切片形状张量中。该嵌入被传递到解码器,该解码器使用掩蔽卷积和自关注层来生成图像切片。

Figure 7. Subscale pixel network architecture

您可以在 YouTube 上观看完整的演示,了解 SPN 架构的详细解释以及围绕本文算法和结果的进一步讨论。

结论

在这篇文章中,我介绍了一种新颖的深度 AR 架构,它能够学习复杂域的分布,如名人图像,并从所得的学习分布中生成高保真样本。生成的样本显示了前所未有的语义一致性和细节的准确性,即使在高分辨率下也是如此,这令人印象深刻。

Figure 8. High-resolution (128x128 pixels) 8-bit images generated using a deep autoregressive model trained on the ImageNet dataset.

本文表明,学习复杂自然图像的分布并获得高样本分辨率和保真度是可能的。获得捕捉整个数据分布的准确数据表示对于生成各种高分辨率样本至关重要,本文介绍的想法是朝着这个方向迈出的重要一步。这对我们 Looka 来说尤其重要,因为我们的目标是创造各种高质量的设计资产,这对创造伟大的设计至关重要。Looka 的使命是让每个人都可以获得伟大的设计,我们使用深度学习来创建与图形设计师在线合作的体验。特别是,我们正在使用深度生成模型,如本文中介绍的模型,来自动生成令人惊叹的设计资产,如独特的字体和符号。

我希望你喜欢这篇文章。如果您有进一步的问题或意见,请随时联系我们。

我是 Looka 的一名数据科学家,在这里,我们利用深度学习让每个人都能接触到并喜欢伟大的设计。如果你有兴趣在 AI 和设计的交叉点工作,可以看看我们的 招聘页面

自动编码器综合介绍

原文:https://towardsdatascience.com/generating-images-with-autoencoders-77fd3a8dd368?source=collection_archive---------1-----------------------

在接下来的几周里,我将发布一系列教程,全面介绍使用神经网络进行无监督和自监督学习,以实现图像生成、图像增强和图像混合。这些主题包括:

  • 可变自动编码器(VAEs)(本教程)
  • 神经风格迁移学习
  • 生成对抗网络

在本教程中,我们将重点关注一种特定类型的自动编码器,称为变分自动编码器。网上有几篇文章解释了如何使用自动编码器,但是没有一篇是特别全面的。在本文中,我计划提供为什么我们可能想要使用 VAEs 的动机,以及它们解决的问题的种类,给出这些神经架构如何工作的数学背景,以及一些使用 Keras 的真实世界实现。

这篇文章借用了哈佛大学 209b 讲座的内容,主要归功于哈佛大学 IACS 系的讲师 T2。

vae 可以说是最有用的自动编码器类型,但在我们尝试处理 vae 之前,有必要了解通常用于数据压缩或去噪的传统自动编码器。

不过,首先,我将通过查看几个示例来让您对 VAEs 可以做的事情感到兴奋。

VAEs 的力量

假设你正在开发一个视频游戏,你有一个开放世界的游戏,有非常复杂的场景。你雇佣了一个图形设计师团队来制作一堆植物和树木来装饰你的世界,但是一旦把它们放到游戏中,你发现这看起来很不自然,因为同一物种的所有植物看起来都完全一样,你能做些什么呢?

首先,你可能会建议使用一些参数化来尝试随机扭曲图像,但是多少个特征就足够了呢?这个变化应该有多大?一个重要的问题是,实现它的计算强度有多大?

这是使用可变自动编码器的理想情况。我们可以训练一个神经网络来学习关于植物的潜在特征,然后每当一个植物出现在我们的世界中时,我们可以从我们“学习”的特征中随机抽取一个样本,并生成一个独特的植物。事实上,这是多少开放世界游戏已经开始在他们的世界中产生风景的方面。

让我们来看一个更形象的例子。假设我们是一名建筑师,想要为任意形状的建筑生成平面图。我们可以让自动编码器网络学习给定任意建筑形状的数据生成分布,它将从我们的数据生成分布中抽取样本,并生成平面图。下面的动画展示了这个想法。

这些对于设计师的潜力可以说是最突出的。想象一下,我们为一家时尚公司工作,任务是创造新的服装风格,事实上,我们可以只训练一个关于“时尚”物品的自动编码器,并允许网络学习时尚服装的数据生成分布。随后,我们可以从这个低维的潜在分布中提取样本,并利用它来创造新的想法。

最后一个示例是我们将在本教程的最后一节学习时尚 MNIST 数据集时使用的示例。

自动编码器

传统自动编码器

自动编码器是非常简单的神经架构。它们基本上是一种压缩形式,类似于使用 MP3 压缩音频文件或使用 JPEG 压缩图像文件的方式。

自动编码器与主成分分析(PCA)密切相关。事实上,如果自动编码器中使用的激活函数在每一层中是线性的,则潜在变量出现在瓶颈(网络中最小的层,aka。代码)直接对应于来自 PCA 的主分量。通常,自动编码器中使用的激活函数是非线性的,典型的激活函数是 ReLU(校正线性单元)和 sigmoid。

网络背后的数学原理相当容易理解,所以我将简要介绍一下。本质上,我们将网络分为两个部分,编码器和解码器。

ϕ表示的编码器功能将原始数据 x 映射到存在于瓶颈处的潜在空间 f。由ψ表示的解码器函数将瓶颈处的潜在空间 F 映射到输出。在这种情况下,输出与输入函数相同。因此,我们基本上是试图在一些广义的非线性压缩之后重建原始图像。

编码网络可以由通过激活函数的标准神经网络函数来表示,其中 z 是潜在维度。

类似地,解码网络可以以相同的方式表示,但是使用不同的权重、偏置和潜在的激活函数。

损失函数可以用这些网络函数来表示,我们将使用这个损失函数通过标准的反向传播过程来训练神经网络。

由于输入和输出是相同的图像,这不是真正的监督或无监督学习,所以我们通常称之为自监督学习。自动编码器的目的是以这样一种方式选择我们的编码器和解码器功能,即我们需要最少的信息来编码图像,以便它可以在另一侧重新生成。

如果我们在瓶颈层中使用的节点太少,我们重新创建图像的能力将会受到限制,并且我们将重新生成模糊或无法从原始图像中识别的图像。如果我们使用太多的节点,那么使用压缩就没有什么意义了。

压缩的例子很简单,例如,每当你在网飞上下载东西,发送给你的数据都是压缩的。一旦它到达你的电脑,它通过一个解压缩算法,然后显示在你的电脑上。这类似于 zip 文件的工作方式,只是它是通过流算法在幕后完成的。

去噪自动编码器

还有几种其他类型的自动编码器。最常用的一种是去噪自动编码器,它将在本教程的后面使用 Keras 进行分析。这些自动编码器在训练之前向数据添加一些白噪声,但是在训练时将误差与原始图像进行比较。这迫使网络不会过度适应图像中存在的任意噪声。我们稍后将使用它来消除文档扫描图像中的折痕和暗区域。

稀疏自动编码器

与直觉相反,稀疏自动编码器具有比输入或输出维度更大的潜在维度。然而,每次网络运行时,只有一小部分神经元激活,这意味着网络本质上是“稀疏的”。这类似于去噪自动编码器,因为它也是一种正则化形式,以减少网络过拟合的倾向。

收缩式自动编码器

收缩编码器与最后两个过程非常相似,但在这种情况下,我们不改变架构,只是在损失函数中添加一个正则项。这可以被认为是岭回归的一种神经形式。

所以现在我们了解了自动编码器是怎样的,我们需要了解它们不擅长什么。一些最大的挑战是:

  • 潜在空间的缺口
  • 潜在空间中的可分性
  • 离散潜在空间

这些问题都可以在这张图表中得到说明。

Latent space representation for MNIST dataset.

这张图向我们展示了不同标记数字在潜在空间中的位置。我们可以看到,潜在空间包含间隙,我们不知道这些空间中的字符可能看起来像什么。这相当于在监督学习问题中缺乏数据,因为我们的网络没有针对潜在空间的这些情况进行训练。另一个问题是空格的可分性,在上图中有几个数字被很好地分开,但也有一些区域的标签是随机散布的,这使得很难分开字符的独特特征(在本例中是数字 0-9)。这里的另一个问题是无法研究连续的潜在空间,例如,我们没有一个为任意输入而训练的统计模型(即使我们封闭了潜在空间中的所有间隙也不会)。

传统自动编码器的这些问题意味着,在我们能够了解数据生成分布并产生新的数据和图像之前,我们还有一段路要走。

现在我们已经了解了传统的自动编码器是如何工作的,我们将继续讨论变化的自动编码器。这些方法稍微复杂一些,因为它们实现了一种来自贝叶斯统计的变分推理。我们将在下一节更深入地讨论这一点

可变自动编码器

VAEs 继承了传统自动编码器的架构,并使用它来学习数据生成分布,这允许我们从潜在空间中随机采样。然后,可以使用解码器网络对这些随机样本进行解码,以生成独特的图像,这些图像具有与网络被训练的图像相似的特征。

对于熟悉贝叶斯统计的人来说,编码器正在学习后验分布的近似值。这种分布通常难以解析,因为它没有封闭形式的解。这意味着我们可以执行计算量大的采样程序,如马尔可夫链蒙特卡罗(MCMC)方法,或者我们可以使用变分法。正如人们可能怀疑的那样,变分自动编码器使用变分推理来生成其对该后验分布的近似。

我们将详细讨论这个过程,但是对于深入的分析,我强烈推荐查看 Jaan Altosaar 的博客文章。变分推理是研究生机器学习或统计学课程的一个主题,但你不需要统计学学位就能理解其基本思想。感兴趣的人可以链接到 Jaan 的文章:

[## 教程-什么是可变自动编码器?—贾恩·阿尔托萨尔

从两个角度理解变分自动编码器:深度学习和图形模型。

jaan.io](https://jaan.io/what-is-variational-autoencoder-vae-tutorial/)

对于那些对基础数学不感兴趣的人,可以直接跳到 VAE 编码教程。

我们首先需要了解的是后验分布,以及为什么我们不能计算它。看看下面的等式,这是贝叶斯定理。这里的前提是,我们想知道如何学习如何从我们的潜变量 z 生成数据 x。这暗示了我们要学习 p(z|x)。不幸的是,我们不知道这个分布,但我们不需要知道,因为我们可以用贝叶斯定理重新表述这个概率。然而,这并不能解决我们所有的问题,因为分母,即证据,通常是难以处理的。然而,并没有失去一切,因为存在一个厚脸皮的解决方案,允许我们近似这个后验分布。事实证明,我们可以将这个推理问题转化为一个优化问题。

为了逼近后验分布,我们需要一种方法来评估建议分布与真实后验分布相比有多好。为了做到这一点,我们使用贝叶斯统计学家最好的朋友,库尔巴克-莱布勒分歧。KL 散度是两个概率分布相似程度的度量;如果相同,则散度为零,如果是正数,则两个分布不同。KL 散度严格来说是正的,虽然它在技术上不是距离,因为函数是不对称的。我们以下面的方式使用 KL 散度。

这个等式可能看起来吓人,但这里的想法很简单。我们提出了一系列可能的分布,这些分布可能就是我们的数据是如何生成的, Q ,并且我们希望找到最佳分布, q* ,它使我们提出的分布和实际分布之间的距离最小化,由于实际分布的困难性,我们试图对其进行近似。这个公式还有一个问题,即我们实际上不知道 p(z|x ),所以我们不能计算 KL 散度。我们如何解决这个问题?

这就是事情变得有点深奥的地方。我们可以做一些数学操作,用所谓的 ELBO(证据下限)和另一个涉及 p(x)的术语重写 KL 散度。

有趣的是,ELBO 是这个等式中唯一的变量,它取决于我们选择的分布。另一项不受我们选择的分布的影响,因为它不依赖于 q 。因此,我们可以通过最大化(因为它是负的)上式中的 ELBO 来最小化 KL 散度。这里的关键点是,我们实际上可以计算 ELBO,这意味着我们现在可以执行优化程序。

因此,我们现在需要做的就是为 Q 想出一个好的选择,然后对 ELBO 求微分,将其设置为零,瞧,我们就有了最佳分布。在这成为可能之前还有一些障碍,首先,我们必须决定选择什么样的发行版家族。

典型地,当定义 q 时,为了简单起见,进行平均场变分推断。这实质上是说,每个变分参数都是相互独立的。因此,对于每个数据点,我们有一个单独的 q ,我们可以将它们相乘,得到一个联合概率,从而得到“平均场”q

实际上,我们可以选择任意多的字段或集群。例如,在 MNIST 的情况下,我们可能选择 10 个分类,因为我们知道可能存在 10 个可能的数字。

我们需要做的第二件事是通常被称为重新参数化的技巧,借此我们将随机变量从导数中取出,因为对随机变量取导数会由于它们固有的随机性而给我们带来更大的误差。

重新参数化的技巧有点深奥,但它基本上是说,我可以将正态分布写成一个平均值加上一些标准差,乘以一些误差。这意味着当求导时,我们不求随机函数本身的导数,而只求它的参数。

如果这没有多大意义,这里有一篇很好的文章解释了这个技巧,以及为什么它比随机变量本身的导数表现得更好:

[## 重新参数化技巧

戈克尔·埃尔多安的个人网站。

gokererdogan.github.io](https://gokererdogan.github.io/2016/07/01/reparameterization-trick/)

这种方法没有一般的封闭解,所以我们在近似后验分布的能力上仍然受到一些限制。然而,事实上,指数分布族有一个封闭形式的解。这意味着我们可以使用标准分布,如正态分布、二项式分布、泊松分布、贝塔分布等。因此,虽然我们可能找不到真正的后验分布,但我们可以找到一个近似,它在给定指数分布族的情况下做得最好。

变分推理的艺术是选择我们的分布族, Q ,使其足够大,以获得后验概率的良好近似,但又不要太大,以至于计算时间过长。

既然我们已经对我们的网络如何被训练来学习我们数据的潜在分布有了一个不错的想法,我们可以看看我们如何使用这种分布来生成数据。

数据生成过程

看下图,我们可以认为我们对数据生成过程的近似决定了我们要生成数字“2”,所以它从潜在变量质心生成值 2。然而,我们可能不希望每次都生成看起来一样的“2”,就像我们的视频游戏中的植物示例一样,所以我们在潜在空间中向这个项目添加一些随机噪声,这是基于随机数和值“2”的分布的“学习”分布。我们把它通过我们的解码器网络,我们得到了一个看起来和原来不同的 2。

这是一个过于简化的版本,它抽象了实际自动编码器网络的架构。下面是在编码器和解码器网络中使用卷积层的实际变分自动编码器的架构表示。我们看到,我们正在分别学习潜在空间内数据生成分布的中心和分布,然后从这些分布中“采样”以生成本质上“虚假”的数据。

学习过程的固有性质意味着看起来相似的参数(刺激相同的网络神经元放电)在潜在空间中聚集在一起,而不是任意隔开。下图对此进行了说明。我们看到我们的值 2 开始聚集在一起,而值 3 逐渐被推开。这是有用的,因为这意味着网络不会任意地将字符放置在潜在空间中,使得值之间的转换不那么虚假。

整个网络架构的概述如下所示。希望,在这一点上,程序是有意义的。我们使用一组图像来训练自动编码器,以学习我们在潜在空间内的均值和标准差,这形成了我们的数据生成分布。接下来,当我们想要生成类似的图像时,我们从潜在空间中的一个质心进行采样,使用我们的标准偏差和一些随机误差稍微扭曲它,然后将它通过解码器网络。从这个例子中可以清楚地看出,最终输出看起来与输入图像相似,但并不相同。

VAE 编码教程

在本节中,我们将研究一个简单的去噪自动编码器,用于消除文档扫描图像上的折痕和标记,以及消除时尚 MNIST 数据集中的噪声。在 MNIST 数据集上训练网络之后,我们将使用 VAEs 来生成新的服装项目。

去噪自动编码器

时尚 MNIST

在第一个练习中,我们将向时尚 MNIST 数据集添加一些随机噪声(椒盐噪声),并尝试使用去噪自动编码器来消除这些噪声。首先,我们执行预处理:下载数据,缩放数据,然后添加噪声。

之后,我们为自动编码器网络创建架构。这涉及多层卷积神经网络、编码器网络上的最大池层和解码器网络上的升级层。

这个模型需要一段时间来运行,除非你有一个图形处理器,它可能需要大约 3-4 分钟的时间。我们的输入图像、带噪声的输入图像和输出图像如下所示。

Input images from fashion MNIST.

Input images with salt and pepper noise.

Output from denoising network

正如你所看到的,我们能够从嘈杂的图像中充分去除噪声,但我们失去了相当数量的服装细节的分辨率。这是我们为强大的网络付出的代价之一。可以调整网络,以便使最终输出更能代表输入图像。

文字清理

去噪自动编码器的第二个例子包括清理扫描图像的折痕和暗区。这是我们希望获得的输入和输出图像。

Input images of ‘noisy’ text data.

Cleaned text images.

这方面的数据预处理有点复杂,所以我不会在这里介绍,但它可以在我的 GitHub 存储库中找到,还有数据本身。网络架构如下。

变型自动编码器

最后,我们将尝试生成时装 MNIST 数据集中出现的服装项目的新图像。

这方面的神经架构稍微复杂一点,包含一个称为“Lambda”层的采样层。

这是架构,但我们仍然需要插入损失函数,并纳入 KL 散度。

我们现在可以查看重构的样本,看看我们的网络能够学习到什么。

我们可以清楚地看到鞋子、手袋以及服装之间的过渡。并非所有的潜在空间都绘制在这里,以帮助图像清晰。我们还可以查看时装 MNIST 数据集中的 10 件服装的潜在空间和颜色代码。

我们看到这些项目被分成不同的组。

最终点评

本教程是自动编码器、变分自动编码器和变分推理的速成课程。我希望读者对此感兴趣,并且现在对什么是自动编码器以及如何在实际应用中使用它们有了更好的理解。

在我的下一个教程中,我将着眼于使用生成式对抗网络制作名人和动漫人物的假图像,这是变型自动编码器的天然垫脚石。

利用生成性对抗网络生成现代艺术

原文:https://towardsdatascience.com/generating-modern-arts-using-generative-adversarial-network-gan-on-spell-39f67f83c7b4?source=collection_archive---------2-----------------------

趣味甘

创建一个生成性对抗网络来生成现代艺术,并在 Spell 平台的 GPU 上对其进行训练

Arts Generated By Our GAN

先决条件

你需要很好地理解:

  1. 图像处理
  2. Python 编程语言
  3. numpy——科学计算图书馆
  4. Keras —深度学习图书馆

和一些基本知识:

  1. 生成对抗网络

使用的数据集

本项目中使用的图像数据收集自

介绍

在本教程中,我们将看一步一步的过程来创建一个生成性的对抗性网络,以生成现代艺术,并使用 Python 和 Keras 编写代码。

之后,为了训练模型,我们将使用一个强大的拼写平台的 GPU 实例。一切都将在途中解释,并提供进一步阅读的链接。

我们开始吧!

探索数据集

在开始之前,让我们看看我们的图像数据集。

WikiArt 收藏了大量不同风格的现代艺术作品。对于我们的特定项目,我们将使用 立体派 风格的图像。

你可以从 WikiArt.org 了解更多的艺术风格和现代艺术。

下载图像

你既可以从 WikiArt 下载你喜欢的图片,也可以通过 cs-chan 前往该库下载 26GB 的 WikiArt 图片。

因为它有所有不同类型的集合,我们将只选择立体主义并将它们存储在名为 dataset 的文件夹中。

处理图像数据

我们数据集中的图像大小不同,为了将它们输入到我们的生成性对抗性神经网络中,我们将把所有图像的大小调整为 128X128。

开始之前,在数据集文件夹所在的根目录下创建一个 python 文件。

现在,让我们编写一个小的 python 脚本,从文件夹中选择所有图像,并将其大小调整为 128X128,然后保存在 cubism_data.npy 文件中。

*## image_resizer.py*
*# Importing required libraries*
**import** os
**import** numpy **as** np
**from** PIL **import** Image

*# Defining an image size and image channel*
*# We are going to resize all our images to 128X128 size and since our images are colored images*
*# We are setting our image channels to 3 (RGB)*

IMAGE_SIZE = 128
IMAGE_CHANNELS = 3
IMAGE_DIR = 'dataset/'

*# Defining image dir path. Change this if you have different directory*
images_path = IMAGE_DIR 

training_data = []

*# Iterating over the images inside the directory and resizing them using*
*# Pillow's resize method.*
print('resizing...')

**for** filename **in** os.listdir(images_path):
    path = os.path.join(images_path, filename)
    image = Image.open(path).resize((IMAGE_SIZE, IMAGE_SIZE), Image.ANTIALIAS)

    training_data.append(np.asarray(image))

training_data = np.reshape(
    training_data, (-1, IMAGE_SIZE, IMAGE_SIZE, IMAGE_CHANNELS))
training_data = training_data / 127.5 - 1

print('saving file...')
np.save('cubism_data.npy', training_data)

我们来分解一下。

在上面的代码块中,在前几行,我们已经导入了执行调整大小操作所需的所有库。

**import** os
**import** numpy **as** np
**from** PIL **import** Image

IMAGE_SIZE = 128
IMAGE_CHANNELS = 3
IMAGE_DIR = 'dataset/'

images_path = IMAGE_DIR

这里,我们使用 Pillow 将所有图像调整到我们想要的大小,并将它们作为 numpy 数组添加到一个列表中。

training_data = []**for** filename **in** os.listdir(images_path):
 path = os.path.join(images_path, filename)
 image = Image.open(path).resize((IMAGE_SIZE, IMAGE_SIZE), Image.ANTIALIAS)
training_data.append(np.asarray(image))

之后,我们使用 numpy 以合适的格式重塑数组,并规范化数据。

training_data = np.reshape(
training_data, (-1, IMAGE_SIZE, IMAGE_SIZE, IMAGE_CHANNELS))
training_data = training_data / 127.5–1

标准化之后,我们将图像数组保存在 npy 二进制文件中,这样我们就不必每次都遍历所有的图像。

np.save(‘cubism_data.npy’, training_data)

这就是处理我们的图像数据。

创建 GAN

现在是我们项目中最激动人心的部分了,从这里开始我们将为生成性对抗网络(GAN)编写代码。

我们将使用Keras——一个深度学习库来创建我们的 GAN。

开始之前,让我们简单了解一下什么是 GAN 及其结构。

甘是什么?

生成对抗网络(GANs)是机器学习领域一项令人兴奋的最新创新。伊恩·哥德费罗在他的论文 中首次提出了生成对抗网络

gan 是生成型模型:在给定一些训练数据后,它们可以创建看起来像你的训练数据的新数据实例。例如,GANs 可以创建看起来像人脸照片的图像,即使这些人脸不属于任何真实的人。

关于 GAN 的一个很好的例子,你可以访问,它是由 Nvidia 创造的。它生成了一个不存在的人的高质量图像。****

听起来很有趣,对吗?

它是如何工作的?

让我们了解它的结构和工作原理。

甘提出了两种模型:生成模型和判别模型。

生成模型负责生成不同种类的噪声数据,而鉴别模型负责鉴别给定数据是真的还是假的。

生成模型不断地训练自己,通过生成假噪声数据来欺骗判别模型,而判别模型从训练集中训练自己来分类数据是否来自数据集,并且不被生成模型欺骗。

GAN structure source

损失函数

GAN 中的鉴别器使用交叉熵损失,因为鉴别器的工作是分类;交叉熵损失是最好的方法。

这个公式表示 p:真实分布和 q:估计分布之间的交叉熵损失。

(p)和(q)是 m 维的,其中 m 是类的数量。

在 GAN 中,鉴别器是一个二元分类器。它需要区分数据是真的还是假的。也就是说 m = 2。真正的分布是一个仅包含 2 项的热向量。

对于 n 个样本,我们可以对损失求和。

上面所示的等式是二元交叉熵损失,其中 y 可以取两个值 0 和 1。

GAN 有一个潜在向量 z,图像 G(z)就神奇地从中生成。我们对真实图像 x 和生成的图像 G(z)应用鉴别器函数 D。

损失函数的目的是将真实图像的预测推向 1,将伪图像推向 0。我们用对数概率项来做。

: ~ 符号表示:分布为,这里的 Ex 表示期望值:由于我们不知道样本是如何被送入鉴别器的,所以我们将它们表示为期望值而不是总和。

如果我们观察联合损失函数,我们将最大化鉴别器项,这意味着 D(x)的 log 应该逐渐接近零,而 D(G(z))的 log 应该接近 1。在这里,生成器试图使 D(G(z))英寸更接近 1,而鉴别器试图做相反的事情。

GAN 的代码

现在,让我们毫不迟疑地写我们的 GAN。

我们将把我们的文件命名为 art_gan.py ,并将其存储在根目录中。这个文件将包含我们的生成器和鉴别器的所有超参数和函数。

让我们写一些代码:

****from** keras.layers **import** Input, Reshape, Dropout, Dense, Flatten, BatchNormalization, Activation, ZeroPadding2D
**from** keras.layers.advanced_activations **import** LeakyReLU
**from** keras.layers.convolutional **import** UpSampling2D, Conv2D
**from** keras.models **import** Sequential, Model, load_model
**from** keras.optimizers **import** Adam
**import** numpy **as** np
**from** PIL **import** Image
**import** os**

在这里,我们导入创建 GAN 所需的所有库和辅助函数。

所有的导入都是不言自明的。在这里,我们正在导入一些 keras 层来创建我们的模型。

现在让我们定义一些参数:

***# Preview image Frame
PREVIEW_ROWS = 4
PREVIEW_COLS = 7
PREVIEW_MARGIN = 4
SAVE_FREQ = 100**# Size vector to generate images from
NOISE_SIZE = 100**# Configuration
EPOCHS = 10000 # number of iterations
BATCH_SIZE = 32**GENERATE_RES = 3
IMAGE_SIZE = 128 # rows/cols*IMAGE_CHANNELS = 3**

在这里的前几行,我们已经定义了图像帧的大小和填充来保存我们生成的图像。

这里是生成我们的图像的潜在维度大小。

EPOCHS 是迭代次数:它定义了我们想要迭代训练图像的次数,而 BATCH_SIZE 是每次迭代中要输入的图像数量。

IMAGE_SIZE 是我们之前调整到 128X128 的图像尺寸,而 IMAGE_CHANNELS 是我们图像中的通道数;也就是 3。

注意:图像应始终为方形尺寸

让我们加载之前创建的 npy 数据文件。

**training_data = np.load(‘cubism_data.npy’)**

为了加载 npy 文件,我们使用 numpy 的 load 函数并将文件路径作为参数传递。

因为我们的数据文件在根目录中,所以不需要额外的路径参数。如果您已经将数据存储在其他地方,您可以使用以下代码来加载数据:

**training_data = np.load(os.path.join(‘dirname’, ‘filename.npy’))**

这就是加载我们的训练数据。

现在我们可以创建生成器和鉴别器函数了。

让我们看看代码:

****def** **build_discriminator**(image_shape): model = Sequential() model.add(Conv2D(32, kernel_size=3, strides=2,
    input_shape=image_shape, padding=”same”))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dropout(0.25)) model.add(Conv2D(64, kernel_size=3, strides=2, padding=”same”))
    model.add(ZeroPadding2D(padding=((0, 1), (0, 1))))
    model.add(BatchNormalization(momentum=0.8))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dropout(0.25)) model.add(Conv2D(128, kernel_size=3, strides=2, padding=”same”))
    model.add(BatchNormalization(momentum=0.8))
    model.add(LeakyReLU(alpha=0.2))
    model.add(Dropout(0.25)) model.add(Conv2D(256, kernel_size=3, strides=1, padding=”same”))
    model.add(BatchNormalization(momentum=0.8))
    model.add(LeakyReLU(alpha=0.2)) model.add(Dropout(0.25))
    model.add(Conv2D(512, kernel_size=3, strides=1, padding=”same”))
    model.add(BatchNormalization(momentum=0.8))
    model.add(LeakyReLU(alpha=0.2)) model.add(Dropout(0.25))
    model.add(Flatten())
    model.add(Dense(1, activation=’sigmoid’)) input_image = Input(shape=image_shape)
    validity = model(input_image)
    **return** Model(input_image, validity)**

分解一下:

如果您对 keras 有所了解,那么代码是不言自明的。

总的来说,我们正在定义一个以 image_shape 为参数的函数。

在这个函数中,我们从 keras 中初始化一个顺序模型,帮助我们创建线性层堆栈。

**model = Sequential()**

之后,我们在顺序模型中添加一些层。

我们的第一层是一个 32 形状的卷积层,其 kernel_size 为 3,我们的步幅值为 2,填充值相同。因为它是第一层,所以它保存输入形状。

要了解这是怎么回事,可以参考 keras 官方文档页面。

简单地说,我们在这里定义一个卷积层,它有一个大小为 3X3 的滤波器,该滤波器跨越我们的图像数据。我们有相同的衬垫,这意味着,没有额外的衬垫。它仍然和原来一样。

**model.add(Conv2D(32, kernel_size=3, strides=2,
  input_shape=image_shape, padding=”same”))model.add(LeakyReLU(alpha=0.2))**

之后,我们添加了一个激活函数 LeakyRelu 层。

类似地,在其他块中,层被添加到顺序模型中,具有一些漏失和批量标准化,以防止过度拟合。

我们模型的最后一层是具有激活函数 sigmoid 的全连接层。

由于我们的鉴别器的工作是分类给定的图像是否是假的,这是一个二元分类任务,sigmoid 是一个将每个值压缩到 0 和 1 之间的激活。

**model.add(Flatten())
model.add(Dense(1, activation=’sigmoid’))**

现在,在初始化我们的鉴别器模型之后,让我们也创建一个生成模型。

****def** **build_generator**(noise_size, channels):
    model = Sequential()
    model.add(Dense(4 * 4 * 256, activation=”relu”,       input_dim=noise_size))
    model.add(Reshape((4, 4, 256))) model.add(UpSampling2D())
    model.add(Conv2D(256, kernel_size=3, padding=”same”))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Activation(“relu”)) model.add(UpSampling2D())
    model.add(Conv2D(256, kernel_size=3, padding=”same”))
    model.add(BatchNormalization(momentum=0.8))
    model.add(Activation(“relu”)) **for** i **in** range(GENERATE_RES):
         model.add(UpSampling2D())
         model.add(Conv2D(256, kernel_size=3, padding=”same”))
         model.add(BatchNormalization(momentum=0.8))
         model.add(Activation(“relu”)) model.summary()
    model.add(Conv2D(channels, kernel_size=3, padding=”same”))
    model.add(Activation(“tanh”)) input = Input(shape=(noise_size,))
    generated_image = model(input)

    **return** Model(input, generated_image)**

分解一下:

这里我们定义了一个函数,它将 noise_size 和 channels 作为参数。

在函数内部,我们再次初始化了一个序列模型。

因为我们的生成器模型必须从噪声向量生成图像,所以我们的第一层是大小为 4096 (4 * 4 * 256)的完全连接的密集层,它将 noise_size 作为参数。

**model.add(Dense(4 * 4 * 256, activation=”relu”, input_dim=noise_size))**

注意:我们已经定义了它的大小为 4096,以便在 4X4X256 的图层中调整它的大小。

之后,我们使用整形图层将完全连接的图层整形为 4X4X256 的形状。

**model.add(Reshape((4, 4, 256)))**

这之后的层块只是一个具有批量归一化和激活函数 relu 的卷积层。

为了看到和理解它的样子,我们来看一下模型摘要:

从 4X4 的形状扩展到 128X128 的大小,这是我们的 training_data 形状。

我们的生成器模型将噪声作为输入,输出图像。

初始化生成器和鉴别器模型后,让我们编写一个助手函数,在一些迭代后保存图像。

****def** save_images(cnt, noise):
    image_array = np.full((
        PREVIEW_MARGIN + (PREVIEW_ROWS * (IMAGE_SIZE + PREVIEW_MARGIN)),
        PREVIEW_MARGIN + (PREVIEW_COLS * (IMAGE_SIZE + PREVIEW_MARGIN)), 3),
        255, dtype=np.uint8)generated_images = generator.predict(noise)generated_images = 0.5 * generated_images + 0.5image_count = 0
    **for** row in range(PREVIEW_ROWS):
        **for** col in range(PREVIEW_COLS):
            r = row * (IMAGE_SIZE + PREVIEW_MARGIN) + PREVIEW_MARGIN
            c = col * (IMAGE_SIZE + PREVIEW_MARGIN) + PREVIEW_MARGIN
            image_array[r:r + IMAGE_SIZE, c:c +
                        IMAGE_SIZE] = generated_images[image_count] * 255
            image_count += 1output_path = 'output'
    if not os.path.exists(output_path):
        os.makedirs(output_path)filename = os.path.join(output_path, f"trained-{cnt}.png")
    im = Image.fromarray(image_array)
    im.save(filename)**

我们的 save_images 函数将计数和噪声作为输入。

在函数内部,它根据我们上面定义的参数生成帧,并存储我们根据噪声输入生成的图像数组。

之后,它会将其保存为图像。

现在,是我们编译模型并训练它们的时候了。

让我们也为此编写一段代码:

**image_shape = (IMAGE_SIZE, IMAGE_SIZE, IMAGE_CHANNELS)optimizer = Adam(1.5e-4, 0.5)discriminator = build_discriminator(image_shape)
discriminator.compile(loss=”binary_crossentropy”,
optimizer=optimizer, metrics=[“accuracy”])
generator = build_generator(NOISE_SIZE, IMAGE_CHANNELS)random_input = Input(shape=(NOISE_SIZE,))generated_image = generator(random_input)discriminator.trainable = **False**validity = discriminator(generated_image)combined = Model(random_input, validity)
combined.compile(loss=”binary_crossentropy”,
optimizer=optimizer, metrics=[“accuracy”])y_real = np.ones((BATCH_SIZE, 1))
y_fake = np.zeros((BATCH_SIZE, 1))fixed_noise = np.random.normal(0, 1, (PREVIEW_ROWS * PREVIEW_COLS, NOISE_SIZE))cnt = 1
**for** epoch **in** range(EPOCHS):
 idx = np.random.randint(0, training_data.shape[0], BATCH_SIZE)
 x_real = training_data[idx]

 noise= np.random.normal(0, 1, (BATCH_SIZE, NOISE_SIZE))
 x_fake = generator.predict(noise)

 discriminator_metric_real = discriminator.train_on_batch(x_real, y_real)discriminator_metric_generated = discriminator.train_on_batch(
 x_fake, y_fake)

discriminator_metric = 0.5 * np.add(discriminator_metric_real, discriminator_metric_generated)generator_metric = combined.train_on_batch(noise, y_real)**if** epoch % SAVE_FREQ == 0:
   save_images(cnt, fixed_noise)
   cnt += 1

   print(f”{epoch} epoch, Discriminator accuracy: {100*  discriminator_metric[1]}, Generator accuracy: {100 * generator_metric[1]}”)**

分解一下:

在这里的前几行中,我们已经定义了我们的输入形状:128X128X3 (image_size,image_size,image_channel)。

之后,我们使用亚当作为我们的优化器。

注:所有参数均来源于论文[1]。

**image_shape = (IMAGE_SIZE, IMAGE_SIZE, IMAGE_CHANNELS)optimizer = Adam(1.5e-4, 0.5)discriminator = build_discriminator(image_shape)
discriminator.compile(loss=”binary_crossentropy”,
optimizer=optimizer, metrics=[“accuracy”])**

初始化优化器后,我们调用 build_discriminator 函数并传递图像形状,然后用损失函数和优化器对其进行编译。

因为它是一个分类模型,我们使用准确性作为它的性能度量。

类似地,在下一行中,我们调用 build_generator 函数并传递 random_input 噪声向量作为它的输入。

**generator = build_generator(NOISE_SIZE, IMAGE_CHANNELS)random_input = Input(shape=(NOISE_SIZE,))generated_image = generator(random_input)**

它将生成的图像作为输出返回。

现在,GAN 的一个重要部分是我们应该阻止我们的鉴别器进行训练。

**discriminator.trainable = **False**validity = discriminator(generated_image)combined = Model(random_input, validity)
combined.compile(loss=”binary_crossentropy”,
optimizer=optimizer, metrics=[“accuracy”])**

因为我们在这里只是训练生成器,所以我们不想调整鉴别器的权重。

这就是对抗性网络中“对抗性”的真正含义。

如果我们不设置这个,生成器会调整它的权重,这样它就能更好的愚弄鉴别器,它也会调整鉴别器的权重,使它更好的被愚弄。

我们不想这样。所以,我们要分开训练他们,互相对抗。

然后,我们用损失函数和优化器编译生成模型。

之后,我们将两个向量定义为 y_real 和 y_fake。

**y_real = np.ones((BATCH_SIZE, 1))
y_fake = np.zeros((BATCH_SIZE, 1))fixed_noise = np.random.normal(0, 1, (PREVIEW_ROWS * PREVIEW_COLS, NOISE_SIZE))**

这些向量由随机的 0 和 1 值组成。

之后,我们创建一个 fixed_noise:这将导致生成的图像被保存下来,我们可以看到它在每次迭代中变得更好。

之后,我们将使用我们定义的时期范围迭代我们的训练数据。

**cnt = 1
**for** epoch **in** range(EPOCHS):
  idx = np.random.randint(0, training_data.shape[0], BATCH_SIZE)
  x_real = training_data[idx]

  noise= np.random.normal(0, 1, (BATCH_SIZE, NOISE_SIZE))
  x_fake = generator.predict(noise)

  discriminator_metric_real = discriminator.train_on_batch(x_real, y_real) discriminator_metric_generated = discriminator.train_on_batch(
 x_fake, y_fake)

  discriminator_metric = 0.5 * np.add(discriminator_metric_real,   discriminator_metric_generated) generator_metric = combined.train_on_batch(noisse, y_real)
  **if** epoch % SAVE_FREQ == 0:
     save_images(cnt, fixed_noise)
     cnt += 1

     print(f”{epoch} epoch, Discriminator accuracy: {100*  discriminator_metric[1]}, Generator accuracy: {100 * generator_metric[1]}”)**

在迭代过程中,我们从真实图像中提取样本,并将其放在 x_real 上。之后,我们定义一个噪声向量,并将其传递给我们的生成器模型,以在 x_fake 中生成一个假图像。

然后,我们分别在真实和虚假图像中训练我们的鉴别器模型。

**discriminator_metric_real = discriminator.train_on_batch(x_real, y_real)discriminator_metric_generated = discriminator.train_on_batch(
 x_fake, y_fake)**

一些研究表明,分别训练他们可以让我们得到更好的结果。

训练后,我们从两个模型中提取指标并取平均值。

**discriminator_metric = 0.5 * np.add(discriminator_metric_real, discriminator_metric_generated)**

通过这种方式,我们获得了鉴别器模型的指标,现在,对于发生器模型,我们在噪声向量和 y_real:上训练它,y _ real:是 1 的向量。

在这里,我们试图训练发电机。超时生成器将从这些输入中变得更好,并且鉴别器将不能鉴别输入是假还是真。

这里需要注意的一点是,我们的组合模型是基于直接链接到鉴别器模型的生成器模型。这里我们的输入是发生器想要的输入:噪声,输出是鉴别器给我们的。

最后,我们有一个 if 语句来检查我们的检查点。

****if** epoch % SAVE_FREQ == 0:
 save_images(cnt, fixed_noise)
 cnt += 1

 print(f”{epoch} epoch, Discriminator accuracy: {100* discriminator_metric[1]}, Generator accuracy: {100 * generator_metric[1]}”)**

如果到达检查点,则保存当前迭代噪声并打印生成器和鉴别器的当前精度。

这都是为了创建 GAN 的编码部分,但我们还没有完成。

我们刚刚为它编写了代码,现在我们必须实际训练这些模型,并查看它的输出表现如何。

训练甘

在普通的笔记本电脑上训练 GAN 是不可能的,因为它需要很高的计算能力。

普通 CPU 的普通笔记本电脑无法处理如此庞大的任务,所以我们准备用 :这是机器学习和深度学习最快最强大的端到端平台。

为什么拼写?

魔咒是构建和管理机器学习项目的强大平台。魔咒负责基础设施,使机器学习项目更容易启动,更快获得结果,更有组织性,比自己管理基础设施更安全。

在每一个法术注册,你可以获得 10 元免费信贷!

简单地说,我们将把我们的数据文件上传到拼写平台,让它处理我们所有的训练任务。Spell 在他们强大的 GPU 中运行我们的任务,这样我们就什么都不用担心了。我们可以从他们的 Web GUI 监控我们的日志,并且我们所有的输出都被安全地保存。

培训过程

在拼写运行我们的项目之前,有几件事情要涉及。

首先,我们必须创建我们的法术账户。在他们的官方页面上有很好很容易上手的文档。

创建帐户后,我们可以使用 pip install 安装 Spell CLI:

**pip install spell**

这就把所有的法术能量都安装到了我们的笔记本电脑上。我们既可以使用 Web GUI,也可以轻松地登录到 spell 服务器,从 cmd 或 bash 执行命令。

为了上传我们的项目,我们将使用命令行工具。

让我们在项目文件夹的根目录中打开命令行终端,并使用拼写登录命令登录到服务器:

**spell login**

成功登录后,现在我们可以上传我们的训练数据文件,并在拼写服务器中运行我们的代码:

**Spell upload “filename”**

之后,我们的训练数据将被上传到服务器。

注意:在服务器运行代码之前,代码已经被推送到 github。

现在我们准备在拼写服务器中执行我们的代码。

在命令行中,让我们运行以下命令:

**Spell run python art_gan.py -t V100 -m uploads/art_gan/cubism_data.npy**

上面的命令在机器类型为 V100 的 Spell 服务器上运行我们的代码,这是一台 GPU 机器。最后一个参数挂载数据集目录,以便我们的代码可以访问它。

现在代码已经成功执行,您可以在控制台上看到日志。如果您想在 GUI 中进行监控,那么您可以登录到 Spell 的 Web GUI,查看“运行”部分。

如您所见,它保存了我们最近运行的所有信息。

就像我们写的代码一样。在每 100 次迭代中,我们生成的图像被保存在输出目录中,并打印带有精度度量的日志。

您可以在日志部分查看它们。

太棒了,不是吗?当它为你训练和保存输出时,你可以做你的其他工作。

输出

现在,训练完成后,Spell 会自动将我们的输出保存在 resources/runs 目录中。

之后,我们可以使用以下命令将 Spell 运行的输出下载到我们的本地机器上:

**spell cp [OPTIONS] SOURCE_PATH [LOCAL_DIR]**

对于这个项目,它将是:

**spell cp runs/44**

您只需输入 runs/ 即可下载该 runs 的内容。

就是这样!!现在,您已经在本地机器上的 Spell 的 GPU 机器上训练了 GAN 的输出。现在,您可以从输出图像中直观地看到 GAN 执行情况。

结论

GANs 是一个令人兴奋且快速变化的领域,它实现了生成模型的承诺,能够在一系列问题领域生成真实的例子。一夜之间理解 GAN 或者任何机器学习、深度学习领域都不是一件容易的事情。这需要耐心、大量的练习和理解。

在以前,对于像我们这样有抱负的 ML 爱好者来说,进行重复的练习来看看发生了什么是不可能的。但是现在,像 Spell 这样的平台帮助我们提供一个系统来运行和管理我们的项目,这样我们就可以运行和测试我们的模型。

我们所创造的只是 GAN 如何被创造和 GAN 能做什么的简单表示。还有更高级的调整有待执行。

为了更进一步,你可以调整参数,看看它如何不同地生成图像。

还有很多东西可以研究。

****如有任何疑问和讨论,你可以从这里加入拼写社区:【https://chat.spell.ml/ ****

参考

[1] 生成对抗网络,伊恩·古德菲勒,让·普盖-阿巴迪,迈赫迪·米尔扎,徐炳,大卫·沃德-法利,谢尔吉尔·奥泽尔,亚伦·库维尔,约舒阿·本吉奥,2014

[2] 生成性对抗网络(GANs)的温和介绍杰森·布朗利,2019【在线】https://machine learning mastery . com/what-are-Generative-Adversarial-Networks-GANs/

[3] 生成对抗网络(GANs)入门指南克里斯,2019【在线】https://skymind.ai/wiki/generative-adversarial-network-gan

借助递归神经网络生成分子

原文:https://towardsdatascience.com/generating-molecules-with-the-help-of-recurrent-neural-networks-c3fe23bd0de2?source=collection_archive---------7-----------------------

理解材料科学的深度学习

2017 年,“数字医学”Spinraza 在经过多年的药物开发后向公众发布,用于治疗脊髓性肌萎缩症(SMA),价格最初为 75 万美元,此后每年为 37.5 万美元。

SMA 的原因是 5 号染色体上 SMN1 基因的简单突变。sm n1 基因外显子中的一个改变的核苷酸序列改变了出生时患有这种疾病的儿童的完整生命轨迹,许多儿童在婴儿期结束前死亡。然而,许多政府和保险公司拒绝支付药品的价格,使得儿童无法获得治疗。这种药物所做的只是,获取邻近内含子序列的反向互补序列,并与之结合。这控制着外显子是否包含在内,因为内含子编码基因的逻辑。许多其他更传统的药物也一样简单,使用抑制或阻止某种疾病机制发生的分子实体或化合物。那么为什么开发一种药物的过程如此昂贵和耗时,我们如何改变这种情况?

The average drug takes 12 years and 1.5B to produce, according to Scientifist. Spinraza, for example, took 12 years from when the compound was discovered.

传统药物开发分两个阶段进行;发现阶段、开发阶段。一旦发现某种疾病的靶标或根本原因/机制,我们需要鉴定化合物并验证这些化合物是否有任何作用来停止或抑制这些疾病的活性。在每 5000 种被测试的化合物中,只有一种具有初步的积极效果,对于那些我们对其毒性或其他生理化学特征没有基本了解的化合物。这导致长期而艰巨的工作,收效甚微甚至毫无结果。与此同时,数百万人死于这些疾病。很大程度上是因为这个原因,投资大多数制药公司不如把你的存款存入高息账户。

但是,我们如何能够尝试和加速我们识别针对特定目标效应的化合物的方法呢?在这种情况下,生成网络的领域迅速普及,以帮助使用网络如 RNNs 生成新的分子。我们的目标是通过全新药物设计来消除我们必须手动测试大量化合物以识别有效化合物的过程,从而加快发现阶段的过程。

从头项目:产生新分子

Each colour corresponds to a sequence of characters in a SMILES string

我的项目的目标是使用递归神经网络生成新的分子。从头简单地意味着从简单分子合成新的复杂分子。然而,有一个主要的警告:我们不知道这些分子有多有用,甚至不知道它们的有效性,但在本文的最后,我提到了我可以扩展这个模型来做到这一点的方法。想法是训练模型学习微笑串中的模式,以便生成的输出可以匹配有效的分子。SMILES 只是基于分子的结构和不同组成部分的分子的字符串表示,并且适合以计算机理解的方式表示分子。

Penicillin as a SMILES String converted to its structural formula (source: Chemistry Stack Exchange)

因为我们将网络文本作为数据输入,所以 RNNs 是生成新的 SMILES 字符串的最佳网络。大多数论文和研究人员推荐使用 LSTM 细胞来增强 RNN 的内部结构,这是一种更高效和有效的相对方法。因此,我们将使用 RNN w/ 2 LSTM 层,在 100,000 个微笑字符串的数据集上进行训练。

第一阶段——测绘

该项目的第一阶段是创建一个将字符映射到整数的指南,以便 RNN 在将结果和输出转换回字符时可以处理数据,反之亦然。我们需要创建一组唯一的字符,并枚举(为每个字符定义一个数值)每一项。微笑字符串由两种类型的字符组成,它们是特殊字符,如“/”或“=”,以及元素符号,如“P”、“Si”、“Mg”等。我们将这些枚举的独特字符放入独特的字典中,

unique_chars = sorted(list(set(raw_text)))
char_to_int = dict((c, i) for i, c in enumerate(unique_chars))
char_to_int.update({-1 : "\n"})

为“\n”创建映射的原因是它表示。txt 文件。

阶段 2—数据预处理

一旦我们为字符映射创建了字典,我们就调用字典 char_to_int 将 SMILES 字符串数据集中的每个字符转换成整数。规范化的工作原理是将字符的每个整数值除以数据集中唯一字符的数量。然后,我们使用 NumPy 将输入数组 X 重新整形为一个用于[样本、时间步长、物理化学特征]的三维数组,这是递归模型的预期输入格式。输出变量 Y 被一键编码以在训练模型后生成新的微笑。一键编码处理的是整数表示,就像我们刚刚做的那样,整数编码变量被删除,新的二进制变量被添加到每个唯一的整数值中。

阶段 3—模型架构

The Model Architecture, consisting of two LSTM layers with 256 units (Gupta et al.)

我构建的架构的设计基于 Gupta 等人的研究论文“为药物设计生成递归网络”。我决定采用这种架构,因为它在创建有效微笑字符串方面产生了 97%的准确性,并且它是一种非常简单的架构。它由两个 LSTM 层组成,每一层都有一个隐藏的状态向量 H,它通过一个又一个单元传递 RNN 从未见过的信息。像这样更多的循环连接允许网络理解更复杂的 SMILES 序列的相关性。我还在这些层上使用了 0.25 的下降正则化,然后是由使用 softmax 激活函数的中子单元组成的密集输出层。Softmax 是一个函数,它将 K 个实数的向量(在我们的例子中是输出向量 Y)作为输入,并将其归一化为由 K 个概率组成的概率分布。如果你想了解更多关于这个激活功能的信息,我会推荐 softmax 功能的 wiki 页面。

# Create the model (simple 2 layer LSTM)
model = Sequential()
model.add(LSTM(128, input_shape=(X.shape[1], X.shape[2]), return_sequences = True))
model.add(Dropout(0.25))
model.add(LSTM(256, return_sequences = True))
model.add(Dropout(0.25))
model.add(LSTM(512, return_sequences = True))
model.add(Dropout(0.25))
model.add(LSTM(256, return_sequences = True))
model.add(Dropout(0.25))
model.add(LSTM(128))
model.add(Dropout(0.25))
model.add(Dense(Y.shape[1], activation='softmax'))

随意添加更多层或改变辍学率,但请记住,NN(神经网络)中的层和神经元越多,计算量就越大,越精确。这个网络是在具有 30GB RAM 的 Paperspace Cloud GPU 上训练的,但是每个 epoch 仍然需要 3 个小时来训练!

第 4 阶段—培训:

对于我们的网络,我使用分类交叉熵作为损失函数,以及 Adam 优化器。我使用了一个包含 100,000 个 SMILES 字符串的数据集,但是我想在不需要等待 4 天的情况下最大限度地利用它,所以我用 512 个批量训练了 10 个时期的模型以供学习。这里的经验法则是理解更多的时期+更小的批量=更好地理解数据,但是代价是更长的训练时间。我们还可以利用检查点,Keras 库中的一个内置函数来保存我们的训练进度,以及每个时期的模型权重,供以后传输或保存。当我们想要在 GPU 或云服务上训练(就像我一样),然后在 CPU 上加载训练节省的权重,以减少项目时间时,检查点是有用的。

# Define checkpoints (used to save the weights at each epoch, so that the model doesn't need to be retrained)
filepath="weights-improvement-{epoch:02d}-{loss:.4f}.hdf5"checkpoint = ModelCheckpoint(filepath, monitor = 'loss', verbose = 1, save_best_only = True, mode = 'min')
callbacks_list = [checkpoint] # Fit the model
model.fit(X, Y, epochs = 19, batch_size = 512, callbacks = callbacks_list) """TO TRAIN FROM SAVED CHECKPOINT"""
# Load weights
model.load_weights("weights-improvement-75-1.8144.hdf5") # load the model
new_model = load_model ("model.h5") assert_allclose(model.predict(x_train),new_model.predict(x_train), 1e-5) # fit the model
checkpoint = ModelCheckpoint(filepath, monitor='loss', verbose=1, save_best_only=True, mode='min')
callbacks_list = [checkpoint]new_model.fit(x_train, y_train, epochs = 100, batch_size = 64, callbacks = callbacks_list)

阶段 5 —生成新分子:

生成新分子的工作相当简单。首先,我们加载预训练的权重,从而避免每次在生成新的微笑字符串之前都必须训练模型。然后,我们从数据集中随机选择一个 SMILES 字符串作为参考字符串,并在范围内生成指定数量的字符,并将整数值转换回字符。从技术上讲,上面的代码可以用于生成任何类型的文本,无论是故事、音乐还是微笑分子。根据自定义调整、学习速度、数据集大小和质量,结果会有所不同,但最终我们应该得到一个字符串,它代表了类似于有效分子的东西。该模型可能首先生成一个只有一个字符的序列(NNNNNN),然后学习在分子中发现的新的子结构和分支(N1CCN(CC1)C(C(F)=C2…)。

下面是分子结构的二维(O1C = C[C @ H]([C @ H]1 O2)C3 C2 cc(OC)C4 c3oc(= O)C5 = C4 CCC(= O)5)I 生成:

2-d molecular structure

以及立体结构:
O1C = C[C @ H]([C @ H]1 O2)C3 C2 cc(OC)C4 c3oc(= O)C5 = C4 CCC(= O)5

3-d molecular structure

可能的改进

  1. ****检查这些分子的有效性:我们不知道我们生成的分子是否有任何用例,甚至是有效的分子结构。我们必须通过将这些分子与用于训练的原始分子进行比较来验证它们。通过为数据计算它们共同的生理化学特征,并对训练数据的特征使用主成分分析,我们可以确定新产生的分子是否被相应地转化。
  2. 微笑字符串是代表分子的最佳方式吗?: LSTMs 充其量只能让生成的文本样本看起来有一定的说服力,因为微笑字符串只是观察分子化学组成的一种基本方式。我们很可能会创造出更好的方法来表现分子的复杂性,以便在未来进行更精确的测试。然而,目前,SMILES 字符串和 RNNs 是使用 ML 生成分子的标准。
  3. ****数据集:通过数据扩充,我们可以对微笑字符串进行排列或不同的排列,并将它们添加到我们的数据集。扩充数据集的另一种方法是枚举原始形式之外的 SMILES 字符串,或者用另一种方式编写它。

An example of data augmentation on image data.

不断变化的药物发现:基于片段的药物发现(FBDD)

SMILES fragment 12-which is known to bind to an active site is used to create the following molecular structures

这种产生分子的方法的一个主要应用是基于片段的药物发现,或 FBDD** 。在这种情况下,我们可以从已知与感兴趣的靶疾病机制结合的片段开始,而不是以标记(一种特殊值或字符,其使用其存在作为终止条件)开始输入。通过将这个片段的微笑串作为输入,我们可以用 RNN“生长”分子的其余部分,创造出更多被证明能抵消某种功能的分子!这种方法肯定很有前途,将来会被更多地使用,这很有趣。**

结论+关键要点

RNNs 提供了一种简单而有效的生成分子的方法,仅使用固体数据集上的几个参数。该领域的大多数研究都希望结合 RL 或对抗性训练等架构,以帮助增加生成的有效分子的数量,或使模型偏向于创建具有特定药物特定属性的分子。希望在未来,通过这种方法,基于片段的药物发现变得更加普遍,并有助于使药物开发更加可行和经济。人工智能是消除创造疗法中猜测的关键。****

关键要点

  • 缓慢而昂贵的药物开发和材料科学研究是当前方法缓慢的直接结果
  • 使用磁共振成像,我们可以加快 R&D 发生的速度。
  • 使用 ML 生成分子最有效的方法是使用 RNN 和斯迈尔斯分子串表示法,但是它们并不是最佳的方法。
  • 在我们能够使用人工智能以更快的速度制造出更准确、更有效的分子结构之前,我们还有很长的路要走,但是有太多的事情值得期待了!

后续步骤

如果您喜欢这篇文章,请务必遵循这些步骤,与我未来的项目和文章保持联系!

  1. 在 Linkedin上与我联系,了解我未来的发展和项目。我目前正在研究 cfDNA,并确定用于早期癌症诊断的独特生物标志物。
  2. 我的网站现在有了我所有的内容,还有我的 Github 。
  3. 请务必订阅我的每月简讯,以查看我参加的新项目、会议和发表的文章!
  4. 随时给我发电子邮件在 seyonec@gmail.com 谈论这个项目和更多!

生成多对比度的 MRI 图像

原文:https://towardsdatascience.com/generating-mri-images-of-multiple-contrast-levels-89c3b6c00e68?source=collection_archive---------11-----------------------

利用 CycleGans 将 T1 加权 MRI 图像转换为 T2 加权 MRI 图像。

放射科医师每年误诊全球 4000 万人🤯

虽然技术等其他事物在不断创新,但我们也必须大幅改进疾病诊断方法。通过简单地减少假阴性和假阳性误诊病例,我们可以真正解决一半的医疗保健问题。

如果存在更好的成像工具和设备,能够更准确地发现患病部位,这可能会挽救数百万人的生命!特别是像癌症这样的疾病,当在早期诊断时,与晚期相比,其 5 年存活率明显更高,但是很少在早期检测到疾病的任何“迹象”,这是一个问题。

核磁共振扫描

让我们来玩一个小游戏,,在这里你可以假装是放射科医生。你的工作是在下面的 MRI 图像中找到异常区域:

提示: 两个 异常区域。

Source: MRI T1-weighted scan

如果我也给你这个核磁共振扫描,这一切会变得容易得多,你也会对你的答案更有信心:

Source: MRI T2-weighted scan

请注意,在上面的 MRI 扫描中,两个异常区域要亮得多,也更容易发现。

Source

上面显示的两幅不同的 MRI 图像具有不同的对比度。在这种情况下,异常区域恰好表明肿瘤的迹象,特别是这名患者患有多发性骨髓瘤。

磁共振成像主要有两种类型, T1 加权磁共振成像和 T2 加权磁共振成像。这两种类型的核磁共振成像对比体内不同的区域。

上面呈现的第一个 MRI 图像是 T1 加权的 MRI 图像👆,而第二个提出的是 T2 加权磁共振成像图像。

T1 加权图像特别突出了脂肪组织,而 T2 加权图像突出了体内的脂肪和水。

  • T1 加权→ 脂肪组织看起来很亮
  • T2 加权→脂肪和水区域看起来都很亮

Summarizes the regions T1 and T2 images highlight

拥有这两种类型的 MRI 扫描可以通过为医生提供更全面的理解来大大提高诊断的准确性。

然而,在实践中,病理学家很少能够访问这两种类型的 MRI 图像用于检查和诊断目的。这是因为多种原因,例如某些扫描时间限制以及其他因素,例如在 MRI 图像中由于噪声或伪影而发现的失真对比度。

克服这些低效率的方法之一是使用一种称为风格转移的人工智能技术,从现有的 MRI 扫描中合成不同对比度水平的 MRI 图像。

具体来说,我利用了一种可以执行风格转移的算法,称为循环生成对抗网络(CycleGAN),从 T2 加权的 MRI 图像合成 T1 加权的 MRI 图像,反之亦然。

什么是风格转移?

风格转移正是它听起来的样子!让我们用一个埃隆·马斯克的类比来进一步分解它😍。

这是 21 世纪的埃隆·马斯克:

埃隆·马斯克(Elon Musk)很酷,但我一直想知道 16 世纪的优秀的老埃隆·马斯克会是什么样子。风格转移让我满足了我的好奇心,这就是它对埃隆·马斯克的影响:

Painting of Elon Musk in the 16th century

那是埃隆·马斯克在 16 世纪的一幅画👆!

这是一个风格转换的演示,将一张“现代”的照片几乎完美地变成了一幅古典绘画。特别是,这被称为 图像到图像的翻译,将图像从一个域转移到另一个域的任务。

这里有更多的例子!

🐴我以前从未见过斑马在美丽的大自然中奔跑,但现在我看到了…

☀️,我真的希望季节转换的魔力真的存在于现实生活中,而不仅仅是图像。

🎨《蒙娜丽莎》五季怎么样?(我知道,我知道,你想说只有四个季节,对吧,我想传统是要打破的。)

🐰史上最可爱的仓鼠!(ps:实际上我不知道那是不是仓鼠,但它可能是)

这里还有一些👆。享受吧。

好的,我得到了样式转移部分,但是是什么使 CycleGan 适合于将样式转移应用于 MRI 图像的特定任务呢?

风格转移并不是一个真正的新概念,已经做了大量的工作。但使 **CycleGAN 成为一个有吸引力的模型的是,它不需要成对的训练数据*** ,但仍然能够合成“惊人”质量的风格转移图像。*

Paired data vs unpaired data

成对数据是 x1 对应 y1、x2 对应 y2 等的数据。就 T1 加权和 T1 加权 MRI 图像而言,如果数据是成对的,这意味着每个 T1 加权 MRI 图像及其对应的 T2 加权 MRI 图像来自同一患者。

不成对数据则是两组数据,其中 x1 不需要对应 y1,x2 到 y2 等等。

先前用于风格转移的机器学习方法工作良好,并且仅在用配对数据训练的情况下产生“体面”的结果。然而,成对数据的大型数据集非常罕见。**

CycleGAN 很有用,因为它可以像其他风格传输方法一样出色地执行,但使用的是不成对数据。寻找数据集是一件痛苦的事情,如果你在机器学习方面做过一些工作,你就会知道这有多痛苦!如果你想要成对数据的大型数据集,那就更痛苦了,而且大多数时候,对于像 MRI 图像这样的数据集,公共成对数据集甚至不存在(或者,我没有挖掘足够多😅).

这就是 CycleGAN 如此有用的原因,与成对数据相比,它可以用不成对数据进行同样好的训练。

在我们深入到 CycleGAN 之前,让我们先来看看正则生成敌对网络(GANs)。

生成对抗网络

GANs 的魔力包括两个关键部分:

  • 生成器——负责生成“逼真”的合成数据(在这种情况下,它们是图像)
  • 鉴别器 —尽力将生成器生成的“虚假”[0]数据与训练数据集中提供的“真实”[1]数据区分开来

让我们用一个类比来帮助我们更直观地理解这一点。

杰西卡是一名专业的艺术品侦探,她的职责是侦查伪造的艺术品。

艺术界有成千上万的“伪造者”在生产“伪造”艺术品。

  • 伪造者的工作(“生成者”)是制作看起来非常“逼真”的赝品,并试图愚弄侦探杰西卡(“鉴别者”)。
  • 杰西卡(“鉴别者”)负责区分“真”艺术品与伪造者(“生成者”)的“假”艺术品。

杰西卡和伪造者本质上是在这场猫和老鼠的竞赛中竞争。为了训练甘斯产生逼真的图像,最终目标是训练生成者(“伪造者”)变得真正擅长愚弄鉴别者(“杰西卡”)。

杰西卡和伪造者都很有竞争力,他们互相依赖,以求更好。随着鉴别器更好地检测由发生器从真实图像合成的假图像,这迫使发生器也变得更好地生成“逼真”的图像。

CycleGAN 式传输,但数据不成对

CycleGAN 比常规 GAN 更复杂,但它包含类似的组件,如发生器和鉴别器。别担心,只是稍微复杂一点,嗯,也许…

让我们首先来看看数据集,它包括两个独立的数据集。我用来训练我的 CycleGAN 模型的两个数据集包括以下内容:

  • 数据集#1: 真实 T1 加权脑 MRI 图像
  • 数据集#2: 真实的 T2 加权脑 MRI 图像

Daily dose of MRI! Left: T1-weighted MRI image, Right: T2-weighted MRI Image. Ps: Another example of how having both types of MRI images allows for a more comprehensive diagnosis.

CycleGAN 的架构有点像 2 个 GAN 的组合,总共由 4 个模型组成(2 组 1 个发生器网络+ 1 个鉴别器网络)。下面是每个 GAN 在一个 CycleGAN 中所负责的内容:

甘#1:

GAN #1 负责对 T1 加权的 MRI 图像(第一数据集)应用风格转移,以合成生成其对应的 T2 加权的 MRI 图像(第二数据集)。

甘#1 发电机:

  • 输入:T1 加权脑 MRI 图像(第一数据集)
  • 输出:合成相应的 T2 加权

GAN # 1 的鉴别器:

  • 输入:T2 加权脑 MRI 图像的数据集(数据集#2) +来自 GAN #1 的发生器的合成生成的 T2 加权脑 MRI 图像
  • 输出:真实[1]或虚假[0]-表示生成的图像与来自数据集#2 的真实图像相比有多真实

甘二号:

GAN #2 负责将风格转移应用于 T2 加权 MRI 图像(第二数据集)以合成生成其对应的 T1 加权 MRI 图像(第一数据集)。

甘#2 发电机:

  • 输入:T2 加权脑 MRI 图像(第二数据集)
  • 输出:合成相应的 T2 加权

GAN # 2 的鉴别器:

  • 输入:T1 加权脑 MRI 图像的数据集(数据集#1) +来自 GAN #2 发生器的合成生成的 T1 加权脑 MRI 图像
  • 输出:真实[1]或虚假[0]-表示生成的图像与数据集#1 中的真实图像相比有多真实

CycleGAN representation

好的,但是发生器和鉴别器的组成部分到底是什么?

发生器的结构由一个编码器-解码器网络组成。

发电机包含三种主要类型的部件:

1。编码器 —由卷积层组成,将图像解压缩为代表其压缩特征的矢量。

  • 接受“真实的”MRI 图像,即来自中提供的数据集的 256 x 256 图像作为输入。
  • 将图像的压缩表示作为特征向量输出。

2。转换器 —由负责解释编码的残差神经网络(ResNet)组成。

  • ResNet 层将来自编码器的特征向量作为输入。
  • 它负责将变换应用于特征向量,以使特征向量与期望的输出相匹配。例如,对于负责将 T1 加权 MRI 图像变换为 T2 加权 MRI 图像的 GAN #1,变换器的工作是变换 T1 加权 MRI 图像的压缩特征向量,使得它类似于 T2 加权 MRI 图像的特征向量。
  • 每个 ResNet 层由两个使用跳过连接的卷积层组成。跳过连接确保早期层中的变换在整个模型中得以保留,因为它解决了渐变消失的问题。这允许输出在重建(由解码器执行)期间保留原始输入图像的大部分特征。

3。解码器 —由解卷积层(与卷积层相反)组成,它将图像的紧凑表示解构成原始大小。

  • 在这种情况下,原始大小是 256 x256 的图像。
  • 解码器将来自 ResNet 层的变换后的特征向量作为输入,并对其进行上采样以生成新的 256×256 图像。

Convolutional neural network

解码器网络的架构要简单得多,由一个执行图像分类的卷积神经网络组成。如上所述,卷积层决定了输入模型的图像是真的[1]还是假的[0]。

在只训练了我的模型 2 个时期后,它就能够合成看起来“干净”的 MRI 图像了!然而,我建议为大约 50 个纪元训练这样的模型,这可能需要几天时间📆。

结果如下:

这是从 T1 加权 MRI 图像生成 T2 加权 MRI 图像的例子之一。

Real: T1–weighted MRI image, Generated: T2-Generated MRI image

这是产生相应 T2 加权 MRI 图像的 T1 加权 MRI 图像的模型的另一个例子。

Real: T2-weighted MRI image, Generated: T1-weighted MRI image

这项技术的含义是疯狂的!CycleGAN 可以用来合成任何对比度级别的 MRI 图像!此外,它甚至有可能被部署精确地导出 CT 扫描、PET 扫描、X 射线等。核磁共振扫描,反之亦然!

关键要点:

  • CycleGAN 使用不成对的数据,这使得它非常有吸引力,因为成对的数据很少,很难找到
  • GANs 包括两个网络:生成器(“伪造者”)和鉴别器(“侦探”)
  • 一个循环中涉及两个 GAN
  • 我训练了一个 CycleGAN 来合成 T1 加权的 MRI 图像,给定 T2 加权的 MRI 图像,反之亦然

在您离开之前,如果您有任何疑问,请随时联系我,并通过 LinkedIn 与我联系!PS:我每月都会发简讯,如果你有兴趣了解这位 16 年的创新者/人工智能爱好者的最新动态, 请随意订阅 这里

用人工智能创作音乐

原文:https://towardsdatascience.com/generating-music-with-artificial-intelligence-9ce3c9eef806?source=collection_archive---------4-----------------------

我从用机器学习研究音乐生成中学到了什么

Photo by Oleg Kuzmin on Unsplash

我五岁时开始弹钢琴。我曾经每天练习大约一个小时,让我告诉你,一个小时感觉像永远。我没有停止思考,但是我继续练习,因为我真的喜欢音乐。

几年后,我开始做一些真正先进的东西。我的手在键盘上飞来飞去,我可以闭着眼睛弹奏。开玩笑的。实际上我并没有那么好,但我希望有一秒钟你认为我是一个钢琴神童或什么的。😉

我几乎喜欢钢琴演奏的每个方面。音乐的声音,琴键的触感…除了乐理以外的一切。这就像你把一个沉迷于规则的老家伙和他的音乐创造力和独创性结合起来。音乐语法,分析和创作音乐时遵循的规则,调号和拍号。这都是一堆你需要记住的漂浮在页面上的随机的东西。

What music theory feels like at times.

但是等等,一大堆数据?很多规则和模式?音符的顺序和序列?这听起来像是(戏剧钢琴曲)机器学习的完美工作!

可惜没那么容易。

用于音乐生成的递归神经网络

注意:如果你需要复习,请随意查看我的文章关于用 RNNs 生成文本。

Visualizing the flow of information in a Recurrent Neural Network. Source.

递归神经网络的快速概述;

  • 普通神经网络不擅长处理时序或时间数据,它们还需要固定的输入大小
  • 递归神经网络通过让后续迭代从最后一次迭代传输数据来解决这个问题,这意味着每次运行时信息都通过网络传递
  • 通过获取一次前向传递的输出并将其输入下一次传递,您可以生成全新的数据序列。这就是所谓的取样
  • rnn 有一些问题,例如当网络太深时出现的消失/爆炸梯度。这通过使用 LSTMs 来解决,LSTMs 基本上在网络中创建快捷方式

因此,在了解了递归神经网络之后,我认为这将完全是创建能够产生新类型音乐的 ML 模型的最佳解决方案。我很接近了。

在做了一些研究并了解了更多关于使用递归神经网络生成音乐的信息后,我发现它工作得相当好。而且其实超级变态。

A sequence generated by an RNN trained by Daniel Johnson. Source.

但是如果你明白我的意思,它仍然没有那种魅力。我不认为这将很快取代我的 Spotify 播放列表中的莫扎特。虽然这首音乐完全由神经网络生成非常酷,但考虑到上下文,我认为大多数人都能够看出它是由机器或我创作的。

这让我想了解更多,深入这个话题,这是我发现的一个超级有趣的事情。

MAESTRO 数据集和 Wave2Midi2Wave

A diagram showing the different parts of Wave2Midi2Wave. Source.

在查看了一些更多的资源后,我发现了一篇研究论文,其中介绍了一个名为 MAESTRO 的新数据集(代表为同步轨道和组织编辑的 MIDI 和音频)。它还提出了一种新的架构,Wave2Midi2Wave,它基本上结合了三种最先进的算法,并在 MAESTRO 数据集上训练它们。

MIDI 基本上是一种技术标准,包括一系列计算机与不同种类音频设备接口的协议。这很有用,因为传输的信息包含有关音符、音高、力度和速度的信息。

这个新数据集如此重要的主要原因是,它包含的数据比以前的所有数据集都多。客观地说,MAESTRO 数据集包含 172 小时的音频和 MIDI 转录。地图数据集仅包含 17.9 小时,音乐网数据集仅包含 15.3 小时。

正如我之前提到的,wave 2 mid 2 wave 基本上是三个不同的艺术模型的组合,它们各自执行不同的任务。首先,Wave2Midi 用于将音频转录为符号表示(Midi)。然后网络的 Midi 部分产生新的内容。所有这些都由 Midi2Wave 合成,以获得逼真的声音音乐。

Wave2Midi:开始和框架

Audio transcription from an audio file to a MIDI representation. Source.

Wave2Midi2Wave 中的第一个网络使用了一种称为 Onsets and Frames 的艺术架构,它可以自动将您的录音转换为 Midi 中的音符。所以,如果你是即兴创作,你可以确切地知道你演奏的是什么!

使用 CNN 和 LSTMs,研究人员能够“预测音高开始事件,然后[使用]这些预测来调节逐帧音高预测。”这基本上意味着模型中的一个神经网络用于预测音符何时演奏(即开始)。而另一个神经网络预测音符演奏多长时间(音符活跃的每一帧)。

Two stacks of neural networks to predict the onset and frames of an audio file. Source.

查看上图,您可以看到一个箭头从开始预测器的输出指向帧预测器中的 BiLSTM 层。这很有用,因为没有相应开始预测的每个帧预测都被移除了。这就像神经网络在反复检查它的预测。

The pink lines in the top image represent onset predictions and the blue lines represent frame predictions. The bottom image shows the output of the network after removing the frames without onsets.

如果你有兴趣了解这个超级酷的模型,你可以查看 TensorFlow Magenta 的博客文章这里,研究论文这里,以及 Colab 笔记本这里!

Midi:音乐变压器

对于 wave 2 mid 2 wave 中的第二个网络,一种特殊类型的转换器用于生成具有长期一致性的全新音乐序列。与其他神经网络相比,该网络的输出更有结构意义。

A diagram showing the events in the network and the long-term relations between them. Source.

在一个常规的转换器中,自我关注被用来模拟单词之间的关系,因为在句子中,一个单词的含义不仅基于它之前的单词,还基于整个句子的上下文。

转换器从网络的所有其他部分收集信息,并根据整个上下文为每个单词生成一个表示。对每个单词重复这一过程以产生新的表示。

An animation showing how Transformers are applied to machine translation. The bubbles represent the representations for each word. Source.

这里的要点是,使用变压器,我们可以根据整个网络的上下文将信息归属于不同的数据。那么让我们回到音乐一代的话题。

原始变形金刚的一个问题是,它依赖于自我关注的绝对位置。当把它应用到音乐中时,变形金刚会在距离、顺序和重复上挣扎。通过使用相对注意力,音乐转换器模型可以关注关系特征并生成超出训练示例中给出的序列。

如果你想了解更多关于音乐转换器的信息,还有一篇附带的博客文章和研究论文!

Midi2Wave: WaveNet

网络的最后一部分采用 WaveNet 模型,并在数据集上对其进行训练,以生成听起来像录音的音乐。 WaveNet 是基于 PixelCNN 的模型架构,专门用于合成音频。

该架构利用了卷积层。因为卷积不像 RNNs 那样使用循环连接,这意味着它们通常比 RNNs 更容易训练。但一个问题是,为了增加感受域(模型可以覆盖的数据量),需要大量的层或超大的过滤器,从而增加了计算成本。

A diagram showing a stack of convolutional layers. Source.

为了解决这个问题,使用了扩张回旋。这基本上意味着,如果跳过某些输入值,可以在更大的区域上应用过滤器。如果你用零来扩大它,你会得到和一个更大的滤波器几乎一样的效果,但是它更有效。

A diagram showing a stack of dilated convolutional layers. Source.

在 MAESTRO 数据集上训练语音合成的艺术模型 WaveNet,给出了一些非常令人难以置信的结果。我在这里链接了 WaveNet 博客文章和研究论文,在这里链接了。

最后的结果

注意:在 TensorFlow Magenta 页面上有更多 wave 2 mid 2 wave 的音频记录。可以在这里 查看

当你把这个和之前的例子比较时,很明显音频更加真实。对我来说,这听起来就像是一个真实的人在弹钢琴。我还想说,虽然有些部分听起来可能不太好听,但整体效果是一首更加连贯的音乐。

看看歌曲的实际结构,音乐转换器在生成结构上有意义的新作品方面更加有效,这一点变得更加清楚。

Top: Music Transformer. Middle: Transformer. Bottom: LSTM. Source.

  • 第一行清楚地表明了音乐中的长期结构和重复模式。
  • 第二行开始时是连贯的模式,但几秒钟后就变成了没有明显结构的音符和和弦的混乱。
  • 最后一行显示了更少的重复、结构和连贯性。

关键要点

  1. 音乐可以用递归神经网络和 LSTMs 生成,但由于它们的顺序性质,它们通常很难训练。
  2. MAESTRO 数据集包括 172 小时的钢琴录音和转录,比任何其他类似的数据集多十倍。
  3. wave 2 mid 2 wave 结合了在 MAESTRO 数据集上为三个任务训练的三个独立的最先进的模型。转录、生成和合成。

在研究用不同类型的神经网络生成音乐的过程中,我学到了很多关于可以用来转录、生成和合成音频的不同方法和模型。有很多我还没有看到的资源和架构,在接下来的一年左右的时间里,这将会是非常令人兴奋的。

感谢阅读!如果您喜欢,请:

  • 在 LinkedIn上添加我并关注我的媒体,了解我的旅程
  • 在我的个人网站查看我的其他项目
  • 留下一些反馈或者给我发邮件(alex@alexyu.ca)
  • 与你的网络分享这篇文章

通过递归神经网络生成具有特定风格的新型鸡尾酒配方

原文:https://towardsdatascience.com/generating-novel-cocktail-recipes-with-a-specific-style-through-recurrent-neural-networks-4339e9168404?source=collection_archive---------24-----------------------

使用自然语言处理和深度学习来生成文本

深度学习现在风靡一时。它被用于从病理学图像分类到谷歌助手或亚马逊 Echo 中使用的语音识别的所有事情。因此,至少把它作为一项技能应用到你的工作流程中似乎是有用的。就像你学习的每一项新技能一样,在整个学习过程中,开始学习并保持动力是很有挑战性的。那么,有什么比选择鸡尾酒作为研究主题更好的激励自己的方式呢?在成功完成项目后,你可以用美味的饮料奖励自己。

简而言之:我计划使用 Python 中的深度学习生成一个程序,可以从头开始生成新的鸡尾酒配方。为此,我选择了递归神经网络 (RNNs),一种经常用于自然语言处理(NLP)的深度学习形式。更具体地说,我用长短期记忆单位(lstm)作为 RNN 的单位来创建一个 LSTM 网络。顾名思义,LSTMs(以及一般的 rnn)具有内存优势,如果您一次生成一个字符或一个单词的连贯文本,并且不希望以混乱的方式结束,这将非常有用。在这里你可以找到一个关于 NLP 的 RNNs 的优秀介绍,但简单来说,这里是 LSTM 的情况:单个 LSTM 由一个包含记忆的单元、一个输入门、一个输出门和一个遗忘门组成。简单地说,输入和遗忘门决定了有多少输入值传输到输出门,门的激活函数通常是逻辑函数。我们有效地从输入数据中学到的是影响这些门的活动的连接的权重,并希望在这个过程中产生令人敬畏的鸡尾酒!

与所有此类项目一样,数据是第一位的。要生成鸡尾酒配方,你首先需要鸡尾酒配方,这样你的 RNN 就可以学习正确的配料和数量等嵌入(根据 Firth 的“一个词保持的公司”)。当然,从理论上讲,你可以选择你遇到的任何鸡尾酒配方,但我决定把自己限制在一个特定酒吧的配方上,用这种人工智能算法模仿他们的风格。更确切地说,我选择了纽约市著名的酒吧死亡&公司。方便的是,我有一本他们极力推荐的书“死亡&公司:现代经典鸡尾酒,有超过 500 种配方】,我曾经(手动)将大约 500 种配方输入到一个文本文件中(每行一个鸡尾酒配方,因为你在假期还会做什么)。重要的是,我在抄写食谱的时候调整了它们。对我们来说,史密斯&克罗斯朗姆酒或圣塔特蕾莎 1796 朗姆酒的差异和共性可能是显而易见的,尤其是在口味上。然而,我简单地称之为“棕色朗姆酒”的东西的太多变体可能会剥夺 RNN 人有效了解棕色朗姆酒和酸橙汁之间联系的机会。我去掉了品牌名称、配料的分类,并将盎司、破折号和滴数转换成统一的毫升数。这当然也意味着我们可能必须通过尝试不同版本的“棕色朗姆酒”来优化生成的配方。

现在有了数据,就可以开始深度学习了!一个很好的资源是合作实验室,这是一个由谷歌提供的免费 Jupyter 笔记本环境。除了能够将你的笔记本连接到你的 Google Drive 文件,你还可以使用免费的 Tesla K80 GPU 进行计算(神经网络比笔记本电脑的 CPU 快得多)。对于使用 RNNs 的文本生成, textgenrnn 是一个基于 Keras/TensorFlow 的高效工具。在我们开始训练之前,我们首先需要设置定义模型架构的超参数。为了建立这个模型,我结合了五层 LSTM 层,每层都有 128 个具有上述栅极的存储单元。此外,我决定使用双向 LSTMs,它将感兴趣的字符之前和之后的字符都考虑在内,以增强 RNN 的上下文意识。在一次以单词为特征的半成功尝试后,我转向了专注于字符的 RNN 版本(更适合 textgenrnn,因为它是基于 Andrej Karpathy 的 char-rnn )。最终文本生成的另一个重要考虑因素是,在生成下一个字符之前,RNN 应该考虑多少个上下文字符,我设置为 40 个。

Watching the RNN grow & learn how to construct cocktail recipes

现在,对于每个时期,完整地通过训练数据,每个字符的 40 个上下文字符被转换成它们的 100 维嵌入,并被馈入和通过五个 LSTM 层。所有的五层也在末端连接到一个关注层。大致基于人类的注意力,注意力层将网络集中在周围角色的特定区域,而淡化其他区域,然后重复转移他们的注意力。RNN 的最终输出是下一个字符的预测概率。在这里,我对我的 RNN 进行了 40 个时期的训练,这意味着训练数据经过了 40 次完整的传递。开始时,RNN 不能构建连贯的单词,如示例所示。然而,在训练过程中的每一步,鸡尾酒配方生成的改进都可以清楚地看到,最后,大多数单词和用法似乎都是正确的。最大的问题可以从鸡尾酒名称中看出,因为输入名称大多是虚构的,并且只出现一次或两次(后缀除外,如“… Daiquiri”或“… Julep”)。

现在好戏开始了!经过 40 个纪元的训练(在 GPU 上大约需要 20 分钟),模型现在可以部署了。还有一个不得不提的细节就是温度。在这里,温度被用作“创造力”(越热越有创造力)的替身,并决定模型创作与输入文本的接近程度。我们现在可以利用这个模型,在给定的温度和所创建的食谱的最大长度下,生成无限数量的受 Death & Co 风格启发的新鸡尾酒食谱。我个人喜欢在我的作品中混合不同的温度,因为这给了你更多的选择。因为你必须选择一点,因为几个食谱是没有意义的。例子包括对“176 毫升肉桂糖浆”或来自不同宇宙的成分的需求,如“15 毫升 laro werry”。不过总的来说,这确实是一个获得新鸡尾酒组合灵感的好方法,通过结合人类和人工智能,创造的食谱可以进一步调整到完美。

如果您想自己制作鸡尾酒配方,您可以在此下载所述 RNN 的模型重量、词汇和配置。此外,如果你对这种鸡尾酒产生了什么以及味道如何感兴趣,请前往我的另一篇文章,在那里我尝试了一些鸡尾酒,并深入研究了机器想出的风味组合。这里只是一个更有趣的创作之一,深奥命名的 Pon Cong 的简短挑逗,我填写了杜松子酒的品牌和详细的说明。干杯!

A cocktail dreamt up by a machine

彭聪

1 颗草莓

45 毫升(1.5 盎司)野生陋居爱尔兰杜松子酒

7.5 毫升(0.25 盎司)香草糖浆

装饰物:1 颗草莓

说明:将草莓与杜松子酒和糖浆混在一起。小心地将混合物滤入一个装满冰块的混合罐中并搅拌。小心地将混合物滤入预冷的玻璃杯中,用切好的草莓装饰。

香草糖浆:将 1 杯水和 1 杯糖与半颗香草豆一起煮沸。过夜离开;紧张。

使用 NVIDIA flownet2-pytorch 实现生成光流

原文:https://towardsdatascience.com/generating-optical-flow-using-nvidia-flownet2-pytorch-implementation-d7b0ae6f8320?source=collection_archive---------5-----------------------

视频分类算法中使用的光流文件创建指南

这篇博客最初发表于blog.dancelogue.com。在之前的帖子中,进行了光流的介绍,以及基于 FlowNet 2.o 论文的光流架构概述。本博客将重点深入光流,这将通过从标准 Sintel 数据和自定义舞蹈视频生成光流文件来完成。将使用 NVIDIA flownet2-pytorch 代码库的 fork 进行,该代码库可在 Dancelogue 关联回购中找到。

本博客的目标是:

  • 启动并运行 flownet2-pytorch 代码库。
  • 下载相关数据集,如原始存储库中提供的示例所述。
  • 生成光流文件,然后研究光流文件的结构。
  • 将流文件转换为颜色编码方案,使其更易于人类理解。
  • 将光流生成应用于舞蹈视频并分析结果。

系统需求

flownet2-pytorch 实现被设计为与 GPU 一起工作。不幸的是,这意味着如果你没有访问权限,就不可能完全关注这个博客。为了缓解这个问题,我们提供了模型生成的样本数据,并允许读者继续阅读博客的其余部分。

本教程的其余部分是使用 ubuntu 18.04 和 NVIDIA GEFORCE GTX 1080 Ti GPU 进行的。Docker 是必需的,并且必须支持 GPU,这可以通过使用NVIDIA-dockerr 包来实现。

下载代码库和数据集

这里列出了继续写博客所需的所有代码和数据(下载数据是自动进行的,因此读者不必手动完成,请参见入门部分):

  • 这个博客的代码库可以从下面的 repo 中克隆。
  • 点击下面的链接可以下载 Sintel 数据,压缩后的文件是 5.63 GB,解压后增加到 12.24 GB。
  • 可以下载自定义数据,包括样本光流 .flo文件,从样本光流文件生成的颜色编码方案,进行光流的舞蹈视频,舞蹈视频的光流视频表示。

完成这篇博客所需的内存空间大约是 32 GB。其原因将在后面解释。

叉子的差异

如前所述,创建了原始 flownet2-pytorch 的一个分支,这是因为在撰写本博客时,原始存储库在构建和运行 docker 映像时出现了问题,例如 python 包版本问题、c 库编译问题等。这些更新包括:

  • 通过修复 python 包版本、更新 cuda 和 pytorch 版本、运行相关层的自动构建和安装、添加 ffmpeg、添加第三方 github 包来修改 Dockerfile,该第三方 github 包将允许流文件的读取、处理和转换到颜色编码方案。
  • 为数据集和训练模型编写下载脚本以便更容易开始,其灵感来自 NVIDIA 的 vid2vid 存储库。

入门指南

考虑到这一点,我们开始吧。第一件事是从https://github.com/dancelogue/flownet2-pytorch中克隆原始存储库的 dancelogue 分支。然后使用以下命令运行 docker 脚本:

bash launch_docker.sh

设置应该需要几分钟时间,之后,应该将终端上下文更改为 docker 会话。

接下来是下载相关的数据集,初始设置所需的所有数据都可以通过在 docker 上下文中运行以下命令来获得:

bash scripts/download.sh

这会将FlowNet2_checkpoint.pth.tar模型权重下载到 models 文件夹,并将MPI-Sintel数据下载到 datasets 文件夹。这是必需的,以便遵循《flownet2-pytorch 入门指南》中指示的推理示例的说明。定制的舞蹈视频以及样本光流.flo文件也被下载。

本博客中的其余命令已经自动化,可以通过以下方式运行:

bash scripts/run.sh

运行推理示例

运行原始推理示例的命令如下:

python main.py --inference --model FlowNet2 --save_flow \ 
--inference_dataset MpiSintelClean \
--inference_dataset_root /path/to/mpi-sintel/clean/dataset \
--resume /path/to/checkpoints

但是,根据 fork,这已修改为:

python main.py --inference --model FlowNet2 --save_flow \ 
--inference_dataset MpiSintelClean \
--inference_dataset_root datasets/sintel/training \
--resume checkpoints/FlowNet2_checkpoint.pth.tar \
--save datasets/sintel/output

让我们来分解一下:

  • --model表示要使用的型号变体。从之前的博客我们看到这个可以是FlowNetCFlowNetCSSFlowNet2,但是对于这个博客它被设置为FlowNet2
  • --resume参数指示训练模型权重的位置。已使用下载脚本将其下载到检查点文件夹中。请注意,训练模型权重有一定的许可限制,如果您需要在本博客之外使用它们,您应该遵守这些限制。
  • --inference参数简单地意味着,基于由来自训练数据的模型权重定义的学习能力,你能告诉我关于新数据集的什么。这不同于训练模型,其中模型权重将改变。
  • --inference_dataset表示将输入何种类型的数据。在当前情况下,它是由MpiSintelClean指定的 sintel。更多选项可以在https://github . com/dance Logue/flownet 2-py torch/blob/master/datasets . py中找到,并被定义为类,例如FlyingChairs。还有一个ImagesFromFolder类,这意味着我们可以输入自定义数据,例如来自视频的帧,我们可以从中得出推论。
  • --inference_dataset_root表示将用于推理过程的数据的位置,该数据已被下载并解压缩到datasets/sintel文件夹中。
  • --save_flow参数表示推断的光流应该保存为.flo文件。
  • --save参数指示推断的光流文件以及日志应该保存到的位置。这是一个可选字段,默认为work/位置。

运行上述命令将生成的光流文件保存到datasets/sintel/output/inference/run.epoch-0-flow-field文件夹中。生成的光流文件的扩展名为.flo,是流场的表示。

分析和可视化光流文件

现在光流文件已经生成,是时候分析结构了,以便更好地理解结果,并将其转换为流场颜色编码方案。本节使用的样本流文件可从以下链接下载。

分析流文件

将光流文件加载到 numpy 是一个相当简单的过程,可以按如下方式进行:

path = Path('path/to/flow/file/<filename>.flo')
with path.open(mode='r') as flo:
    np_flow = np.fromfile(flo, np.float32)
    print(np_flow.shape)

上面的语法基于 python3,其中文件被加载到一个缓冲区中,然后被送入 numpy。接下来的事情是试图理解由打印语句实现的流文件的基本特性。假设您使用提供的样本流文件,print 语句应该输出(786435,)。这意味着对于每个流文件,它包含一个数组,数组中有 786453 个元素。单个流文件的内存占用大约为 15.7 MB,尽管看起来很小,但增长非常快,尤其是在查看具有数千帧的视频时。

在继续之前,我们需要看看 http://vision.middlebury.edu/flow/code/flow-code/README.txt中定义的光流规范。我们关心的是以下内容:

".flo" file format used for optical flow evaluationStores 2-band float image for horizontal (u) and vertical (v) flow components.
Floats are stored in little-endian order.
A flow value is considered "unknown" if either |u| or |v| is greater than 1e9. bytes  contents 0-3     tag: "PIEH" in ASCII, which in little endian happens to be the float 202021.25
          (just a sanity check that floats are represented correctly)
  4-7     width as an integer
  8-11    height as an integer
  12-end  data (width*height*2*4 bytes total)
          the float values for u and v, interleaved, in row order, i.e.,
          u[row0,col0], v[row0,col0], u[row0,col1], v[row0,col1], ...

基于上述规范,下面的代码将允许我们正确地读取流文件(借用自https://github . com/georgegach/flowiz/blob/master/flowiz/flowiz . py)。

with path.open(mode='r') as flo:
  tag = np.fromfile(flo, np.float32, count=1)[0]
  width = np.fromfile(flo, np.int32, count=1)[0]
  height = np.fromfile(flo, np.int32, count=1)[0] print('tag', tag, 'width', width, 'height', height) nbands = 2
  tmp = np.fromfile(flo, np.float32, count= nbands * width * height)
  flow = np.resize(tmp, (int(height), int(width), int(nbands)))

基于光流格式规范,希望上面的代码对正在发生的事情更有意义,即我们得到标签,然后是宽度,接着是高度。打印语句的输出是tag 202021.25 width 1024 height 384。从给定的规范中,我们可以看到标签匹配健全性检查值,流文件的宽度是 1024,高度是 384。请注意,在读取文件缓冲区并将其加载到 numpy 时,正确的顺序很重要,这是因为 python 中读取文件的方式(字节是顺序读取的),否则标签、高度和宽度会混淆。现在我们已经有了宽度和高度,我们可以读取其余的光流数据,并将其调整为更熟悉的形状,这是使用np.resize方法完成的。

理解流向量如何被调整大小的一个快速方法是将它们打印到终端,这是通过运行以下代码来完成的:

>> print(flow.shape)
(384, 1024, 2)>> print(flow[0][0])
[-1.2117167 -1.557275]

正如我们所料,新表示的形状意味着高度为 384,宽度为 1024,并且具有由 2 个值组成的位移向量。关注位置0, 0处的像素,我们可以看到该点的位移向量似乎指向左侧和底部,即 x,y 图的左下象限,这意味着我们预计该位置的颜色代码是浅蓝色,甚至是基于下面给出的颜色编码方案的绿色。

可视化流文件

有不少开源代码库是为了可视化光流文件而编写的。为此选择的那个可以在 github 库https://github.com/georgegach/flowiz中找到。这样做的原因是,它允许从颜色编码方案中生成视频剪辑,这在稍后阶段将是有用的。假设使用了本教程开头提供的 docker 上下文,可以使用以下命令来生成光流的彩色编码图像文件。

python -m flowiz \
datasets/sintel/output/inference/run.epoch-0-flow-field/*.flo \
-o datasets/sintel/output/color_coding \
-v datasets/sintel/output/color_coding/video \
-r 30

这将获取光流文件并生成图像文件,其中的位移向量用颜色编码,如下所示。

为了理解颜色编码方案,请查看之前关于光流的博客。在位置 0,0,即图像的右下部分,我们确实可以看到浅蓝色,这是我们从位移向量中预期的颜色,即它是指向左侧和底部的向量的颜色。

将光流应用于舞蹈视频

在这一节中,我们将使用一个舞蹈视频,并从中生成光流文件。舞蹈视频是:

它包括一个真实世界中的舞蹈编排课程。

生成帧

当 flownet 代码库接收图像时,我们需要做的第一件事是将视频转换成帧,这可以通过以下使用 ffmpeg 的命令来完成。

ffmpeg -i datasets/dancelogue/sample-video.mp4 \
datasets/dancelogue/frames/output_%02d.png

它将在帧文件夹中按顺序输出帧,顺序很重要,因为 flownet 算法使用相邻图像来计算图像之间的光流。生成的帧占用 1.7 GB 的内存,而视频只有 11.7 MB,每帧大约 2 MB。

产生光流

光流表示可以通过运行以下命令来生成。

python main.py --inference --model FlowNet2 --save_flow \
--inference_dataset ImagesFromFolder \
--inference_dataset_root datasets/dancelogue/frames/ \
--resume checkpoints/FlowNet2_checkpoint.pth.tar \
--save datasets/dancelogue/output

这类似于我们在 sintel 数据集上运行的推理模型,不同之处在于从--inference_dataset参数变为ImagesFromFolder,并在代码库中定义。--inference_dataset_root是生成的视频帧的路径。生成的光流文件占用 14.6 GB 的存储器,这是因为对于这个例子,每个光流文件大约为 15.7 MB。

生成颜色编码方案

生成颜色编码方案的命令是:

python -m flowiz \
datasets/dancelogue/output/inference/run.epoch-0-flow-field/*.flo \
-o datasets/dancelogue/output/color_coding \
-v datasets/dancelogue/output/color_coding/video \
-r 30

这使用了 flowviz 库和 ffmpeg。它不仅将光流颜色编码生成为.png文件,而且-v -r 30参数在30 fps从图像文件生成视频。生成的彩色编码帧占用 422 MB 的内存,其中包括一个 8.7 MB 的视频文件,如果你正在浏览这个博客,它的名称是000000.flo.mp4

结果

生成的光流的视频表示如下:

舞蹈动作的要点可以从生成的视频中看出,不同的颜色表示动作的方向。然而,尽管视频中没有明显的运动,但可以看到有很多背景噪音,特别是在中心舞者周围。不幸的是,不清楚为什么会这样。

尺寸影响

当运行 flownet 算法时,需要注意大小含义,例如,一个 11.7 MB 的视频在提取时会生成一个 1.7 GB 的单个帧文件。然而,当生成光流时,这变成包含所有光流表示的 14.6 GB 文件。这是因为每个光流文件占用大约 15.7 MB 的存储器,然而每个图像帧占用 2 MB 的存储器(对于所提供的例子的情况)。因此,当运行光流算法时,需要注意计算需求与空间的权衡。在为视频构建深度学习系统时,这种权衡将影响架构,这意味着要么以计算时间为代价按需(即,懒惰地)生成光流文件,要么以存储空间为代价提前生成所有需要的格式和表示并将其保存到文件系统。

结论

我们已经看到了如何使用 NVIDIA 的 flownet2-pytorch 实现的分支来生成光流文件,并对光流文件有了一个大致的了解。下一篇博客将介绍如何使用光流表示来理解视频内容,并将重点放在 2 流网络上。

如果您有任何问题或需要澄清的事情,您可以在https://mbele.io/mark和我预约时间

参考

  • https://blog . dance Logue . com/什么是光流,为什么有关系/
  • https://blogs . NVIDIA . com/blog/2016/08/22/差异-深度学习-训练-推理-ai/
  • https://stack overflow . com/questions/28013200/reading-middlebury-flow-files-with-python-bytes-array-numpy

通过生成密码来揭开生成模型的神秘面纱—第 1 部分

原文:https://towardsdatascience.com/generating-passwords-with-generative-models-from-probabilistic-to-deep-learning-approaches-54d41d8810e3?source=collection_archive---------23-----------------------

从概率到深度学习方法

理解朴素贝叶斯模型和变分自动编码器(VAE)在生成任务中的区别。

Photo by Dan Meyers on Unsplash

介绍

机器学习和深度学习模型已经在广泛的行业中展示了它们的能力,网络安全当然也不例外。一个相对较新的研究例子是 PassGAN,这是一个深度学习模型,可以生成逼真的密码,从而提高暴力攻击的有效性[1]。

在这篇文章中,我想借用这个想法,并用它作为一个例子来解释生成模型和判别模型之间的差异,以及强调(并证明)深度学习在高维数据方面优于传统概率建模的优势。

判别模型与生成模型

在 ML/DL 模型中有一个非常著名的分类法,它由生成模型和判别模型组成,每种模型都有自己独特的特征。然而,给初学数据的科学家造成困惑是极其常见的。事实上,这是完全可以理解的,因为这个名字可能会误导他们的用例。直觉上,你会认为一个判别模型会被用来判别多个类和生成新的合成数据,当然,这是绝对正确的。然而,这并不意味着创成式模型不能用作分类器,正如其名称最初所暗示的那样。

不同之处在于模型如何学习。简而言之,生成模型学习数据是如何生成的,并因此使用它来对看不见的数据进行分类,而判别模型只学习每个类之间的差异(边界)。

为了给你一个更具体的例子,想象一下:我们有一个人和动物的涂鸦集合,我们想创建一个模型,可以将涂鸦作为输入,并反馈它看起来更像人还是动物。

有趣的是,生成模型将首先学习如何绘制人类和动物的涂鸦,当给定一个看不见的涂鸦时,它将绘制一个动物和一个人,并将其与给定的进行比较。

或者,辨别模型将学习每个类别的细微差别,即动物有尾巴、人类的姿势、形状等,并在没有学习任何绘画知识的情况下使用这些来辨别两个类别。简单吧?

尽管判别模型因其简单性而在传统上更受青睐[2],但生成模型也有其自身的优势,正变得越来越受欢迎。当有缺失数据时,甚至在检测异常值时,它们表现得特别好。甚至,毕竟,我们可能想要生成新的数据,这是判别模型所不能做到的。事实上,直到最近,生成模型才达到生成内容的真实水平(见下图)。

Face generation with generative modelling. Source: David Foster. “Generative Deep Learning.” [3]

可能性

我尽可能地避免使用数学术语,但是为了更清楚地建立判别和生成模型,引入一些数学概念是必要的。

假设我们有一些观察数据 X 用标签 Y. 标记,从概率的角度来看,一个判别分类器将试图对 P(Y|X) 的条件概率建模。也就是说,给定观察值 X,我标记 Y 的概率是多少?(不要把条件概率和联合概率 P(A,B) 混淆,联合概率是指 A 和 B 同时发生的概率)。另一方面,生成建模试图直接对概率P(X)建模,简单来说,首先获得观察值 X 的概率是多少?注意,标签对于这个模型不是必需的,但是,如果我们想要执行分类,标签可以用于定义 P(X|Y)。

简化的生成模型

为了实际理解什么是生成模型,让我们想象一个极其简化的场景,其中只有二维的生成模型。这个例子的灵感来自大卫·福斯特的《生成性深度学习》一书,我强烈推荐这本书!

考虑在下面的二维空间上由称为P数据的规则生成的一些点:

生成模型的目的是生成一个新点 X = (x,y),该点看起来像是由P数据生成的。由此,我们来构造一个对P数据的估计,称为P模型。一种可能的估计是在橙色边界框内的任何地方生成一个点的均匀概率分布,以及在边界框外生成一个点的概率为零,如下图所示。

回到前面章节的创成式模型描述,我们刚刚创建了一个模型,它首先定义了如何创建数据点!虽然过于简单,但您刚刚开发了一个生成模型!

现在让我们更深入一点,观察我们的模型相对于真实的 P 数据分布的表现。注意,原始的 P 数据代表该土地上生长的树木的概率分布(见下图)。一棵树在有土壤的地方生长的几率大致相等,但在水中生长的几率为零。

这强调了数据科学家的另一个非常可取的特征。对先验数据分布的高级认知能力与数据科学家的领域专业知识直接相关。对于这个例子,根据自然经验,我们知道树木不能在水上生长!类似地,在真实世界的场景中,大多数情况下,数据科学家后退一步分析问题域是有帮助的,这样在未来就有可能对数据模型的结果进行推理。

值得注意的是,尽管 P 模型P 数据的过度简化,但它设法掌握了原始分布的主要机制。从P模型中采样 3 点 A、B、C,很明显我们的模型并不完美。点 C 无法从P*数据中生成,但人工点 AB 与真实点无法区分。这是生成模型的主要目的。生成不同于现有数据的新数据,但看起来像是由相同的规则创建的。*

概率与深度学习方法

在这一部分,我们将通过实际例子来探索为什么深度学习对生成模型的快速发展做出了重大贡献。但是首先,有必要提出概率方法,以便有一个可以比较的基准。

最大似然估计

最大似然估计是一种统计技术,可用于计算参数,使我们的模型生成给定数据的可能性最大化。这一开始听起来可能有点混乱,所以让我们把它放到上面例子的上下文中。

假设上面的橙色框是一个概率密度函数,简单来说是一个函数,给定我们的样本空间中的一个点(地图上的 x,y)返回一个从 0 到 1 的值,一个概率。直观上,概率密度函数(积分)上所有点的总和应该总是等于 1。回到我们的例子,因为盒子代表均匀分布,边界盒子外面的概率是 0,里面的概率是常数。在数学符号中,它可以表示为:

继续,设θ是一组 4 个参数{θ1,θ2,θ3,θ4},一个似然函数L(θ|x)试图回答以下问题:

给定点 x 参数的一些具体值有多大可能?

但是你可能想知道这些参数是干什么的?这些来自一个众所周知的统计学领域,叫做参数建模。换句话说,这是一种用有限的一组参数来表示概率分布的方法。在这种背景下,我们的概率分布(框!)可以用四个参数建模,左上角点(θ1,θ2)和右下角点(θ3,θ4)。更现实的例子是高斯(正态)分布,它有两个参数,均值μ和标准差σ。

更准确地说,似然函数定义如下:

这是由θ参数化的概率密度函数返回的在 x 处的概率。

现在,如果不是只有一个数据点,而是有 n 个数据点 Xn = { x1x2 ,…, xn }那么可能性可以被评估为:

然而,由于该乘积可能很难处理,因此也可以用对数形式表示,此时乘积变成一个和,从而更容易区分:

顺便说一下,转换成对数形式是可能的,因为自然对数是一个单调递增的函数。简单地说,当 x 增加时,y 也增加,所以最大值不变。

既然有了这些,就有可能回到最初的概念,最大似然估计。或者简单地说,找到最好地解释数据集 X. 的一些最佳参数θ,相当于说这些参数最有可能被用于对生成 X. 的概率分布进行建模。正式地,这被定义为:

所有这些应该给你一个更清晰的画面,如何最大似然估计可以用来创建一个生成模型,但仍然,这都是理论,上面使用的例子只是为了有一个更容易理解的可视化参考。在下一节中,我们将应用这里所描述的来开发一个有些用处的生成模型。

用于密码生成的朴素贝叶斯

让我们再一次构建一个故事,假设你很难想出密码,所以你想出了一个好主意,创建一个为你创建密码的生成模型!

Source: Giphy.com

请记住,这是一个假设的应用程序,用于在实践中应用这里描述的模型,并获得实践经验,而不仅仅是解释背后的理论。更重要的是,这里展示的方法和技术也有实际应用,例如特定于域的密码暴力破解,将随机密码生成过程替换为更容易记住但具有同等安全性的过程等等。这里不做描述,但提供给读者作为进一步探索的启示。

您已经创建了您的密码想要包含的元素列表:

文字:过关,咖啡馆,宾果,hyper,李特,哈克曼,忍者,贝比
数字: 1234,111,777,000,0101,2019,2018,1,2,10,123
,特殊:!、@、$、%、
、_
大写: A、E、T、P*

并定义了您的密码应该遵循的标准格式:

大写+单词+数字+特殊

基本上,你的每个密码都可以用这 4 个特征来定义,它们总是以相同的顺序排列:一个大写字母,一个单词,一个数值和一个特殊字符。所有这些都来自上面提供的列表。

总的来说,这等于 8 * 11 * 6 * 4 = 2112 种组合!当然,您可以简单地为您的密码中的每个特征选择一个随机元素,然后使用它但是您希望每次都避免随机密码,因为它会变得更难记住。相反,根据对您以前的密码的观察,最好比其他密码更频繁地使用一些密码。用更正式的术语来说,应该有一个有利于某些元素的分布过程。

最初,您按照相同的格式收集了过去使用过的 30 个密码:

以下是数据集的前 10 个密码:

让我们问自己一个问题。拥有密码 x 的概率是如何定义的?

回想一下,密码 x 由 4 个特征定义。这相当于我们在上面的简单例子中描述的地图点,但是它现在有 4 个维度——x1,x2,x3,x4,而不是 **x,yT22。

直观上,我们可以说答案是同时有 x1,x2,x3,x4 一起发生的概率。所以:

这可以使用 链式规则 进一步扩展到条件概率。因此,上面的表达式变成:

为了继续使用朴素贝叶斯模型,我们必须做一个强有力的假设。每个特征都是相互独立的。也就是说,大写字母与单词或数值的选择无关。这是一个相当幼稚的假设,因此得名。更明确地说:

考虑到这一点,前面从链规则导出的表达式被简化为:

等等,当我们描述最大似然估计时,概率密度函数是由分布参数集θ参数化的,它有 4 个参数,因为我们知道分布可以描述为一个盒子。但是,在这种情况下,概率是如何参数化的呢?

因为我们的数据集由离散值组成,或者更抽象地说,由一组有限值的元素组成,所以我们可以使用多项式分布,结果是多项式朴素贝叶斯。在这种情况下,我们可以简单地为模型的每个特征的每个值分配一个参数,这样就产生了总共8+11+6+4-4=25个参数。

-4 是为了补偿每个要素的最后一个值,因为它不必进行计算,因为它被强制使总和等于 1。

此外,要找到多项式分布中的最大似然估计,我们只需将每个特征值的出现次数除以总观察次数,如下所示:

**

Maximum Likelihood Estimation of feature parameters.

既然我们已经计算了每个特征的最大似然估计值,就可以从每个特征中抽取一个值,并将它们连接在一起以获得一个新密码!以下是我列出的由该模型生成的 10 个新密码:

注意,我们的模型已经生成了最初在数据集中没有的密码(Ahyper777!,Apass10$ …。)!

您可以在下面的 Google Colab 链接中找到生成式朴素贝叶斯模型的相关代码:

* [## 谷歌联合实验室

多项式朴素贝叶斯——生成模型

colab.research.google.com](https://colab.research.google.com/drive/1oUEPz7Kl7TqgWHpfSHPU4NY4CCs3aZlU#scrollTo=aWdPKcXXlVl7)

旁注—可选阅读

当然,为了使文章尽可能简洁,有些细节被省略了,但我会在这里提到它们,以供参考,如果你想自己查找的话。

例如:如果一个元素没有出现在初始数据集中,会发生什么?假设“hyper”这个词在之前的密码中没有使用过?那么 MLE 将返回 0 概率,因此没有机会由模型生成。为了缓解这个问题,有平滑技术,如拉普拉斯或李德斯通平滑。

此外,我们只讨论了生成数据,而没有讨论分类,因为这些帖子的概念是生成模型。朴素贝叶斯也可以通过使用贝叶斯定理、作为分类器,但为此,要求数据点有标签。

转到第 2 部分

恭喜你!您刚刚从头开始创建了一个真正的概率生成模型!当然,这是一个非常简单的方法,但是希望你明白了!

回想一下,这仅仅是因为我们依赖于朴素贝叶斯独立性假设,这很好!在某些情况下,它工作得非常好,但在下一部分中,我们将探索当这个假设崩溃时会发生什么,以及深度学习如何能够拯救我们!

参考

[1] B. Hitaj,P. Gasti,G. Ateniese,F. Perez-Cruz, PassGAN:密码猜测的深度学习方法,计算机科学中的应用密码学和网络安全讲义,217–237 页,2019。

[2] Ng、Andrew Y 和 Michael I. Jordan。判别分类器与生成分类器:逻辑回归和朴素贝叶斯的比较。神经信息处理系统的进展。2002.

[3]福斯特 D. 生成性深度学习:教机器画画、写字、作曲、演奏。第一版。奥莱利;2019.*

使用 RNNs 生成神奇宝贝名称

原文:https://towardsdatascience.com/generating-pokémon-names-using-rnns-f41003143333?source=collection_archive---------19-----------------------

字符级单词生成的一个例子

不久前,当我完成 Coursera 上的深度学习专业时,我决定尝试实施我学到的一些东西,因为每个参加这些课程的人都知道理论是不可思议的,但实践几乎只是一个预制的代码,有一些空白需要填充。我认为这不是一个很好的学习方法,所以我想从头开始编码。最吸引我的例子是生成看起来像模型给出的数据的单词。课程用了恐龙的名字,我决定改用神奇宝贝的名字。我使用 keras 和 python 来生成 entor、incono 和 areacita 之类的名字。代码可以在我的 github 上找到。

模型

为了像我一样在字符的基础上生成名字,我不得不使用递归神经网络(RNNs)。这些网络以“时间”步长的形式接受一系列输入。这些输入中的每一个在被转换成输出之前都要经过一层或多层神经元。用于从输入到神经元、从神经元到输出以及从一个时间的神经元到下一个时间的神经元的权重在每个时间步长是相同的。这使得网络可以模拟序列中后面的元素依赖于前面的元素的情况,比如时间序列或文本。

Example of 3-to-3 RNN. Each input X is converted into neurons h by using weights W. The neurons are then converted into outputs y using a different set of weights and are passed to the next time step using another set of weights.

有各种可能的输入/输出组合可用于具有不同数量元件的 rnn。例如,有必要使用具有许多输入(比如每个单词一个)而只有一个输出的网络,以便进行情感分析并将文本分类为正面或负面。为了生成名称,所使用的体系结构是多对多的,具有相同数量的输出作为输入。

需要提供给这个模型的数据首先是作为输入分解成字符的姓名。每个时间步长的输出(这里,时间步长=字符)是序列中的下一个字符。例如,如果输入是“皮卡丘”,则对应的输出是“ikachu”。注意输出末尾的空格,它使得输入和输出具有相同的字符数。这很重要,因为神经网络具有固定的大小,所有数据都必须具有该大小。这个空格也告诉模型这个名字已经结束了。

数据需要以这种特殊方式格式化的原因是,该模型在预测时用于一个接一个地预测新名称的字母。我给模型一个空字符(不是空格!)作为第一个输入和第一个输出,是我用来生成名字的第一个字母的字符的概率分布。然后,这个字母作为第二个输入,生成第二个字符的概率分布,继续下去,直到得到一个空格,这意味着名字的结尾。

收集和清理数据

为了训练这样一个生成模型,我需要尽可能多的数据。在这种情况下,数据只是所有现存神奇宝贝的名字列表。原来有一个很好看的网站有一个 API 收集了一堆关于神奇宝贝的数据。我只需要名字,所以很容易使用。

这产生了 964 个名字的列表,但是有一些问题。许多神奇宝贝被多次列入名单。有些有巨大的进化,表现为“名字巨大”,许多其他特征也是如此。对此,我发现的最简单的解决方案是删除破折号后的所有内容。然而,一些真实的名字有破折号,所以我不得不在清理之前处理它们。例如,我不得不手动将“mr-mime”改为“mr mime”。最后一个问题是“porygon-2”。因为我不想在我允许的字符中包含数字,所以我把这个神奇宝贝的名字改成了‘porygon two’。

在处理完所有这些细节后,我用破折号进行了拆分,只保留了单词的第一部分。这导致许多名字的副本出现在列表中,所以我必须删除重复的。这给出了 806 个神奇宝贝名字的最终计数。

最后一个重要的步骤是在每个名字后面加一个句号。我不得不这样做,因为有些名字中包含空格,所以我不能用空格作为名称结束的标志。这个时期会做这项工作。

到目前为止,我只把名字当作一个字符列表,但对于神经网络来说,理解这些字符,对它们进行一次性编码是很重要的。这意味着每个字符都被表示为一个向量,其大小与我考虑的不同字符的数量相同。在这种情况下,它是 a-z 加上一个空格和一个句点,所以是 28 个字符。除了与编码的字符相对应的条目之外,这个向量的每个条目都是零。单词中的每个字符都是这样编码的,它们组合成一个矩阵来代表一个完整的名字。因为 RNN 具有固定的大小,所以这个矩阵必须足够大以编码最长的名字,所以较短的名字在末尾有一些空向量的实例。我选择使用这样的约定:矩阵的每一行都是一个字符,所以矩阵的大小为(max_char,char_dim),其中 max_char 是名称中的最大字符数,char_dim 是字符空间的维数。

为了对此进行编码,我首先创建了一个字典,在字符和一次性编码索引之间进行转换。然后我定义了重要的量,最后创建了上面描述的训练数据。

需要注意的一点是,没有将数据拆分为训练集和测试集。这是因为这不是一个通常的监督学习任务,其中有一个固定的预期输出。因此,我能够使用所有的数据来训练模型。

训练模型

准备好数据后,最后一步是创建和训练递归网络。

我决定选择 LSTM 图层,因为我发现这是最普通的图层。长短期记忆层由一些不同的激活组成,这些激活以某种方式结合起来,以记住在先前的时间步骤中发生的事情。它能够自己学习过去要走多远。层的大小是通过训练模型并查看哪一个生成的结果最好来决定的。输出的密集层由一系列 softmax 激活组成,这些激活给出了每个字符在每个位置出现的概率。我再次使用 Adam 优化器,因为它是最常见的一个,并且我使用分类交叉熵损失,因为 softmax 激活了输出。

因为这里的目标不是预测输出,所以很难评估学习的进度。对于这样的问题,没有度量是有用的。我决定在训练模型时,在每个时期生成几个名字,以判断模型的表现。

这个函数基本上实现了上面描述的生成名称的过程。它从一个空输入开始,并将其提供给模型。然后,它将第一个输出作为概率分布来采样一个字符,然后将该字符作为生成的名称的第一个元素。这个部分名称再次被馈送到网络,并且第二输出现在被用作概率分布来对第二字符进行采样。这种情况会持续下去,直到找到一个句点,或者直到该单词达到网络的大小。

这个生成单词的函数在训练模型时被用作 keras 回调函数。

这在训练期间每 25 个时期产生三个名字。获得的名称的几个例子是

Names generated after epoch 0:
dxjaemprwpk.
zykhv.
uzvlzwbvisa.Names generated after epoch 125:
ugerli.
yunof.
mhanurs.Names generated after epoch 275:
urcono.
iggyy.
louk.

显然,最初的模型产生了垃圾,但它很快开始产生可行的单词。然而,125 个时代后生成的单词看起来一点也不像我们对神奇宝贝的期望。训练结束时的名字看起来更像其他神奇宝贝的名字。甚至会出现真实姓名,因此模型接近过度拟合。根据目标,这两种情况都是有用的。

如果你读了这篇文章,并觉得它有趣/有用,我非常感谢你!不要犹豫,留下你的评论或者问任何你可能有的问题。我心中还有很多项目想做,想写些什么:)

用马尔可夫链生成启动名称

原文:https://towardsdatascience.com/generating-startup-names-with-markov-chains-2a33030a4ac0?source=collection_archive---------16-----------------------

因为生成新内容并不复杂

毫无疑问,机器学习最有趣的应用是生成模型。

在数据中寻找模式并生成与你的数据相似但又独特的新内容的想法,一直让我着迷。

所以我决定开发一个简单的文本生成器,用马尔可夫链来创建创业公司的名字。

但是首先,简单介绍一下马氏链🔗

马尔可夫链

马尔可夫链是随时间发生的随机过程的模型。

马尔可夫链之所以这样叫,是因为它们遵循一个叫做马尔可夫性质的规则。马尔可夫特性表明,在一个过程中,无论接下来发生什么,都只取决于它现在的状态。

例如,考虑仅使用当前天气信息预测第二天天气的例子。通过分析一些实际数据,我们可以发现这些情况:

  • 假设今天是晴天,明天 90%的时间也会是晴天
  • 假设今天是晴天,明天 10%的时间会下雨
  • 鉴于今天是雨天,明天也将有 50%的时间是雨天
  • 假设今天下雨,明天 50%的时间会是晴天

这是通过下面的马尔可夫链建模的,其中每个圆圈是一个状态,箭头中的数字代表从当前状态变化的概率。

Image source: https://www.kdnuggets.com/2018/03/introduction-markov-chains.html

因此,如果我们想对明天做出预测,我们只需要验证我们当前所处的状态(晴天或雨天),并使用转移概率来计算下一个状态更有可能出现。

对马尔可夫链的深入解释,加上一些很酷的动画,可以在这里找到:http://setosa.io/ev/markov-chains/

Image source: http://setosa.io/ev/markov-chains/

马尔可夫链在文本生成中的应用

那么,我们如何应用这个想法来生成文本呢?嗯,实际上很简单。

名字或句子基本上是一个字符序列,这些序列遵循一些模式。

例如,如果我让你说出以 whe__ 开头的单词,你会很快想到何时、何地、何时等等。虽然喘息是一个完全有效的词,但考虑到开头的 whe_ ,它出现的频率较低。换句话说,给定状态 whe ,我们将最有可能改变到状态 when,wherewhen而不是状态wheeping

那么,在给定数据的情况下,我们如何建立一个模型来捕捉这些概率呢?

为此,我将向您展示如何使用单词 startupstatisticartist 构建一个简单的马尔可夫链。首先,我们将列出每个 3 个字符的元组的所有状态转换:

**Startup**
sta -> tar
tar -> art
art -> rtu
rtu -> tup**Statistic**
sta -> tat
tat -> ati
ati -> tis
tis -> ist
ist -> sti
sti -> tic**Artist** art -> rti
rti -> tis
ist -> ist

现在,如果你仔细观察这些状态,你会注意到它们中的一些是在不同的元组中共享的。为了更好地形象化,让我们创建一个字典,其中每个条目是一个状态,值是下一个状态及其权重。

{
   "sta": {
      "tar": 1,
      "tat": 1
   },
   "tar": {
      "art": 1
   },
   "art": {
      "rtu": 1,
      "rti": 1
   },
   "rtu": {
      "tup": 1
   },
   "tat": {
      "ati": 1
   },
   "ati": {
      "tis": 1
   },
   "tis": {
      "ist": 2
   },
   "ist": {
      "sti": 1
   },
   "sti": {
      "tic": 1
   },
   "rti": {
      "tis": 1
   }
}

哒哒!这就是我们的马尔可夫链。很简单,不是吗?(PS:从技术上讲,马尔可夫链是用一个带有概率的转移矩阵来定义的,而不是权重。我们可以很容易地转换成一个转换矩阵,但是对于我们所想到的问题,这是一个更好的可视化方法。

现在,我们如何用这个产生新的数据呢?

基本上有四个步骤,让我们逐一介绍:

第一步:从一些初始随机状态开始

您可以选择任何一个州作为起始位置,但是,您很可能会生成没有任何意义的文本。例如, rtu 是一个有效的初始状态,但是你在现实生活中找不到一个以这些字母开头的单词(至少我想不出来)

更好的方法是在另一个字典中记录起始状态,并从那里选择第一个状态。在我们的例子中,可能的初始状态是 sta (因为启动和统计都从 sta 开始)和 art 。对于我们的示例,让我们选择 sta

步骤 2: 考虑其权重,随机选择其一个过渡状态

对于元组 sta,可以去 tar 或者 tat,两者概率相同(权重相同)。在真实情况下,考虑到数据集中的分布情况,它们会有不同的权重,但由于我们刚刚使用了三个词,所以它们具有相同的权重。让我们随机选择元组 tar。

步骤 3: 将新的状态添加到生成的文本中

到目前为止,我们已经从状态 sta 开始,并过渡到状态 tar 。所以我们现在生成的字是

第四步:使用新状态重复第一步,直到找到停止字符,或者直到您对结果满意

现在,对于我们当前的状态 tar ,唯一可能的状态是 art ,所以我们生成的字变成了 start

现在让我们以更快的方式继续这个算法。从艺术可以去 rti 或者 rtu 。让我们选择 rti 。如果继续应用算法,很快就会生成我们的新词: Startist ,是 startup 和 artist 的混合体。

尽管这个例子非常简单,但它展示了马尔可夫链的潜力。

既然我们已经手动“实现”了一个马尔可夫链,那么让我们用 Python 来实现,使用真实的数据,你可以得到实际有用的结果。

我们来编码吧!

我们先从导入一些模块开始。我们只需要两个:读取 CSV 数据的 pandas ,以及(不出所料)生成随机数的 random

*import pandas as pd
import random*

作为我们的初创公司名称生成器的数据集,我们将使用来自大约 18000 家公司的 2015 年转储数据。

数据集没有那么大,但是您会看到,即使数据库比这小得多,马尔可夫链也能很好地工作。

读取我们公司的数据非常简单:pandas read_csv 函数接受一个 URL 作为参数并返回一个数据帧。我们还删除了符号,并将名称转换为小写。

*companies = pd.read_csv('[https://github.com/notpeter/crunchbase-data/blob/master/companies.csv?raw=true'](https://github.com/notpeter/crunchbase-data/blob/master/companies.csv?raw=true'))
companies['name'] = companies['name'].replace({r'[^\w ]':''}, regex=True)
companies['name'] = companies['name'].apply(lambda n:str(n).lower())*

正如我们之前所讨论的,为马尔可夫链建模的最简单的方法是一个包含状态和转移权重的字典。

*chain = build_markov_chain(companies['name'].tolist(), 3)
print(chain['sta'])*

如果您运行上面的代码,您将得到以下结果:

*{
   'tar':290,
   'tat':151,
   'ta.':52,
   'ta ':35,
   'tac':55,
   'tag':43,
   'tal':46,
   'tay':34,
   'tau':22,
   'tad':14,
   'tam':19,
   'tas':19,
   'taq':5,
   'tan':92,
   'tab':23,
   'tap':6,
   'tak':8,
   'tai':22,
   'taf':16,
   'tax':5,
   'ta™':1,
   'tah':2,
   'tav':5,
   'tae':1,
   'taj':1,
   'taw':1,
   'taa':2,
   'taz':1
}*

这是什么意思?考虑到当前状态是元组 sta ,这些是马尔可夫链上的下一个状态和权重的列表。下一个状态权重越高,就越有可能过渡到下一个状态。

例如,如果你拿第一个州 tar 来说,它在这个州列表中的权重最大。直觉上,这是有意义的,因为它可能捕捉到单词 startup 的出现。

现在我们需要构建一个函数,考虑到权重,从链中返回一个随机的元组

最后,神奇的事情发生了:让我们创造一些新词。

让我们一步一步地进入我们的生成函数。

*tuple = select_random_item(chain['_initial'])    
result = [tuple]*

还记得我们提到过,最好跟踪初始元组,并选择其中一个作为初始状态吗?这正是我们在这里所做的。

*while True:        
    tuple = select_random_item(chain[tuple])        
    last_character = tuple[-1]        
    if last_character == '.':          
       break 
    result.append(last_character)*

这是我们浏览马尔可夫链的地方,考虑它的概率。我们选择一个随机加权的下一个状态,并将该状态的最后一个字符附加到我们的结果字符串中。然而,如果最后一个字符是一个句点,我们停止我们的生成,因为这是我们链的结尾。

我们可以添加额外的规则,比如生成给定最小或最大长度的单词,但现在让我们保持简单。

*generated = ''.join(result)    
if generated not in chain['_names']: 
    return generated    
else:        
    return generate(chain)*

最后,我们将所有生成的字符连接在一起,并进行最后的验证。因为没有什么可以阻止马尔可夫链生成一个已经存在的名字,并且我们对创建新名字感兴趣,所以如果生成的名字已经在我们的数据库中,我们将简单地生成一个新名字。

结果

这里有几个来自我们的 Startup Name Generator 的例子。

  • 多莫斯
  • Hup 在线
  • 武班基
  • 小丽鱼
  • Ignaly
  • iFly

很酷吧。😎

更多想法

最后一个想法,如果我们为每个行业生成特定的创业公司名称会怎么样?太棒了,你不觉得吗?

让我们做吧,这将是非常容易的🙃

我们唯一要做的事情就是只考虑我们感兴趣的行业的例子来建立我们的马尔可夫链。

这是我们的结果:

旅游创业公司

*print(generate_amount_by_category('Travel',5))*
  • 潘戈
  • 电影学
  • Nextrive
  • Triptel
  • 斯汀吉

科技创业公司

*print(generate_amount_by_category('Technology',5))*
  • Naco 创新
  • Kicksense
  • 网络观察
  • 乔尼
  • 数据

自己试试

你可以自己尝试使用这个 Google Colab 链接或者直接从我的 GitHub 下载源代码。

* [## 启动名称生成器

colab.research.google.com](https://colab.research.google.com/drive/1Fr9khK_OzNZyoV87F2dce0-Zk29F7feq)

你有什么想法?对新内容有什么建议吗?反馈?请在评论中告诉我。

希望你喜欢:)*

使用 GANs 从文本描述生成合成图像

原文:https://towardsdatascience.com/generating-synthetic-images-from-textual-description-using-gans-e5963bae0df4?source=collection_archive---------8-----------------------

真实图像的自动合成是极其困难的任务,甚至最先进的 AI/ML 算法也难以满足这种期望。在这个故事中,我将讨论如何从描述图像的文本描述中生成逼真的图像。如果你是生成性对抗网络[GAN]的粉丝,那么你来对地方了。

GAN 在 2014 年由 Ian Goodfellow 介绍,从那时起,这个主题本身在研究社区变得非常受欢迎,我们看到在几年内发表了大量论文。深度卷积 GAN [DC-GAN]就是其中之一。今天的话题是关于 DC-甘。

你能猜出这个图像是真实的可爱的婴儿还是甘想象出来的吗?

这个图像实际上是由 GAN 生成的。这项工作由 NVIDIA 的 Karras 等人完成,论文名为 StyleGAN 。本文的目的是生成高分辨率的人脸图像。您可以访问 https://thispersondoesnotexist.com网站,每次访问该网站都会随机生成人脸图像。自开始以来,GAN 在很短时间内经历了许多发展,今天我们正处于生成与真实图像难以区分的图像的阶段。GAN 模型非常擅长生成随机图像,但要控制 GAN 生成我们感兴趣的图像却极其困难。在这个主题中,我将讨论如何从详细描述图像的文本描述中生成图像。

讨论主题:我将讨论一个 GAN 公式,它将文本描述作为输入,并生成文本输入中描述的 rgb 图像。举个例子,给定

“这朵花有许多小而圆的粉红色花瓣”

因为输入将生成如下具有圆形粉红色花瓣的花的图像:

香草甘的工作原理:在继续之前,让我们快速了解一下香草甘的工作原理。

如果你已经了解香草甘,可以跳过这一节。

GAN 由两个独立的网络组成。一个称为发生器,另一个称为鉴别器。发生器在给定随机噪声[从潜在空间采样]的情况下生成合成样本,鉴别器是一个二元分类器,用于区分输入样本是真实的[输出标量值 1]还是虚假的[输出标量值 0]。生成器生成的样本被称为假样本。

这一表述的美妙之处在于生成器和鉴别器之间的对立性质。鉴别器希望以最好的方式完成它的工作,当一个假样本(由生成器生成)被提供给鉴别器时,它希望将其称为假样本,但生成器希望以某种方式生成样本,以便鉴别器在将其称为真样本时出错。在某种意义上,生成器试图欺骗鉴别器。

让我们快速看一下目标函数以及优化是如何完成的。这是一个最小-最大优化公式,其中生成器希望最小化目标函数,而鉴别器希望最大化相同的目标函数。

鉴别器希望将 D(G(z))的可能性驱动到 0。因此,它希望最大化(1-D(G(z))),而生成器希望将 D(G(z))的可能性强制为 1,以便鉴别器在调用生成的样本作为真实样本时出错。因此,生成器希望最小化(1-D(G(z))。

当数据分布和模型分布相同时,目标函数的这种最小-最大公式化具有全局最优,这意味着如果优化函数收敛到全局最小值,则模型已经学习了输入训练数据集中存在的基础数据分布。跟随甘的论文进行更好的理解。

文本到图像公式化:在我们的公式化中,不是只有噪声作为生成器的输入,而是首先将文本描述转换成文本嵌入,与噪声向量连接,然后作为输入提供给生成器。作为一个例子,文本描述已经被转换成 256 维嵌入,并与 100 维噪声向量(从正态分布中采样)连接。此公式将帮助生成器生成与输入描述一致的图像,而不是生成随机图像。

对于鉴别器,不是只有图像作为输入,而是发送一对图像和文本嵌入作为输入。输出信号为 0 或 1。早期鉴别器的职责只是预测给定图像是真是假。现在,Discriminator 又多了一个额外的职责。除了识别给定图像是可读的还是伪造的,它还预测给定图像和文本是否相互对齐的可能性。这个公式迫使生成器不仅生成看起来真实的图像,而且生成与输入文本描述一致的图像。

为了实现鉴别器双重责任的目的,在训练期间,一系列不同的(图像、文本)对作为输入给出如下:

  1. 作为输入和目标变量的(真实图像、真实字幕)对被设置为 1
  2. (错误图像,真实字幕)对作为输入,目标变量设置为 0
  3. 作为输入和目标变量的(伪图像、真实字幕)对被设置为 0

这里要注意一件非常有趣的事情,从鉴别器的角度来看,当(假图像,真实字幕)对的目标变量为 0 时。发生器损耗设置为 1,因为发生器希望鉴别器将其作为真实图像输出。

数据集:这个解决方案使用了一个非常流行的开源数据集。它被称为牛津花-102 数据集,它有 102 个不同类别的大约 8k 张图像,每张图像有 10 个不同的标题描述图像。人们可以用各种不同的方式写标题,这个数据集就是一个很好的例子,它涵盖了每张图片的各种各样的标题。这个丰富的数据集有助于我们学习更好的文本嵌入,并有助于解决以不同方式表达相同意图的可变性问题。

如何学习文本嵌入:有几种无监督学习文本嵌入的方法。学习文本嵌入的一个非常成功的方法是跳过思维向量。这种预先训练的向量可用于多种目的,以解决下游应用。另一种流行的学习文本嵌入的方法叫做三元组丢失。对于三重损失公式,选择相同图像的两个字幕,其中一个被认为是锚,而另一个被认为是正的。来自不同类别随机字幕被认为是负面的。可以参考我之前的故事,了解更多关于三重态丢失的知识。

[## 使用三重损失的图像相似性

你训练过机器学习模型解决分类问题吗?如果是,数量是多少

towardsdatascience.com](/image-similarity-using-triplet-loss-3744c0f67973)

您可以参考下面的 git 存储库作为三元组丢失实现的参考。

[## sanku-lib/image_triplet_loss

这个库是以下“中等”故事的实现:使用三元组损失执行的图像相似性…

github.com](https://github.com/sanku-lib/image_triplet_loss)

结果:正如您在下面看到的,即使文本以所有不同的格式书写,该模型也能够解释意图并相应地生成图像。由于模型是在花的图像上训练的,因此输入“我想要一只有白色条纹的黑猫”将会生成一个随机图像。

结论:该工作为生成对抗网络的未来提供了一个很好的方向。研究界在控制 GAN 产生什么样的图像方面取得了良好的进展。随着这一领域的研究取得更多的进展,你可以期待在不久的将来会有更好的结果。

参考文献:

1.https://thispersondoesnotexist.com/

2.生成性对抗网络[https://papers . nips . cc/paper/5423-generative-Adversarial-Nets . pdf

3.生成性对抗性文本到图像的合成[【https://arxiv.org/pdf/1605.05396.pdf】T4

4.深度卷积生成对抗网络的无监督表示学习[https://arxiv.org/pdf/1511.06434.pdf

5.跳过思维向量[https://arxiv.org/pdf/1506.06726.pdf

6.一种基于风格的生成性对抗网络生成器架构[https://arxiv.org/pdf/1812.04948.pdf

7.https://github.com/reedscot/icml2016

8.https://github.com/paarthneekhara/text-to-image

9。https://github.com/ryankiros/skip-thoughts

10。https://github.com/carpedm20/DCGAN-tensorflow

使用 TensorFlow 2.0 生成文本

原文:https://towardsdatascience.com/generating-text-with-tensorflow-2-0-6a65c7bdc568?source=collection_archive---------10-----------------------

Photo by AussieActive on Unsplash

序文

在工作中,我大部分时间都在处理表格数据,所以扩展到相邻的机器学习领域有助于拓宽我的视野,识别潜在的应用……去年,我不得不钻研计算机视觉,以便完成微软在 AI 期末项目中的专业开发计划,今年我决定开始学习更多关于文本生成的知识。

我选择了伊利亚特作为我的训练文本,因此有了上面的卫城图片。虽然我也在 PyTorch、Keras(带有 TensorFlow 后端)和 TensorFlow 中实现了递归神经网络(RNN)文本生成模型,但我发现 TensorFlow 2.0 的到来非常令人兴奋,并且对机器学习的未来充满希望,因此我将在本文中重点讨论这个框架。

代码和文本可以在我的公共 Github 库中找到。我已经从古腾堡项目中提取了文本,并在上传到资源库之前进行了预处理。你也可以在这里找到关于 RNN 文本生成的优秀教程。

设置

让我们下载项目需要的东西,并确认一切都如预期的那样,GPU 可用(您肯定希望在这个项目上使用 GPU,这会节省您很多时间):

from __future__ import absolute_import, division, print_function, unicode_literals!pip install tensorflow-gpu==2.0.0-alpha0
import tensorflow as tfimport numpy as np
import os
import datetimefrom tensorflow.python.client import device_lib
print(device_lib.list_local_devices())print(“TensorFlow version: “, tf.__version__)

如果一切正常,你会看到你正在使用 TensforFlow 2.0.0-alpha0,如果在谷歌的 Colab 上运行代码,你会看到一个名为特斯拉 T4 的漂亮的 GPU 机器。我喜欢检查设备列表,尤其是在 Colab 上,因为有时我会忘记更改运行时类型,所以这是一个提醒。在这种情况下,由于 tensorflow-gpu 下载,Colab 会将您放在 GPU 运行时上,否则默认为 CPU。

要在 Google Colab 中运行代码,要么通过文件>上传笔记本菜单直接在 Colab 网站上传笔记本,要么只需点击笔记本左上角的相应图标。

要将文本下载到 Colab,请使用以下代码片段:

from google.colab import filesuploaded = files.upload()for fn in uploaded.keys():
    print(‘User uploaded file “{name}” with length {length}    bytes’.format(name=fn, length=len(uploaded[fn])))

注意:Colab 中的“代码片段”是迷你解决方案的重要资源。

您将在“文件”选项卡下找到上传的文本文件,考虑到文件上传到笔记本本身时会通知您,您甚至不需要查找它。您可能知道,您在 Colab 中的工作和文件是短暂的,在您下次登录时就会消失,因此在您注销之前将您的工作保存到其他地方是很重要的。

import os
path = os.getcwd()text = open(path + ‘/Iliad_v3.txt’,  ‘rb’).read().decode(encoding=’utf-8')
print(“Text is {} characters long”.format(len(text)))

文本应该有 886,809 个字符长,所以不是一个大样本。出于好奇,我们也可以查一下字数,这样我就知道高中的时候这篇课文是否值得跳过:

words = [w for w in text.split(‘ ‘) if w.strip() != ‘’ or w == ‘\n’]
print(“Text is {} words long”.format(len(words)))

应该有 153,260 个单词,所以真的没有当时看起来那么长。

为了确保机器正在读取预期的内容,请快速检查前 100 个字符:

print(text[:100])
achilles' wrath, to greece the direful spring
of woes unnumber'd, heavenly goddess, sing!
that

对,就是这样!

准备课文

创建一个由唯一字符排序的向量—在此文本中应该有 34 个字符:

vocab = sorted(set(text))
print (‘There are {} unique characters’.format(len(vocab)))
char2int = {c:i for i, c in enumerate(vocab)}
int2char = np.array(vocab)
print(‘Vector:\n’)
for char,_ in zip(char2int, range(len(vocab))):
    print(‘ {:4s}: {:3d},’.format(repr(char), char2int[char]))

让我们来看一个数字映射示例,看看文本的数字表示:

text_as_int = np.array([char2int[ch] for ch in text], dtype=np.int32)
print (‘{}\n mapped to integers:\n {}’.format(repr(text[:100]), text_as_int[:100]))

从文本中创建训练和验证数据(确保训练片段可被批量大小整除,在本例中为 64),并查看形状是否符合预期:

tr_text = text_as_int[:704000] 
val_text = text_as_int[704000:] print(text_as_int.shape, tr_text.shape, val_text.shape)

建立模型

我喜欢将(大部分)可调参数放在一个地方,以便在需要进行多次调整时可以方便地访问:

batch_size = 64
buffer_size = 10000
embedding_dim = 256
epochs = 50
seq_length = 200
examples_per_epoch = len(text)//seq_length
#lr = 0.001 #will use default for Adam optimizer
rnn_units = 1024
vocab_size = len(vocab)

准备训练和验证数据集,然后检查形状:

tr_char_dataset = tf.data.Dataset.from_tensor_slices(tr_text)
val_char_dataset = tf.data.Dataset.from_tensor_slices(val_text)tr_sequences = tr_char_dataset.batch(seq_length+1, drop_remainder=True)
val_sequences = val_char_dataset.batch(seq_length+1, drop_remainder=True)
def split_input_target(chunk):
    input_text = chunk[:-1]
    target_text = chunk[1:]
    return input_text, target_texttr_dataset = tr_sequences.map(split_input_target).shuffle(buffer_size).batch(batch_size, drop_remainder=True)val_dataset = val_sequences.map(split_input_target).shuffle(buffer_size).batch(batch_size, drop_remainder=True)print(tr_dataset, val_dataset)

最后,建立模型——我使用了两个 LSTM 层和辍学:

def build_model(vocab_size, embedding_dim, rnn_units, batch_size):
     model = tf.keras.Sequential([
     tf.keras.layers.Embedding(vocab_size, embedding_dim,
     batch_input_shape=[batch_size, None]),
     tf.keras.layers.Dropout(0.2),
     tf.keras.layers.LSTM(rnn_units,
     return_sequences=True,
     stateful=True,
     recurrent_initializer=’glorot_uniform’),
     tf.keras.layers.Dropout(0.2), 
     tf.keras.layers.LSTM(rnn_units,
     return_sequences=True,
     stateful=True,
     recurrent_initializer=’glorot_uniform’),
     tf.keras.layers.Dropout(0.2),
     tf.keras.layers.Dense(vocab_size)
 ])

return modelmodel = build_model(
    vocab_size = len(vocab),
    embedding_dim=embedding_dim,
    rnn_units=rnn_units,
    batch_size=batch_size)

顺便说一句,如果在谷歌云平台(GCP)上设置这个模型,你可能会得到一个警告"<tensor flow . python . keras . layers . recurrent . unified lstm object…>:注意,这个图层没有针对性能进行优化。请使用 tf.keras.layers.CuDNNLSTM 在 GPU 上获得更好的性能。但是,CuDNNLSTM 不可用,因此不确定这是否是以前 TensorFlow 版本的剩余警告,而 LSTM 在 2.0 中已经针对性能进行了优化,或者 CuDNNLSTM 只是尚未可用。

运行模型

检查输出形状和模型,并定义损耗:

model.summary()for input_example_batch, target_example_batch in tr_dataset.take(1):
    example_batch_predictions = model(input_example_batch)
    print(example_batch_predictions.shape)def loss(labels, logits):
    return tf.keras.losses.sparse_categorical_crossentropy(labels,    logits, from_logits=True)example_batch_loss  = loss(target_example_batch, example_batch_predictions)
print("Loss:      ", example_batch_loss.numpy().mean())

让我们使用 Adam optimizer,并在验证错误没有改善的 10 个时期之后停止训练:

optimizer = tf.keras.optimizers.Adam()
model.compile(optimizer=optimizer, loss=loss)
patience = 10
early_stop = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=patience)

创建目录来保存我们的检查点,然后…运行!

checkpoint_dir = ‘./checkpoints’+ datetime.datetime.now().strftime(“_%Y.%m.%d-%H:%M:%S”)
checkpoint_prefix = os.path.join(checkpoint_dir, “ckpt_{epoch}”)checkpoint_callback=tf.keras.callbacks.ModelCheckpoint(
    filepath=checkpoint_prefix,
    save_weights_only=True)history = model.fit(tr_dataset, epochs=epochs, callbacks=[checkpoint_callback, early_stop] , validation_data=val_dataset)print (“Training stopped as there was no improvement after {} epochs”.format(patience))

在我的例子中,训练在第 25 个时期停止,这意味着验证误差的最后一次改善是在第 15 个时期。趋势(下图)是人们可以预期的:首先,验证误差甚至略好于训练误差(即,一个时期的验证损失是使用改进的训练模型计算的,因为它是在该时期的末尾,而训练损失是使用各批损失的平均值评估的——在开始时,这可能导致验证误差降低),但随着时间的推移,训练和验证集出现分歧——训练误差持续下降,而验证变平,然后开始恶化:

生成文本

Photo by Ksenia Makagonova on Unsplash

让我们从最近的检查点加载权重(或者将 load.weights 行调整到任何其他检查点),并生成一个一千字符的文本:

model = build_model(vocab_size, embedding_dim, rnn_units, batch_size=1)
model.load_weights(tf.train.latest_checkpoint(checkpoint_dir)) 
model.build(tf.TensorShape([1, None]))def generate_text(model, start_string):

    print('Generating with seed: "' + start_string + '"')

    num_generate = 1000 input_eval = [char2int[s] for s in start_string]
    input_eval = tf.expand_dims(input_eval, 0) text_generated = [] temperature = 1.0 model.reset_states()
    for i in range(num_generate):
        predictions = model(input_eval)
        predictions = tf.squeeze(predictions, 0)
        predictions = predictions / temperature
        predicted_id = tf.random.categorical(predictions,      num_samples=1)[-1,0].numpy()
        input_eval = tf.expand_dims([predicted_id], 0)
        text_generated.append(int2char[predicted_id]) return (start_string + ''.join(text_generated))print(generate_text(model, start_string="joy of gods"))

以下是我得到的信息:

对于不到一百万字符的文本样本的 10 分钟单 GPU 训练来说,这是一个相当好的输出!

感谢您的阅读,我希望这段代码将成为您进一步探索文本生成的良好起点!

用 LSTM 为 Kaggle 内核生成标题

原文:https://towardsdatascience.com/generating-titles-for-kaggle-kernels-with-lstm-957541aff48f?source=collection_archive---------17-----------------------

Photo by Donatello Trisolino from Pexels

使用 PyTorch 的小型深度学习项目

介绍

当我第一次发现序列模型时,我惊讶于我们可以如此容易地将它们应用于广泛的问题:文本分类、文本生成、音乐生成、机器翻译等等。在本文中,我将重点介绍创建模型的一步一步的过程,不会涉及序列模型和 LSTMs 理论。

我有了一个想法,使用元 Kaggle 数据集来训练一个模型,为 Kaggle 生成新的内核标题。内核是用户发布在 Kaggle 上的 R 或 Python 语言的笔记本。Kaggle 用户可以投票支持内核。根据支持票的数量,果仁会获得奖章。生成内核标题的 Model 可以帮助捕捉 Kaggle 内核的趋势,并作为编写新内核和获得奖牌的灵感。在本文中:

  • 我描述了如何从元数据集中加载和预处理内核数据。
  • 我演示了如何训练 PyTorch LSTM 模型来生成新的 Kaggle 标题并显示结果。

这个小项目的完整代码可以在 GitHub 上获得,或者你可以在 Kaggle 上玩代码。

加载数据

首先,我需要加载数据。我正在加载内核和 KernelVersions 表,其中包含所有内核的信息、每个内核的投票总数(稍后我会解释为什么我们需要这个)和内核标题。

列出流行的内核名称

下一步是列出最流行的内核标题,然后将其转换成单词序列并传递给模型。结果是内核标题极其混乱:拼写错误的单词、外来词、特殊符号或者有像‘kernel 678 hggy’这样糟糕的名字。

这就是为什么:

  • 我从分析中丢弃没有投票的内核。我假设向上投票的内核应该有更好的质量和更有意义的标题。
  • 我根据投票总数对内核进行排序,而只选择投票最多的内核

预处理内核标题并创建词汇表

我决定尝试一个基于单词的模型。这就是为什么,在下一步,我需要创建一个词汇表,它应该被用来编码单词序列。

要创建词汇表,我必须执行以下步骤:

  • 清理每个标题去掉标点符号,所有单词小写。
  • 将每个标题拆分成单词并将每个单词添加到词汇表中。
  • 引入一个符号,表示标题的结尾(我选了.,不过可以改),加入词汇表。

让我们引入一个简单的函数来清理内核标题:

现在我们来介绍一个标题结尾的符号和一个单词提取功能:

下一步是制作由提取的单词组成的词汇表:

准备训练集

在本节中,我将为我们的未来模型创建一个训练集:

  • 介绍使用上面创建的词汇表将每个单词编码成张量的函数。我使用单词的一键编码:每个单词被表示为一个张量,其中 0 和 1 的位置都是 0 和 1,这与单词在词汇表中的索引有关。使用单词嵌入代替一次性编码无疑是对我的方法的改进。
  • 从内核标题中生成序列。序列的长度是一个超参数。我选择了长度等于 3 的序列。因此,我们给该模型一个包含 3 个单词的编码的张量和一个预测目标,该预测目标包含后面第 4 个单词的索引。

以下函数将单词编码成张量:

现在让我们从最流行的内核名称中生成单词序列:

构建序列模型

下一步是构建一个简单的 LSTM 模型:

  • 模型的输入和输出大小应该等于词汇表的大小,因为我们试图预测一个序列的下一个单词;
  • LSTM 区块有 128 个隐藏单元;
  • 一个线性层从隐藏尺寸转换成输出尺寸;
  • 使用 Softmax 激活

所以让我们用 PyTorch 定义并初始化一个模型:

我还需要一个实用函数将模型的输出转换成一个词:

训练模型

现在,数据集和模型已经为训练做好了准备。在训练之前,我需要做的另一件事是引入一个函数,它将词汇表中单词的索引转换为张量:

下一步是设置超参数和设备(CPU 或 GPU,如果可用):

定义模型培训程序:

现在训练本身的一切都准备好了:

作为训练的结果,我们应该看到损失是如何随着像这样的时期的数量而减少的:

Training loss decreases over the number of epochs

来自模型的示例内核标题

最激动人心的部分来了。现在我们可以使用我们训练过的模型来生成新的内核标题!我们需要做的就是编写一个简单的采样程序:

  1. 介绍标题中最大字数(以 10 为例);
  2. 向模型传递零个张量作为初始字和隐藏状态
  3. 重复以下步骤,直到对标题符号的结尾进行采样或超过标题中的最大字数:
  • 使用来自模型输出的概率来得到序列的下一个单词
  • 将采样的字作为下一个输入传递给模型。

因此,让我们定义采样函数,并从模型中采样一些标题:

结论

在这个小项目中:

  • 我加载并预处理了真实文本数据。
  • 我创建了一个基于单词的序列模型,可以用来生成新的内核标题。

你可以看到这个模型没有产生有意义的东西,但是仍然有一些有趣的结果,比如:

  • 财富碗数据挖掘
  • 补充批准的数据库
  • 平面忽略人口竞争
  • 规划超级食物处方调查
  • 晚餐课网络放映
  • 弹性网游乐场

当模型挤入现实生活数据时,这种事情就会发生。它们包含缩写、昵称、不同语言的单词、拼写错误的单词等等。当然,你可以通过更好的数据预处理来改善这些结果。我在下面描述了改善结果的措施。

进一步改进

虽然我设法获得了一些令人兴奋的结果,但我还有很多可以改进的地方:

  • 更好的数据清理:许多标题应该从分析中删除,因为它们不是英文的,或者它们就是不能使用(例如“kernel123”)。
  • 自动纠正拼错的单词:标题可以通过自动纠正拼错的单词进行预处理(比如考虑 PySpell 包)。这个过程需要很长时间。然而,这仍然是一种选择,因为数据预处理只在训练前进行一次。
  • 超参数调整:我认为学习率和序列长度可以被调整以达到更好的结果。
  • 使用 单词嵌入 代替对单词的一键编码

使用通用句子编码器生成葡萄酒推荐

原文:https://towardsdatascience.com/generating-wine-recommendations-using-the-universal-sentence-encoder-d086edd13d00?source=collection_archive---------17-----------------------

探索自然语言处理

自从我在大学学习修辞理论和技术交流时第一次读到图灵测试,自然语言处理(NLP)就让我着迷。我们交流的复杂性和微妙性似乎一直是使我们成为独特和智慧物种的决定性因素,因此训练机器理解语言将交流从如此模糊、有说服力和深情的东西转变为似乎机械、有序和可预测的东西。一旦我开始编码,没过多久我的好奇心就驱使我更好地理解我们如何使用机器学习来获得对自然语言的新见解,并推导出我们可能错过的细微差别。例如,最近发表的一篇论文讨论了 NLP 如何用于材料科学的新发现。

我一直在玩的 NLP 工具之一是托管在 Tensorflow-hub 上的通用句子编码器(使用)。使用预先训练的模型,将文本编码成 512 维向量。它针对大于单词长度的文本进行了优化,并针对各种数据源进行了训练。有几种不同的用法。我选择了使用深度平均网络(DAN)训练的模型,因为它比基于变压器的模型占用的资源更少。我使用该工具的第一个项目是基于葡萄酒描述和我的搜索查询之间的语义相似性生成葡萄酒推荐。该项目在 www.robotsdodream.com举办

The Auto-Sommelier allows a user to input a query and generate three wine recommendations.

数据

由模型编码的葡萄酒数据来自在kaggle.com 上找到的葡萄酒评论数据集。它包含大约 130,000 行数据,包括国家、描述、标题、品种、酒厂、价格和评级等列。将数据放入 dataframe 后,我删除了包含重复描述的行和价格为空的行。我还将数据限制在有超过 200 条评论的葡萄酒品种上。

*#import dependancies*
**import** **numpy** **as** **np**
**import** **pandas** **as** **pd
import** **tensorflow** **as** **tf**
**import** **tensorflow_hub** **as** **tfhub
import** **sqlite3
from** **sqlite3** **import** Error
**import io**#create a connection to the sqlite database.
conn = sqlite3.connect('db\wine_data.sqlite', detect_types = sqlite3.PARSE_DECELTYPES)
c = conn.cursor()*#read the table in the database.*
wine_df = pd.read_sql('Select * from wine_data', conn)*#Drop the duplicate descriptions.*
wine_df = wine_df.drop_duplicates('description')*#drop null prices.*
wine_df = wine_df.dropna(subset=['price'])*#filter the dataframe to include only varieties with more than 200 reviews.*
wine_df = wine_df.groupby('variety').filter(**lambda** x: len(x) > 200)

通过排除少于 200 条评论的品种来减少数据,我得到了 54 种葡萄酒。通过谷歌搜索剩下的品种,我可以添加一个颜色栏,这样用户就可以通过想要的葡萄酒颜色来限制他们的搜索。

*#create a column named color.*
wine_df["color"] = ""*#used to update the database with the wine color. Manually updated each wine variety.*
c.execute("update wine_data set color = 'red' where variety = 'Aglianico'  ")*#commit the update to the database so it saves.*
conn.commit()*#remove all the records without a color.*
wine_df = pd.read_sql("select country, description,rating,price,province,title,variety, winery, color  from wine_data where color in ('red', 'white', 'other')", conn)
wine_df.to_sql('wine_data', conn, if_exists = "replace")

清理完数据,就剩下 100228 行了。

设置通用句子编码器

基于 DAN 的模型大约有 800mb,所以我觉得在本地托管它很重要。使用 OS 库,我设置了模型缓存的位置,并且能够从本地目录调用它,而不是每次都下载它。

**import** **os***#create the directory in which to cache the tensorflow universal sentence encoder.*
os.environ["TFHUB_CACHE_DIR"] = 'C:/Users/Admin/Downloads'
download = tfhub.Module("https://tfhub.dev/google/universal-sentence-encoder/2")

下载完模型后,在指定的目录下会出现一个文件,名字类似于1 FB 57 C3 FFE 1a 38479233 ee 9853 DDD 7 a 8 a 8 a 8 c 47。

创建函数

即使下载了模型,应用程序的最初几个迭代也是资源密集型的,而且慢得令人恼火。经过一点研究和修改,我决定使用函数来减少 tensorflow 构建图形和编码数据的开销和时间。通过使用占位符,我相信性能会得到提高,因为它降低了图形的复杂性。以这种方式编码数据会比较快。

def embed_useT():
    with tf.Graph().as_default():
        text_input = tf.compat.v1.placeholder(dtype = tf.string, shape=[None])
        embed = tfhub.Module('C:/Users/Admin/Downloads/1fb57c3ffe1a38479233ee9853ddd7a8ac8a8c47')
        em_txt = embed(text_input)
        session = tf.compat.v1.train.MonitoredSession()
    return lambda x:session.run(em_txt, feed_dict={text_input:list(x)})*#run the model.*
embed_fn = embed_useT()*#encode the wine descriptions.*
result = embed_fn(wine_df.description)

对所有描述进行编码会消耗系统资源,并占用 2gb 或更多的 RAM。为了节省系统内存,我将 numpy 数组保存到我的 SQLite 数据库中。从数据库调用数组而不是对其进行动态编码,这使我可以在使用 2g ram 的虚拟机上运行应用程序。在运行中对它们进行编码,我使用了一台至少有 4g 内存的机器,即使这样有时也不够。由于我在 stackoverflow 上找到了一个解决方案,将 numpy 数组保存到数据库变得很容易:

def adapt_array(arr):
    '''
    [http://stackoverflow.com/a/31312102/190597](http://stackoverflow.com/a/31312102/190597) (SoulNibbler)
    '''
    out = io.BytesIO()
    np.save(out, arr)
    out.seek(0)
    return sqlite3.Binary(out.read())

def convert_array(text):
    out = io.BytesIO(text)
    out.seek(0)
    return np.load(out)

# Converts np.array to TEXT when inserting.
sqlite3.register_adapter(np.ndarray, adapt_array)# Converts TEXT to np.array when selecting,
sqlite3.register_converter("array", convert_array)c.execute("create table embeddings (arr array)")conn.commit()c.execute("insert into embeddings (arr) values (?)", (result, ))conn.commit()#return the array
c.execute("select * from embeddings")
data = c.fetchone()[0]

对葡萄酒描述进行编码后,我创建了一个函数,通过对用户查询进行编码并找到两个数组的点积来输出葡萄酒推荐:

def recommend_engine(query, color, embedding_table = result): wine_df = pd.read_sql('Select * from wine_data', db.session.bind) embedding = embed_fn([query])#Calculate similarity with all reviews
    similarity_score = np.dot(embedding, embedding_table.T) recommendations = wine_df.copy()
    recommendations['recommendation'] = similarity_score.T
    recommendations = recommendations.sort_values('recommendation', ascending=False)#filter through the dataframe to find the corresponding wine color records.
    if (color == 'red'):
        recommendations = recommendations.loc[(recommendations.color =='red')] 
        recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
                                    , 'rating','color']]
    elif(color == "white"):
        recommendations = recommendations.loc[(recommendations.color =='white')] 
        recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
                                    , 'rating','color']]
    elif(color == "other"):
        recommendations = recommendations.loc[(recommendations.color =='other')] 
        recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
                                    , 'rating','color']]
    else:
        recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
                                    , 'rating','color']]

    return recommendations.head(3).T

测试功能:

query = "fruity, rich, easy to drink, sweet"
color = 'red'recommendation = recommend_engine(query, color)
print(query)recommendation.head(3).T

探索所有的葡萄酒数据并提出一种基于搜索查询生成推荐的轻量级方法是很有趣的。我计划继续探索通用句子编码器,并思考新的项目来挑战自己和改进我的代码。点击这里查看我的 github 上的其余项目代码:

[## 弯曲游戏/葡萄酒推荐

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/bendgame/WineRecommend)

把所有的放在一起

**import** **numpy** **as** **np**
**import** **pandas** **as** **pd
import** **tensorflow** **as** **tf**
**import** **tensorflow_hub** **as** **tfhub
import** **sqlite3
from** **sqlite3** **import** Error
**import io**conn = sqlite3.connect('db\wine_data.sqlite', detect_types = sqlite3.PARSE_DECELTYPES)
c = conn.cursor()*#read the table in the database.*
wine_df = pd.read_sql('Select * from wine_data', conn)*#Drop the duplicate descriptions.*
wine_df = wine_df.drop_duplicates('description')*#drop null prices.*
wine_df = wine_df.dropna(subset=['price'])*#filter the dataframe to include only varieties with more than 200 reviews.*
wine_df = wine_df.groupby('variety').filter(**lambda** x: len(x) > 200)*#create a column named color.*
wine_df["color"] = ""*#used to update the database with the wine color. Manually updated each wine variety.*
c.execute("update wine_data set color = 'red' where variety = 'Aglianico'  ")*#commit the update to the database so it saves.*
conn.commit()*#remove all the records without a color.*
wine_df = pd.read_sql("select country, description,rating,price,province,title,variety, winery, color  from wine_data where color in ('red', 'white', 'other')", conn)
wine_df.to_sql('wine_data', conn, if_exists = "replace")**import** **os***#create the directory in which to cache the tensorflow universal sentence encoder.*
os.environ["TFHUB_CACHE_DIR"] = 'C:/Users/Admin/Downloads'
download = tfhub.Module("https://tfhub.dev/google/universal-sentence-encoder/2")def embed_useT():
    with tf.Graph().as_default():
        text_input = tf.compat.v1.placeholder(dtype = tf.string, shape=[None])
        embed = tfhub.Module('C:/Users/Admin/Downloads/1fb57c3ffe1a38479233ee9853ddd7a8ac8a8c47')
        em_txt = embed(text_input)
        session = tf.compat.v1.train.MonitoredSession()
    return lambda x:session.run(em_txt, feed_dict={text_input:list(x)})*#run the model.*
embed_fn = embed_useT()*#encode the wine descriptions.*
result = embed_fn(wine_df.description)def recommend_engine(query, color, embedding_table = result): wine_df = pd.read_sql('Select * from wine_data', db.session.bind) embedding = embed_fn([query])#Calculate similarity with all reviews
    similarity_score = np.dot(embedding, embedding_table.T)recommendations = wine_df.copy()
    recommendations['recommendation'] = similarity_score.T
    recommendations = recommendations.sort_values('recommendation', ascending=False)#filter through the dataframe to find the corresponding wine color records.
    if (color == 'red'):
        recommendations = recommendations.loc[(recommendations.color =='red')] 
        recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
                                    , 'rating','color']]
    elif(color == "white"):
        recommendations = recommendations.loc[(recommendations.color =='white')] 
        recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
                                    , 'rating','color']]
    elif(color == "other"):
        recommendations = recommendations.loc[(recommendations.color =='other')] 
        recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
                                    , 'rating','color']]
    else:
        recommendations = recommendations[['variety', 'title', 'price', 'description', 'recommendation'
                                    , 'rating','color']]

    return recommendations.head(3).Tquery = "fruity, rich, easy to drink, sweet"
color = 'red'recommendation = recommend_engine(query, color)
print(query)recommendation.head(3).T

谢谢大家!

  • 如果你喜欢这个, 跟我上 Medium 了解更多
  • 通过订阅 获得完全访问权限并帮助支持我的内容
  • 我们来连线一下LinkedIn
  • 用 Python 分析数据?查看我的 网站

—埃里克·克莱本

生成,风格:NVIDIA 的高逼真 GAN 图像背后的机制

原文:https://towardsdatascience.com/generating-with-style-the-mechanics-behind-nvidias-highly-realistic-gan-images-b6937237e3c6?source=collection_archive---------11-----------------------

如果你在去年年底关注任何机器学习新闻,你可能会看到这样的图像流传,这是 NVIDIA 团队最近的一篇论文指定的一种新的生成对抗网络(GAN)架构的结果:

An apparently randomly selected set of faces produced by NVIDIA’s “Style-Based” GAN

如果你关注这一领域,那么听到一些新奇味道的甘产生令人瞠目结舌的结果并不是一种新的体验,但即使按照最近提高的标准,这些图像也是令人震惊的。第一次,我确信我个人无法区分这些照片和真实的照片。从纸张框架的字里行间来看,这种方法的主要目标似乎实际上是创建一种生成器架构,其中全局和局部图像特征以更可分离的方式表示,因此可以更容易地配置来指定和控制您想要生成的图像。事实上,这些图像也非常逼真,这似乎是一个令人愉快的副作用。

(作为题外话,这篇文章将假设一个基本的背景知识如何卷积甘工作;如果你没有这样的背景,这篇文章是一个很好的起点)

但是首先,最基本的

传统的卷积 gan 的工作方式是对某个分布的向量 z 进行采样,将该向量投影到低分辨率空间形式,然后执行一系列转置卷积,将 2×2 特征空间上采样到 4×4,然后到 8×8,依此类推。虽然 Z 向量只是随机采样,但我们的最终目标是在图像分布和我们的参考分布 Z 之间创建一个映射,使得 Z 中的每个向量都对应于一个真实的图像。因此,尽管一开始毫无意义,但每个特定的 z 最终都对应于它将产生的图像的编码属性。

在其最简单的形式中,转置卷积通过学习滤波器矩阵(例如,3x3)并将其乘以每个像素的值来在空间上向外扩展其信息。4×4 表示中的每个单个“像素”影响输出的 3×3 小块中的值;这些面片重叠并相加,以创建最终的“展开”表示。

上图虽然有助于建立简化的直觉,但有一点误导,因为它看起来像是放大的面片的值必须从单个像素的单个信息中分离出来。请记住:在网络的这一点上,四个“像素”中的每一个都包含一个完整的向量,可能相当于 128 或 256 个特征地图的信息。

由于较大的“上采样”图像中的大多数区域将仅从某一组“父”像素获得信息(例如,4x4 图像中的左上像素仅包含来自 2x2 图像中的左上像素的信息),因此每一级的信息需要在空间上有所不同——以便能够展示不同组件在空间中的位置——但也需要有所全局化,因为如果我们试图创建一幅黑白图像, 每一个 2x2 像素都需要包含这些信息,以确保它被传递给下一代,我们不会以最终图像的一大块没有得到备忘录而告终。 从指定完整图像的完全全局 Z 向量开始,每个像素负责向其子像素传达它需要向其子像素传达的信息,以此类推,直到最后一层“子像素”只是输出图像的 RGB 像素。

这是转置(或“反进化”)网络(尽管这是一个令人困惑的术语,因此不推荐)正在解决的基本问题,如 GAN 发生器中使用的网络:如何将信息和指令分配到不同的空间区域,以便最终能够协调全球一致的高质量图像的产生。

全球化思考,本地化生产

如前一节所述,在典型 GAN 的生成器的层中,全局信息(指定所有区域需要协调的图像范围参数)和局部信息(我们应该将手、眼睛和头发放在哪里)都混合在一个共享的特征向量中,从一层传递到下一层。

由 NVIDIA 论文提出的方法,他们称之为“基于风格的生成器”,采取了一种不同的方法:不是在网络的开始只输入一个向量,而是在网络的每一层重新注入一个全局参数向量,称为 W,以及从随机向量样本 Z 学习到的转换的输出。

浏览左边的图表:首先,从 Z 分布中进行绘制,它通常类似于多维高斯分布。然后,使用映射网络将 z 向量转换成 w 向量。这种转换的想法是,通过 z 和 w 之间的映射,我们可能能够获得更自然或更清晰的概念表示。(“解开”在这里意味着向量的每个维度都对应于一个独立的特征轴,图像沿着该轴变化,如头发颜色或年龄)。该论文对此的解释是,由于我们通常受限于我们可以轻松采样的分布类型,因此以轴对齐的方式表示图像概念并仍然填充采样分布的所有区域并对应于相干点可能并不容易。

在生成器方面,我们不是从通常的随机 z 向量开始,而是从一个学习到的常数 4x4 特征向量开始,只是为了获得正确的形状。然后,我们看到两个操作,噪声和风格注入,然后在整个网络中重复。

谣传

首先执行噪声处理,在图中表示为 B 和加法运算符。随机生成一个噪声图(最初大小为 4x4,但在随后的层中,无论表示在那里的维度如何),并传递到网络中。每个要素地图都会将此值的缩放版本添加到其值中,并将每个地图的唯一缩放因子作为网络参数学习。这具有随机扰动每个特征图的值的效果,并且重要的是,基于那里的采样噪声的幅度,以不同的量扰动图的每个空间像素处的值。我会绕回来,试着建立一些直觉来解释为什么这是一件有价值的事情

风格注入

在噪声之后,网络执行“样式”注入,这是一种基于全局样式参数的学习归一化形式。这里我们使用映射网络生成的 w 向量,它捕获图像的全局规格。在执行该操作的每个地方,我们使用学习的仿射变换(基本上是典型的单个神经网络层)来接受该全局向量 w,并输出包含在网络中该点处存在的每个特征图的两个值的向量,一个比例参数和一个偏移(或“偏差”)参数。这些参数用于所谓的自适应实例规范化,简称 AdaIN,这是一种应用单独的每特征移动和重新缩放的操作。

在上面的等式中,索引 i 指的是特定的特征图。换句话说,我们取第 i 个特征图(记住,它是在一些空间维度上展开的)并计算它的平均值和标准偏差。然后,我们执行归一化和重新缩放操作,这让人想起 batch norm:减去并除以平均值和 sd,然后乘以并加上缩放和偏移参数。

这两个操作允许我们通过我们学习的每个特征的比例和偏移参数来控制正在生成的每个图像的每个特征的均值和方差。关于所有这些操作,最重要的事实是它们是全局执行的,一次跨所有空间区域。如果你认为(非常粗略地)这些特征映射中的每一个都是控制各种图像特征的刻度盘——肤色、头发长度、两眼之间的距离,那么基于从我们的全局风格参数 w 计算出的值执行这种重新缩放操作就像将这些刻度盘从默认的“平均脸”位置移动到我们想要的这个特定图像的值。在这种架构中,每个反卷积操作不再需要学习如何记住全局信息,并在所有空间区域保持一致:这种一致性是免费的。

这两种操作,即噪声和风格驱动的归一化,是这种架构的核心——通过在去卷积和上采样的任何一侧应用这两种操作来实现网络功能。总的来说,它们似乎具有将信息“分解”成更可分离和可单独控制的成分的效果,并有助于更真实地生成随机图像元素。

这噪音是怎么回事?

作者使用噪声注入的基本原理是,图像的某些方面,如果不是严格意义上的完全随机,至少在信息上没有意义,并且当噪声被直接提供给网络时,更容易以令人信服的随机方式生成。例如,考虑下面左边图片(a)中小女孩头发的卷曲,或者右边相同位置叶子的确切位置。当单个卷发或树叶的位置和方向看起来随机时,这两者看起来更真实。

This figure shows the same generated image, but with injected noise removed at different levels of the network. (a) shows the default StyleGAN, with noise at all levels. In (b), all noise is removed from the network. In (c), noise is applied at the later layers responsible for fine detail, but not at coarser/lower resolution layers. Finally, in (d), that is swapped, and noise is present for coarse layers but not fine ones. The same orientation of a/b/c/d follows for the boy on the right.

然而,令人信服的随机性对于一个网络来说实际上是相对难以原生生成的;由于网络中的一切都只是确定性的数学变换,因此随机性通常会被一些具有明显模式或周期性的参数函数所近似。作为一个例子,考虑左下角矩形中的男孩的照片:叶子以大约均匀的间隔放置,以一种看起来不是特别真实的方式。

考虑噪声作用的另一种方式是给网络一种方法,从给定图像的等效似是而非的变化分布中容易地进行采样。左边的图像显示了一个生成的图像,然后显示了当您使用所有相同的全局元素生成该图像时所得到的差异,但是使用了不同的精细噪声实例。结果通常是非常相似的图像,但是对于图像的核心特征来说,细节上的微小变化并不重要。虽然很明显这些人都不是“真实的”,但你可以把这想象成给同一个人拍不同的照片,但随着风或灯光的改变,这些随机元素的外观会有所不同。

你很有型

这解释了噪声的价值,但我们从这种风格的注入设置中得到什么好处呢?提醒一下,样式是通过每个特征图计算的两个归一化参数在每个图像的基础上配置的,这些参数是基于全局样式向量 w 确定性地计算的。顺便说一句,术语“风格”用于指这些全局参数,因为它们全局地影响图像,并影响广泛的美学和内容特征,让人想起风格转移工作,其中一个艺术家的视觉风格用于照片或另一个艺术家的工作。我认为这有点令人困惑,并且更愿意将样式视为配置,或者全局参数设置,但我仍然偶尔使用“样式”,因为这是本文使用的术语。

回到我们的比喻,样式是一种在每个特征的基础上“调节”图像生成的方式,演示样式如何控制结果图像的一种方式是,看看当您将两个不同图像的特征设置组合在一起时会发生什么。因为风格注入在每一层单独发生,这可以很容易地通过将人 A 的 w 向量提供给某一组层,并将人 B 的 w 向量提供给其余层来完成。这导致一些层根据人 A 的参数进行配置,而其他层根据人 B 的参数进行配置。这就是上图中显示的内容:在每一行中,我们取最左边的图像,用相应列中的图像替换掉它的一些样式参数。对于前三行,我们从源中交换粗略的样式参数,对于后两行、中间行和最后一行,只有精细的样式参数从备用图像中“导入”。(注意,这些都不是真实的图像,只是来自输入 z 分布的不同人工绘制,然后使用映射网络将其映射到 w 向量)

可以预见,重新配置图像的粗略参数具有最显著的影响,完全改变年龄、性别和面部形状以匹配源图像,但种族和整体调色板与目的地保持不变。当我们只改变精细级别参数时,我们得到的是一个具有相同性别、表情和面部表情,但头发和肤色有微小变化的人。根据金发女孩原则,中间层介于两者之间:更像是两个图像的平等融合。

所有这些都展示了一种有用的灵活性:这种架构不仅仅能够在生成的图像之间进行插值,并使全局和局部特征共同变化,而是允许在特定比例甚至逐个特征的基础上对合并或修改进行更大的控制。通常,这种级别的生成控制可以通过训练一个类条件模型来实现,在这个模型中,您可以为每个图像生成一个指定的类。我们还没有达到能够指定一组图像指令,并将其翻译成生成器可以遵循的蓝图的地步,但是这种方法使我们更接近于在没有直接类监督的情况下做到这一点的能力。

缩小

我记得曾读到有人对这篇论文发表过一个有趣的看法(可惜我忘了是谁),那就是,与其说它是 GAN 设计的进步,不如说它是许多非常聪明的针对图像的发生器设计。我认为这是一个需要记住的很好的区别,无论是在这里还是更广泛的 ML 中:由于如此多的现代深度学习研究都集中在图像上,保持对什么样的成功代表普遍进步与特定领域进步的持续了解是有价值的。并不是说聪明的特定领域的工作有什么错误,相反我认为它有巨大的价值,但是我们应该小心将“在图像上有令人印象深刻的进步”与“在更广泛的学习任务上有令人印象深刻的进步”混为一谈。

快速提醒:我深入研究了这篇论文,对自己的理解相对有信心,但还没有像以前的一些帖子那样对相关文献进行彻底的回顾,所以我可能误解了风格根与当前艺术水平的关系。如果你认为是这样,请告诉我!

使用 Python Faker 库生成大型 CSV 数据。

原文:https://towardsdatascience.com/generation-of-large-csv-data-using-python-faker-8cfcbedca7a7?source=collection_archive---------10-----------------------

对于那些需要大量虚假数据来试验不同算法的学习者来说。各种领域每秒钟都有大量数据在线生成,但出于学习和实验目的,原始数据由于安全性和许多其他限制而无法使用。所以我在这里谈论的是使用 Python 的一个名为 Faker 的库生成大量的虚假数据。

Faker 图书馆

Faker 是一个生成假数据的 Python 包。

使用 pip 安装 Faker 库:

pip install Faker

Python 用法

faker。Faker() 初始化一个伪生成器,可以根据不同的数据类型为不同的属性生成数据。faker generator 的不同属性打包在“providers”中。不同造假者的名单可以在这里找到。它还拥有 ipv4 互联网提供商和其他社区提供商,如 web、云和 wifi。可以使用fake . add _ provider(custom provider)创建和添加自定义提供程序。

不同数据类型的一些假生成器如下所示。本笔记本中给出了不同提供商的更详细使用方法。

from faker import Faker
from faker.providers import internetfake = Faker()fake.pybool()   # Randomly returns True/Falseprint(fake.pyfloat(left_digits=3, right_digits=3, positive=False, min_value=None, max_value=None))   # Float dataprint(fake.pystr(min_chars=None, max_chars=10))  # String dataprint(fake.pylist(nb_elements=5, variable_nb_elements=True))  # Listfake.add_provider(internet)
print(fake.ipv4_private())  # Fake ipv4 address

数据输出如下所示:

Some faker functions with output

faker。Faker() 可以将区域设置作为参数,以返回本地化的数据。默认区域设置是 en_US。它支持印地语、法语、西班牙语、中文、日语、阿拉伯语、德语和更多的 T21 语。

from faker import Fakerfake_H = Faker('hi_IN')   # To generate Hindi Fake data
fake_H.name()

命令行用法:

Faker 也可以在安装后从命令行调用。

faker [-h] [--version] [-o output]
      [-l {bg_BG,cs_CZ,...,zh_CN,zh_TW}]
      [-r REPEAT] [-s SEP]
      [-i {package.containing.custom_provider otherpkg.containing.custom_provider}]
      [fake] [fake argument [fake argument ...]]where;
-h, --help : shows a help message
--version : shows the program version
-o : output file
[-l {bg_BG,cs_CZ,...,zh_CN,zh_TW}] : allows using localized provider
[-r REPEAT] : To generate specified number of outputs
[-s SEP] : Separator to separate generated outputs
[-i {package.containing.custom_provider otherpkg.containing.custom_provider}] : to add custom providers
[fake] : name of fake to generate an output for (e.g. name, address)

CSV 的生成

带有虚假数据的大型 CSV 文件可以非常容易地生成任意数量的记录。你需要做的只是传递 CSV 的标题,并在标题中为每一列指定数据属性。

Faker 有助于生成各种类型的数据,如姓名、电子邮件、url、地址、电话号码、邮政编码、城市、州、国家、日期、时间等等。生成假 CSV 数据的代码如下所示。

你可以在这里找到代码文件。希望这篇文章对你有所帮助,并为你提供了一些有意义的见解!非常欢迎您的宝贵反馈。快乐学习!!!

面向初学者的生成性对抗网络(GANs ):生成分心驾驶员的图像

原文:https://towardsdatascience.com/generative-adversarial-networks-gans-for-beginners-82f26753335e?source=collection_archive---------7-----------------------

生成对抗网络(GANs)是指一组通常用于生成刺激(如图片)的神经网络模型。GANs 的使用挑战了计算机没有创造力的教条。GANs 的应用仍处于早期阶段,但这是一个非常令人兴奋的研究领域。在这里,我回顾了 GAN 的基本组成部分,并展示了一个我用来生成分心驾驶员图像的示例 GAN。具体来说,我将审查一个瓦瑟斯坦甘。如果读者对 Wasserstein GAN 背后的理论更感兴趣,我建议你参考链接的论文。这篇文章对应的所有代码都可以在我的 GitHub 上找到。

我们开始吧!GAN 由两种类型的神经网络组成:生成器和鉴别器

发电机

生成器的工作是获取噪声并创建图像(例如,一个分心的司机的照片)。

Generator

这到底是怎么回事?我们首先从创建噪声开始,对于小批量中的每一件商品,噪声由一个 0 到 1 之间的随机正态分布数字的向量组成(在注意力分散的驾驶员的例子中,长度是 100);注意,这实际上不是一个向量,因为它有四个维度(批量大小,100,1,1)。

然后,我们必须从一个数字向量到一个完整的图像,我们使用转置卷积来完成。对于以前有计算机视觉经验的读者,您可能熟悉可以对图像进行缩减像素采样的普通卷积图层。例如,下图显示了一个卷积层,内核为 3x3,步幅为 1,没有填充。可以看出,输入的大小从 4×4 减小到 2×2。

Convolution layer with a 3x3 kernel, stride of 1, and no zero padding. Image from the Convolution Arithmetic Tutorial.

也有过滤器“跳过”像元的跨距卷积层。例如,下面是一个具有 3x3 内核、步幅为 2 且没有填充的卷积层。可以看出,输入的大小从 5×5 减少到 2×2。

Convolution layer with a 3x3 kernel, stride of 2, and no zero padding. Image from the Convolution Arithmetic Tutorial.

对于转置卷积,输入通常会被上采样,而不是被下采样。例如,下面是一个转置卷积层,其内核为 3x3,步幅为 1,没有零填充。可以看出,输入的大小从 2x2 增加到 4x4。

Transposed convolution layer with a 3x3 kernel, stride of 1, and no zero padding. Image from the Convolution Arithmetic Tutorial.

还有带步幅的转置卷积层。例如,下面是一个转置卷积层,其内核为 3x3,步幅为 2,没有零填充。可以看出,输入的大小从 2×2 增加到 5×5。

Transposed convolution layer with a 3x3 kernel, stride of 2, and no zero padding. Image from the Convolution Arithmetic Tutorial.

利用 GAN 发生器,我们实际上是对噪声进行上采样,直到它达到一幅图像的大小。在这样做的同时,我们也减少了过滤器的数量。具体细节见我的 GitHub 上的代码。

鉴别器

鉴别者的工作是拍摄一幅图像,并试图判断它是真的还是假的(即鉴别假的和真的图像)。该模型实际上非常简单,它基本上包括使用一组标准卷积层和 stride 对图像进行下采样,最终达到一个值。这个值就是损失。如下文在训练模型中所述,对真实和伪生成的图像都计算该损失。在对“图像”进行下采样时,我们增加了滤镜的数量。再一次,查看我的 GitHub 上的代码以获得准确的细节。

训练模型

现在我们有了生成器和鉴别器模型,我们可以开始训练它们了!事实证明,对于 GANs 来说,重要的是我们的鉴别器真的很擅长区分真假图像。因此,每次更新生成器权重时,我们都会更新鉴别器的权重 5–100 次(详见代码)。好吧,很好,但是我们到底要怎么训练鉴别者呢?其实挺容易的。首先,我们取一小批真实图像,并让它们通过鉴别器。鉴频器的输出是实际损耗。然后我们让噪声通过我们的发生器,让这些假图像通过鉴别器。鉴别器的这个输出就是假损耗。通过从实际损耗 ( 实际损耗 - 假损耗)中减去假损耗来计算鉴频器损耗。相对于该损失更新权重。因此,正如你所看到的,生成器基本上是在试图欺骗鉴别器,这就是生成对抗网络的对抗部分。

那么生成器如何变得善于欺骗鉴别器呢?训练发电机其实很简单。我们只是制造一些噪音,让它通过发生器,让这些假生成的图像通过鉴别器。该输出是发电机损耗,用于更新发电机的权重。

这就是训练 GAN 的全部内容!真的不太复杂。现在让我们来看一个 GAN 的动作。

生成分心司机的图像

在这里,我使用 Kaggle State Farm 分心驾驶员检测数据集来训练 GAN,以生成分心驾驶员的图像(我也包括训练未分心的控制驾驶员)。该数据集基本上由一大堆分心司机的照片组成,如司机发短信、化妆或与另一名司机交谈。这个数据集最初是由 State Farm 作为 Kaggle 竞赛发布的,用于训练一个分类器来检测司机如何分心。如果你还记得几年前,State Farm 引入了在汽车上安装摄像头的想法,这种摄像头基本上可以检测司机是否分心,并可能根据这些信息调整保费(我实际上不知道这是否是他们检测分心司机的意图)。

开始训练吧!只是一个小注意,我最初将图像下采样为 64x64 像素,以便我可以更快地训练 GAN,因此这些图像的质量不如原始分辨率好。下面是一个时期后生成的 64 幅图像示例。如你所见,它们看起来什么都不像。让我们继续训练。

After 1 epoch

现在我们可以看到在 20 个纪元后,它看起来确实像是在创造汽车司机的照片!

After 20 more epochs

经过一段时间的训练,我们得到了一些相当合理的图片。看看下面两张图片,你可以看到一个例子产生分心的司机。好像这个人在打手机(酷!).

After training for a little while

Generated distracted driver

太好了!这些图像是完美的吗?不,但是只要付出很少的努力,它们就不会太差(至少在我看来是这样!).我发现神经网络能够学习如何生成图像,这真是令人惊讶。GANs 是一个真正令人兴奋的研究领域,它开始打破计算机没有创造力的假设。GANs(例如 CycleGANs)最近还有许多其他的突破,它们甚至更有趣,我可能会在以后写出来。再次,在我的 GitHub 上查看这篇博文的代码,并关注未来关于 GANs 和其他机器学习主题的帖子!

生成性对抗网络——学习创造

原文:https://towardsdatascience.com/generative-adversarial-networks-learning-to-create-8b15709587c9?source=collection_archive---------10-----------------------

一窥 GANs 背后的设计、训练、损失函数和算法

假设我们有一个卧室图像的数据集和一个图像分类器 CNN,它在这个数据集上被训练来告诉我们一个给定的输入图像是否是一个卧室。假设图像的大小为 16 * 16。每个像素可以有 256 个可能的值。因此有无限多的可能输入(即 256 种⁶* ⁶或~10⁶ ⁶可能的组合)。这确实使我们的分类器模型成为一个高维概率分布函数,它给出了来自这个大输入空间的给定输入是卧室的概率。

因此,如果我们可以学习这种用于分类目的的卧室图像数据分布的高维知识,我们应该肯定能够利用相同的知识甚至生成全新的卧室图像?事实证明,是的,我们可以。

虽然生成建模有多种方法,但我们将在本帖中探索生成对抗网络。最初的 GAN 论文发表于 2014 年,深度卷积生成对抗网络(DCGANs)在论文中介绍,并一直是流行的参考。这篇文章基于对这两篇论文的研究,对 GANs 做了很好的介绍。

GAN 是一个网络,其中同时训练两个模型,生成模型 G 和判别模型 D。生成模型将被训练以通过捕获与训练数据集相关联的数据分布来产生新的卧室图像。鉴别模型将被训练以将给定的输入图像正确地分类为真实的(即来自训练数据集图像)或虚假的(即由生成模型产生的合成图像)。简单来说,判别模型是典型的 CNN 图像分类器模型,或者更具体地说,是二值图像分类器。

与判别模型相比,生成模型略有不同。它的目标不是分类,而是生成。在给定输入图像的情况下,鉴别模型吐出表示不同类别的激活向量作为输出,而生成模型则相反。

Generative vs Discriminative Model

它可以被认为是一个反向 CNN,在某种意义上,它将采用一个随机数向量作为输入,并产生一个图像作为输出,而正常的 CNN 则相反,采用一个图像作为输入,并产生一个数字或激活向量(对应于不同的类)作为输出。

但是这些不同的模型是如何协同工作的呢?下图给出了该网络的示意图。首先,我们将随机噪声向量作为生成模型的输入,生成图像输出。我们将这些生成的图像称为假图像或合成图像。然后我们有鉴别模型,该模型将来自训练数据集的假图像和真图像作为输入,并产生分类该图像是假图像还是真图像的输出。

An illustration of Generative Adversarial Network

用这两个模型训练和优化这个网络的参数就变成了一个两个人的极大极小游戏。鉴别模型的目标是最大限度地将图像正确分类为真与假。相反,生成模型的目标是最小化正确地将假图像分类为假的鉴别器。

反向传播用于像常规 CNN 一样训练网络参数,但是存在两个具有不同目标的模型的事实使得反向传播的应用不同。更具体地说,涉及的损失函数和在每个模型上执行的迭代次数是 GANs 不同的两个关键方面。

判别模型的损失函数将只是与二元分类器相关联的常规交叉熵损失函数。取决于输入图像,损失函数中的一项或另一项将为 0,并且结果将是图像被正确分类的模型预测概率的负对数。换句话说,在我们的上下文中,“y”对于真实图像是“1”,而“1–y”对于虚假图像是“1”。“p”是图像是真实图像的预测概率,“1-p”是图像是伪造图像的预测概率。

Cross Entropy Loss for a Binary Classifier

上面的概率“p”可以表示为 D(x),即由鉴别器 D 估计的图像“x”是真实图像的概率。重写后,看起来像下面这样:

Dicriminator’s loss function

基于我们如何分配上下文,等式的第一部分将被激活,而第二部分对于真实图像将为零。对于假图像来说,反之亦然。记住这一点,第二部分中图像“x”的表示因此可以由“G(z)”代替。换句话说,在给定“z”作为输入的情况下,假图像被表示为模型“G”的输出。“z”只不过是模型“G”产生“G(z)”的随机噪声输入向量。不必太担心其余的数学符号,这与 GAN 论文中提出的鉴频器 D 的损失函数相同。乍一看,这些信号令人困惑,但本文中的算法通过“上升”其随机梯度来更新鉴别器,从而提供了清晰度,这与如上所述的最小化损失函数是相同的。这是论文中函数的一个快照:

From here

回到发生器 G,G 的损失函数将反过来,即最大化 D 的损失函数。但是等式的第一部分对生成器没有任何意义,所以我们真正要说的是第二部分应该最大化。因此,G 的损失函数将与 D 的损失函数相同,只是符号被翻转,第一项被忽略。

Generator’s loss function

这是论文中发电机损耗函数的一个快照:

From here

我也很好奇,想知道更多关于生成模型的内部情况,因为它做了一些直观上与典型的 CNN 图像分类相反的事情。如 DCGAN 论文中所示,这是通过整形和转置卷积的组合来实现的。这是论文中发电机的示意图:

DCGAN Generator from here

转置卷积不同于卷积的逆卷积,在给定原始卷积输出的情况下,转置卷积不会恢复输入,而只是改变形状。下图展示了上面发电机模型背后的数学原理,尤其是 CONV 层。

Illustration of a regular convolution used in CNNs followed by two examples of up-sampling achieved through transposed convolutions. The result of the first example is used as input in the second and third examples with the same kernel to demonstrate transposing is not the same as deconvolution and is not meant to recover an original input.

报纸上还有一些有趣的地方值得注意。一个是原始论文提出的算法中的内部 for 循环。这意味着,对于 k > 1,对于 G 的每次迭代,我们对鉴别器 D 执行多次训练迭代。这是为了确保 D 得到充分训练,并且与 G 相比更早地学习。我们需要一个好的 D 来愚弄 G。

From here

另一个相关亮点是发生器可能记忆输入示例的问题, DCGAN 论文通过使用 3072-128-3072 去噪丢失正则化 RELU 自动编码器(基本上是一种减少和重建机制)来解决该问题,以最大限度地减少记忆。

DCGAN 论文还强调了当生成器被操纵以忘记它正在生成的卧室图像中的某些对象时,它是如何表现的。他们通过丢弃与第二高卷积层特征集中的窗口相对应的特征图来实现这一点,并展示了网络如何用其他对象替换窗口空间。

还演示了基于对作为发生器输入给出的噪声向量“Z”执行的运算的附加操作。就像当从“微笑的女人”的向量中减去产生“中性女人”的向量,并将结果添加到“中性男人”的向量时,合成的向量产生“微笑的男人”图像,透视输入和输出空间之间的关系以及两者之间发生的概率分布映射。

虽然上面看到了算法和损失函数的其他变体,但这有望为这个有趣的主题提供一个合理的介绍。

生成性对抗网络:重振旧的视频游戏纹理

原文:https://towardsdatascience.com/generative-adversarial-networks-revitalizing-old-video-game-textures-669493f883a0?source=collection_archive---------16-----------------------

Comparison of traditional resampling vs ESRGAN output, and the original image on the right.

如果你的屏幕顶部有一个大的绿色条,等一分钟!正在加载!

如果有一件事是人们喜欢在视频游戏中谈论的,那就是他们的图形保真度。这些年来,衡量游戏进步的标准是现代硬件带来下一波“新一代图形”的能力。但这并不意味着我们不再喜欢昔日的游戏。我们很多人都有一种强烈的怀旧情绪,对过去的游戏(和它们的图像)的热爱。生活在这样一个时代是多么令人兴奋啊,机器学习可以直接应用在一种叫做单图像超分辨率的方法中,以增强那些过去遗迹的纹理,并使它们更多地融入现代世界。

我在这里使用的模型 SRGAN 基于这篇论文【https://arxiv.org/abs/1609.04802

以及在 https://github.com/xinntao/ESRGANECCV 2018展示的原始模型的扩展

Before and after comparisons of Ocarina of Time textures

在我们深入这个模型的内部工作之前,理解 SISR 是什么以及它是如何工作的是很重要的。它在图片和游戏纹理领域之外有许多应用,如显微镜和雷达,但为了清楚起见,我们将只讨论数字媒体的应用。

SISR 模型试图从低分辨率图像中吸收高分辨率图像,同时保持图像的保真度不变。意味着没有图像噪声,没有伪像。直到最近几年,很难在不丢失大量纹理细节的情况下缩放图像。通常,超分辨率算法会试图创建一个成本函数来最小化增强的高分辨率图像和基础图像之间的 MSE(均方误差)。MSE 的降低与峰值信噪比直接相关。(PSNR)不幸的是,这种测量是通过逐个像素的比较来完成的,通常会导致高度模糊的图像,例如双三次图像放大或最近邻变换。SISR 模型通常比那些重采样方法实现更高的保真度,尽管随着分辨率的提高,您开始看到类似的行为模式,或者在某些情况下像素开始融合在一起。比较 SRGAN,以其增强的未来版本如下。正如你所看到的,当我们继续向上缩放时,眼睛开始有点塌陷。但这无疑是对简单取样方法的改进。

那么我们来谈谈 GAN 网络到底是什么。分解一下。

生成+对抗+网络。

这个术语的生成部分来自于这样一个事实,即甘寻求创建内容作为算法的输出。对抗性术语暗指算法的生成部分需要某种东西与之竞争,一个对手。网络指的是如何将生成性和对抗性模型联系在一起,以最终合作实现模型的最终目标。对于图像,GAN 网络试图从它们的训练集中生成新的图像,而对抗模型试图确定生成的图像是真是假。像 SISR 一样,基于图像的 GAN 网络寻求最小化成本函数,尽管这里有更广泛的误差测量,例如由 GAN 网络生成的特征映射之间的欧几里德距离。

SRGAN

所以现在你可能会猜到这只是超分辨率生成对抗网络的缩写。基于 GAN 的 SISR 方法。SRGAN 用从 VGG(视觉几何组)网络的特征地图计算的新损失函数来代替 MSE 成本最小化(记住,这是在逐个像素的基础上测量的,并且可以留给我们过度平滑的表示)。

2017 年,SRGAN 是最先进的,是同类中最好的。但是世界不会为任何人而停止。输入新的竞争对手…

ESRGAN:简介

以及一些理解其重要性的必备知识

ESRGAN 向 SRGAN 引入了残差中残差密集块。通常,当模型中有许多复杂层时,层数越多,效率越低,因为越接近完全精度,最小化误差的总和就越低,并且这些层在某个点开始相互竞争。使用传统的方法,当层数超过 25 层时,你实际上开始失去准确性。

最小化是如何计算的?

由于消失梯度问题,深度网络在训练期间很难参数化。渐变用于计算模型早期层的权重。这种重复经常会使梯度变得无限小,正如你所想象的,网络越深,梯度就越小。我们使用梯度来计算成本函数。如果我们不能引入一种方法来处理这个问题,最终这个成本函数将会开始增加。

剩余连接的引入

2015 年,ResNet 将通过实施剩余网络改变世界。他们的理论是“身份快捷连接”将允许连接的层符合残差映射。

设 H(x)是所需的底层映射。我们试图使堆叠的非线性层符合另一个映射 F(x):= H(x)-xF(x):= H(x)-x。

原始映射可以重铸为 F(x)+x。他们理论上认为优化残差映射比优化原始映射更容易。

他们是对的。

恒等式快捷连接寻求学习恒等式函数,该函数简单地将当前层的计算权重和前一层(l+1)的偏差值的权重矩阵设置为 0。通过这样做,新层(l + 2)的激活与层 l 相同

吴恩达对此解释得比我好得多,并且通过一些数学推导,绝对值得一看。

结果是,与标准网络相比,该网络停止了梯度成本函数的退化,并提高了性能。太神奇了!

改善剩余网络

此后不久,该社区爆发了寻求优化这一新方法的研究人员的涌入。提出了剩余层的预激活,这将允许梯度使用捷径连接来跳过任何层而不受阻碍。这进一步改进了剩余方法,将 1001 层网络带入世界,其性能优于更浅的同类网络。

ESRGAN 定制的 SRGAN 及其开山鼻祖 ResNet

除了 ESRGAN 的 RRDB 方法之外,他们还放弃了批量归一化图层,并替换为残差缩放和一分钟初始化学习速率。然后,它利用 RaGAN 或相对论平均 GAN 来衡量一个图像与另一个图像的相关性,即这个图像更真实还是更不真实,而不是衡量一个图像是否是假的。

SRGAN 的感知损失函数在它的计算中使用 VGG 特征激活后,ESRGAN 在激活前移动该利用率

所有这些导致图像比以往任何时候都更清晰。

最终想法:

我已经使用这个模型,并在一系列现代纹理上训练它,并将其应用于旧 N64 和 PlayStation 1 纹理,结果令人惊叹。

然而,仍有改进的余地。当图像中有大量像素时,或者对于没有太多重复图案的图像,模型有时可以放大成几乎像浮雕一样的实例,如第一幅图像所示。我的假设是,艺术形式与任何其他类型的图像都非常不同,我需要收集适当的训练数据,即高分辨率像素艺术。这可能很难找到,甚至更难(耗时!)来制作。

如果你知道任何艺术家或者你自己愿意为这个项目做贡献,请在 otillieodd@gmail.com 联系我

我希望能够编辑这篇文章,并与社区分享升级的任天堂 64 和 Playstation 纹理,因为我认为它可以对游戏进行一些非常酷的修改,并给我们老前辈一些新的理由来重播我们的最爱,但我仍在研究这样做是否合法。

到那时,感谢阅读!

生成式图形设计:算法驱动的设计会改变我们的设计方法吗?

原文:https://towardsdatascience.com/generative-graphic-design-will-algorithm-driven-design-change-our-approach-in-designing-38aea9e68d16?source=collection_archive---------26-----------------------

机器学习一直是人们感兴趣的话题,它是人工智能(AI)学科的一个子集,它以其迷人的性质引发了伦理和道德问题,尤其是现在机器已经到来,并且正在加速学习。在当今这个时代,机器已经被实现来完成各种任务,从以较低成本进行大量生产到社交媒体平台上的数据外包,这些任务都是简单的任务,大部分过程都是重复的,除了这些任务的启动和控制方面之外,可以在没有人工输入的情况下完成。生成式设计本身已经被建筑和土木工程使用了一段时间(就上下文而言,Autodesk 会提供这样的工具)。但是,一个强大的工具来帮助生成尽可能多的迭代的想法对于像图形设计这样的创意领域来说似乎是一个很好的工具。作为一项本质上不是功利任务的工作,平面设计仍然需要大量的人力投入来解决问题,同样的道理也适用于建筑和土木工程,这一过程将在下面讨论。对于那些不熟悉解决(图形)设计问题的过程的人来说,即使它因设计师/设计团队的不同而不同,变量通常是相同的。

以人为本的设计过程

毫无疑问,起点是在同一点上:定义问题并开始研究,然后经历战略路线,根据时间、预算、请求和其他在所述项目之上的微观变量来计划解决问题的方法。有些人会直接进行实验来寻找最佳方法。设计师同事可能熟悉来回修改,以满足客户的需求,并希望前期制作和/或后期制作,决策是双方不可避免的。这个过程是渐进的,但它包含了对进步的反思。不存在“一刀切”的流程,正如一句名言所说的那样“***【每个人都不一样】(在我们的例子中,每个人都是设计师)。设计过程本身涉及无数需要创造性良知的决策输入,并且关于每个变量的这种决策事件不能完全交给机器,因为机器还没有能力获得创造力。除非我们生活在一个高度智能和有能力的机器人被大规模生产的时代,但在那之前,我只是超越了自己。*****

涉及计算机程序和一组约束,生成式设计的亮点是它的迭代过程,该过程创建了无数排列供最终产品选择,从视觉上看,产品看起来像是在不断变化,好像它一直在进化。这个图形操纵过程可以分为两种类型(为了便于即时识别,这些名字是我自己拼凑的): 基于作者的输入基于受众的输入

根据我的观察,基于作者的输入设计在很大程度上依赖于作者(设计者),从算法协作到产生输出的约束集,当完成时,输出是固定不变的。基于作者的输入设计的一个例子是麻省理工学院媒体实验室波士顿身份的 E Roon Kang 、 Richard The、和 Studio TheGreenEyl 的合作,其算法设计产生了 45,000 种排列。

********

Image: Richard The http://www.rt80.net/medialab/

另一方面,基于受众的输入设计通过插入他们的约束集让受众参与完成,这增加了更多的体验价值。这方面的一个例子是“Phase”,这是一个由类型设计者 Elias Hanzer 创建的生成类型工具,由 Florian Zia 开发,它对手动滑块做出反应,该滑块实时操纵其形式或通过语音输入发出声音。

My input in creating my custom type. Visit: https://www.eliashanzer.com/phase/

一般来说,生成设计中的实验性质允许我们创作者在可能性无限的情况下进行更深入的实验。对于一些人来说,这可能是一种解放,因为这个生成工具不仅为我们的设计生成了无限量的迭代,还为我们赢得了时间。在某种程度上,这听起来可能有点吓人,现在这种可用的技术可以创建比我们更多的迭代,实现我们可以想象的无限潜力。那么这对我们意味着什么呢?

现代问题需要现代解决方案

“人工智能会取代我的工作吗?”对于设计师来说,这听起来已经过时了,因为它已经得到了“不”的回答,因为创造性的努力是无法在人类层面的经验上实现的(至少现在是这样),而计算创造力仍然是一个不断增长的研究领域。但是,有一个条件。

随着工作场所需求的不断增长,以及一些人感觉竞争加剧,随着平庸成为一张必须远离的脏网,寻求从趋势和相似性中脱颖而出的差异的更深更广实验的需求也在增加。但这不一定是可怕的。例如,该工具在确定动态品牌身份或创建实时数据可视化方面的潜力是巨大而有影响力的,它可能会成为未来的游戏规则改变者,这也伴随着它的缺陷。现实是,虽然它完美创造可能性的能力可能会取代今天的设计师,但它肯定不会取代明天的设计师。因此,今天我们手中有了这个强大的工具,我们如何为明天生存和发展?

乔治城大学计算机科学副教授 Cal Newport 在他的书《深度工作》中解释说,他声称在新经济中有两个群体将蓬勃发展(这是前所未有的增长和技术影响的结果,这些技术正在大规模重组我们当前的经济)那些能够利用智能机器进行创造性工作的人和那些在他们的领域中的明星。**

作为设计师,我们拥有的力量实际上是不可估量的:同时制定和打破规则。决策者不断地在我们每天使用的、看到的和经历的事物中重新定义美。我们未来在设计方面的创造性努力可能是人类和高智能机器之间的开放合作,就像今天我们的设备和软件一样。这个想法现在听起来可能很可笑,但它可能会成为未来的新规范。

卡尔·纽波特还在《深度工作》中慷慨地指出了在新经济中茁壮成长的两个核心能力:快速掌握硬东西的能力和精英水平的生产能力,就质量和速度而言。快速掌握硬东西的能力让你更容易适应新经济的变化。不断发展的技术的加速速度可能会吓到那些跟不上的人,他们更有可能被遗漏,因为需求本身将适应并发展到市场上可以获得的东西。从长远来看,现在花时间学习你没有机会钻研的新技能或软件可能是值得的。擅长你做的与众不同的事情,没有人能像你一样做,这听起来也是一项可靠的投资。技术不会也不会很快停止,我们作为一个物种已经进化了数百万年,这一次也不例外。在这里,我不会也永远不会去反对传统的,动手的媒体,如打印。主要目标是充分利用和适应技术进步。

引用我今年参加的一个设计讲座,“我们每天都在升级我们的设备,为什么我们自己和我们的工作流程不升级呢?”

遗传算法——用例子逐步解释

原文:https://towardsdatascience.com/genetic-algorithm-explained-step-by-step-65358abe2bf?source=collection_archive---------2-----------------------

Photo by David Clode on Unsplash

在本文中,我将通过解决一个非常简单的优化问题来解释遗传算法(GA)是如何工作的。这篇笔记的思想是通过一步一步地解决一个优化问题来理解算法的概念。

让我们使用满足下面表达式的 GA 来估计 a 和 b 的最佳值。

任何优化问题都始于一个目标函数。上面的等式可以写成:

据了解,该函数的值为 0。这个函数是我们的目标函数,目标是估计 a 和 b 的值,使得目标函数的值最小化到零。整个优化过程将在下面的四个主要步骤中进行解释,并用 R 进行编码,用于一次迭代(或生成)。

第一步

这个步骤从猜测 a 和 b 值的初始集合开始,这些集合可能包括也可能不包括最优值。这些数值组被称为“染色体”,这个步骤被称为“初始化群体”。这里人口意味着集合 a 和 b [a,b]。用随机均匀函数产生 a 和 b 的初始值,在这个优化问题中,在 1 到 10 之间产生 6 组 a 和 b 的值。生成初始染色体的 R 代码如下所示。

intial_popu <- NULL
x <- 1
repeat {
  crm <- runif(2,1,10)
  crm <- as.integer(crm)
  intial_popu <- rbind(intial_popu,crm)
  x = x+1
  if (x == 7){
    break
  }
}
rownames(intial_popu) <- c('Cromosome1','Cromosome2','Cromosome3','Cromosome4','Cromosome5','Cromosome6')print(intial_popu)
##            [,1] [,2]
## Cromosome1    5    9
## Cromosome2    9    7
## Cromosome3    9    9
## Cromosome4    3    3
## Cromosome5    7    8
## Cromosome6    8    4

第二步

在这个步骤中,计算每个染色体的目标函数值。目标函数的值也称为适应值。这一步非常重要,被称为“选择”,因为从群体中选择最适合的染色体用于后续操作。

基于适应值,选择具有产生低值适应函数值的可能性(因为我们的目标函数值需要为 0)的更合适的染色体,并允许其在后续世代中存活。一些染色体因不适合产生低适应值而被丢弃。

遗传算法中应用最广泛的选择方法之一是“轮盘赌法”。轮盘赌方法将在下面详细讨论。

轮盘赌方法

轮盘赌是一个饼图,其中每个饼图的值用适合度概率来表示。注意,适应值和适应概率是两个不同的术语。在这个优化问题中,产生低适应值的染色体具有高适应概率。每个染色体的适应度概率是根据适应度值计算的。具有高适应概率的染色体将有更高的机会被选择。以下表达式用于计算单个染色体的适合度概率。

其中, FP =第 i 条染色体的适应度概率, Fi =第 i 条染色体的适应度值

Roulette wheel showing fitness probabilities of chromosomes

在该图中,显示了使用上述表达式计算的六个不同染色体的适合度概率。所有适合度概率的总和必须总是等于 1。

为了选择最合适的染色体,生成了六个随机概率(即生成 0 到 1 之间的六个值)。例如,假设生成的六个概率是:

1 号染色体的 Pr 01 = 0.02
2 号染色体的 Pr 02 = 0.13
3 号染色体的 Pr 03 = 0.40
4 号染色体的 Pr 04 = 0.60
5 号染色体的 Pr 05 = 0.85
6 号染色体的 Pr 06 = 0.96

基于上述概率值在轮盘赌轮盘上的位置进行选择,以累积适合度概率的比例表示选择上述值所在的段进行下一步。请记住每个片段代表其对应的染色体。为了更好的理解,轮盘赌轮盘被拉直,并显示生成的概率值的位置。

Positions of the random fitness probabilities on Roulette wheel

在此图中,染色体 1、2、5、6 是从 6 条染色体中选出的。染色体的顺序从左到右,蓝色是染色体 1,橙色是染色体 6。这些染色体将用于下一步的交叉操作。最后,新的染色体组是:

新染色体-1 =染色体-1
新染色体-2 =染色体-1
新染色体-3 =染色体-2
新染色体-4 =染色体-2
新染色体-5 =染色体-5
新染色体-6 =染色体-6

上面的新染色体是交叉操作的潜在亲本。据观察,染色体-3 和-4 已被丢弃不适合。

对于这个优化问题,下面给出一段 R 代码来选择最适合的染色体(新群体)。

## Function to compute fitness
fit <- function(A){
  a <- A[1]
  b <- A[2]
  return(((2*a^2 + b) - 57))
}
fitness <- apply(intial_popu, 1, FUN = 'fit')
fitting <- 1/(fitness)
probfitting <- fitting/sum(fitting)#generate random values of fitness prob. from 0 to 1
prob_gen <- runif(6,0,1)
newpopulation <- NULL
for(rr in prob_gen){
  sum <- 0
  for(prob in probfitting){
    sum <- sum + prob
    if(rr < sum){
      bin <- prob
      cromosomeS <- which(probfitting == bin, arr.ind = T)
      if(length(cromosomeS)>1){
        cromosomeS <- cromosomeS[1]
      } else{
        cromosomeS <- cromosomeS
      }
      cromname <- paste0('Cromosome',cromosomeS[1])
      newcromosome <- intial_popu[which(rownames(intial_popu) == cromname),]
      break
    }
  }
  newpopulation <- rbind(newpopulation,newcromosome,deparse.level = 2)
}
rownames(newpopulation) <- rownames(intial_popu) print(newpopulation)
##            [,1] [,2]
## Cromosome1    5    9
## Cromosome2    5    9
## Cromosome3    9    7
## Cromosome4    5    9
## Cromosome5    5    9
## Cromosome6    5    9

第三步

这一步叫做'交叉'。在这个步骤中,染色体以基因的形式表达。这可以通过将 a 和 b 的值转换成二进制字符串来实现,这意味着这些值需要用 0 或 1 来表示。例如,9 的二进制形式是[1001]。

什么是跨界?

交叉是由于两个亲代染色体之间的交配而发生的单个(0 或 1)或一组基因(例如[1,0,1])的变化。交叉操作后产生的新染色体称为‘后代’。下图解释了交叉过程。永远记住交叉发生在亲代染色体之间。

Crossover operation explained

在我们目前的优化问题中,从步骤 2 中获得的染色体是用二进制表示的。例如,如果 a = [1,0,0,1]和 b = [1,1,1,0]的二进制表示则染色体[a,b]表示为[1,0,0,1,1,1,1,0]。所有染色体都转换成二进制,写成 6 行 8 列的矩阵形式。

一个重要的参数在这里发挥作用,它被称为交叉参数。该参数值介于 0 和 1 之间。值为 0.5 表示,在六条染色体中,允许三条染色体交叉产生三个后代。

接下来是职位的选择。基因将在染色体的选定位置进行交换。例如,如果染色体是[1,1,0,1,1,0,0,1],位置是 2(左起)。那么值 1 将被相同位置的交配染色体的值所取代。请记住,可以选择多个位置或区段进行交叉。

包含将整数转换成二进制字符串和交叉操作函数的 R 代码块如下所示。

##Function to convert integer to binary
binary <- function(x) {
  i <- 0
  string <- numeric(32)
  while(x > 0) {
    string[32 - i] <- x %% 2
    x <- x %/% 2
    i <- i + 1 
  }
  first <- match(1, string)
  string[first:32] 
}##create binary matrix of 8 cols and 6 rows
binary_popu <- matrix(NA,nrow = 6,ncol = 8)
for(i in 1:nrow(newpopulation)){
 x <- binary(newpopulation[i,1])
binary_popu[i,1:length(x)] <- x
y <- binary(newpopulation[i,2])
binary_popu[i,5:(4+length(y))] <- y
  }
rownames(binary_popu) <- rownames(newpopulation)
cross_paramter <- 0.5
i = 1
crom_cross <- NULL
while(length(crom_cross) < 3){
  cross.crossover.prob <- runif(6,0,1)
  crom_cross <- which(cross.crossover.prob < cross_paramter,arr.ind = T)
  i = i + 1
}
parents <- binary_popu[crom_cross,]
position = 2 ##crossover position
cross_parent <- parents
cross_parent[1,1:position] <- parents[2,1:position]
cross_parent[2,1:position] <- parents[3,1:position]
cross_parent[3,1:position] <- parents[1,1:position]

listofindex <- which(row.names(binary_popu) %in% row.names(cross_parent))
offSpring <- binary_popu
offSpring[listofindex,] <- cross_parentprint(offSpring) ##offspring after crossover
##            [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## Cromosome1    1    0    1   NA    1    0    0    1
## Cromosome2    1    0    1   NA    1    0    0    1
## Cromosome3    1    0    0    1    1    1    1   NA
## Cromosome4    1    0    1   NA    1    0    0    1
## Cromosome5    1    0    1   NA    1    0    0    1
## Cromosome6    1    0    1   NA    1    0    0    1

步骤 4

这一步叫做“突变”。突变是改变基因值的过程,即用 0 代替 1,反之亦然。例如,如果后代染色体是[1,0,0,1],突变后就变成了[1,1,0,1]。在这里,后代染色体的第二个值被决定突变。它已从 0 更改为 1。

现在的问题是,需要改变多少基因,在什么位置改变。突变参数决定了多少基因将被突变。如果突变参数为 0.1(通常保持低值)。那么允许总基因的 0.1 倍变异。在本优化问题中,基因的总数是 48(6×8)。所以允许 4.8 ~ 5 个基因突变。

关于突变位置,选择行和列的 5 个随机值。突变过程如下图所示。

Illustration of mutation process

变异后,二进制染色体被转换成整数形式,并计算适应值。如果任何一个染色体产生的目标适应值等于 0,我们就此打住。否则,通过将突变染色体等同于新群体,该过程将从步骤 2 重复到步骤 4。

这一步的 R 代码块如下所示。

mutation_paramter <- 0.09
no.of.mutations <- 4  ## Calculated as nrow(offSpring)*ncol(offSpring)*mutation_paramter

randrow <- round(runif(no.of.mutations,1,nrow(offSpring)))
rancol <-  round(runif(no.of.mutations,1,ncol(offSpring)))

## Now get the offsprings by mutating at above position
for(r in 1:length(randrow)){
  if(is.na(offSpring[randrow[r],rancol[r]])){
    offSpring[randrow[r],rancol[r]] <- NA
  }else{
    if(offSpring[randrow[r],rancol[r]] == 0){
      offSpring[randrow[r],rancol[r]] <- 1
    }else{
      offSpring[randrow[r],rancol[r]] <- 0
    }
  }
}

print(offSpring) ## Chromosomes after mutation
##            [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
## Cromosome1    1    0    1   NA    1    0    0    1
## Cromosome2    1    0    1   NA    1    0    0    1
## Cromosome3    1    0    0    1    1    1    0   NA
## Cromosome4    1    0    1   NA    0    0    0    1
## Cromosome5    1    0    1   NA    1    0    0    1
## Cromosome6    1    1    1   NA    1    0    0    1## Now convert binary back to integer
binary_decimal = function(base_number, base = 2) {
  split_base = strsplit(as.character(base_number), split = "")
  return(sapply(split_base, function(x) sum(as.numeric(x) * base^(rev(seq_along(x) - 1)))))
}
offSpring_inter <- matrix(NA,6,2)
for(i in 1:nrow(offSpring)){
  a <- offSpring[i,1:4]
  a <- na.omit(a)
  a <- as.numeric(paste(a, collapse = ""))
  a <- binary_decimal(a)
  b <- offSpring[i,5:8]
  b <- na.omit(b)
  b <- as.numeric(paste(b, collapse = ""))
  b <- binary_decimal(b)
  offSpring_inter[i,1] <- a
  offSpring_inter[i,2] <- b
}
rownames(offSpring_inter) <- rownames(offSpring)
## Chromosomes converted back to integer after end of 1st of generation
print(offSpring_inter)
##            [,1] [,2]
## Cromosome1    5    9
## Cromosome2    5    9
## Cromosome3    9    6
## Cromosome4    5    1
## Cromosome5    5    9
## Cromosome6    7    9

这个优化问题的最终结果如下所示,其中计算了 10 代的适应值。染色体 6 即[a,b] = [5,7]是产生适应值等于 0 的最优解

## Iteration:  1 
## Cromosome1 Cromosome2 Cromosome3 Cromosome4 Cromosome5 Cromosome6 
##        -30         76        -17        -18         -3        -45 
## Iteration:  2 
## Cromosome1 Cromosome2 Cromosome3 Cromosome4 Cromosome5 Cromosome6 
##         -3         45        -40        -42        -30         -3 
## Iteration:  3 
## Cromosome1 Cromosome2 Cromosome3 Cromosome4 Cromosome5 Cromosome6 
##         -3         -3         -3         -3         -7         -3 
## Iteration:  4 
## Cromosome1 Cromosome2 Cromosome3 Cromosome4 Cromosome5 Cromosome6 
##         -3         -2         -2         -3         -3         -3 
## Iteration:  6 
## Cromosome1 Cromosome2 Cromosome3 Cromosome4 Cromosome5 Cromosome6 
##         -3         -3         -3         -3         -2         -3 
## Iteration:  7 
## Cromosome1 Cromosome2 Cromosome3 Cromosome4 Cromosome5 Cromosome6 
##         -3        -20         -3         -3         -3         -2 
## Iteration:  8 
## Cromosome1 Cromosome2 Cromosome3 Cromosome4 Cromosome5 Cromosome6 
##         -3         -2         -3         -2         -2         -2 
## Iteration:  9 
## Cromosome1 Cromosome2 Cromosome3 Cromosome4 Cromosome5 Cromosome6 
##         46         -2         -2        -20         -2         -2 
## Iteration:  10 
## Cromosome1 Cromosome2 Cromosome3 Cromosome4 Cromosome5 Cromosome6 
##         -3        -19         -1         47         -1          0## The final set of Chromosomes
##            [,1] [,2]
## Cromosome1    5    4
## Cromosome2    4    6
## Cromosome3    5    6
## Cromosome4    7    6
## Cromosome5    5    6
## Cromosome6    5    7

参考

使用进化算法的多目标优化(2005)

遗传算法与回溯:N 皇后问题

原文:https://towardsdatascience.com/genetic-algorithm-vs-backtracking-n-queen-problem-cdf38e15d73f?source=collection_archive---------13-----------------------

回溯求解器和遗传算法性能的比较。

几个月前,我熟悉了遗传算法。我开始阅读它,我对它感到非常惊讶。遗传算法解决的最著名的问题之一是 n 皇后问题。我使用 python 3 实现了我的遗传解算器,加上著名的老式回溯解算器。我实现了一个象棋类(回溯求解器)和一个 GeneticChess 类(遗传求解器)。这些类都有一个二维列表的属性板。列表的每一行都用 N 个零填充。

回溯求解器

如你所知,回溯求解器是一个简单的函数,它通过在棋盘的第一行放置一个皇后来开始解决问题,并试图将第二个皇后放在第二行,这样就不会与第一个皇后冲突。它继续一行一行地把皇后放在棋盘上,直到把最后一个放在第 n 行。如果它不能填充一行中的任何瓷砖,它会返回并改变前一行皇后的位置。

下面的树描述了回溯算法如何解决 4 皇后问题。

4-queen backtracking solution

回溯求解器将为我们找到解决方案。但是随着 N 的增加,它变得更慢。如果 N=25,则需要 322.89 秒才能找到答案,而当 N=26 时,则需要永远的时间!因此,需要一种能更快找到解决方案的方法。这是回溯法:

**def solveBackTracking(self,col):****if col >= self.size:
    self.solutions.append(self.board)
    return True****for i in range(self.size):
    if self.isSafe(i,col):
    self.board[i][col] = 1
        if self.solveBackTracking(col+1) == True:
            return True** **self.board[i][col] = 0****return False**

遗传算法求解器

一种方法是使用遗传算法来解决这个问题。那么遗传算法是如何工作的呢?

基本想法来自于自然界发生的事情。在一个环境中,存在一些染色体(或一族)。这些染色体结合在一起,在环境中创造了一些孩子。新的染色体是其父母 DNA 的结合,并且它自身也发生了变异。当然,环境有人口限制。因为每条染色体都是独一无二的,所以可以理解的是,有些染色体比其他的强。根据自然法则,强壮的生物会存活到下一代,而弱小的会死去。因此,我们期望每一代都由更强壮的染色体组成。这就是遗传算法的工作原理。

应采取以下步骤来实现遗传算法:

  1. 创建染色体表示
  2. 创建一个效用函数
  3. 创建一个交叉函数
  4. 创建一个变异函数
  5. 创造环境

现在让我们进入这些步骤来创建我们的遗传算法。

第一步:染色体

基本上,染色体(也称为 gen)是一个解决方案的表示,不管它是否有效。我们如何表示一个 n 皇后解?一种方法是创建一个用 0 填充的二维列表,然后用 N 个代表女王位置的 1 填充它。这可能是第一个想到的东西,但实际上并不好。一个更好更简单的表示是染色体是一个长度为 n 的列表,每个索引指定了棋盘的一列。每个索引的值都在 0 到 N-1 之间,表示一列中皇后的行。

第二步:效用函数

效用函数是决定一个解决方案有多好的函数。所以这个函数把 gen 作为它的参数,并返回一个数字,这个数字就是效用。在这种情况下,我们的效用函数将基于皇后位置来评估冲突的数量。它是每个皇后左侧冲突数量的总和。因此,如果效用函数返回 0,我们知道板上没有冲突,因此,我们有我们的解决方案。

**def utilityFunction(self,gen):** **hits = 0
    board = self.createBoard(self.size)
    self.setBoard(board,gen)
    col = 0** **for dna in gen:
        try:
            for i in range(col-1,-1,-1):
                if board[dna][i] == 1:
                    hits+=1

        for i,j in zip(range(dna-1,-1,-1),range(col-1,-1,-1)):
            if board[i][j] == 1:
                hits+=1
        for i,j in zip(range(dna+1,self.size,1),range(col-1,-1,-1)):
            if board[i][j] == 1:
                hits+=1
        col+=1
     return hits**

第三步:交叉功能

我说过,孩子的染色体是父母 DNA 的组合。这个过程叫做交叉。这个函数是使遗传算法比回溯求解器更快的关键函数。存在许多交叉函数,你甚至可以实现自己的函数。该函数以两条染色体作为参数。这些是父母,他们将创造新的孩子染色体。每当一个列表中的两个元素之差小于 2 时,我决定将第一个列表中的元素与第二个列表中的元素交换。

**def crossOverGens(self,firstGen,secondGen):

    for i in range(1,len(firstGen)):
        if abs(firstGen[i-1] — firstGen[i])<2:
            firstGen[i],secondGen[i] = secondGen[i],firstGen[i]
        if abs(secondGen[i-1] — secondGen[i])<2:
            firstGen[i],secondGen[i] = secondGen[i],firstGen[i]**

第四步:变异函数

在交叉过程之后,子对象被创建。现在,孩子试图以某种方式改变自己,以降低效用值。交叉后,gen 中的一些元素可能是多余的(例如[1,1,2,3])。突变功能将删除冗余元素,并用 gen 中未使用的元素填充它们。另外,将从染色体的左侧和右侧选择两个随机元素,并将它们交换。这种方法可能会降低效用。

**def MutantGen(self,gen):** **bound = self.size//2
    from random import randint as rand
    leftSideIndex = rand(0,bound)
    RightSideIndex = rand(bound+1,self.size-1)
    newGen = []
    for dna in gen:
        if dna not in newGen:
            newGen.append(dna)
    for i in range(self.size):
        if i not in newGen:
            newGen.append(i)** **gen = newGen
     gen[leftSideIndex],gen[RightSideIndex] =      gen[RightSideIndex],gen[leftSideIndex]
     return gen**

5 .环境

现在我们有了我们的功能,让我们创造我们的环境和它无情的规则。首先我们初始化第一代染色体,它们只是一些随机的染色体。之后,检查所有染色体,以找出解决方案是否已经存在。如果它不存在,染色体开始创造孩子。因为群体超过了它的极限,所以计算每个染色体的效用。具有较高效用(较高冲突)的那些将从环境中移除,而具有较低效用的那些将被选择。现在第二代产生了。这个循环继续创造下一代,直到找到解决方案。

**def solveGA(self):
    self.initializeFirstGenereation()
    for gen in self.env:
        if self.isGoalGen(gen):
            return gen
    while True:
        self.crossOverAndMutant()
        self.env = self.makeSelection()
        if self.goalIndex >= 0 :
            try:
                return self.goal
            except IndexError:
                 print(self.goalIndex)
        else:
            continue**

结果

正如我提到的,回溯求解器最多只能解决 N=25 的问题,这需要大约 322.89 秒才能找到答案。GA 求解器仅用 1.83 秒就找到了 N=25 的解。我实现的交叉和变异函数不是最好的算法,但我还是很快得到了结果。我测试了从 N=4 到 N=66 的 GA 解算器,对于 N=66,该算法求解该问题的最大时间为 125.93 秒。我甚至试过 N=80,在 122.82 秒内得到解!这太神奇了!该算法基于随机数。它可能看起来比回溯求解器更糟糕,但结果却非常有趣。我强烈建议你自己实现 B-Solver 和 GA-Solver,看看遗传算法的魔力。你可以在我的 Github 链接找到我的代码。

希望这篇文章对你有帮助!

基因组数据、区块链和货币

原文:https://towardsdatascience.com/genomic-data-blockchain-and-money-a6e5597ebe3e?source=collection_archive---------22-----------------------

基因组数据市场即将出现。买卖基因组数据将比以往更加容易

基因检测和测序一年比一年便宜。半导体革命加上大量的资金已经导致了更快的 DNA 测试。

Photo by William Moreland on Unsplash

很大程度上,由于 DNA 测试和测序成本的降低,接受测试越来越受欢迎。这一趋势在对自己祖先感兴趣的消费者、对研究感兴趣的科学界和对金钱感兴趣的制药行业中同样流行。后者正在花费数亿美元购买基因组数据,以了解各种基因对不同药物疗法的反应,这意味着你的基因组数据可能会被出价最高的人收购。

金钱游戏

如果数据是新油,基因数据就是这种油的无铅过滤高辛烷值版本。像 23andMe 和杰诺斯这样的公司向做基因测试的顾客收费。一旦他们有了顾客的基因数据,他们就把它卖给制药和研究公司。拥有其数据的人每次请求可以收到 50-200 美元。

[## 23andMe 从葛兰素史克获得 3 亿美元用于开发新药

总部位于伦敦的制药巨头葛兰素史克公司正与旧金山遗传学初创公司 23andMe 合作,开发…

www.forbes.com](https://www.forbes.com/sites/matthewherper/2018/07/25/23andme-gets-300-million-boost-from-glaxo-to-develop-new-drugs/)

所有这些初创公司都因其潜力获得了大量资金。人类有 99.5%的相同 DNA。这意味着只有 0.5%的基因组定义了人类之间的独特差异。这组差异被理解为遗传变异,并通过你基因中的变异数量来量化。根据社区调节的参考基因组测量变异。

虽然一些消费者可能选择简单地将他们的匿名 DNA 数据捐赠给科学,以帮助推进医学研究,但其他人可能希望自己赚钱,而不是让检测公司利用消费者提供的数据..瑞士制药巨头罗氏公司的美国分公司提出支付高达 6000 万美元,以获取 23andMe 数据库中约 3000 名帕金森病患者的数据。这笔交易为每套数据设定了 2 万美元的价值。

[## 23andMe 以 6000 万美元的价格向基因泰克出售帕金森病患者的 DNA 数据

总部位于加州的个人基因公司 23andMe 正在向生物技术公司 Genentech 出售其客户的数据

www.techtimes.com](http://www.techtimes.com/articles/25237/20150108/23andme-to-sell-dna-data-of-parkinsons-customers-to-genentech-for-60-million.htm)

区块链和交易

虽然一些公司如 23andme 和 genos 提供基因检测以及出售数据的资金,但某些其他公司只是专注于创建这些数据的交易网络。

一家名为 Zenome 的公司计划为网络参与者提供的基因组数据建立一个分散的存储系统,并在内部加密货币的帮助下提供财政支持。他们的愿景是在网络内开始基因组和个人数据的自由交换。将有可能找到一个人,他具有特定的(你感兴趣的)眼睛颜色、年龄、体重、国籍和对他的基因组信息的访问权(对基因组的非敏感部分)。

https://zenome.io/about/

另一家类似的初创公司 EncrypGen 已经开始交易其 DNA 令牌。EncrypGen 的基因链是为两类人服务的

  1. 那些已经做了或想要做基因测试,但希望更好地控制自己的数据以及通过匿名向科学家出售数据获利的可能性的人,以及
  2. 研究人员希望更好地访问匿名数据,并能够向直接使用其数据的人支付费用。

EncrypGen

有了所有这些选择,又有一只独角兽引领着这个领域。在从 Khosla Ventures 牵头的 A 轮融资中筹集了 430 万美元后,Nebula Genomics 不再需要个人基因组公司作为数据所有者和数据购买者之间的中间人。相反,数据所有者可以从星云测序设施或其他来源获得他们的个人基因组数据,加入星云区块链的点对点网络,并直接与数据购买者联系。这种模式降低了有效的测序成本,并增强了对个人基因组数据的保护。

Left — The popular Model | Right — The Nebula

更有趣的是,他们与 Veritas Genetics 合作,Veritas Genetics 是一家获得 5100 万美元资金的初创公司,艾莉·莉莉等也是投资者。相比之下,EncrypGen 筹集了大约 100 万美元,很容易看出 Nebula 有更大的机会将“基因组区块链网络”变成现实。

无论基因组测序的状况如何,它的市场已经越来越受欢迎。看看这些市场是反乌托邦还是最终造福人类,将会很有趣。

轻轻潜入卷积神经网络背后的数学

原文:https://towardsdatascience.com/gentle-dive-into-math-behind-convolutional-neural-networks-79a07dd44cf9?source=collection_archive---------0-----------------------

神经网络之谜第五部分

自动驾驶、医疗保健或零售只是计算机视觉让我们实现一些直到最近还被认为是不可能的事情的一些领域。今天,无人驾驶汽车或自动化杂货店的梦想听起来不再那么超前了。事实上,我们每天都在使用计算机视觉——当我们用面部解锁手机或在社交媒体上发布照片之前自动修饰照片时。卷积神经网络可能是这一巨大成功背后最关键的组成部分。这一次,我们将扩大我们对神经网络如何与特定于 CNN 的想法一起工作的理解。请注意,这篇文章将包括相当复杂的数学方程,但是如果你对线性代数和微分不熟悉,不要气馁。我的目标不是让你记住那些公式,而是给你提供下面正在发生的事情的直觉。

附注:我第一次决定用一个音频版本来丰富我的艺术作品,我诚挚地邀请你来听听。你会在上面找到 Soundcloud 的链接。在这篇文章中,我主要关注 CNN 的典型问题。如果你正在寻找更多关于深度神经网络的一般信息,我鼓励你阅读我在本系列的其他帖子。像往常一样,带有可视化和注释的完整源代码可以在我的 GitHub 上找到。开始吧!

介绍

过去我们了解了所谓的密集连接神经网络。这些网络的神经元被分成若干组,形成连续的层。每个这样的单元连接到相邻层的每个单个神经元。下图显示了这种架构的一个示例。

Figure 1. Densely connected neural network architecture

当我们基于一组有限的已定义特征来解决分类问题时,这种方法非常有效——例如,我们根据足球运动员在比赛中记录的统计数据来预测他的位置。然而,当处理照片时,情况变得更加复杂。当然,我们可以将每个像素的亮度视为一个独立的特征,并将其作为输入传递给我们的密集网络。不幸的是,为了让它适用于典型的智能手机照片,我们的网络必须包含数千万甚至数亿个神经元。另一方面,我们可以缩小照片,但在这个过程中我们会丢失有价值的信息。我们马上发现传统策略对我们毫无用处——我们需要一种新的巧妙方法来使用尽可能多的数据,同时减少必要的计算和参数数量。这就是 CNN 发挥作用的时候。

数字照片数据结构

让我们先花一分钟解释一下数码图像是如何存储的。你们大多数人可能意识到它们实际上是巨大的数字矩阵。每个这样的数字对应于单个像素的亮度。在 RGB 模型中,彩色图像实际上由三个这样的矩阵组成,对应于三个颜色通道——红色、绿色和蓝色。在黑白图像中,我们只需要一个矩阵。每个矩阵都存储从 0 到 255 的值。这个范围是存储关于图像的信息的效率(256 个值完全适合 1 个字节)和人眼的灵敏度(我们区分同一颜色的有限数量的阴影)之间的折衷。

Figure 2. Data structure behind digital images

盘旋

K ernel 卷积不仅用于 CNN,也是许多其他计算机视觉算法的关键元素。这是一个过程,我们采用一个小的数字矩阵(称为内核或过滤器),我们把它传递到我们的图像,并根据过滤器的值进行转换。根据以下公式计算后续特征图值,其中输入图像用 f 表示,我们的核用 h 表示。结果矩阵的行和列的索引分别用 mn 标记。

Figure 3. Kernel convolution example

在将我们的过滤器放置在一个选定的像素上之后,我们从内核中取出每个值,并将它们与图像中相应的值成对相乘。最后,我们总结所有内容,并将结果放在输出特征图的正确位置。上面我们可以看到这样的操作在微观尺度下是什么样子,但更有趣的是,我们可以通过在完整的图像上执行它来实现它。图 4 显示了几种不同滤波器的卷积结果。

Figure 4. Finding edges with kernel convolution [Original Image]

有效且相同的卷积

正如我们在图 3 中看到的,当我们用 3x3 内核对 6x6 图像执行卷积时,我们得到了 4x4 特征图。这是因为只有 16 个独特的位置,我们可以在这张图片中放置我们的过滤器。由于我们每次进行卷积时,图像都会缩小,所以在图像完全消失之前,我们只能进行有限次数的卷积。此外,如果我们观察我们的内核如何在图像中移动,我们会发现位于外围的像素的影响远小于图像中心的像素。这样我们会丢失图片中包含的一些信息。下面你可以看到像素的位置如何改变它对特征图的影响。

Figure 5. Impact of pixel position

为了解决这两个问题,我们可以用额外的边界填充我们的图像。例如,如果我们使用 1px 填充,我们将照片的大小增加到 8x8,这样,使用 3x3 滤镜的卷积输出将是 6x6。通常在实践中,我们用零填充额外的填充。根据我们是否使用填充,我们处理两种类型的卷积——有效卷积和相同卷积。命名是相当不幸的,所以为了清楚起见: Valid —意味着我们使用原始图像,Same —我们使用它周围的边框,这样输入和输出的图像大小相同。在第二种情况下,填充宽度应满足以下等式,其中 p 是填充,而 f 是滤波器尺寸(通常为奇数)。

步进卷积

Figure 6. Example of strided convolution

在前面的例子中,我们总是将内核移动一个像素。然而,步长也可以被视为卷积层超参数之一。在图 6 中,我们可以看到如果使用更大的步幅,卷积会是什么样子。当设计我们的 CNN 架构时,如果我们希望感受野重叠更少,或者如果我们希望我们的特征图的空间维度更小,我们可以决定增加步长。考虑到填充和步幅,输出矩阵的维数可以使用下面的公式计算。

向第三维度的过渡

体积上的变换是一个非常重要的概念,它不仅允许我们处理彩色图像,更重要的是允许我们在一个图层中应用多个滤镜。第一个重要的规则是,滤镜和你要应用它的图像,必须有相同数量的通道。基本上,我们的操作与图 3 中的例子非常相似,不过这次我们将三维空间中的值对相乘。如果我们想在同一个图像上使用多个过滤器,我们分别对每个过滤器进行卷积,将结果一个叠在另一个上面,然后将它们组合成一个整体。接收到的张量(我们可以称之为 3D 矩阵)的维数满足以下等式,其中: n —图像大小, f —滤波器大小, nc —图像中的通道数,p—使用的填充, s —使用的步距, nf —滤波器数。

Figure 7. Convolution over volume

卷积层

使用我们今天所学的一切,建立一个单一层次的 CNN 的时候终于到了。我们的方法与我们用于密集连接神经网络的方法几乎相同,唯一的区别是,这次我们将使用卷积,而不是使用简单的矩阵乘法。正向传播包括两个步骤。第一个是计算中间值 Z ,它是将前一层的输入数据与 W 张量(包含滤波器)卷积,然后加上偏置 b 得到的结果。第二种是将非线性激活函数应用于我们的中间值(我们的激活用 g 表示)。矩阵方程的爱好者会在下面找到合适的数学公式。如果你对正在讨论的任何操作不清楚,我强烈推荐我的上一篇文章,其中我详细讨论了密集连接的神经网络内部正在发生的事情。顺便说一下,在下面的插图中你可以看到一个小的可视化,描述了方程中使用的张量的维数。

Figure 8. Tensors dimensions

连接切割和参数共享

在文章的开头,我提到密集连接的神经网络不擅长处理图像,因为需要学习大量的参数。现在我们已经了解了卷积是怎么一回事,让我们来考虑它如何让我们优化计算。在下图中,2D 卷积以略微不同的方式进行了可视化-用数字 1-9 标记的神经元形成接收后续像素亮度的输入层,而单位 A-D 表示计算的要素地图元素。最后但同样重要的是,I-IV 是来自内核的后续值——这些必须学习。

Figure 9. Connections cutting and parameters sharing

现在,让我们来关注卷积层的两个非常重要的属性。首先,你可以看到,并不是所有连续两层中的神经元都是相互连接的。例如,单元 1 只影响 a 的值其次,我们看到一些神经元共享相同的权重。这两个特性意味着我们需要学习的参数要少得多。顺便说一下,值得注意的是,来自过滤器的单个值影响特征图的每个元素-这在反向传播的上下文中是至关重要的。

卷积层反向传播

任何试图从头开始编写自己的神经网络的人都知道,前向传播不到成功的一半。真正的乐趣是在你想回去的时候开始的。如今,我们不需要为反向传播而烦恼——深度学习框架为我们做了这件事,但我觉得了解引擎盖下发生的事情是值得的。就像在密集连接的神经网络中一样,我们的目标是计算导数,然后使用它们在一个称为梯度下降的过程中更新我们的参数值。

在我们的计算中,我们将使用链式法则——我在以前的文章中提到过。我们希望评估参数变化对最终特征图的影响,以及随后对最终结果的影响。在我们开始讨论细节之前,让我们就我们将使用的数学符号达成一致——为了让我的生活更轻松,我将放弃偏导数的完整符号,而采用下面可见的简化符号。但是请记住,当我使用这个符号时,我总是指成本函数的偏导数。

Figure 10. Input and output data for a single convolution layer in forward and backward propagation

我们的任务是计算与当前层参数相关联的导数 dW[l]db[l] - ,以及将传递给上一层的 dA[ l -1] - 的值。如图 10 所示,我们接收 dA[l] 作为输入。当然,张量 dWWdbb 以及 dAA 的尺寸分别是相同的。第一步是通过将我们的激活函数的导数应用于我们的输入张量来获得中间值 dZ[l] 。根据链式法则,这个操作的结果将在后面使用。

现在,我们需要处理卷积本身的反向传播,为了实现这一目标,我们将利用一种称为全卷积的矩阵运算,如下图所示。注意,在这个过程中,我们使用了内核,我们之前将它旋转了 180 度。这个运算可以用下面的公式来描述,其中滤波器用 W 来表示, dZ[m,n] 是一个标量,属于从前一层得到的偏导数。

Figure 11. Full convolution

池层

除了卷积层,CNN 经常使用所谓的池层。它们主要用于减少张量的大小和加速计算。这一层很简单——我们需要把我们的图像分成不同的区域,然后对每一部分执行一些操作。例如,对于 Max Pool 层,我们从每个区域中选择一个最大值,并将其放在输出中的相应位置。与卷积层的情况一样,我们有两个可用的超参数——过滤器大小和步幅。最后但同样重要的是,如果您正在为多通道图像执行池化,则每个通道的池化应该单独完成。

Figure 12. Max pooling example

池层反向传播

在这篇文章中,我们将只讨论最大池反向传播,但是我们将学习的规则(稍作调整)适用于所有类型的池层。由于在这种类型的层中,我们没有任何必须更新的参数,我们的任务只是适当地分发 gradiwents。正如我们所记得的,在最大池的前向传播中,我们从每个区域中选择最大值,并将它们传递到下一层。因此,很明显,在反向传播期间,梯度不应该影响没有包括在正向传递中的矩阵元素。在实践中,这是通过创建一个记住第一阶段中使用的值的位置的掩码来实现的,我们稍后可以利用它来转移梯度。

Figure 13. Max pooling backward pass

结论

如果你设法来到这里,祝贺你。非常感谢你花时间阅读这篇文章。如果你喜欢这篇文章,考虑把它分享给你的朋友,或者两个或五个朋友。如果你注意到思维方式、公式、动画或代码有任何错误,请告诉我。

这篇文章是“神经网络的奥秘”系列的另一部分,如果你还没有机会,请阅读其他文章。此外,如果你喜欢我目前的工作,请在 Twitter 和 Medium 上关注我,并在 GitHub 和 Kaggle 上查看我正在进行的其他项目。保持好奇!

回声状态网络简介

原文:https://towardsdatascience.com/gentle-introduction-to-echo-state-networks-af99e5373c68?source=collection_archive---------8-----------------------

也是油藏计算的介绍

本帖将回答以下问题:

  1. 什么是回声状态网络?
  2. 为什么以及何时应该使用回应状态网络?
  3. python 中的简单实现示例

下图是对论文多变量时间序列表示和分类的储层计算方法的简化,但它很好地抓住了 ESNs 的要点。每个组件将在下面的章节中详细介绍。

Echo State Networks are recurrent networks. f is a nonlinear function (such as tanh) which makes the current state dependent on the previous state and the current input

什么是回声状态网络?

回声状态网络是一种递归神经网络,是油藏计算框架的一部分,具有以下特殊性:

  • 输入-隐藏层('水库'): Win 之间的权重以及'水库': Wr 之间的权重是随机分配的是不可训练的
  • 输出神经元的权重(“读出”层)是可训练的(,可以学习,因此网络可以复制特定的时间模式
  • 隐藏层(或“储层”)与输入的连接非常稀疏(通常为< 10% connectivity)
  • the reservoir architecture creates a recurrent 非线性嵌入(下图中的 H )),然后可以连接到所需的输出,这些最终权重是可训练的
  • 可以将嵌入连接到不同的预测模型(用于分类问题的可训练神经网络或岭回归器/SVM)

油藏计算

储层计算是神经网络的扩展,其中输入信号连接到固定(不可训练)和随机动态系统(储层),从而创建更高维度的表示(嵌入)。这种嵌入然后通过可训练单元连接到期望的输出。

储层计算的非递归等价物是极限学习机,仅由仅具有可训练读出层的前馈网络组成。

工作流程

对于形状为 N,T,V 的输入,其中 N 是观测值的数量,T 是时间步长的数量,V 是变量的数量,我们将:

  • 选择储层 R 的大小和控制连接稀疏性水平的其他参数,如果我们想要对泄漏建模,维数减少后的理想组件数量等
  • 通过从随机二项式分布中取样,生成(V,R)个输入权重 Win
  • 通过从具有给定密度的均匀分布中取样,生成(R,R)储层权重 Wr ,该参数设置了稀疏程度
  • 将高维状态表示 H 计算为当前时间步长(N,V)的输入乘以内部权重加上先前状态再乘以储层矩阵(R,R)的非线性函数(通常为 tanh)
  • 可选地,我们可以运行降维算法,例如 PCA 到 D 分量,这将 H 带到(N,T,D)
  • 通过使用例如整个储层和训练回归器来映射状态 t 到 t+1,创建输入表示:一个表示可以是所有计算的斜率和截距的矩阵。另一种选择是使用 H 的平均值或最后值
  • 通过使用可训练的 NN 结构或通过使用其他类型的预测器,将这种嵌入连接到期望的输出。上述论文建议使用岭回归

为什么以及何时应该使用回声状态网络?

  • 传统的神经网络结构受到消失/爆炸梯度问题的困扰,因此,隐藏层中的参数要么变化不大,要么导致数值不稳定和混沌行为。回声状态网络没有这个问题
  • 传统的神经网络结构计算昂贵,回声状态网络非常快,因为在储层上没有反向传播相位
  • 传统的神经网络会被分叉破坏
  • ESN 非常适合处理混沌时间序列

履行

该论文提供了一个简洁的、有良好文档记录的流水线实现,提出了每一步的各种方法(权重初始化方案、维度减少、输入表示、读出层)。我通过精选步骤创建了更简化的版本,如 PCA、基于岭回归的储层表示和输出的线性回归连接,因为这些选项在我的输入中表现最佳。我在这里提供了这个版本。

参考

https://github . com/FilippoMB/Reservoir-Computing-framework-for-variable-time-series-class ification

https://www . research gate . net/post/what _ is _ the _ realition ship _ between _ deep _ learning _ methods _ and _ reservoir _ computing _ if _ any

Geo 实验,A/B 测试的完美补充

原文:https://towardsdatascience.com/geo-experiments-the-perfect-complement-to-a-b-testing-1e0939996d26?source=collection_archive---------25-----------------------

它是什么,对你的营销有什么帮助?

这将是一个由三部分组成的系列,讨论地理实验及其在营销中的应用。

第一部分:它是什么?它对你的营销有什么帮助?

第二部分:理解地球物理实验背后的数学原理

第三部分:Geo 实验应用实例及 R 代码

测试和学习的面包和黄油

A/B 测试(又名分割测试)对于帮助营销人员消除猜测并做出基于数据的决策至关重要。对于大多数营销人员来说,这是着陆页优化的形式。您将流量分成不同的组,向其中一个组展示页面的一些更改,同时保持其他组的所有内容不变,测量感兴趣的特定指标(注册率、点击率等)的差异,并确定两组之间的差异是否具有统计学意义。一些付费营销专家可能在谷歌广告或脸书广告中做过 A/B 测试,在这些广告中,受众受到不同广告格式或广告文案的影响。两者的方法相似,但应用方式不同。

那么为什么营销人员要进行 A/B 测试呢?这是营销人员戴上科学家帽子的地方。营销人员进行 A/B 测试,以了解某件事的因果和增量影响,无论是登录页面的变化还是脸书营销活动的广告文案。他们想知道,对于他们所做的这件事,它的增量影响是什么,这样他们就可以对下一步该做什么做出明智的决定。

A/B 测试已经成为营销人员进行测试和学习的基础。但是如果我让你设计一个 A/B 测试来回答下面的每个问题,你会怎么做呢?

  1. 了解脸书活动对客户转化的增量影响?(也就是说,我想知道对整体客户转化率的实际影响,而不是你的脸书业务经理在转化率栏下报告的内容)
  2. 了解广告牌广告对网站访问量的影响

考虑一下吧。

让我们仔细检查每个问题,看看为什么我们最喜欢的 A/B 测试不起作用:

  1. 您可以 A/B 测试您的脸书活动,以了解 CTR 或参与度等指标的增量影响,但客户转化率略有不同。为什么?因为在你的整个测量框架下,存在着一个以非完美方式分配信用的归因模型。因此,即使您正在运行 A/B 测试来了解客户转换,它也只能为您提供两个活动之间的相对比较。它没有提供该活动是否带来增量客户的总体视图。你不知道你是否只是从其他渠道获得了客户转化。
  2. 这个很简单。首先,您没有任何直接的响应指标可以衡量。其次,你计划如何创建你的控制和测试组?你计划在一个经过广告牌的城市里,蒙住一半人口的眼睛,以确保他们看不到广告牌,而让另一半人看到它吗?

当您无法控制您的人口或没有感兴趣的度量标准的直接度量时,A/B 测试不起作用。虽然 A/B 测试是营销人员的主要工作,但我们也看到了它的局限性,以及需要额外的工具来帮助营销人员回答重要的问题。

面包和橄榄油:地理实验

有时候面包和黄油是不够的,你必须改变一下。面包和橄榄油通常也搭配得很好。那么 Geo 实验到底是什么?简而言之,地理实验就像 A/B 测试,但是使用地理来定义你的控制和治疗组,而不是个人或网络 cookies。在 Geo 实验中,地理区域被分为治疗组和对照组。治疗组中的区域暴露于市场干预,而对照组中的区域保持现状。营销干预持续一段时间,并观察响应度量。想法是检测在治疗区域中的响应度量中是否有增量提升。

让我们以上面的脸书问题为例,假设我们正在美国开展广告活动。首先,我们在美国随机选择一组城市,将他们分为治疗组和对照组。就像 A/B 测试一样,随机化是实验设计的关键部分。然后在脸书业务经理中,我们将活动设置为仅在治疗组的城市中运行。我们在一段时间内开展活动,并通过比较对照组和治疗组之间的差异来衡量获得的增量客户(不知道归因模型)。例如,我们可能会看到这样的内容:

这是由谷歌开发的 GeoexperimentsResearch R 包制作的图表,该包实现了 Geo Experiment 方法,并提供了一种简单的方法来进行分析。我将在第 3 部分演示如何使用这个 R 包!但在较高层次上,y 轴可以是客户转化率。在我们的示例中,x 轴分为三个不同的时间段:

  • 测试前期(2 月 5 日—3 月 31 日):活动开始前
  • 测试期(4 月 1 日—4 月 28 日):活动进行期间
  • 冷却期(2005 年 4 月 29 日-5 月 5 日):活动停止运行,但可能会有一个广告涓涓细流挥之不去的影响

上图显示了观察到的响应度量随时间的变化与预测的反事实的对比。我们将在第 2 部分详细讨论这一点,但本质上,如果营销活动没有进行,我们会观察到反事实。中间的图说明了按天估算的升力的观察值和反事实值之间的差异。最后,下图是我们在实验中观察到的总升力。

我上面的解释是对方法论的过度简化。为了真正了解发生了什么,你需要进入引擎盖内,看看发动机。Geo 实验背后的方法和数学不同于传统的 A/B 测试,但总体思路是相似的。如前所述,我将把数学的详细解释留到本系列的第 2 部分。我将在第 2 部分介绍的方法是来自 Google 的研究,所以如果您感兴趣,可以先看一看。一行解释:回归模型用于学习控制区域和治疗区域之间的可交换性因子,然后用于预测干预期间的反事实。也许这句话对你来说根本没有任何意义。别担心,我会用简单的术语来分解它!敬请期待!

我想花一点时间来强调 Geo 实验是营销科学中回归的另一个用例。如果你没有读过我的文章“营销分析师应该在他们的分析工具包中拥有的一样东西”,看看为什么回归是每个营销分析师应该在他们的工具包中拥有的工具。

Geo 实验绝不是为了取代传统的 A/B 测试。它们服务于非常不同的目的,回答不同的问题,但两者同样重要。就像他们说的,“没有放之四海而皆准的”,你不应该只在面包上涂黄油。继续添加一些品种,橄榄油也很棒!

挑战和局限

到目前为止,我可能已经向您介绍了这种新工具有多棒,但是像任何其他工具一样,Geo Experiment 也有其自身的局限性和挑战:

  • 管理费用:建立一个地理实验可能需要更多的工作,这取决于你如何建立你的活动。您可能需要重组您现有的数字营销账户,使您能够在城市/地区级别开展营销活动,以创建您的控制和治疗小组。
  • 平台:并不是每一个你投放广告的营销平台都允许你在城市/地区层面开展活动。例如,你可以在城市/地区层面投放脸书付费广告,但是当你在播客中投放广告时,你没有这个能力。
  • 预算:根据你的业务、活动和许多其他因素,你需要的活动预算会有很大的不同。对于刚刚开始数字营销的公司,我还不会考虑地理实验。如果你的业务已经成熟,你正在寻求优化,那么我认为这是一个很好的选择。
  • 控制变量:你能控制发生在不同城市的营销活动吗?例如,您的组织在特定城市开展的其他营销活动是否可能与您的地理实验重叠?

最后,永远记住为正确的工作选择正确的工具。不存在一刀切!

原载于 2019 年 3 月 25 日artofmarketingscience . github . io

带弹性搜索的 Geo-GraphQL

原文:https://towardsdatascience.com/geo-graphql-with-elasticsearch-b01a6bdf0dc8?source=collection_archive---------22-----------------------

教程

Photo by chuttersnap on Unsplash

我们最近在 RigUp 举办了第二届黑客马拉松,我的团队获得了客户类别的第一名!我们的解决方案包括定制的抓取器、队列、数据 ETL 和结果数据的查询。然后,我们编写了一个 React 应用程序来提供流畅的可视化来显示这些数据。📈由于我们只有 48 小时,我们的代码还没有准备好投入生产。

本教程探索了我在空闲时间改进项目的方法。我决定编写一个 GraphQL 服务器来访问我们的 ElasticSearch 地理数据。我选择的语言是 Scala ,利用了 Akka Http 和 Sangria 库。应该注意的是,RigUp 不是 Scala 之家,只是 Scala 是我背景的一大部分。

对于我们的黑客马拉松,我们为不同类型的文档建立了多个 ElasticSearch 索引,但是每个文档类型都有一个纬度和经度。这要求我们向 ElasticSearch 发出多个 API 请求,这意味着要复制大量的搜索逻辑。由于我们在地图上查看数据,我们利用了 Elastic 的地理边界框查询。

// Pseudocode
fetch('/users', { geo_bounding_box, ...some_filter_here });
fetch('/coffee-shops', { geo_bounding_box, ...other_filter });

理想情况下,我们希望创建一个简洁的 GQL 查询,其中地理边界框将传播到嵌套查询。在 geoSearch 下添加继承边界框变量的其他模型应该很容易:

users and coffeeShops can access bbox variable

$bbox 引用将指向我们在 graphiql 的查询变量窗格中定义的“bbox”对象。我们过滤掉这个框之外的用户。

“bbox” variable as an object in the bottom Query Variables pane

下面从桑格利亚汽酒文档以及 HowToGraphQL Scala 教程中获取重磅灵感。我们将创建 GraphQL 查询,根据名称和地理位置过滤用户和咖啡店。

项目设置

所有最终代码都可以在 GitHub 上获得

弹性搜索

最简单的设置是使用下面的 docker-compose 文件,或者在本地安装 Elastic 并在默认端口(9200)上运行。

跑步docker-compose up -d应该能让你开始。确保您可以在浏览器中从 ElasticSearch 得到响应,网址为 localhost:9200

要加载我们的测试用户和咖啡店,将目录切换到 scripts 文件夹并运行加载脚本:

$ cd src/main/resources/scripts/
$ ./load-test-data.sh

导航到http://localhost:9200/test-users/_ search?pretty 应该会给你一个用户列表。

属国

资源

让我们将graphiql.html添加到我们的资源目录中(在/src/main/resources下),这样我们就可以有一个操场来测试我们的 GraphQL 查询。我们将在下面看到一个路由,它将从资源目录中提供这个文件。

主服务器

只有两条路线:一个接受到/graphql 的 POST,另一个提供静态资源。现在,向 graphql 端点发出 POST 请求只会返回一个字符串。我们在/src/main/scala下创建Main.scala

模型

模型可以分为几类:变量、响应和公共变量。变量是将被映射到 GraphQL 参数的类。这些响应将是来自 GraphQL 服务器的响应,并将直接绑定到 GraphQL 模式中。这些输入和输出之间可以共享公共模型,这一点很快就会清楚。

让我们添加一个包含嵌套目录和类的模型文件夹,如下所示:

 ├── Main.scala
    └── models
        ├── common
        │   └── Location.scala
        ├── responses
        │   ├── CoffeeShop.scala
        │   ├── SearchResponse.scala
        │   └── User.scala
        └── variables
            ├── BBox.scala
            └── Filter.scala

普通的

Location是一个简单的 case 类,具有纬度经度属性。

变量

让我们建立我们的边界框和过滤器类。BBox以两个Location对象左上方右下方为属性,Filter 以可选BBox和可选String对象为属性。顶部左侧底部右侧与我们屏幕上渲染地图的角落相关。

反应

让我们创建一个通用的SearchResponse类:

一个User案例类将有名称、位置属性。位置属性将是一个类型为Location的对象。

我们的UsersResponse case 类将包含一个总计属性和一个用户列表。

CoffeeShopCoffeeShopResponse模型与用户和用户响应模型非常相似:

核心代码

让我们继续在/src/main/scala中创建/添加以下文件

├── Elastic.scala
├── GraphQLSchema.scala
├── GraphQLServer.scala
├── Main.scala
└── models

GraphQL 模式

要深入了解 Sangria 和 GraphQL 模式定义,请参阅 Sangria 文档

在这里,我们将模型与一个 GraphQL 模式联系起来:

弹性搜索

在 HowToGraphQL 教程中,作者使用 Slick 和内存中的 H2 数据库来保存和查询数据。我们将使用橡皮筋。我们创建一个特征来保存我们的弹性配置和方法(使得测试更容易):

接下来,我们将添加一个实现这个特征和我们定义的方法的类:

Sangria 有一个随 GraphQL 查询流动的上下文概念。这对我们的用例非常重要,因为它将保存我们的弹性类和 BBox 变量的实例。

我们可以在GraphQLSchema.scala中将我们的上下文定义为一个简单的 case 类:

case class MyContext(elastic: Elastic, bbox: Option[BBox] = None)

GraphQL 服务器

现在我们将创建一个 GraphQL 服务器,它将拥有一个 Akka Http Route和一个我们的Elastic类的实例。下面的端点方法获取一个JsValue,解析它,并返回一个Route

你会看到我们打电话给executeGraphQLQuery。让我们接下来构建它:

这里是我们传递弹性实例以及之前定义的GraphQLSchema.SchemaDefinition的地方。让我们不要忘记更新Main.scala来将请求路由到我们的 GraphQLServer:

测试我们的设置

为了运行我们的服务器,我们使用 sbt。从根目录:

$ sbt ~reStart

导航到 localhost:8080 并输入我们的查询和 bbox 变量:

当我们使用以下边界框坐标进行搜索时,我们将看到从查询中返回 3 个用户。所有这些用户都位于德克萨斯州的奥斯汀。

{
  "data": {
    "geoSearch": {
      "users": {
        "hits": [
          {
            "id": 3,
            "name": "Ricky", 
            "location": ...
          },
          {
            "id": 4,
            "name": "Carter", 
            "location": ...
          },
          {
            "id": 5,
            "name": "Mitch", 
            "location": ...
          }
        ]
      }
    }
  }
}

让我们调整边界框来覆盖更多的区域:

我们看到第四个用户,他正好在加利福尼亚州的圣地亚哥:

{
  "id": 1,
  "name": "Duane", 
  "location": {
    "lat": "32.715736",
    "lon": "-117.161087"
  }
}

我们最后一次调整边界地理框:

我们在🇲🇽墨西哥城看到了我们的第五个也是最后一个用户

{
  "name": "Matt",
  "id": 2,
  "location": {
    "lat": "19.42847",
    "lon": "-99.12766"
  }
}

扩展我们的设置

难题的最后一部分是添加一个额外的字段来搜索和过滤我们的用户。我们将添加一个名称过滤器,这样我们就可以进行如下查询:

为了按名称过滤,让我们更新Elastic.scala中的buildQuery方法:

现在,如果我们从上面运行新的查询,我们将只看到 Matt 和 Mitch 返回!非常容易添加新功能。

{
  "data": {
    "geoSearch": {
      "users": {
        "hits": [
          {
            "id": 2,
            "name": "Matt",
            "location": {
              "lat": "19.42847",
              "lon": "-99.12766"
            }
          },
          {
            "id": 5,
            "name": "Mitch",
            "location": {
              "lat": "30.366666",
              "lon": "-97.833330"
            }
          }
        ],
        "total": 2
      }
    }
  }
}

最后,假设我们希望在地理框中搜索名称以“M”开头的用户,以及该地区名称为“Starbucks”的咖啡店

{
  "data": {
    "geoSearch": {
      "users": {
        "hits": [
          {
            "id": 2,
            "name": "Matt",
            "location": {
              "lat": "19.42847",
              "lon": "-99.12766"
            }
          },
          {
            "id": 5,
            "name": "Mitch",
            "location": {
              "lat": "30.366666",
              "lon": "-97.833330"
            }
          }
        ],
        "total": 2
      },
      "coffeeShops": {
        "hits": [
          {
            "name": "Starbucks"
          },
          {
            "name": "Starbucks"
          }
        ],
        "total": 2
      }
    }
  }
}

我们可以快速将一个简单的 React 应用程序与 Mapbox 和 Apollo 连接起来,以显示我们的一些数据(源代码):

Display our users within the map’s bounding box

npx create-react-app gql-elastic-app
cd gql-elastic-app/
npm install apollo-boost @apollo/react-hooks graphql
npm install react-mapbox-gl mapbox-gl --save

让我们开始我们的UserFeatures组件,它将把我们的用户映射到 Mapbox 特性:

现在我们添加 GraphQL 查询字符串:

让我们在应用程序组件中设置 Mapbox:

现在轮到阿波罗了:

接下来,我们需要为地图的边界框添加一些状态:

一个快速实用函数,将地图框的Bounds对象转换成我们自己的BBox对象:

最后,我们添加了两个处理程序,它们接收地图事件并更新我们的本地状态:

运行该应用程序会像上面的 GIF 一样将你放大到德克萨斯州的奥斯汀,并将显示 3 个用户。如果我们将地图移到圣地亚哥,我们会看到第四个用户:

您也应该看到我们在墨西哥城的第 5 位用户!如果你一直跟随,你会注意到一个 CORS 错误。这是一个简单的修复方法,已在回购的[Main.scala](https://github.com/duanebester/gql-elastic-scala/blob/master/src/main/scala/Main.scala#L44) 中解决。

希望你喜欢用 GraphQL & ElasticSearch 进行地理搜索!所有的代码都是开源的。😎欢迎 PRs、评论等!

Scala 后端代码—https://github.com/duanebester/gql-elastic-scala

反应前端代码—https://github.com/duanebester/gql-elastic-app

使用 Python 进行地理编码

原文:https://towardsdatascience.com/geocode-with-python-161ec1e62b89?source=collection_archive---------1-----------------------

如何将物理地址转换为地理位置→经纬度

Photo by Thor Alvis on Unsplash

数据集很少是完整的,通常需要预处理。想象一下,一些数据集只有一个地址列,而没有纬度和经度列来表示地理上的数据。在这种情况下,您需要将数据转换成地理格式。将地址转换为地理信息(纬度和经度)以绘制其位置的过程被称为地理编码

Geocoding 是将一个 物理地址 描述为地球表面上一个 位置 计算过程(以数值坐标表示)——维基百科

在本教程中,我将向您展示如何借助 Geopy 和 Geopandas 库在 Python 中执行地理编码。如果您已经安装了 Anaconda 环境,让我们用 Pip 安装这些库。

pip install geopandas
pip install geopy

如果你不想安装库并直接与本教程附带的 Jupyter 笔记本交互,本文底部有 Github 与 MyBinder 的链接。这是一个集装箱化的环境,它允许你直接在网上实验本教程,而不需要任何安装。数据集也包含在这个环境中,因此本教程不需要下载数据集。

地理编码单个地址

要对单个地址进行地理定位,可以使用 Geopy python 库。 Geopy 有不同的地理编码服务可供选择,包括谷歌地图、ArcGIS、AzureMaps、Bing 等。其中一些需要 API 键,而另一些则不需要。

Geopy

作为我们的第一个例子,我们使用的是建立在 OpenStreetMap 数据之上的 nomist 地理编码服务。让我们对一个地址进行地理编码,巴黎的埃菲尔铁塔。

locator = Nominatim(user_agent=”myGeocoder”)
location = locator.geocode(“Champ de Mars, Paris, France”)

我们创建了保存地理编码服务的locator,命名。然后,我们传递我们创建的定位器来对任何地址进行地理编码,在本例中,是 Eifel tower 地址。

print(“Latitude = {}, Longitude = {}”.format(location.latitude, location.longitude))

现在,我们可以打印出我们创建的位置的坐标。

Latitude = 48.85614465, Longitude = 2.29782039332223

尝试一些不同的地址。在下一节中,我们将介绍如何对熊猫数据帧中的许多地址进行地理编码。

对熊猫的地址进行地理编码

让我们阅读本教程的数据集。在本教程中,我们使用商店地址数据集的示例。CSV 文件可通过此链接获得。

[## addresses.csv

Dropbox 是一项免费服务,可以让你将照片、文档和视频带到任何地方,并轻松分享。从不发电子邮件…

www.dropbox.com](https://www.dropbox.com/s/nt9ab4nnhpyrmxe/addresses.csv?dl=0)

下载 CSV 文件,用熊猫看。

df = pd.read_csv(“addresses.csv”)
df.head()

下表提供了 DataFrame 表的前五行。如您所见,没有纬度和经度列来映射数据。

Ddataframe

我们将地址列连接成一个适合地理编码的列。例如,第一个地址是:

Karlaplan 13,115 20,STOCKHOLM,Stockholms län, Sweden

我们可以像这样连接 pandas 中的地址列,为地理编码创建一个地址列:

一旦我们创建了地址列,我们就可以像下面的代码片段一样开始地理编码。

  • 1-我们首先在每个地址之间延迟 1 秒钟进行地理编码。当您对大量物理地址进行地理编码时,这非常方便,因为地理编码服务提供商可以拒绝对服务的访问。

  • 2 —通过应用我们创建的geocode来创建一个df['location']列。

  • 3 —第三,我们可以将纬度、经度和海拔高度创建为一个元组列。

  • 4 —最后,我们将纬度、经度和海拔列分成三个单独的列。

上面的代码生成了一个带有纬度和经度列的数据帧,您可以使用自己选择的任何地理可视化工具绘制该数据帧。让我们看一下数据帧的前几个草图,但是首先,我们将清理掉不需要的列。

df = df.drop([‘Address1’, ‘Address3’, ‘Address4’, ‘Address5’,’Telefon’, ‘ADDRESS’, ‘location’, ‘point’], axis=1)df.head()

cleaned table with latitude and longitude

我将使用 lyum 来绘制我们创建的点,但也可以随意使用您选择的任何其他地理可视化工具。首先,我们用叶子将位置显示为圆形地图。

下面生成的地图将地理编码地址显示为圆圈。

Map

或者,如果您喜欢带有聚合点簇的深色背景,您可以执行以下操作:

下面是一个黑暗的背景地图与集群点地图在叶。

Clustered map

结论

在许多需要坐标系的定位任务中,地理编码是一项关键任务。在本文中,我们看到了如何用 Python 进行地理编码。还有许多其他服务提供免费或付费的地理编码服务,您可以在 GeoPy 中进行试验。我发现 Google Maps 地理编码服务比我们在本教程中使用的 Openstreetmap 服务更强大,但是它需要一个 API 密钥。

为了在没有任何安装的情况下与本教程进行交互和实验,我创建了一个活页夹。进入 GitHub 库,点击启动活页夹。

[## shaka som/地理编码

此时您不能执行该操作。您已使用另一个标签页或窗口登录。您已在另一个选项卡中注销,或者…

github.com](https://github.com/shakasom/geocoding)

或者直接访问 Jupyter 笔记本活页夹链接:

[## GitHub:shaka som/geocoding/master

单击运行此交互式环境。来自活页夹项目:可复制、可共享、交互式计算…

mybinder.org](https://mybinder.org/v2/gh/shakasom/geocoding/master)

地理探索——必须用咒语把他们都抓住

原文:https://towardsdatascience.com/geoconquesting-gotta-catch-em-all-with-a-spell-492d5c99d637?source=collection_archive---------31-----------------------

Photo by — @jay_skyler

Niantic 是如何通过 AR 游戏获得大量权力和用户数据的

你可能还记得神奇宝贝 Go 这个迷人的游戏?这款游戏由总部位于旧金山的美国软件开发公司 Niantic,Inc .制作,该公司因开发增强现实手机游戏 Ingress、Pokémon Go 和哈利波特:巫师团结而闻名。该公司成立于 2010 年,名为 Niantic Labs,是谷歌内部的一家初创公司,Niantic 是从谷歌地图衍生出来的。Kotaku 在 2019 年 10 月撰写的一篇文章中深入解释了该公司及其当前的努力。这是这篇文章的摘要。它质疑追踪所有位置数据的能力,并对增强现实有一些批评性的想法。

Niantic 每分钟可以追踪你的位置 13 次

“今天,当你使用巫师 UnitePokémon Go 或 Niantic 的任何其他应用程序时,你的每个动作都会被记录和存储——根据一项 Kotaku 调查的结果,每分钟多达 13 次。即使知道应用程序会记录他们的位置数据的玩家,一旦看到他们通过自己的脚步向 Niantic 讲述了多少自己的生活,通常也会感到惊讶。”

首席执行官约翰·汉克(John Hanke)此前曾领导过由美国陆军投资的地图技术初创公司。他之前的公司 Keyhole 被谷歌收购了。他们意识到谷歌计划用 3D 方式绘制整个世界的地图。

Niantic 能通过游戏影响人们吗?

“如果你有人们在世界各地移动时使用的移动计算和服务,”汉克在 2016 年对伯克利商学院的一次演讲中说,“我们问自己的问题是,‘这些服务会影响人们在现实世界中的行为吗?他们正在使用的产品会导致他们走上一条不同的道路,驾驶一条不同的道路,偏离他们通常要走的轨迹吗?如果你能通过提供给人们的信息服务做到这一点,那么对于那些想改变人们行为的企业来说,这将是一个巨大的机会,让他们去那些他们不会去的地方。"

以这种方式通过游戏驱动这些动作,并将现实世界与增强现实相结合。无处不在的计算是数字世界在任何时间、任何地点与物理世界的无缝集成。也被称为“中介现实”

反乌托邦

Kotaku 文章中提到的非常有趣和扭曲的 AR 愿景:

Pokémon Go 引发了隐私争议,归咎于一个漏洞,该漏洞涉及用户给予 Niantic 大量权限:联系人,位置,存储,摄像头,以及对 iPhone 用户来说,完整的谷歌帐户访问权限,这不是游戏的一部分。

星球尺度的真实世界 AR?这不全是娱乐和游戏

Niantic 在他们的网站上表示,他们计划在未来发布一个“星球级的真实世界 AR 平台”,这将更有可能将游戏体验集成到真实世界的直播镜头中。

Kotaku 调查了欧洲的数据请求,发现了以下情况:

Kotaku 总共分析了 Niantic games 的 10 名玩家自愿与我们分享的 25000 多条位置记录。平均而言,我们发现 Niantic 在玩巫师联合的游戏中每分钟保持大约三个位置记录,几乎是它在玩神奇宝贝 Go 时的两倍。对于一名玩家来说,Niantic 在一天中的几乎每个小时都至少有一次位置记录,这表明该游戏正在收集数据,甚至在玩家不玩游戏的时候也与 Niantic 分享这些数据。

通过使用这些信息,Kotaku 可以识别他们的家,工作和他们的一些习惯。

数据可能不像我们想的那样匿名

数据可以成功匿名的想法长期以来一直备受争议。今年 7 月,伦敦帝国理工学院的研究人员能够在一个“匿名化”的数据集中准确地重新识别出 99.98%的美国人。

Niantic 目前的估值超过 40 亿美元。并不总是向服务的用户传达他们的数据用于什么目的。

广告市场研究公司 Emarketer 预计,广告商将在定位广告上花费 290 亿美元,也称为“地理定位”这些公司正在整合数字广告和实体广告。

影响和识别的专利

Niantic 在 2018 年收购一家名为 Tick Tock AI 的公司时获得的一项于今年 8 月发布的专利描述了一项旨在通过游戏性来激励数据收集的技术[……]Niantic 持有的另一项专利,也是从 Tick Tock AI 获得的,描述了一种可以使用计算机视觉来“识别鞋子,确定具体型号,确定鞋子属于约翰·史密斯,并区分约翰·史密斯拥有和穿着的其他鞋子”的软件根据该专利,通过使用“……音频(例如,烹饪的噪音)、烹饪前的食物图像、烹饪人的活动识别数据、烹饪开始的时间和烹饪完成的时间”,可以将大量亲密的上下文信息与物品相关联

这往好里说是引人入胜,往坏里说是令人担忧。想想 Niantic 能做出什么事来真是奇怪。

正如 Niantic 的一名前员工所言:“谈论公司的初衷几乎无关紧要,因为我认为创建这样一个组织会随着时间的推移而招致腐败。这更像是一个问题,我们如何构建对公共福利负有财政责任的公司?”

可能值得一提的是,这篇文章只是塞西莉亚·达纳斯塔西奥和德茹夫·梅赫罗特拉写的真正令人惊叹的文章的呼应和总结。同样,如果你想仔细阅读,请查看:

[## 《精灵宝可梦 Go》的创作者绘制了世界地图。现在他们正在绘制你的地图

《哈利·波特:巫师团结》, Pokémon Go 背后公司的最新游戏,让玩家驾驭…

kotaku.com](https://kotaku.com/the-creators-of-pokemon-go-mapped-the-world-now-theyre-1838974714/amp?__twitter_impression=true&fbclid=IwAR0ghwIvm6CHAo8mkfIiYQjxkU-bO_64il_ft-0NJFMfradYBNL9IyoHx0Q)

这里是#500daysofAI,您正在阅读的是第 194 条。500 天来,我每天都写一篇关于人工智能或与之相关的新文章。

使用 BigQuery 进行地理定位:在 20 秒内识别出 7600 万个 IP 地址

原文:https://towardsdatascience.com/geolocation-with-bigquery-de-identify-76-million-ip-addresses-in-20-seconds-e9e652480bd2?source=collection_archive---------32-----------------------

四年前,我们发布了第一个去识别 IP 地址的方法- 使用 Google BigQuery 的 GeoIP 地理定位- ,现在是时候进行更新了,包括最好和最新的 BigQuery 功能,如使用最新的 SQL 标准,处理嵌套数据,以及更快地处理连接。

重要更新 : 我在 2020 年离开了谷歌,加入了雪花——所以我无法保持更新我的旧帖子。如果你想尝尝雪花啤酒,加入我们吧——我在❄️.玩得很开心

这篇较新的帖子将向您展示如何在 Snowflak e 中运行地理定位——没有这里描述的任何预处理——感谢 Snowflak 运行 Java UDFs 的能力。

[## MaxMind 和雪花的免费 IP 地址地理定位

让我们在雪花中编写一个 Java UDF,使用 MaxMind 的 GeoLite2 免费地理定位数据对 IP 地址进行地理定位——

hoffa.medium.com](https://hoffa.medium.com/free-ip-address-geolocation-with-maxmind-and-snowflake-676e74ea80b8)

BigQuery 是 Google Cloud 的无服务器数据仓库,旨在实现可伸缩性和快速性能。使用它,您可以探索大型数据集,以找到新的和有意义的见解。为了遵守当前的政策和法规,在分析包含个人数据的数据集时,您可能需要取消用户的 IP 地址。例如,在 GDPR 下,一个 IP 地址可能被认为是 PII 或者个人数据。

用一个粗略的位置替换收集到的 IP 地址是帮助降低风险的一种方法 BigQuery 已经准备好提供帮助。让我们看看怎么做。

如何识别 IP 地址数据

在这个如何轻松识别 IP 地址的示例中,我们使用:

  • 2001 年至 2010 年间,维基百科从匿名编辑那里收集了 7600 万个 IP 地址
  • MaxMind 的 Geolite2 免费地理定位数据库
  • BigQuery 改进的字节和联网功能NET.SAFE_IP_FROM_STRING(), NET.IP_NET_MASK()
  • BigQuery 的新超能力处理嵌套数据,生成数组,并运行令人难以置信的快速连接
  • 新的 BigQuery Geo Viz 工具使用谷歌地图 API 来绘制世界各地的地理点。

让我们直接进入查询。使用下面的代码将 IP 地址替换为通用位置。

编辑维基百科的顶级国家

以下是用户编辑维基百科的国家列表,后面是要使用的查询:

#standardSQL# replace with your source of IP addresses
# here I'm using the same Wikipedia set from the previous article
WITH source_of_ip_addresses AS (
  SELECT REGEXP_REPLACE(contributor_ip, 'xxx', '0')  ip, COUNT(*) c
  FROM `publicdata.samples.wikipedia`
  WHERE contributor_ip IS NOT null  
  GROUP BY 1
)SELECT country_name, SUM(c) c
FROM (
  SELECT ip, country_name, c
  FROM (
    SELECT *, NET.SAFE_IP_FROM_STRING(ip) & NET.IP_NET_MASK(4, mask) network_bin
    FROM source_of_ip_addresses, UNNEST(GENERATE_ARRAY(9,32)) mask
    WHERE BYTE_LENGTH(NET.SAFE_IP_FROM_STRING(ip)) = 4
  )
  JOIN `fh-bigquery.geocode.201806_geolite2_city_ipv4_locs`  
  USING (network_bin, mask)
)
GROUP BY 1
ORDER BY 2 DESCQuery complete (20.9 seconds elapsed, 1.14 GB processed)

编辑维基百科的顶级城市

这些是从 2001 年到 2010 年收集的用户编辑维基百科的热门城市,然后是要使用的查询:

# replace with your source of IP addresses
# here I'm using the same Wikipedia set from the previous article
WITH source_of_ip_addresses AS (
  SELECT REGEXP_REPLACE(contributor_ip, 'xxx', '0')  ip, COUNT(*) c
  FROM `publicdata.samples.wikipedia`
  WHERE contributor_ip IS NOT null  
  GROUP BY 1
)SELECT city_name, SUM(c) c, ST_GeogPoint(AVG(longitude), AVG(latitude)) point
FROM (
  SELECT ip, city_name, c, latitude, longitude, geoname_id
  FROM (
    SELECT *, NET.SAFE_IP_FROM_STRING(ip) & NET.IP_NET_MASK(4, mask) network_bin
    FROM source_of_ip_addresses, UNNEST(GENERATE_ARRAY(9,32)) mask
    WHERE BYTE_LENGTH(NET.SAFE_IP_FROM_STRING(ip)) = 4
  )
  JOIN `fh-bigquery.geocode.201806_geolite2_city_ipv4_locs`  
  USING (network_bin, mask)
)
WHERE city_name  IS NOT null
GROUP BY city_name, geoname_id
ORDER BY c DESC
LIMIT 5000`

探索一些新的 BigQuery 特性

这些新的查询符合最新的 SQL 标准,支持一些我们将在这里回顾的新技巧。

新的 MaxMind 表:再见数学,你好 IP 掩码

可下载的 GeoLite2 表不再基于范围。现在他们使用适当的 IP 网络,如“156.33.241.0/22”。

使用 BigQuery,我们将这些解析成带有整数掩码的二进制 IP 地址。我们还对 GeoLite2 表进行了一些预处理,将网络和位置合并到一个表中,并添加了已解析的网络列,如下所示:

#standardSQL
SELECT *
  , NET.IP_FROM_STRING(REGEXP_EXTRACT(network, r'(.*)/' )) network_bin
  , CAST(REGEXP_EXTRACT(network, r'/(.*)' ) AS INT64) mask
FROM `fh-bigquery.geocode.201806_geolite2_city_ipv4` 
JOIN `fh-bigquery.geocode.201806_geolite2_city_locations_en`
USING(geoname_id)

地理定位百万分之一的 IP 地址

要在该表中找到一个 IP 地址,如“103.230.141.7”,可能需要这样做:

SELECT country_name, city_name, mask
FROM `fh-bigquery.geocode.201806_geolite2_city_ipv4_locs` 
WHERE network_bin = NET.IP_FROM_STRING('103.230.141.7')

但那不管用。我们需要使用正确的面具:

SELECT country_name, city_name, mask
FROM `fh-bigquery.geocode.201806_geolite2_city_ipv4_locs` 
WHERE network_bin = NET.IP_FROM_STRING('103.230.141.7') & NET.IP_NET_MASK(4, 24)

这就得到了一个答案:这个 IP 地址似乎住在南极洲。

按比例放大

这看起来很容易,但我们还需要几个步骤来找出 GeoLite2 表(超过 300 万行)和大量 IP 地址源之间的正确掩码和连接。

这就是主查询中的下一行所做的:

SELECT *
     , NET.SAFE_IP_FROM_STRING(ip) 
       & NET.IP_NET_MASK(4, mask) network_bin
  FROM source_of_ip_addresses, UNNEST(GENERATE_ARRAY(9,32)) mask

这基本上是使用所有可能的掩码(数字在 9 到 32 之间)应用交叉连接,并使用这些掩码来屏蔽源 IP 地址。接下来是真正精彩的部分:BigQuery 设法以极快的速度处理正确的连接:

USING (network_bin, mask)

BigQuery 在这里只选择一个被屏蔽的 IP——屏蔽的 IP 和带有给定掩码的网络相匹配的 IP。如果我们更深入地挖掘,我们会在 execution details 选项卡中发现 BigQuery 做了一个“内部 HASH JOIN EACH WITH EACH ON”,这需要大量的洗牌资源,但仍然不需要两个大型表之间的完全交叉连接。

进一步匿名化数据

这就是 BigQuery 如何帮助您用粗略的位置替换 IP 地址,并提供单个行的聚合。这只是可以帮助您降低处理数据风险的一种技术。GCP 提供了其他几个工具,包括云数据丢失防护 (DLP),可以帮助你扫描和识别数据。您现在有几个选项来探索和使用数据集,让您遵守法规。你用什么有趣的方式使用去身份数据?让我们知道。

在 BigQuery 中找到最新的 MaxMind GeoLite2 表,这要感谢我们的谷歌云公共数据集。

原发布于 2019 年 7 月 8 日https://dev . to

用于姿态估计的几何深度学习

原文:https://towardsdatascience.com/geometric-deep-learning-for-pose-estimation-6af45da05922?source=collection_archive---------3-----------------------

从单目图像中寻找物体姿态的理论和 Pytorch 实现教程

计算机视觉和机器人学的中心问题之一是理解物体相对于机器人或环境是如何定位的。在这篇文章中,我将解释背后的理论,并给出 Pavlakos 等人的论文“基于语义关键点的 6 自由度物体姿态”的 pytorch 实现教程。

在这种方法中,有两个步骤。第一步是预测 2D 图像上的“语义关键点”。在第二步中,我们通过使用透视相机模型最大化预测的语义关键点集合和对象的 3D 模型之间的几何一致性来估计对象的姿态。

Overlay of the projected 3D model on the monocular image

关键点定位

首先,我们使用标准的现成对象检测算法,如 fast-RCNN,在感兴趣的对象上放置一个边界框。然后,我们只考虑关键点定位的对象区域。为此,本文使用了“堆叠沙漏”网络架构。该网络接收一幅 RGB 图像并输出一组热图——每个关键点一个热图。热图允许网络表达其对一个区域的信心,而不是回归关键点的单个 x,y 位置。

从上图可以看出,网络有两个沙漏。此外,每个沙漏具有下采样部分和上采样部分。第二个沙漏的目的是优化第一个沙漏的输出。缩减像素采样部分由交替的卷积层和最大池层组成。当输出达到 4 X 4 的分辨率时,上采样开始。上采样部分由卷积和上采样(去卷积)层组成。使用第一和第二沙漏的输出的 L2 损耗来训练网络。

Left — Raw image with bounding box detection, Right — Cropped Image with keypoint heatmaps overlayed

姿态优化

现在我们有了关键点,我们可以用它们来找到姿势。我们所需要的只是我们感兴趣的物体的模型。本文作者定义了一个可变形模型 S,它由一个平均形状 B_0 加上一些用主成分分析计算的变量 B_i 组成。形状被定义为 3xP 矩阵,其中 P 是关键点的数量。

主要的优化问题是减少下面的残差。这里 W 是齐次坐标中的归一化 2D 关键点的集合。z 是表示关键点深度的对角矩阵。r 和 T 分别是旋转矩阵和平移向量。我们优化的未知数是 Z,R,T 和 c。

下面是我们希望最小化的实际损失。这里,D 是关键点的置信度——我们这样做是为了惩罚网络更确定的关键点上的错误。损失的第二项是正则化项,意在惩罚与感兴趣模型的平均形状的大偏差。

就是这样!得到的 R 和 T 定义了对象的姿态。现在让我们看看 pytorch 的实现。

Pytorch 实现

对于实现,我们将严格遵循宾夕法尼亚大学 CIS 580 中提供的代码。我通过合并一些文件和删除一些数据扩充步骤简化了代码。

让我们直接进入代码。首先,我们需要克隆一个存储库:

git clone [https://github.com/vaishak2future/posefromkeypoints.git](https://github.com/vaishak2future/posefromkeypoints.git)

我们需要解压缩 data.zip,以便顶层目录包含三个文件夹:data、output 和 utils。现在,让我们运行朱庇特笔记本。我们将检查的第一个代码块是 Trainer 类。这个类加载训练和测试数据集,并对其进行一些转换,使其成为我们想要的格式。数据被裁剪和填充,因此我们只查看感兴趣对象周围的边界框。然后,地面真实关键点的位置被表示为热图。然后,数据被转换成适当格式的张量并归一化。最后,培训师还会加载沙漏模型。一旦我们调用了 train 方法,我们就完成了关键点定位。

**class** **Trainer**(object):

    **def** __init__(self):
        self.device = torch.device('cuda' **if** torch.cuda.is_available() **else** 'cpu')

        train_transform_list = [CropAndPad(out_size=(256, 256)),LocsToHeatmaps(out_size=(64, 64)),ToTensor(),Normalize()]
        test_transform_list = [CropAndPad(out_size=(256, 256)),LocsToHeatmaps(out_size=(64, 64)),ToTensor(),Normalize()]
        self.train_ds = Dataset(is_train=**True**, transform=transforms.Compose(train_transform_list))
        self.test_ds = Dataset(is_train=**False**, transform=transforms.Compose(test_transform_list))

        self.model = hg(num_stacks=1, num_blocks=1, num_classes=10).to(self.device)
        *# define loss function and optimizer*
        self.heatmap_loss = torch.nn.MSELoss().to(self.device) *# for Global loss*
        self.optimizer = torch.optim.RMSprop(self.model.parameters(),
                                             lr = 2.5e-4)
        self.train_data_loader = DataLoader(self.train_ds, batch_size=8,
                                            num_workers=8,
                                            pin_memory=**True**,
                                            shuffle=**True**)
        self.test_data_loader = DataLoader(self.test_ds, batch_size=32,
                                           num_workers=8,
                                           pin_memory=**True**,
                                           shuffle=**True**)

        self.summary_iters = []
        self.losses = []
        self.pcks = []

    **def** train(self):
        self.total_step_count = 0
        start_time = time()
        **for** epoch **in** range(1,400+1):

            print("Epoch **%d**/**%d**"%
                    (epoch,400))

            **for** step, batch **in** enumerate(self.train_data_loader):
                self.model.train()
                batch = {k: v.to(self.device) **if** isinstance(v, torch.Tensor) **else** v **for** k,v **in** batch.items()}
                self.optimizer.zero_grad()
                pred_heatmap_list = self.model(batch['image'])
                loss = self.heatmap_loss(pred_heatmap_list[-1], batch['keypoint_heatmaps'])
                loss.backward()
                self.optimizer.step()                                          

                self.total_step_count += 1

        checkpoint = {'model': self.model.state_dict()}
        torch.save(checkpoint, './output/model_checkpoint.pt')

在我们开始姿势优化之前,我们需要定义一个我们会经常用到的自定义函数。Rodrigues 函数将帮助我们将轴角表示向量转换为 3×3 旋转矩阵。我们这样定义它,以便我们可以使用 pytorch 的亲笔签名的功能。

**class** **Rodrigues**(torch.autograd.Function):
    @staticmethod
    **def** forward(self, inp):
        pose = inp.detach().cpu().numpy()
        rotm, part_jacob = cv2.Rodrigues(pose)
        self.jacob = torch.Tensor(np.transpose(part_jacob)).contiguous()
        rotation_matrix = torch.Tensor(rotm.ravel())
        **return** rotation_matrix.view(3,3)

    @staticmethod
    **def** backward(self, grad_output):
        grad_output = grad_output.view(1,-1)
        grad_input = torch.mm(grad_output, self.jacob)
        grad_input = grad_input.view(-1)
        **return** grad_input

rodrigues = Rodrigues.apply

最后,我们编写姿态优化函数,其中我们使用相机模型将 2D 关键点转换成归一化的齐次坐标,然后将它们与旋转和平移后的地面真实 3D 关键点进行比较。当损失低于我们的阈值时,我们停止优化。

**def** pose_optimization(img, vertices, faces, keypoints_2d, conf, keypoints_3d, K):
    *# Send variables to GPU*
    device = keypoints_2d.device
    keypoints_3d = keypoints_3d.to(device)
    K = K.to(device)
    r = torch.rand(3, requires_grad=**True**, device=device) *# rotation in axis-angle representation*
    t = torch.rand(3 ,requires_grad=**True**, device=device)
    d = conf.sqrt()[:, **None**]
    *# 2D keypoints in normalized coordinates*
    norm_keypoints_2d = torch.matmul(K.inverse(), torch.cat((keypoints_2d, torch.ones(keypoints_2d.shape[0],1, device=device)), dim=-1).t()).t()[:,:-1]
    *# set up optimizer*
    optimizer = torch.optim.Adam([r,t], lr=1e-2)
    *# converge check*
    converged = **False**
    rel_tol = 1e-7
    loss_old = 100
    **while** **not** converged:
      optimizer.zero_grad()
      *# convert axis-angle to rotation matrix*
      R = rodrigues(r)
      *# 1) Compute projected keypoints based on current estimate of R and t*
      k3d = torch.matmul(R, keypoints_3d.transpose(1, 0)) + t[:, **None**]
      proj_keypoints = (k3d / k3d[2])[0:2,:].transpose(1,0) 
      *# 2) Compute error (based on distance between projected keypoints and detected keypoints)*
      err = torch.norm(((norm_keypoints_2d - proj_keypoints)*d)**2, 'fro')
      *# 3) Update based on error*
      err.backward()
      optimizer.step()
      *# 4) Check for convergence*
      **if** abs(err.detach() - loss_old)/loss_old < rel_tol:
        **break**
      **else**:
        loss_old = err.detach()    

*#       print(err.detach().cpu().numpy())*

    R = rodrigues(r)
    plt.figure()
    plot_mesh(img, vertices, faces, R.detach().cpu().numpy(), t.detach().cpu().numpy()[:,**None**], K.detach().cpu().numpy())
    plt.show()
    **return** rodrigues(r)[0].detach(), t.detach()

当您运行上述函数时,您应该会得到如下令人惊叹的结果:

重要的实现细节到此为止!确保您运行它,并试验不同的超参数和转换,以了解它们如何影响结果。我希望这有所帮助。请给我任何意见或更正!

参考

[1] G .帕夫拉科斯等 2017。来自语义关键点的 6 自由度物体姿态

将自动驾驶中的 2D 物体检测提升到 3D

原文:https://towardsdatascience.com/geometric-reasoning-based-cuboid-generation-in-monocular-3d-object-detection-5ee2996270d1?source=collection_archive---------5-----------------------

单目 3D 对象检测使用单目图像(通常是 RGB 图像)预测 3D 边界框。这项任务基本上是不适定的,因为在 RGB 图像中缺少关键的深度信息。幸运的是,在自动驾驶中,汽车是(很大程度上)已知形状和大小的刚体。那么,一个关键的问题是如何有效地利用汽车的强先验来推断传统 2D 对象检测之上的 3D 边界框。

与产生具有中心(x,y)和 2D 尺寸(w,h)的 4 自由度(DoF)轴对准边界框的传统 2D 对象检测相比,自动驾驶环境中的 3D 边界框通常具有 7 个 DoF: 3D 物理尺寸(w,h,l)、3D 中心位置(x,y,z)和偏航。注意,滚转和俯仰通常假定为零。现在的问题是,我们如何从一个四自由度的物体恢复一个七自由度的物体?

Tight constraint between 2D and 3D bounding boxes (source)

Deep3DBox ( 使用深度学习和几何 ,CVPR 2017)的开创性工作提出的一种流行的方法是从 2D 边界框包围的图像片中回归观察角度(或局部偏航,或偏心偏航,如我以前的帖子中所解释的)和 3D 对象大小(w,h,l)。局部偏航和 3D 对象大小(通常假设在子类型平均值周围具有小方差的单峰分布)都与对象外观紧密相关,因此可以从裁剪的图像碎片中推断出来。为了完全恢复 7 DoF,我们只需要用三个未知数(x,y,z)来推断 3D 位置。

幸运的是,我们可以利用 3D 边界框的透视投影应该与其 2D 检测窗口紧密配合的事实。这种约束迫使至少一个长方体顶点投影到 2D 盒的四个边上。

The pipeline to infer 3D position from 2D bounding box

跟随 Deep3DBox 的脚步,后面的论文也明确遵循同样的提法。他们的贡献是添加不同形式的第二阶段,以微调生成的 3D 长方体,在本文稍后详细讨论。

  • FQNet : 用于单目 3D 物体检测的深度拟合度评分网络 (CVPR 2019)
  • Shift R-CNN:Shift R-CNN:具有封闭形式几何约束的深度单目 3D 物体检测 (TCIP 2019)
  • 级联几何约束 : 通过级联几何约束和使用 3D 结果的净化 2D 检测对自主车辆进行 3D 包围盒估计 (ArXiv,2019 年 9 月)

2D/3D 紧密约束

由严格约束构成的四个方程可以写成如下。对于由左上角和右下角的坐标(x_min,y_min,x_max,y_max)参数化的每个 2D 边界框,我们有:

在上面的等式中,我已经标注了每个矩阵变量的大小。X(1)到 X(4)代表投影位于 2D 边界框边界上的 4 个选定顶点。我们将推迟 4 个顶点的选择。()_x 函数取 齐次坐标 的 x 分量,因此它是第一和第三分量之间的比值。同样的逻辑也适用于()_y 函数。有 3 个未知数,4 个方程,所以是超定问题

请注意,在上面的等式中,我们想要求解 T。为了使求解 T 更容易,稍微重写一下上面的等式是有用的。很容易证明这两种形式的公式是等价的。为了简单起见,我在这里只展示第一个等式。

逐步求解方程

让我们重写上面的等式,并用 3x4 形状的矩阵 M 表示一大块已知参数。

用 Python numpy 约定的矩阵公式写出来,它是

上面的等式可以重新排列为

有了四个等式,我们可以将左侧重写为 4x3 矩阵 A,将右侧重写为 4x1 矩阵 b。通过对 A 进行 Moore-Penrose 伪求逆(numpy . linalg . pinvPython 中的),可以通过最小二乘法拟合来解决这个超定线性等式。

顶点和最佳解决方案的选择

我们没有谈到的一件事是,如何从 8 个长方体顶点中选择 4 个落在 2D bbox 的四个边上。在 Deep3DBox 的原论文中有一段很长的论述,在合理的假设下,似是而非的配置数量可以从 8⁴减少到 64 个。 Shift R-CNN 有类似的结论,但得出这个数字的推理略有不同。

4 example viewpoints for the projection of 3D cuboid (source)

个人觉得级联几何约束的解释最容易理解。

  1. 从汽车长方体的四个侧面中选择一个作为面向观察者的侧面(例如,上图中汽车的 5-4-0-1 正面作为面向观察者的侧面)。注意,这仅取决于局部偏航或观察角度。
  2. 如上图所示,选择四个视点中的一个(例如,左边的例子与四个视点中的左上视点相匹配)。
  3. 对于上面的两个场景,接触 2D bbox 的顶边和底边的顶点是固定的,但是我们仍然有四个选择来选择长方体的两个垂直边上的哪两个顶点来符合 2D bbox 的左侧和右侧。对于底部的两个场景,情况正好相反——接触 2D bbox 左侧和右侧的顶点是固定的,但是我们有四个关于顶部和底部的选择。

因此,总的来说,我们有 4x4x4=64 种可能的配置。

一旦 64 个构型通过上述 4 个方程,这 64 个解就按照拟合长方体的 8 个投影顶点的最紧密 bbox 与 2D bbox 之间的拟合误差(如 Deep3DBox,FQNet)或 IoU 得分进行排序(如 Shift R-CNN)。

到目前为止,我在 Github 上找到了这个几何约束的两个实现,但是它们在选择使用哪个顶点方面有很大的不同。

缺点和第二阶段

上述严格约束方法通过将 3D 建议紧凑地放置在 2D 检测框中来推断 3D 姿态和位置。这种方法在理论上听起来很完美,但是它有两个缺点:1)它依赖于 2D bbox 的精确检测——如果在 2D bbox 检测中有适度的误差,在估计的 3D 边界框中可能有大的误差。2) 优化纯粹基于包围盒的大小和位置,不使用图像外观提示。因此,它不能从训练集中的大量标记数据中受益。为了解决这个问题,有几篇论文跟进了 Deep3DBox 提出的上述工作流,并用第二个细化阶段对其进行了扩展。

FQ-Net classifies an image patch with 3D bbox wireframe overlay (source)

FQ 网络提出使用求解的最佳拟合作为 3D 中的种子位置,以密集地采样 3D 提议。然后,训练神经网络,通过查看具有 3D 提议的 2D 投影的图像补片(绿色线框),来辨别 3D 提议和地面实况之间的 3D IoU。这个想法听起来很疯狂,但实际上行得通。

ShiftNet postprocessing after 2D/3D optimization

Shift R-CNN 通过“主动”回归建议的偏移来避免密集建议采样。他们将所有已知的 2D 和 3D bbox 信息输入到一个名为 ShiftNet 的快速简单的全连接网络中,并精确定位 3D 位置。

我对最优化的看法

上面的优化步骤,包括具有第二阶段的步骤,都假设 3D 尺寸和局部偏转的估计是绝对正确的,没有任何误差,并且最小二乘法最小化的误差来自 2D 边界框预测中的噪声。这有点不切实际,最理想的方法是允许 3D 尺寸和局部偏航的估计有一些变化,并且共同优化 7 DoF 的误差。这将使约束方程变得非线性,并使上述具有漂亮的封闭形式解的优化步骤无效。

快速而肮脏的选择

除了上述严格的约束,实际上有一种更快的方法来估计车辆的 3D 位置,简单地基于 2D 检测框或相关联的关键点的大小。

The geometric similarity in 2D/3D projection

如果我们可以知道三维长方体上三个关键点在图像平面上的投影位置,我们就可以通过简单的几何相似性原理来估计距离。假设我们有了顶面、底面和 3D 长方体中心的投影(如上图所示),就可以得到通过主点的光线和通过 3D 长方体中心的光线之间的光线角。这个射线角度也叫方位角,是连接局部偏航和全局偏航的关键。确切地说,应该有两个光线角度分量,一个在 u 或 x 方向,一个在 v 或 y 方向。

然后根据几何相似性,我们得到 f/z = H_p/H,其中 H_p 是上下表面中心投影在图像平面上的 v 差(以像素为单位),H 是 3D 物体的高度(以米为单位),f 是焦距(以像素为单位),z 是纵向距离(以米为单位)。利用射线角度和 z,我们可以执行坐标变换,并恢复对象的 3D 位置。

这正是 级联几何约束 在推断初始 3D 位置时所做的(在将其馈送给高斯-牛顿算法以求解约束方程之前)。诚然,上面的方程是凸的,应该有一个全局最优值,因此对初始条件不敏感,但这是另一回事)。

此外,其他几篇论文也使用汽车尺寸和关键点的强大先验知识来估计深度。

  • monosr:单目 3D 物体检测利用精确提议和形状重建,CVPR 2019
  • GS3D :一种高效的自动驾驶 3D 物体检测框架,CVPR 2019
  • MonoGR2

特别是,monosr用 2D bbox 高度近似距离,然后从 RoIAligned 特征回归残差。这实际上等于上图中的 H_p 和 H,可能会导致一些误差。 GS3D 用乘法因子 0.93 近似 2D bbox 高度。这个因子是从分析训练数据集获得的,以反映上图中 H_p 和 H 之间的差异。 MonoGR2 (原谅我给这个来自俄罗斯的伟大作品指定了一个快速处理,因为他们没有给出一个吸引人的名字)用图像中投影的挡风玻璃高度回归汽车上的各个关键点和近似距离。挡风玻璃的 3D 高度来自本研究中使用的匹配 3D CAD 模型。

我个人比较喜欢上面详细介绍的 级联几何约束 的方法,这是最实用可靠的方案。但是,如果你真的想要一个“快速和肮脏”的估计,而不进入优化业务,其他方法也工作。

几何推理的强力替代:直接回归?

除了上面的紧约束,几何推理,我还见过有人直接回归深度 d 或者视差 1/d,比如CenterNet(Objects as point——顺便问一下为什么还没有在任何顶级会议上被接受?)和 SS3D : 单目 3D 对象检测和使用交集-并集损失训练的盒拟合端到端。显然这是可行的,但是也许用上面的快速粗略估计给出一个更好的初始化会使它收敛得更快?

外卖食品

  • 深度在单目图像中很难预测,但它在用单目图像估计精确的 7 自由度 3D 长方体中是至关重要的。我们可以使用强烈的视觉线索和先前的信息,如汽车的平均尺寸,来进行有根据的猜测。这是我们人类的方式。
  • 假设 2D 边界框是精确的,我们可以求解四个 2D/3D 严格约束方程。
  • 通过利用 2D 包围盒的大小或已知关键点之间的距离,我们可以得到快速和粗略的估计。
  • 我们也可以直接回归距离或差异(虽然没有广泛流行)

参考

[1] A Mousavian 等人, Deep3DBox : 利用深度学习和几何的 3D 包围盒估计 (2017),CVPR 2017

[2] L 刘等, FQNet : 单目三维物体检测的深度拟合度评分网络 (2019),2019

[3] A Naiden 等,Shift R-CNN:Shift R-CNN:具有闭合形式几何约束的深度单目 3D 物体检测 (2019),TCIP 2019

[4] J Fang 等,级联几何约束 : 通过级联几何约束和使用 3D 结果的净化 2D 检测进行自动驾驶车辆的 3D 包围盒估计 (2019),ArXiv,2019 年 9 月

[5]J·Ku 等,monosr:单目 3D 物体检测利用精确提议和形状重建 (2019),CVPR 2019

6 B 李等, GS3D :一种面向自动驾驶的高效三维物体检测框架 (2019),2019

[7] I Barabanau, MonoGR2: 通过关键点上的几何推理进行单目 3D 物体检测 (2019),2019 年 5 月

[8] Y 周等, CenterNet: 物为点 (2019),ArXiv,2019 年 4 月

[9]E jrgensen 等人, SS3D : 单目 3D 对象检测和使用交集-并集损失训练的盒拟合端到端 (2019),ArXiv,2019 年 6 月

使用 Python 进行地理解析

原文:https://towardsdatascience.com/geoparsing-with-python-c8f4c9f78940?source=collection_archive---------6-----------------------

挖掘文本中的地理地名并绘制它们

“The Quaker City in a Storm,” frontispiece from Mark Twain’s The Innocent’s Abroad; Source: Project Gutenberg

地理解析是指从文本中提取地名,并将这些名称与专有名词和空间坐标明确匹配的过程。然后可以将这些坐标标绘在地图上,以便可视化所讨论文本的空间覆盖区。地理分析是一种在地理学中称为地名解析的特殊程序:然而,尽管地理分析和地名解析都处理文本中具体地理实体的识别,但地名解析通常涉及从结构化、明确的引用中简单推导地理;例如,邮局使用地理编码的州缩写进行路由。另一方面,Geoparsing 表示输入文本包含非结构化歧义;例如,一个文本可能引用美国南部的一个国家和一个州——乔治亚州,而解决这种模糊性是地质公园研究者的任务。

在信息科学、文学分析和数字人文领域,爱丁堡地质公园自 2015 年以来一直作为开源工具使用,严格用于地质公园历史文献和经典作品的任务。爱丁堡地质公园可以在网上免费获得,它让研究人员不仅可以在纸上,还可以在电脑屏幕上追踪约翰·斯坦贝克的《T4 与查理的旅行》或乔治·奥威尔的《通往威根码头之路》。该程序获取输入文本,精确定位位置名称,用地名词典(类似地图集的地理目录)交叉引用这些名称,并在谷歌地图上绘制输出结果。通过这种方式,学者们可以用上帝的视角看到寄信人或小说主角的旅行,每个离散的目的地都在互动的全景中。

借助于几个现成的软件包,我们可以很容易地用 Python 构建我们自己的初级爱丁堡地质公园。以下是这样做的尝试。举个例子,我将解析马克·吐温的国外的无辜者。对于这项任务来说,这是一个恰当的文本:这部小说出版于 1859 年,是吐温一生中最著名的作品之一,也是有史以来最畅销的游记之一。从美国到法国,从敖德萨到耶路撒冷,吐温和来自 15 个不同州的 60 位同胞走遍了全球,到处都是地名。

对于这个地质分析器,需要下面的包。我会在下面的脚本中清楚地说明每个人在做什么。

>import numpy as np
>import matplotlib.pyplot as plt
>%matplotlib inline
>
>import pandas as pd
>import geopandas as gpd
>
>from urllib import request
>from geotext import GeoText
>
>from geopy.geocoders import Nominatim
>from geopy.exc import GeocoderTimedOut
>
>from shapely.geometry import Point, Polygon
>import descartes

首先要做的是抓住无辜者。全文可通过古腾堡项目免费在线获得。Python 的自然语言处理库 NLTK 原生提供了 18 个古腾堡文本用于练习。不幸的是,无辜者不在其中,所以我将使用来自urllib模块的requests对象,传递原始数据的 url。txt,然后用 utf-8 解码。

>url = "[http://www.gutenberg.org/files/3176/3176-0.txt](http://www.gutenberg.org/files/3176/3176-0.txt)"
>response = request.urlopen(url)
>raw = response.read().decode('utf8')
>print(f'{type(raw)}, \n{len(raw)}, \n{raw[:501]}')<class 'str'>, 
1145397, 
Project Gutenberg's The Innocents Abroad, by Mark Twain (Samuel Clemens)

This eBook is for the use of anyone anywhere at no cost and with
almost no restrictions whatsoever.  You may copy it, give it away or
re-use it under the terms of the Project Gutenberg License included
with this eBook or online at www.gutenberg.net

Title: The Innocents Abroad

Author: Mark Twain (Samuel Clemens)

Release Date: August 18, 2006 [EBook #3176]
Last Updated: February 23, 2018

Language: English

印在我的 Jupyter 笔记本控制台上的是这本书的扉页;整个文本只是一个由 1145397 个字符组成的大字符串。该字符串包含我将尝试挖掘的所有地理参考。NLP 包空间的自动处理管道包括名称实体识别,给国家、州和城市分配“地缘政治实体”标签然而,我无法在 SpaCy 中找到一种简单的方法来只提取城市——除了编写一个交叉引用维基百科摘要的迭代函数——所以我改用 GeoText,它有一个容易提取城市名称的属性。

>places = GeoText(raw)
>cities = list(places.cities)
>cities['Tangier',
 'Paris',
 'Temple',
 'Como',
 'Garibaldi',
 'Rome',
 'Roman',
 'Naples',
 'Naples',
 ...]

像 SpaCy 一样,GeoText 可以识别地理命名的实体,但是在 GeoText 中调用.cities只会返回城市名称。请注意,我没有删除重复的城市条目;我想保留这些,这样当我绘制它们时,我的地图就包含了参考频率。

现在,我需要一本地名词典,以便用明确的空间坐标具体地标出这些城市的名称。爱丁堡地质公园有专门的历史地名词典,但我没有权限查阅。相反, OpenStreetMap 是一个受维基百科模式启发的合作地图:它是免费的,任何人都可以编辑。OSM 有一个名为“命名”的搜索工具,给定一个城市或州的名称,它会对该名称进行反向地理编码,并返回其地理坐标。所以我只需要给 nomim 一份城市名的列表。有许多方法可以做到这一点,但一种方法是通过 Python 包 GeoPy ,它抽象出了 nomim 的 API,并返回包含在输入搜索的第一个结果中的坐标。

>geolocator = Nominatim(timeout=2)
>
>lat_lon = []
>for city in cities: 
>    try:
>        location = geolocator.geocode(city)
>        if location:
>            print(location.latitude, location.longitude)
>            lat_lon.append(location)
>    except GeocoderTimedOut as e:
>        print("Error: geocode failed on input %s with message %s"%>
>             (city, e))
>lat_lon35.7642313 -5.81862599789511
48.8566101 2.3514992
31.098207 -97.3427847
45.9394759 9.14941014540895
-29.2562253 -51.5269167
41.894802 12.4853384
49.67887 4.31419
40.8359336 14.2487826
40.8359336 14.2487826

我将 API 的超时设置为 2 秒,并包含一个错误处理语句,如果 API 超时,该语句将跳过当前搜索。我的希望是,如果单个搜索时间超过 2 秒,它就不是一个真正的城市名称,因此脚本会从最终的地图中剔除非名称。我把城市名称和坐标输入熊猫数据框:

>df = pd.DataFrame(lat_lon, columns=['City Name', 'Coordinates'])
>df.head(7)

目前被格式化为元组的坐标需要被转换成点对象,因为每个城市将由地图上的一个点来表示。Python 包 Shapely 就是这么做的。下面,我正在遍历包含坐标元组的 dataframe 系列,将它们分别转换为点,并切换纬度和经度的顺序,因为这是我下载的地图对象使用的顺序。

>geometry = [Point(x[1], x[0]) for x in df['Coordinates']]
>geometry[:7][<shapely.geometry.point.Point at 0x116fe3b10>,
 <shapely.geometry.point.Point at 0x116ff9190>,
 <shapely.geometry.point.Point at 0x116fe0c10>,
 <shapely.geometry.point.Point at 0x116fe0a10>,
 <shapely.geometry.point.Point at 0x116fe0250>,
 <shapely.geometry.point.Point at 0x116fe0850>,
 <shapely.geometry.point.Point at 0x116fe0210>]

将这些点对象放回数据帧将使我们能够轻松地绘制它们。现在,我将使用一个geo pandasdata frame 来代替 pandas dataframe,它可以轻松处理这些类型的对象。

>## coordinate system I'm using
>crs = {'init': 'epsg:4326'}
>
>## convert df to geo df
>geo_df = gpd.GeoDataFrame(df, crs=crs, geometry=geometry)
>geo_df.head()

最后一步是在地图上标出位置。我没有删除重复的位置条目这一事实意味着,如果我设置了标记的透明度,那么引用频率较高的位置会比只引用一次的位置看起来更不透明。这是通过plot对象中的alpha参数完成的。不透明的标记应该大致对应于贵格城号实际航行过的城市,透明的标记对应于仅仅提到过的城市。

>## world map .shp file I downloaded
>countries_map =gpd.read_file('Countries_WGS84/
>                              Countries_WGS84.shp')
>
>f, ax = plt.subplots(figsize=(16, 16))
>countries_map.plot(ax=ax, alpha=0.4, color='grey')
>geo_df['geometry'].plot(ax=ax, markersize = 30, 
>                        color = 'b', marker = '^', alpha=.2)

那是马克·吐温的《国外的无辜者》,地质公园。

乔治·海沃德:喜剧演员、律师和数据科学家

原文:https://towardsdatascience.com/george-hayward-comedian-lawyer-and-data-scientist-86aae7d740b?source=collection_archive---------22-----------------------

苹果 | 谷歌 | SPOTIFY | 其他 | 剪辑

乔治·海沃德在 TDS 播客

编者按:这是迈向数据科学播客“攀登数据科学阶梯”系列的第八集,由 Jeremie Harris、Edouard Harris 和 Russell Pollari 主持。他们一起经营一家名为sharpes minds的数据科学导师创业公司。可以听下面的播客:

每周,我都会与试图进入数据科学领域的人进行几十次对话。谈话的主题各不相同,但我很少会在离开时不被问到这样的问题:“鉴于我在[金融/物理/统计/经济学等]方面不同寻常的背景,你认为我有机会进入数据科学领域吗?”。

从现在起,我对这个问题的回答将是把他们引向今天的嘉宾,乔治·约翰·乔丹·托马斯·阿奎那·海沃德。

乔治[姓名省略]海沃德的数据科学生涯证明了品牌和讲故事的力量。在斯坦福大学完成了 JD/MBA 学位,并在 Hackerrank 的 SQL challenges 中获得了第一名,之后他继续为谷歌的一家初创公司工作,随后为其他一些公司工作。现在,你可能会问喜剧和法律如何可能导致数据科学职业。

冒着泄露阴谋的风险,我们谈话的答案非常清楚:数据科学不是关于数字运算的,而是关于交流的。现在,这个播客确实是最好听的,但是既然你正在读这个,我会尽我所能写下我最喜欢的带回家的东西:

  • 在任何给定的公司中,都有大量的数字(即关键指标)很重要。您的客户平均使用您的产品多长时间?平均购买价格是多少?有多少比例的用户会推荐他们的朋友?不过,归根结底,如果您想通过分析避免瘫痪并保持专注,那么拥有一个明确定义的指标进行优化是非常重要的。对于任何数据科学家来说,能够思考和论证指标选择都是至关重要的。
  • 扩展最后一点:不是每个人都同意你选择的度量标准。通常,这种冲突没什么大不了的,但是如果你认为最能准确反映公司状况的指标恰好描绘了一幅更负面的画面,你可能会面临一些使用它的内部阻力。George 分享了一个关于当数据科学以这种方式变得政治化时会发生什么的精彩故事,但底线是:清楚地传达为什么选择公制 X 而不是公制 Y 的能力通常对行业的成功至关重要。
  • 求职过程中你会面临一次又一次的拒绝。因此,你需要找到除了工作邀请之外的东西来保持你的动力。庆祝小胜利是一门艺术(例如,获得第一次面试,通过第一次面试,获得第一次现场面试,甚至第一次、第十次或第一百次被拒!),但这是一门很值得学习的艺术。
  • 这不是导师的重要性第一次在这些播客中出现,但乔治职业生涯中的一个大主题是他找到导师的能力,并与他们培养关系,这种关系会转化为宝贵的经验,甚至是未来的机会。

你可以在推特上关注乔治,地址是@乔治 _ 海沃德或者点击这里查看他的数据科学网站!

TDS 播客—剪辑

如果你在 Twitter 上,请随时与我联系 @jeremiecharris !

我脑海中的乔治亚(和机器学习)

原文:https://towardsdatascience.com/georgia-and-machine-learning-on-my-mind-f32669cc090a?source=collection_archive---------30-----------------------

利用数据搭建更好的桥梁

An inspector at work. Photo by Amogh Manjunath on Unsplash

问题

最近,美国土木工程师协会将美国基础设施的整体健康状况评为 D+。我们的基础设施陈旧。桥梁是这一组日渐衰败的资产的一个主要方面。了解和管理这些结构的状况对于佐治亚州交通部(GDOT)的持续目标至关重要。为了帮助实现这些目标,我们的分析将建立预测模型,以了解桥梁何时处于需要维修或更换的危险之中。我们的目标是在检查开始前,利用现有数据预测桥梁状况的两个测量值,即状况等级充分性等级

GDOT(和其他 DOT)将从多方面的分析中受益。

  • 预测模型将允许问题的早期检测。
  • 这将允许更有效地分配桥梁检查员资源,并可能提高整个桥梁检查管道的成功率。
  • 最后,预测模型将提供一个更安全的基础设施网络,因为我们现在正在使用未开发的数据来确保公众的健康和安全。

数据集

我们的大部分数据来自联邦公路管理局国家桥梁库存(NBI)提供的免费桥梁库存这里。该数据不包括高程数据,而我们希望将高程数据作为一个要素包括在内,因此我们使用 MapQuest 的开放式高程 API 来访问该数据集,并将其与 NBI 数据相结合。

分析

数据科学不是黑匣子,避免它成为黑匣子的最好方法是非常了解你的数据。所以我们从探索性数据分析开始。首先,我们来看看佐治亚州的桥长分布。

有趣的是,在佐治亚州大多数的桥都不到 100 英尺长,我敢打赌这违背了你的直觉。一个要点是,并不是所有的桥都像你在州际公路上看到的那样。

关于桥梁,我们还想知道什么?我们可以看看这些桥建造的年代分布,从而了解它们的年代分布。

我们可以看到,在 20 世纪 50 年代末,60 年代初出现了一个建设高峰。够酷的是,这对应于一个真实的历史事件,德怀特·艾森豪威尔的联邦援助高速公路法案的通过。这个法案创造了现在美国的州际系统。链接此处。这也是我们在美国的基础设施,更确切地说是在格鲁吉亚的基础设施急需修复的另一个原因。他们中的许多人属于婴儿潮一代。

让我们来看看该州桥梁的地理分布。

Atlanta dominates

相当整洁,但是这一个与我们期望的相一致。大多数桥梁位于主要的大都市中心,如亚特兰大、奥古斯塔、萨凡纳和梅肯。哦,底部的空白处呢?那是诺基沼泽。还要注意顶部和右侧的分布条。

让我们也看看条件评级和充分性评级的分布,我们试图预测的变量。状况等级是一个从 0 到 9 的离散分数,它被赋予桥梁、桥面、上部结构和下部结构的三个位置。把甲板想象成汽车行驶的地方,上部结构主要是支撑甲板的横梁,下部结构是其他东西都位于其上的桥墩/柱子/桥台。另一方面,充分性评级是一个从 0 到 100 的连续分数,主要基于条件评级,但也基于其他几何因素。我们可以看到,三者的分布非常相似,上层建筑的形状似乎相对最好。

Condition Rating

机器学习

为了预测桥梁评级,我们必须准备在机器学习模型中使用的数据。这被称为预处理。大多数时候,你不会简单地将数据转储到一个黑盒模型中,然后抱最好的希望。在我们的例子中,选择的特性如下

特征:纬度、经度、海拔、年龄、结构长度、设计荷载、道路宽度、年日交通量(ADT)、货车百分比、偏斜度、水平净空

这些特征主要是通过领域知识选择的,而不是从数据集中人工生成的。它们都代表了工程师可以访问的关于桥梁的相当容易访问的信息。

所有要素都在不同的比例上,并且许多都有异常值,如我们在上面的桥长图中看到的。这些异常值和要素的相对比例可能会对根据数据生成的模型产生过大的影响。由于这是不可取的,我们使用 sklearn.preprocessing 中的 QuantileTransformer 来准备数据。

机器学习管道

对于该分析中的大多数模型,管道由转换器和超参数上的网格搜索构成。使用嵌套交叉验证将模型拟合到数据,并在保留集上进行评估。以下是岭回归模型的示例代码。

模型性能

执行所有步骤后的模型结果如下所示。

回归模型

分类型号

总的来说,我们可以看到分类模型优于回归模型。这主要是由于设计载荷特性。我们的模型中使用的设计荷载并不是一个真正的连续变量,而是包含了模型的新信息,因此分类器比回归更能利用这些信息。逻辑回归二元分类器比所有其他模型都有优势,这将在后面讨论。

模型评估

评估分类器模型的最好方法之一是开发一个混淆矩阵。对于预测任意数量的 n 个类别的所有混淆矩阵,开发了一个 n×n 矩阵,其中对角线表示真实预测,并且任何偏离对角线的值都是预测中的误差。在二元分类的情况下(是某物,不是某物),那么矩阵对角线以外的值代表假阳性和假阴性。随机森林分类器的混淆矩阵是输出的一个很好的例子,如下所示。

Random Forest, non-random results

最佳性能模型

我们注意到逻辑回归模型-2 类的表现优于所有模型,但是为什么它比其他模型都好呢?有多重原因。一个原因是我们将 10 个不同的条件评级值映射为 2,差/好。如果这三个位置中的任何一个的状况等级为 4 或更低,则该桥被评定为差。一般来说,当你减少类的数量时,模型会表现得更好,我们已经证明了这一点。

然而,结果并不像看起来那么乐观。我们的 2 级模型遭受了高度的阶级不平衡。回头参考上面的条件评级图,我们可以看到,当我们将目标变量重新聚集成两个类别时,它们中的大多数将属于“良好”类别,这意味着条件评级不代表有缺陷的评级。因此,逻辑回归模型的高精度被过分夸大了,仅仅因为大多数值不属于“差”类。在这种情况下,精度和召回率等指标将提供比准确性更准确的模型性能评估。

结论

通过这一分析,我们已经表明,我们可以使用从 FHWA 容易获得的数据,有意义地预测佐治亚州桥梁充分性评级和桥梁状况评级的结果。这些模型可用于帮助交通部的资产管理业务,并将为该部和纳税人提供重要价值。

这篇文章只是触及了全部分析的表面。在GithubT2【这里查看完整的笔记本和支持代码

干杯!

优步 H3 的地理空间索引

原文:https://towardsdatascience.com/geospatial-indexing-with-ubers-h3-766399b690c?source=collection_archive---------2-----------------------

六边形动力!

Photo by Jonas Svidras on Unsplash

在本文中,我将介绍优步的 H3 地理空间索引系统。作为该公司众多开源项目中的一个,H3 系统允许你快速有效地索引你的数据,以备日后查询。

地理空间索引对于大规模聚合和查询数据至关重要。这种类型的数据通常很丰富,难以索引或搜索,并且结构可能很复杂。区分特定区域的多边形可能很难处理。想想一个城市的边界。你需要多少个点来有效地确定给定的车辆是否已经进入一个城镇或者甚至一个加油站?你需要的点数越多,你需要的 CPU 计算就越多。硬件负担过重会导致响应时间变慢和资源使用增加。

一个高效的地理空间索引系统可以帮助你克服这些障碍。在 H3 的情况下,解决方案采取散列方案的形式。

H3 是如何工作的?

H3 算法将地球表面划分为六边形网络。您可以从可用的十六级中选择每个六边形包含的细节数量。你可以认为这些是地图上的“缩放”级别。每深入一步,六边形就会变小,你需要更多的六边形来覆盖相同的区域。

每个六边形都是独一无二的,并且是可以识别的。您可以通过一个唯一的 64 位标识符、一个数据库表的理想关键字或一个内存中的字典来寻址各个六边形。这些标识符在“缩放”级别上是一致的,因此您可以随意混合和匹配它们。

您对 H3 的第一个方法可以是把它想象成一个明亮的地理空间散列方案。有了它,您可以使用简单的值查找快速确定区域包含。您可以轻松地对地理空间观测进行聚类,并将其显示在地图上。

但是还有更多。为了让您更好地理解 H3 的能力,我将用 Python 展示一个简单的用例。

回到英国交通事故

我在 Medium 上的第二篇文章是关于绘制英国交通事故热点。我决定从 H3 的角度重新审视它,作为本文的一个例证。当时,我关心的是找到交通事故报告最多的地区,并绘制地图。绘制重要事件频率的区域是优步每天都需要解决的问题,尽管规模要大得多(当然是为了不同的用例)。

在这里,我决定使用 H3 进行索引、聚合和显示。说明本文的代码可以在 GitHub 库上找到,我建议您使用它来跟随本文。你只需要打开一本 Jupyter 笔记本:

uk-accident-h3.ipynb

在这个文件中,我们主要看到的是与第一个版本相同的过程。我们加载数据,清理数据,并使用相同的 DBSCAN 算法对数据进行聚类。我们将利用 H3 的能力对位置进行分组,并以图形方式将它们表示为六边形簇,而不是麻烦地为这些层寻找形状。

使用 H3 显示区域

一旦我们得到了 DBSCAN 聚类的结果,我们就为数据集获得了一个额外的列,即聚类数。噪声点的簇号为 -1 ,并且不相关。从聚集的位置到地图形状是一个将它们散列成 H3 六角键的问题。这就像调用一个转换函数一样简单:

h3_key = h3.geo_to_h3(latitude, longitude, level)

得到的值是一个字典的关键字,我们在字典中存储六边形形状和共享该关键字的位置的数量。为了获得地理空间多边形,我们需要调用另一个函数:

h3.h3_to_geo_boundary(h3_address=h3_key)

这个函数接受一个 H3 键,并返回六边形顶点的纬度和经度列表,我们可以很容易地用它在地图上显示。要查看地图,我们只需遍历字典并创建多边形形状。相关功能是:

map = create_map(clusters)

要测试解决方案的灵敏度,您可以调整两个 DBSCAN 参数和 H3 电平参数:

eps_in_meters = 50.0
num_samples = 10
h3_level = 11

这是我们最终得到的结果:

H3 clusters generated from DBSCAN

与 H3 聚类

现在我们可以更进一步,使用 H3 直接对数据进行聚类。我们将使用所有输入数据并将其散列到 H3 键中,而不是通过 DBSCAN。我们不是显示所有可能的六边形,而是限制每个六边形出现的次数。这种限制将有助于整理地图,使其更具响应性。

生成的地图与第一张略有不同,但这是合理的。毕竟,我们使用的是不同的假设。请记住,DBSCAN 使用基于密度的标准对位置进行聚类。从某种意义上说,这是一种揭示结构的算法。另一方面,H3 使用一种强加结构的方法,定义哪些区域用作集群。

结论

这篇文章对优步的 H3 进行了一次相对短暂而肤浅的探索。这是一个方便的工具来执行地理空间索引和分析。我希望这已经激起了您更深入地研究这个库并将其添加到您的地理空间分析工具箱中的欲望。并且乐在其中。我做到了。

参考

[1] H3:优步的六边形层次空间索引

[2] H3 Python GitHub 库

[3] 英国事故 GitHub 知识库

相关文章

[## H3 的快速地理空间索引

H3 六角电力重装上阵!

towardsdatascience.com](/fast-geospatial-indexing-with-h3-90e862482585) [## 使用 HDBSCAN 进行地理聚类

如何使用 HDBSCAN、H3、图论和 OSM 探索地理数据。

towardsdatascience.com](/geographic-clustering-with-hdbscan-ef8cb0ed6051) [## joo Paulo Figueira-数据科学家- tb.lx by 戴姆勒卡车和公共汽车| LinkedIn

查看 joo Paulo Figueira 在全球最大的职业社区 LinkedIn 上的个人资料。圣保罗列出了 1 份工作…

www.linkedin.com](https://www.linkedin.com/in/joao-paulo-figueira/)

GeoVec:用于地球科学的单词嵌入

原文:https://towardsdatascience.com/geovec-word-embeddings-for-geosciences-ac1e1e854e19?source=collection_archive---------21-----------------------

词语嵌入的类比、分类、关联和空间插值。

本帖中引用的推荐读物

[## 深度学习和土壤科学-第 1 部分

预测土壤性质的土壤光谱。预测多种土壤特性的多任务卷积神经网络…

towardsdatascience.com](/deep-learning-and-soil-science-part-1-8c0669b18097) [## 深度学习和土壤科学—第二部分

使用上下文空间信息的数字土壤制图。从点信息生成土壤图的多任务 CNN。

towardsdatascience.com](/deep-learning-and-soil-science-part-2-129e0cb4be94)

介绍

正如我在关于深度学习和土壤科学的第一篇文章中所描述的,土壤科学家的部分工作是在野外进行的,包括尽可能全面地描述我们所看到的。这些都是重要的记录,有助于我们形成研究区域的心智模型,并提醒我们可能忘记的细节。

以下是(部分)典型的土壤描述:

Ap1 — 0 到 7 英寸;棕色(10 年 5/3)灰色细砂质壤土,非常暗的灰褐色(10 年 3/2)潮湿;弱细粒状结构;软,非常易碎,不粘,稍有塑性,常见的非常细和细根;很少非常细的间隙孔和管状孔;15%直径小于 2.0 毫米的沙状浮石;中性(pH 6.6);清晰平滑的边界。(0 至 8 英寸厚)

Ap2 — 7 到 9 寸;棕色(10 年 5/3)灰色细砂质壤土,非常暗的灰褐色(10 年 3/2)潮湿;弱中粒结构;稍硬,易碎,不粘,稍有塑性;普通非常细和细根;常见的微细和极微细管状孔隙和间隙孔隙;20%直径小于 2.0 毫米的沙状浮石;中性(pH 7.0);清晰的波浪形边界。(0 至 7 英寸厚)

我们可以看到,它是按层组织的,包含颜色、根的存在、孔隙的描述、结构类别(估计的粘土、淤泥和沙子的比例)等细节。大多数情况下,描述遵循一些推荐的格式,但它们可能包含或多或少的自由格式文本,这取决于研究。

这些图层描述通常附有样本,这些样本被送到实验室,然后可以用于制作土壤属性地图,例如,我在使用 CNN进行数字土壤制图中描述的地图。但是描述本身几乎从不使用,尽管它们包含了重要的信息。例如,与浅色层相比,深色层的有机物浓度相对较高(当然,也有例外)。

单词嵌入

为了使用描述中包含的有价值的信息,我和我的同事 Ignacio Fuentes 决定用自然语言处理(NLP)来生成特定领域的单词嵌入。我不打算解释什么是单词嵌入,但是你可以找到一些好文章,比如这个单词嵌入介绍。

模型开发

由于大多数语言模型考虑了单词的共现,我们使用了相对较大的 280,764 篇与地球科学相关的全文文章的语料库。在对文本进行预处理(标记化、删除停用词等)之后。),我们拟合了一个手套模型来生成可以在其他应用中使用的单词嵌入。

单词嵌入的评估

下载 280,764 篇文章,对它们进行预处理,并拟合手套模型,实际上是这个过程中最简单的部分。由于我们需要评估生成的向量空间,我们创建了一个领域特定的测试套件,考虑三个任务,即类比、相关性和分类。

如果这些任务听起来不熟悉,这里有一个简短的描述和例子。

  • 类比:给定两对相关的单词,a:b 和 x:y,任务的目的是回答问题“a 对 x 就像 b 对?”。与矿物及其颜色相关的一个例子是“蓝铜矿之于蓝色,正如孔雀石之于 __?(绿色)”。
  • 相关度:对于给定的一对单词 (a,b) ,如果单词不相关或相关,则由人类主体分别分配 0 或 1 的分数。一个例子是配对“(Andisol,Volcano)”并且由于 Andi sol(土壤类型)与火山区域相关,因此相关度得分应为 1。
  • 分类:给定 2 组单词 s1 = {a,b,c,…}s2 = {x,y,z,…} ,该测试应该能够使用聚类算法将每个单词正确地分配到其对应的组中(参见结果中的示例)。

结果

我们将我们的特定领域嵌入(GeoVec)与 GloVe 作者提供的通用领域嵌入进行了比较,我们观察到整体性能提高了 107.9%。当然,考虑到任务的特殊性,这是一个预期的结果。

类比

如果你熟悉单词嵌入(或者你读过这篇单词嵌入介绍),你大概见过展示首都城市和国家、国王-男性/女王-女性,或者其他组类比关系的情节。在这项工作中,我们能够获得类似的结果,但与地球科学有关。

Fig. 1: Two-dimensional PCA projection of selected words. Simple syntactic
relationship between particle fraction sizes and rocks (left panel) and advanced semantic
relationship between rocks and rock types (right panel).

从情节来看,任何一对相关词都可以表示为类比。例如,从左图中,可以得出类似的结论“粘土岩之于粘土,就像砂岩之于 __?(沙子)”而第一个模型输出确实是“沙子”。在左图中,可以观察到简单的类比,主要是句法上的,因为“粘土岩”包含“粘土”一词。右侧面板显示了一个更高级的关系,其中岩石名称被分配给其对应的岩石类型。

分类

在分类的情况下,下图显示了 k-means 算法可以正确区分嵌入组的两个示例。左图显示了来自两个不同分类系统(美国农业部和 WBR)的土壤类别组。两个分类系统中都只有一个模糊的土壤类别(变性土),但嵌入正确地编码了这种关系,将该类别置于两组之间。右侧面板显示了嵌入如何对来自不同聚合级别的信息进行编码的示例。在左图中,相同的土壤被正确地区分为两组,与右图中的岩石类型相比,它们形成了一个粘性组。

Fig. 2: Two-dimensional PCA projection of selected categorisations. Clusters
representing soil types from different soil classification systems (left panel) and a
different aggregation level where the same soil types are grouped as a single cluster
when compared with rocks (right panel).

插值嵌入

也许你已经看到了一些很酷的图像潜在空间插值的例子,比如下面的人脸插值例子,但它在单词嵌入的上下文中并不常用。

Fig. 3: Linear interpolation in latent space between real images (Kingma and Dhariwal, 2018)

在单词的情况下,我们想要探索内插嵌入(两个单词之间的空间)是否产生一些…

为了生成插值嵌入,我们通过使用以下公式获得两个单词嵌入的线性组合:

v _ int=α∫v _ a+(1α)∫v _ b

其中 v_int 是内插嵌入, v_av_b 是两个选定字的嵌入。通过在范围[0,1]内改变α的值,我们生成了嵌入的梯度。对于通过插值获得的每个中间嵌入,我们计算语料库中所有单词的余弦相似度,并选择最接近的一个。

Fig. 4: Interpolated embedding in a two-dimensional PCA projection showing a size
gradient with “clay”<“silt”<“sand”<“gravel”<“cobble”<”boulder”. Red and blue dots represent
selected words (“clay” and “boulder”) and black dots
represent the closest word (cosine similarity) to the interpolated embeddings.

在左边的图片中,你可以看到单词“boulder”和“clay”之间嵌入的渐变。这两个极端的词对应不同的颗粒大小,分别为粗颗粒和细颗粒。一个更完整的颗粒大小列表是,按照从粗到细的顺序,“漂石”>“卵石”>“砾石”>“沙子”>“淤泥”>“粘土”。所得的插值嵌入实际上对应于(接近于)这些颗粒尺寸,处于相同的顺序!

我们希望看到插值的结果(尽管如此,我们还是很惊讶!)因为我们想探索空间插值嵌入的想法,这更接近我们的领域。

嵌入的空间插值

该项目的目的是根据钻孔观测结果生成一张三维地质图,分布如下图所示。描述有相关的坐标和深度,类似于本博客顶部的土壤描述。

为了执行 3D 插值,首先我们必须生成“描述嵌入”。由于这是一个概念验证,我们决定使用简单的方法来计算每个描述中单词嵌入的平均值,从而为每个描述生成一个包含 300 个组件(GeoVec 组件的数量)的单个嵌入。

在插入嵌入后,我们获得了一个 3D 模型,看起来像:

Fig. 5: 3D lithological map of classes (left panel) and its associated measures of uncertainty. Uncertainties correspond to Confusion Index (CI) between the first and second most likely class (middle panel) and Entropy (right panel).

左图显示了每个体素的最可能的类(从多类分类器得到),中间图显示了每个体素的第一和第二最可能的类之间的混淆指数,而右图显示了相应的熵。

插值过程和多类分类器的完整描述可以在相应的出版物中找到(目前它正在审查中,但我会在出版物被接受后更新这篇文章)。

最后的话

这些只是在地球科学中使用单词嵌入的第一次尝试。结果非常有趣,因为手套模型似乎很好地捕捉了许多“自然”属性(如颗粒大小)。当然,这只有在语料库足够大且足够多样化的情况下才有可能。

我们公开了嵌入内容,这样人们就可以使用和试验它们。我们还将使测试套件可用,以允许人们用新的和更复杂的测试来扩展它,并且还将它们用作新的(和更好的)测试的基线。)模特。

我看到了在地球科学中使用单词嵌入的巨大潜力。多年来收集的大量描述性信息可以被“拯救”和使用。我还认为用单词嵌入来补充数字数据是可能的,所以我会继续尝试并撰写相关文章。敬请期待!

引文

关于这项工作的更多细节可以在相应的论文中找到。

  • Padarian,j .和 Fuentes,I .,2019 年。地学应用中的单词嵌入:土壤相关概念的发展、评价和实例。土壤,5,177–187,https://doi.org/10.5194/soil-5-177-2019。
  • Fuentes,j . Padarian,t . iwan aga,w .维尔伍特,2019。使用单词嵌入进行钻孔描述的 3D 岩性绘图。计算机与地球科学(正在审查中)。

embbedings 可从以下网址获得:

  • Padarian 和 I . Fuentes,2019 年。吉奥维克。https://doi.org/10.17605/OSF.IO/4UYEQ。

参考

Kingma,D.P .和 Dhariwal,p .,2018 年。辉光:带有可逆 1x1 卷积的生成流。神经信息处理系统进展(第 10215-10224 页)。

从 R 控制台历史记录中获取任何美国音乐排行榜

原文:https://towardsdatascience.com/get-any-us-music-chart-listing-from-history-in-your-r-console-6bd168f192cb?source=collection_archive---------11-----------------------

了解 R 的抓取功能,并编写一个简单的函数来抓取过去任何日期的美国音乐图表

我们很幸运生活在一个我们可以得到几乎任何我们想要的事实的时代。如果我们想找出 1980 年以来排行榜前 200 名的专辑,我们只需要去官方的 Billboard 200 网站,输入日期,列表上方就会出现一个漂亮的展示,里面有专辑封面和所有漂亮的东西。

但是我们通常不关心好的东西,我们不想访问一个网站,点击几次来获得我们需要的信息。如果我们可以通过简单的功能或命令在我们的控制台中获得它,这不是很好吗?

嗯,如果网站结构良好,并从结构化数据集中访问数据,那么很可能你可以抓取它,这意味着你可以将你想要的精确信息提取到一个向量或表格中,允许你进行分析或做任何事情。

在这篇文章中,我们将使用包rvestxml2来回顾 R 中的基本 web 抓取。这些软件包非常容易使用。到本文结束时,我们将创建一个名为get_charts()的函数,它将一个日期、一个图表版本和一个排名位置向量作为其参数,并立即返回该日期这些位置的图表条目。我希望这将鼓励您在无数其他 web 数据源上进行尝试。

对于本教程,你需要安装dplyrxml2rvest软件包。你还需要使用谷歌浏览器。

开始行动——刮本周的公告牌 100 大热门

我们将从如何刮出本周的 Billboard Hot 100 开始,以获得艺术家和标题的排名列表。如果你看看 https://www.billboard.com/charts/hot-100的热门 100 页,你可以观察到它的整体结构。它有各种各样的横幅和广告,还有很多正在进行的事情,但你可以立即看到页面上有一个热门的 100 个列表,所以我们知道我们想要的信息在这个页面上,我们需要导航底层代码来找到它。

R 中的包rvestxml2旨在使提取和分析当今大多数网站背后的深度嵌套的 HTML 和 XML 代码变得容易。HTML 和 XML 是不同的——我不会在这里详细讨论——但是您通常需要rvest来挖掘并找到您需要的特定 HTML 节点,以及xml2来提取包含您想要的特定数据的 XML 属性。

在我们加载包之后,我们想要做的第一件事就是从网页中读取 html,这样我们就有了一个挖掘的起点,可以找到我们想要的节点和属性。

# required libraries
library(rvest)
library(xml2)
library(dplyr)# get url from input
input <- "https://www.billboard.com/charts/hot-100"# read html code from url
chart_page <- xml2::read_html(input)

现在我们有了一个列表对象chart_page,它包含两个元素,一个用于网页的头部,另一个用于网页的主体。

我们现在需要使用 Chrome 来检查网站。右击网站,选择“检查”。这将打开一个面板,显示所有嵌套的 HTML 和 XML 代码。当您将鼠标滚动到这段代码上时,您会看到它所涉及的页面部分被突出显示。例如,您可以在这里看到,当我将鼠标放在突出显示的<div class = "container chart-container ...">上时,我们感兴趣的部分会突出显示,这很有意义。

如果您继续扩展这一部分并遵循这种方法,您将最终找到填充图表列表的特定 HTML 和 XML 代码。如果您看得足够近,您会看到图表项目都具有格式<div class='chart-list-item' ...。我们可以使用rvesthtml_nodes()函数深入页面主体,并使用xml2xml_find_all()函数获取所有将chart-list-item作为其类的<div>节点。

# browse nodes in body of articlechart <- chart_page %>% 
    rvest::html_nodes('body') %>% 
    xml2::xml_find_all("//div[contains([@class](http://twitter.com/class), 'chart-list-item  ')]")View(chart)

这给了我们一个嵌套的编号列表,我们可以点击和浏览,就像这样:

现在我们注意到,包含我们感兴趣的数据的实际 XML 类实际上在chart-list-item后面有一个空格,所以如果我们重写前面的命令,使其有一个额外的空格,这应该可以解析出包含我们想要的数据的节点。然后我们可以使用xml2xml_attr()函数将排名、艺术家和标题提取到向量中。

# scrape data
  chart <- chart_page %>% 
    rvest::html_nodes('body') %>% 
    xml2::xml_find_all("//div[contains([@class](http://twitter.com/class), 'chart-list-item  ')]")# get rank, artist and title as vectorrank <- chart %>% 
    xml2::xml_attr('data-rank')

  artist <- chart %>% 
    xml2::xml_attr('data-artist')

  title <- chart %>% 
    xml2::xml_attr('data-title')# create dataframe, remove NAs and return result
  chart_df <- data.frame(rank, artist, title)
  chart_df <- chart_df %>% 
    dplyr::filter(!is.na(rank))View(chart_df)

这就是我们想要的,一个很好的列表,很高兴知道有 100 行是我们期望的:

概括地从任何日期提取任何图表

所以这需要做大量的调查工作,钻研 HTML 和 XML 可能会很烦人。有像 SelectorGadget 这样的 Chrome 插件可以帮助解决这个问题,但是我发现它们是不可预测的,我更喜欢像我上面做的那样研究下面的代码。

然而,既然我们知道了数据的位置,我们现在可以让它变得更加强大。如果你玩玩 billboard.com 网站,你会注意到你可以通过简单地编辑 URL 来获得任何历史日期的特定图表。例如,如果你想看 1983 年 3 月 22 日的广告牌 200,你只需去 https://www.billboard.com/charts/billboard-200/1983-03-22。

因此,这允许我们使用上面的代码,并通过创建一个接受我们感兴趣的日期、图表类型和位置的函数来轻松地对其进行概括。让我们用日期(今天)、图表类型(默认为热门 100)和位置(前 10 位)一些默认值来编写这个函数。

get_chart <- function(date = Sys.Date(), positions = c(1:10), type = "hot-100") {# get url from input and read html
  input <- paste0("[https://www.billboard.com/charts/](https://www.billboard.com/charts/)", type, "/", date) 
  chart_page <- xml2::read_html(input)# scrape data
  chart <- chart_page %>% 
    rvest::html_nodes('body') %>% 
    xml2::xml_find_all("//div[contains([@class](http://twitter.com/class), 'chart-list-item  ')]")rank <- chart %>% 
    xml2::xml_attr('data-rank')

  artist <- chart %>% 
    xml2::xml_attr('data-artist')

  title <- chart %>% 
    xml2::xml_attr('data-title')# create dataframe, remove nas and return result
  chart_df <- data.frame(rank, artist, title)
  chart_df <- chart_df %>% 
    dplyr::filter(!is.na(rank), rank %in% positions)chart_df}

好了,让我们来测试我们的功能。1983 年 3 月 22 日排名前 20 的单曲是什么?

1970 年 4 月 1 日排名前 10 的专辑是什么?

我喜欢rvestxml2的地方在于它们是多么简单和强大。看看这个函数的内容有多精简——创建一个非常强大的东西并不需要花费太多时间。尝试一下其他来源的网络数据,如果您创建了任何其他很酷的抓取功能,可以在这里随意添加到 Github repo 中。

最初我是一名纯粹的数学家,后来我成为了一名心理计量学家和数据科学家。我热衷于将所有这些学科的严谨性应用到复杂的人的问题上。我也是一个编码极客和日本 RPG 的超级粉丝。在LinkedInTwitter上找我。

你可以在这里***xml2*这里了解更多关于* *rvest* *

在数据科学写作方面做得更好,机会就会增加

原文:https://towardsdatascience.com/get-better-in-data-science-writing-and-the-opportunities-will-grow-9d37fdada262?source=collection_archive---------35-----------------------

Photo by Ian Stauffer on Unsplash

如何在一年内将你的数据科学写作提高 3700%

改善沟通的 9 个技巧

我们一直都这样做。

写作是我们交流的一个重要部分。我们写电子邮件、短信和博客。我们撰写项目报告和技术文档。我们写求职信和简历。我们写不完的文字,一整天都在写。

请记住,你写的东西通常是你唯一的机会,让你可以向别人展示你需要的生意、金钱或善意。

—威廉·津瑟

他是对的。不要因为不够清楚而错失良机。如果写作是我们每天最常做的事情,想象一下哪怕提高一点点的回报。

在这篇文章中,我将通过一些简单的步骤,让你的写作更有效率,并提供一些最好的建议。

数据科学家通常需要向非技术受众解释他们的方法和发现。例如,经理或营销团队。

Photo by Icons8 Team on Unsplash

避免行话和杂乱的句子。不厌其烦地讲清楚,讲个人。

清晰的文字可以比作进行主成分分析。在 PCA 中,目标是选择解释数据中大部分变化的变量,并简化计算过程。

https://en.wikipedia.org/wiki/Scree_plot#/media/File:Screeplotr.png

通过在你的文章中仔细选择最重要的事实和想法,并删除不太重要的,你可以让你的故事更容易被你的读者接受。

写得更好的 9 个简单步骤

以下步骤将帮助您更好地讲述您的数据科学故事。查看最后的参考资料,了解更深入的信息。

1.养成每天写作或重写 30 分钟的习惯

例如,在健身方面,如果你偶尔训练,你的肌肉不会有任何增长。只有当你经常锻炼时,你的肌肉才会开始生长并变得更强壮。同样,精神任务随着一致性而提高。

有才华的人之所以有才华,并不是因为他们曾经做过某件事,而且很棒。他们做了成千上万次的事情,只有在那之后,他们才成为传奇。做事多次。 写日常。你做得越多,就会做得越好。

正如《华氏 451 度》的作者雷·布雷德伯里所说

“数量产生质量。如果你只写几样东西,你就完了。”

生活中的许多事情都遵循指数增长曲线。开始时,你的收益很小,最后会高得多。

如果你在一年中每天提高 1%的技能,那么在一年结束时,你将获得 3700%的累积进步。

# Cumulative gains after 365 days
1.01^365 * 100
= 3778.343%

Daily 1% improvements result in a 3700% gain in one year

2.从结构开始

我得到的这个写作技巧来自我最喜欢的作家之一,

“学结构。研究你最喜欢的非小说类书籍,特别要注意这本书是如何在书的层次上组织的,然后是章节层次,然后是段落层次。结构让其他一切变得更容易。”

您可以将此应用于撰写数据科学故事。分析你喜欢的数据科学文章的结构。作者如何组织整篇文章?他是如何构建每一段的?他如何利用故事将数据嵌入其中?这将帮助你理解和发现你自己的成功之路。结构会给你方向。

使用框架

写好一个故事的关键往往在于能够组织好自己的思路。为了以书面形式组织你的思想,你需要一个框架。任何框架都比没有好,甚至比开始-中间-结束帮助还要简单。

Photo by Eliabe Costa on Unsplash

你的卧室衣柜如何整理你的衣服?同样,即使是一个粗略的文章计划也会让一切变得更容易。尤其是在数据科学项目中,写作可能会变得复杂。有一个框架把不同的部分放在一起,会使构建最终的故事更加容易。

博览群书,但要读得透彻。研究你在 medium.com 或其他数据科学博客上找到的最佳文章。看看它们是如何在段落或句子层面上作为一个整体来构建的。

3.设定截止日期

截止日期帮助我们在更少的时间里做更多的事情。想象一下,你有一年的时间写完一本书。但是你很有野心,你给自己设定了一个期限,要在一个月内完成。你认为这一个月结束时事情会是什么样子?你可能无法完成,但你会进步很多。

Photo by Luke Chesser on Unsplash

对于数据科学文章,我会创建一个快速的初稿,我必须在一个小时内完成。这个练习将教你选择最重要的事实,并在你的文章中去掉不太重要的。这是让你的听众清楚明白的先决条件。

  • 如果你只有 60 分钟来写 2000 字,你没有时间分心。这个限制将帮助你选择需要做的事情,放弃不太重要的事情。

这样做将有助于你掌握对项目核心的关注。

就像我们在化学课上学到的,气体会充满它们所在的空间。就像一滴古龙水会在房间的另一个角落被感觉到。任务膨胀以填满分配给它们的时间空间。这就是众所周知的帕金森定律,这个术语是由西里尔·诺斯古德·帕金森创造的。我使用伽马分布函数创建了一个描述原始帕金森定律的类似曲线。

完成一项任务的总努力(曲线下面积)随着允许时间的增加而增加。

除了帮助你管理时间之外,真正的好处是让你学会如何快速提取数据的核心。

4.简单解释一下

我们倾向于把使用复杂的句子和大量的术语作为我们智慧的一部分。T2:但是智慧的真正标志是能够把事情解释得更简单。清晰的文字需要更清晰、更简单的思维。我最喜欢爱因斯坦的一句名言是:

“如果你不能简单地解释它,你就不够了解它”

5.用故事。

故事在我们的大脑中根深蒂固,因为它们对生存至关重要。在书面语言出现之前,故事是我们传递信息的唯一方式。

也许我们需要被讲很多遍才能了解事实和数字故事只需要讲一遍就永远不会被忘记。你的故事与真实生活事件或真实具体的商业问题联系得越紧密,读者就越容易理解。

“数据和故事的区别在于此:数据列出了发生的事情;故事表达了事情发生的方式和原因。数据按数量和频率汇编事实;故事揭示了这些事实背后的因果关系。故事消除不相关,专注于动态变化。

将个人兴趣与数据科学写作结合起来

在帖子中加入你的个人风格。读者喜欢知道文本背后的人是谁,喜欢了解真实人物的经历和更多信息。

6.具体点

美国参议员 S.I. Hayakawa 和语义学专家介绍了抽象的概念阶梯。非常具体的概念在底部,更一般的概念在阶梯的顶部。下面是奶牛贝西的例子:

source: http://www.atlas101.ca/pm/concepts/ladder-of-abstraction/

使用一般概念来介绍一个主题,并通过给出具体的例子来解释你所得到的结果,尽可能降低抽象层次。当给出一个非常具体的例子时,大脑工作得最好,然后它可以更容易地理解复杂的主题。

如果你曾经使用过显微镜来观察一只小昆虫的部分,你知道你必须把物镜对准焦点。就像特定信息聚焦大脑一样。

避免使用你的直接判断,而是列出事实。

南 I Hayawaka 在《语言、思想和行动》中对此做了很好的解释:

而不是告诉读者,“这是一个可怕的事故!”我们可以让读者自己说出来。可以说,读者是通过自己得出结论来参与交际行为的。因此,一个有技巧的作家通常是一个特别擅长选择那些肯定会以期望的方式打动读者的事实的人。比起一系列明确的判断,我们更有可能被这样的描述性和事实性的文字所说服,因为作者并没有要求我们相信他所说的事故是“可怕的”。

7.改变段落

网上阅读和书本阅读是不同的。人们不喜欢文字墙。使用不同长度的段落和句子。

大声朗读那些句子,你会更好地感受到不同之处。人类的大脑不断监测环境的变化,变化捕捉,单调扼杀人类的注意力。改变句子的长度使用短、中、长句,让句子更有音乐感。

8.使用合适的图片和标题

如果你听说过罗伯特·恰尔迪尼关于说服的研究,你可能会对这些图片如何帮助你更有效地传达信息有所启发。

一本在市场营销方面很有影响力的书《劝说前》( pre-suisation)提供了证据,证明我们的行为受到我们在采取行动之前所做或所见的事情的影响。

例如,在 Mandel 和 Johnson 的实验中,当在线家具店的登录页面使用金钱作为背景图像时,访问者更关心价格,但是当登录页面上显示蓬松的云时,他们对舒适度更感兴趣,并购买更昂贵的物品。让你的读者或商业伙伴明白你想要传达的信息。

标题和图片通常是你的潜在读者看到的第一件事。通过使用与你希望他们所处的心态相关的恰当形象或信息来支持你的发现。

如果您的数据科学解决方案是关于降低生产线成本,请使用钱的图像,如果您找到了提高客户满意度的方法,请使用开心的客户照片。

想想你想把你的读者放在什么心情?这里有一段罗伯特·恰尔迪尼的简短视频,他给出了一些关于压力的建议。

9.获得可见性

网络上的噪音是巨大的。做好工作只是一半。你需要让世界知道你创造了什么。

挑战在于如何让你的观众理解。

馆长网站或博客可以提高你的数据科学博客的流量。例如,当我把我的博客提交给 R Bloggers 时,我一天的流量比我过去几周的流量还要多。

其他一些例子有:

显然,medium.com(如果你向数据科学提交会更好)。

Reddit

推特。

加贺

看到最终产品会迫使你更快地完成它。例如,当我第一次使用 R Markdown 创建一篇博客文章,并在本地或使用 medium editor 查看时,我可以比使用 word 文档更快地完成文章。

在大多数语言中,否定词支配肯定词。背后的进化原因很可能是为了保护自己免受危险。

当我们看到或听到标题中的负面词汇或限制时,我们会停下来思考更久。这就是为什么当我们看到标题为“最后的机会,还有 3 个小时就可以享受优惠”的邮件时,我们更有可能点击我们的邮箱。

你会学到什么?

写作和做数据科学项目都是为了解决问题。在你的项目中,你正在解决一个业务问题。在你的写作中,你正在解决一个问题,比如如何组织一个混乱或复杂的故事,如何找到相关的材料,以及如何对它们进行排序。

成为一个强有力的沟通者会给你带来新的工作机会、新的伙伴关系和更好的关系。

摘要

如果你写的东西对解决一个问题有价值,或者提供了一些见解,或者以一种有趣的方式解释了一个抽象的概念不要等到它成为历史上最完美的文章。

你电脑里的某些东西对你或这个世界没什么帮助。T4:分享比隐藏更好。如果你这样做了,你可以应用本指南中的一些技巧来提高你的数据科学写作。

不要担心任何错误。我们都是人,我们都从犯错中学习。接受不完美打开了改进之门。

不仅在数据科学中应用这些技巧,而且在任何类型的写作中应用,你都会看到进步。

数据科学写作帮助你获得反馈,激发讨论和改进。

你不一定要成为某个主题的专家才能写它,写它才能成为这方面的专家。

资源:

故事经济学。由罗伯特·麦基,托马斯·杰雷斯等人。

关于写好。威廉·津瑟。(我的字幕来自这本书)

一鸟接一鸟。安妮·拉莫特。

雷·布雷德伯里最伟大的写作建议。lithub.com。

提高写作的 100 种方法。作者加里·普洛斯特

帕金森定律。经济学家。伦敦。

为什么 25 个单词的句子长度是我们的极限。英国政府内部

预先劝说:影响和说服的革命性方法,罗伯特·恰尔迪尼博士

影响力:说服的心理学。罗伯特·恰尔迪尼博士

为什么人们会在网上分享?纽约时报。

分享有用的内容是帮助彼此克服噪音和获取相关知识的好方法。最近的一项研究发现,人们会分享更多他们认为有用的内容。

谢谢你读到这里。希望你从中有所收获或者有所启发。

下次见!

塞尔达尔·科鲁尔

用摩丁获得更快的熊猫,甚至在你的笔记本电脑上。

原文:https://towardsdatascience.com/get-faster-pandas-with-modin-even-on-your-laptops-b527a2eeda74?source=collection_archive---------3-----------------------

用 Modin 扩展交互式熊猫工作流。

Source

通过更改一行代码来扩展您的熊猫工作流程

Pandas 是一个在数据科学领域无需介绍的库。它提供了高性能、易于使用的数据结构和数据分析工具。然而,当处理大量数据时,单核上的 Pandas 变得不够用,人们不得不求助于不同的分布式系统来提高性能。然而,提高性能的代价是陡峭的学习曲线。本质上,用户可能只是希望 Pandas 运行得更快,并不希望为他们特定的硬件设置优化他们的工作流程。这意味着人们希望对 10KB 数据集和 10TB 数据集使用相同的 Pandas 脚本。摩丁提出通过优化熊猫来提供解决方案,以便数据科学家将时间花在从数据中提取价值上,而不是花在提取数据的工具上。

摩丁

摩丁 是加州大学伯克利分校rise lab的一个早期项目,旨在促进分布式计算在数据科学中的应用。这是一个多进程数据框架库,具有与 pandas 相同的 API,允许用户加速他们的 Pandas 工作流程。

Modin 在 8 核机器上将 Pandas 查询速度提高了 4 倍,只需要用户在笔记本上修改一行代码。该系统是为现有的 Pandas 用户设计的,他们希望自己的程序运行得更快,规模更大,而不需要进行重大的代码更改。这项工作的最终目标是能够在云环境中使用熊猫。

装置

摩丁是完全开源的,可以在 GitHub 上找到:https://github.com/modin-project/modin

可以从 PyPI 安装 Modin:

pip install modin

对于 Windows,其中一个依赖是射线。Ray 在 Windows 上还没有本地支持,所以为了安装它,需要使用 WSL(Linux 的 Windows 子系统)。

摩丁如何加快执行速度

在笔记本电脑上

考虑一台 4 核现代笔记本电脑,其数据框架非常适合。熊猫只使用一个 CPU 核心,而另一方面,摩丁使用所有的核心。

Utilisation of cores in pandas vs modin

基本上,modin 所做的只是提高了 CPU 所有内核的利用率,从而提供了更好的性能。

在大型机器上

在大型机器上,摩丁的用处变得更加明显。让我们假设有一些服务器或一些非常强大的机器。所以熊猫仍然会使用一个核,而摩丁会使用所有的核。下面是read_csv 在 144 核计算机上与熊猫和摩丁的性能对比。

source

熊猫有一个很好的线性扩展,但那是因为它仍然只使用一个核心。可能很难看到绿色条,因为它们在摩丁很低。

通常,2gb 大约需要 2 秒,18gb 大约不到 18 秒。

体系结构

让我们来看看摩丁的建筑。

数据帧分割

分区模式沿着列和行进行分区,因为它在支持的列数和行数方面为 Modin 提供了灵活性和可伸缩性。

Source

系统结构

摩丁被分成不同的层。:

  • 熊猫 API 暴露在最顶层
  • 下一层包含查询编译器,它从 pandas API 层接收查询并执行某些优化。
  • 最后一层是分区管理器,它负责数据布局和重排、分区,以及序列化发送到每个分区的任务。

a general architecture for modin

在 Modin 中实现 pandas API

pandas API 非常庞大,这可能是为什么它有如此广泛的使用案例的原因。

pandas API

由于手头有如此多的操作,摩丁采用了数据驱动的方法。这意味着摩丁的创造者观察了人们在熊猫身上通常使用的东西。他们去了 Kaggle,对那里所有的笔记本和脚本进行了大规模的搜集,最终找出了
最受欢迎的熊猫方法,如下所示:

pd.read_CSV是熊猫迄今为止使用最多的方法,其次是pd.Dataframe.因此,在摩丁,他们开始按照受欢迎程度的顺序实施和优化一些东西:

  • 目前,摩丁支持大约 71% 的熊猫 API。
  • 根据研究,这代表了约 93%的使用量。

光线

摩丁使用射线提供了一种毫不费力的方式来加速熊猫的笔记本、脚本和库。Ray 是一个高性能分布式执行框架,目标是大规模机器学习和强化学习应用。相同的代码可以在单台机器上运行,以实现高效的多处理,并且可以在集群上用于大型计算。你可以在 GitHub 上找到雷:github.com/ray-project/ray。

使用

进口

摩丁包装了熊猫并透明地分发数据和计算,通过一行代码的改变加速了熊猫的工作流程。用户继续使用以前的 pandas 笔记本,同时体验到来自 Modin 的相当大的速度提升,即使是在单台机器上。只需要修改导入语句,其中需要导入modin.pandas 而不是简单的pandas.

import numpy as np
import modin.pandas as pd

让我们使用由随机整数组成的 Numpy 构建一个玩具数据集。注意,我们不必在这里指定分区。

ata = np.random.randint(0,100,size = (2**16, 2**4))
df = pd.DataFrame(data)
df = df.add_prefix("Col:")

当我们打印出来的时候,它是一个 Modin dataframe。

type(df)modin.pandas.dataframe.DataFrame

如果我们用 head 命令打印出前 5 行,它会呈现一个 HTML 表,就像 pandas 一样。

df.head()

比较

Modin 管理数据的划分和重组,以便用户能够专注于从数据中提取价值。以下代码是在一台 2013 年的 4 核 iMac 上运行的,内存为 32GB。

pd.read_csv

read_csv 是目前为止熊猫用的最多的操作。我们在熊猫 vs 摩丁中使用 read_csv 的时候做一个快速对比。

  • 熊猫
%%timeimport pandas 
pandas_csv_data = pandas.read_csv("../800MB.csv")-----------------------------------------------------------------CPU times: user 26.3 s, sys: 3.14 s, total: 29.4s
Wall time: 29.5 s
  • 摩丁
%%time
modin_csv_data = pd.read_csv("../800MB.csv")-----------------------------------------------------------------CPU times: user 76.7 ms, sys: 5.08 ms, total: 81.8 ms
Wall time: 7.6 s

有了 Modin, **read_csv** 只需更改导入语句即可在 4 核机器上实现高达 4 倍的速度提升

df.groupby

熊猫 groupby 写的特别好,速度特别快。但即便如此,摩丁还是胜过熊猫。

  • 熊猫
%%timeimport pandas_ = pandas_csv_data.groupby(by=pandas_csv_data.col_1).sum()
-----------------------------------------------------------------CPU times: user 5.98 s, sys: 1.77 s, total: 7.75 s
Wall time: 7.74 s
  • 摩丁
%%timeresults = modin_csv_data.groupby(by=modin_csv_data.col_1).sum()
-----------------------------------------------------------------CPU times: user 3.18 s, sys: 42.2 ms, total: 3.23 s
Wall time: 7.3 s

默认为 pandas 实现

如果有人想使用尚未实现或优化的 pandas API,实际上可以默认使用 pandas。这使得该系统可用于使用尚未在 Modin 中实现的操作的笔记本电脑,即使性能会有所下降,因为它现在将使用 pandas API。当默认为熊猫时,您会看到一条警告:

dot_df = df.dot(df.T)

一旦计算完成,它返回一个分布式的 Modin 数据帧。

type(dot_df)
-----------------modin.pandas.dataframe.DataFrame

结论

摩丁仍处于早期阶段,似乎是一个非常有前途的大熊猫的补充。Modin 为用户处理所有的分区和洗牌,这样我们就可以专注于我们的工作流程。Modin 的基本目标是使用户能够在小数据和大数据上使用相同的工具,而不必担心改变 API 以适应不同的数据大小。

自从这篇文章发表后,很多人一直问我,就报价而言,摩丁和 Dask 有什么不同。下面是作者的详细对比:

[## 质疑:达斯克和摩丁有什么区别?第 515 期摩丁-项目/摩丁

github.com](https://github.com/modin-project/modin/issues/515#issuecomment-477722019)

参考

https://rise . cs . Berkeley . edu/blog/modin-pandas-on-ray-2018 年 10 月/

熟练掌握降价

原文:https://towardsdatascience.com/get-fluent-in-markdown-da6319f70c9d?source=collection_archive---------30-----------------------

你肯定听说过减价。用过吗?如果没有,就要开始了。现在。它将彻底改变你输入纯文本的方式。

Photo by Chris Leggat on Unsplash

Markdown 是一种用于键入纯文本的格式化语法。这是给纯文本添加格式的最简单的方法,比如标题、粗体文本、斜体文本、有序和无序列表、图像、链接、代码段等等。以下是开始在 Markdown 中输入的一些理由

  • 它拥有一个关键特性——使用HTML的能力。像<br><h1>...</h1><p>...</p>等标签可以在 Markdown 中随意使用。
  • 读起来很容易,也很愉快。
  • 到处都是。它是 Github 上使用的默认标准(非官方)。各种网站都接受减价,包括媒体。用 Markdown 编写的任何内容都可以导出,而不会影响格式。
  • 它不会很快消失。毕竟,它是纯文本格式,这是不变的。
  • 使用 Markdown,你可以利用文字处理器的能力,不用文字处理器,只用你的键盘。

降价是一件大事。学习有多重要?

Markdown 只不过是使用特殊字符进行格式化。看一看。

标题:

标题的大小由文本前的散列符号(# ) 的数量决定。

# Heading 1:对应最大尺寸。与在HTML中使用<h1>相同。

## Heading 2:对应使用HTML中的<h2>

### Heading 3:对应使用HTML中的<h3>

…以此类推,直到<h6>

段落:

Markdown 自动检测每一个空行的段落。与在HTML中使用<p>相同。

粗体和斜体:

只需将文本括在两个星号(**text**)或两个下划线(__text__)之间,以粗体显示。要倾斜文本,请在文本前后使用单个星号(*text*)或下划线(_text_)。

I **love** _writing_ in __Markdown__.

单词“love”和“Markdown”将以粗体显示。“writing”一词将用斜体表示。

若要合并,请使用三个星号或三个下划线(***text***)或(___text___)。也可以使用两个星号和一个下划线的组合,反之亦然(**_text_**)。

大宗报价:

要对一个段落进行块引用,只需在文本前添加>。相当于在 Medium 中使用 " 选项。

有序列表:

在每个列表项前使用数字后跟句点。这相当于在HTML中使用<ol>...</ol><li>元素。

无序列表:

在每个列表项前使用-+*。添加制表符缩进嵌套列表,包括有序列表和无序列表。

代码:

用反斜杠(text)将代码括起来,以添加内联代码。这相当于在HTML中使用<code>...</code>

这还不是全部!以上足以让你入门。点击查看更多降价语法。

降价就是这么简单!只需几个特殊字符,你就可以轻松格式化你的纯文本。记得用扩展名.md保存文件。

任何文本编辑器都支持 Markdown。检查 Typora 。

注意:本文是使用 Markdown 编写的。

获取用于教学和实验的手绘可视化数据

原文:https://towardsdatascience.com/get-hand-drawn-visualization-shaped-data-for-teaching-and-experimenting-391425fe3171?source=collection_archive---------43-----------------------

drawdata.xyz

实验和教学对遵循特定模式/形状/分布的定制/伪造数据的需求并不新鲜。最近我写了一篇关于 {fakir} 的文章,这是一个用于生成虚假数据的 R 包。

更进一步,如果您可以* *** 绘制 **一个可视化并下载该特定可视化的数据,会怎么样?太棒了,对吧?我很想用这样一个!

感谢 Vincent D. Warmerdam 创造了 drawdata.xyz 这是我从未见过的美丽事物。

需要吗?

很多时候,当我们教授数据科学中的某些内容时,比如说“正相关”,我们需要展示一个具有正相关数据点的散点图。虽然看起来很简单,但要找到符合模式/形状的数据并不容易。在寻找数据的过程中,许多人对解决他们最初打算解决的问题失去了兴趣。

解决方案— drawdata.xyz

Courtesy: drawdata.xyz

正如在上面的动画中演示的那样,drawdata.xyz 是一个免费的服务,它允许您绘制您想要的可视化模式/形状,并下载csvjson可用于这种可视化的数据。

目前 drawdata.xyz 支持以下可视化:

  • 折线图
  • 散点图
  • 柱状图

验证解决方案

我试着用 Python 使用从上面的动画data.csv中下载的数据,看看数据是否真的遵循相似的形状,只是为了验证,下面是我从seaborn中得到的图

所以,它起作用了——就像它承诺的那样。

生成自己数据的步骤:

  • 打开 drawdata.xyz ,向下滚动/导航至您喜欢的可视化格式
  • 使用屏幕画布和鼠标指针为所选可视化绘制所需的形状/图案
  • 下载 csv或复制json随心所欲
  • 如果你想尝试不同的图案/形状,重置画布

参考

  • https://twitter.com/fishnets88/status/1189272650100678657

笔记

  • 上面显示的由创建者(Vincent d . warmer dam‏)快速生成模式跟踪/成形数据的 drawdata 项目托管在实际的服务器上,这耗费了开发者的经常性成本以及开发和维护时间,因此如果您将它用于任何商业目的或者想要捐赠/鼓励这些努力,请在https://www.buymeacoffee.com/koaning支持开发者。
  • 我与该项目和开发人员都没有关系,这只是我试图编写和展示一个经过深思熟虑的项目,它可以帮助数据科学教学和实验。

参与 SciPy!

原文:https://towardsdatascience.com/get-involved-with-scipy-5daf700c83ad?source=collection_archive---------35-----------------------

SciPy 希望你的想法能帮助它变得更加用户友好

Photo by Lum3n.com from Pexels

你听说过 SciPy。

你可能用过。

您可能已经浏览了一些技术文档和用户指南。您甚至可能对文档有自己的看法…

但是你有没有想过实际参与进来,让 SciPy 知道他们如何改进他们的文档?告诉 SciPy 你喜欢什么不喜欢什么?

你认为如何改进文档?

现在你的机会来了!

GIF via GIPHY

什么是 SciPy?

是科学(SciPython(Py)!SciPy 是一个免费的开源 Python 库。它用于科学计算和技术计算。它包含了优化、线性代数、积分、插值、特殊函数、 FFT 、信号、图像处理、 ODE 解算器等理工科常见任务的模块。

SciPy 使用 NumPy 数组作为基本的数据结构。它有科学编程中各种常用任务的模块。这些任务包括积分(微积分)、常微分方程求解和信号处理。SciPy 构建在 NumPy 数组对象上。这是 NumPy 堆栈的一部分。该堆栈包括像 Matplotlib 、 Pandas 和 SymPy 这样的工具,以及一套不断扩展的科学计算库。

你怎么能参与进来?

快速调查一下!

It’s here! https://forms.gle/eK3x2ohJs1sLPJEk8

关于调查

当我在 NumPy 致力于在技术文档中创建一个面向初学者的部分时,Maja Gwózdz 正在 SciPy docs 中努力工作。她正在梳理 SciPy 文档,以创建对您更有帮助的东西。她正在接触整个社区(就是你!)找出你喜欢什么和不喜欢什么,她会喜欢你的投入!

正如 Maja 在她的谷歌文档季提案中所写的:

“我打算对现有文档进行重构,以便具有不同需求的用户可以轻松访问它。不言而喻,研究人员最有可能对高级和微妙的特性感兴趣,而没有专业知识的用户则喜欢一步一步的指南和图表。

出于个人和专业原因,我对这个项目感兴趣:首先,我想为 SciPy 做出重大贡献,因为我自己的研究已经从它那里受益匪浅;其次,我经常在其他软件中遇到文档不足(或缺少文档)的情况,并且总是想知道要快多少(如果是全部的话!)如果向用户提供详尽的指南,他们可以学会如何使用代码。"

[## NumPy、SciPy 和 Google Docs 季,天啊:见见 Maja Gwózdz

在谷歌文档季期间,了解更多关于与 NumPy 和 SciPy 配对的技术作家的信息

towardsdatascience.com](/scipy-meet-maja-gwozdz-61616cc35c08)

Maja 对社区中所有希望被倾听的人进行了调查。这是一个举手参与的绝佳机会!您可以在此处找到该调查,它旨在让您尽可能多地投入时间和精力。

这些问题非常简单,大多数都有简单的选择题答案。您将回答这样的问题:“您使用文档的哪些部分?”以及“应该改进/添加哪些文档特性?”在选择题下面,可以添加自己的评论和建议。

这很快,很容易,而且非常有帮助。如果您使用过 SciPy 和 SciPy 文档,Maja 希望收到您的来信。

花一两分钟大声说出来,让别人听到!

Photo by White Gold Photography from Pexels

如果你是数据科学、机器学习和人工智能的新手,你可能想看看 NumPy 的终极初学者指南!

[## NumPy 初学者终极指南

开始使用 NumPy 需要知道的一切

towardsdatascience.com](/the-ultimate-beginners-guide-to-numpy-f5a2f99aef54)

构建竞争对手价格监控仪表板的终极指南

原文:https://towardsdatascience.com/get-rid-of-boring-stuff-using-python-part-2-b84d1e9ea595?source=collection_archive---------11-----------------------

用不到 20 行代码就能完成!

使用 Python 摆脱无聊的东西(第 2 部分)

感觉自己的工作充满了重复性的工作?

为什么不开始考虑如何实现自动化呢?

事情是这样的,今天我要介绍一个工具来自动化你枯燥的东西——Python。Python 可能是最容易学习的语言。因为你掌握了 Python 技能,你不仅能提高你的生产力,还能专注于你更感兴趣的工作。

欢迎来到使用 Python 系列摆脱无聊的东西!请随意访问这个链接,你将能够看到这个正在进行的系列中的所有故事。

现在让我们假设你是一名手机销售商,在一个电子商务平台上销售产品。

你会有一份竞争对手的名单…

你会想监测你的竞争对手是如何设置他们的价格,以便你可以稍微降低你的价格,以更具竞争力。

另一个场景,假设你在一家电子商务公司做销售,你有一个客户,阿迪达斯。

因此,你需要监控阿迪达斯是否在每个电子商务平台上销售相同的价格,如果不是,那么你也可以质疑他们的定价。

价格监控仪表板非常重要,尤其是在电子商务中。当两个卖家在销售同一产品时,价格是顾客是否会选择购买该产品的决定因素。

我们开始吧!

我就用你在亚马逊做卖家的例子,卖华为 P30 Pro 。所以,今天你将建立一个非常简单的仪表板——Google Sheet,来监控你的价格有多有竞争力。

这是我将要分享的议程:

第 1 部分 —输入竞争对手的详细信息。

第 2 部分——获取您的 google sheet 证书文件。

第 3 部分——在竞争对手的网站上进行网页抓取【可视化】

第 4 部分—竞争对手网站上的网页抓取[编码]

跟随整个旅程,你会发现让你无聊的事情自动化并在 5 秒内更新你的价格是多么简单。

第 1 部分—输入竞争对手的详细信息。

创建一个 google 表单,输入示例竞争对手的链接。给你的华为 P30 Pro 定个价。

为列 Competitive 定义一个条件格式,规则是如果你的价格比你的竞争对手低,它将是 1,单元格将填充绿色。否则,将其设置为 0 并用红色填充单元格,以提醒您的竞争对手正在设定比您更低的价格。

第 2 部分—获取 google sheet 的凭证文件。

按照这个链接,一步一步地,你将能够以 JSON 格式检索你的证书文件。在 JSON 格式的凭证文件中,您将能够看到您的电子邮件帐户,如下面的紫色框所示。

然后,将您的服务帐户的电子邮件共享到您刚刚创建的 google sheet,如下图所示。

然后点击发送按钮,就大功告成了!

第 3 部分—竞争对手网站上的网络抓取[可视化]

首先,在 google chrome 中启动竞争对手的网站,右键单击并选择 Inspect,然后您将能够在 Snapshot 1 中查看下面的快照。

Snapshot 1

然后,单击顶部中间的紫色括号,您将看到一个光标,然后单击红色括号检查产品价格的 HTML 元素,如下所示(快照 2)。

Snapshot 2

接下来,请注意快照 2 中上方的紫色框,这是我们需要提取的路径:

HTML 标记名:span

HTML 标记名属性 : priceblock_ourprice

*如果你不熟悉 HTML, 这个 对于上面的术语会是一个很好的参考。

所以现在让我们从编码部分开始吧!

第 4 部分—竞争对手网站上的网络抓取[编码]

访问谷歌工作表

按照上面的要点连接到 google sheet。

请注意, gc.open_by_key() 的输入如下:11 du 3 qbpoxlbuxj-o _ zerndjdqq 8 pnbmsazpebbfbwyc 0。这实际上是 Google 找到你对应的 google sheet 的唯一标识符。

您可以获得如下所示的唯一标识符(紫色框):

Snapshot 3

从谷歌工作表中提取数据

使用 get_all_values() 函数从 sheet_name: Sheet1 的 google 工作表中检索数据。

然后,将该值存储到 pandas 数据框中,如下所示:

df = pd.DataFrame(sht1.worksheet("Sheet1").get_all_values()[1:])

你已经完成了 70%!

网页抓取

记住价格 HTML 标签:

HTML 标签属性 : priceblock_ourprice

所以现在,我们使用美汤解析器来获取你需要的元素。

想象汤的格式如下:

soup.find( HTML 标签,{标签属性:属性值})

在我们的案例中:

HTML 标记名:span

标签属性:id

属性值:价格块 _ 我们的价格

soup = BeautifulSoup(res.text)
price = soup.find("span", 
                 {"id": "priceblock_ourprice"}
                 ).text.replace("$","")

更新谷歌工作表的最新价格

使用 update_acell(cell number,value) 函数将我们刮到的价格插入到 google sheet 中,我们就完成了

sht1.worksheet("Sheet1").update_acell('D3', price)

将上面提到的所有内容与下面的代码结合起来:

最终想法

我目前是一名数据科学家。数据增长真的很快,所以让自己具备良好的搜集技能很重要,因为你将能够为你的机器学习模型获得更多数据。

感谢你阅读这篇文章。欢迎在下面留下你感兴趣的话题的评论。我将在未来发布更多关于我的经历和项目的帖子。

关于作者

Low 魏宏是 Shopee 的数据科学家。他的经验更多地涉及抓取网站,创建数据管道,以及实施机器学习模型来解决业务问题。

他提供爬行服务,能够为你提供你所需要的准确和干净的数据。你可以访问这个网站查看他的作品集,也可以联系他获取抓取服务。

你可以在 LinkedIn 和 Medium 上和他联系。

[## 低微红—中等

在媒体上阅读低纬鸿的作品。Shopee 的数据科学家。每天,低伟鸿和其他成千上万的…

medium.com](https://medium.com/@lowweihong?source=post_page---------------------------)

摆脱恐惧,不到五分钟就掌握 Git。

原文:https://towardsdatascience.com/get-rid-of-your-fear-and-conqueror-git-in-less-than-five-minutes-56930c269ffd?source=collection_archive---------19-----------------------

为什么我们要写另一个指南?

我们写另一个是因为我们需要帮助自己真正理解 Git 是如何工作的,它能为我们做什么,我们需要稍微更深入的理解。

让我这样说吧,亲爱的读者们,我和我的朋友决定一起在一张纸上画一幅画,作为学校的家庭作业。我们在图书馆见面,复印了两份我们开始做的东西,我们都带了一份回家这是。我们都在图上添加了更多的东西,当我们明天回到学校时,我们剪切并粘贴我们改变的部分,然后影印改变这是合并。如果我们都擦除了同一个区域,必须有人选择使用哪个部分,这就是解决冲突。因为每次有东西改变时都有复印件,如果我不喜欢我所做的,我可以扔掉所有新的,这是重置。如果我们不喜欢我们所做的,那么我们可以烧掉所有新的复印件,这就是恢复。

让我们转到 Git 视角。对于 Git 这样的系统,我会首先在 Git 服务器上创建文件,并添加修改。然后,我提交那些变更到存储库。然后,我的朋友开始拉最新的变化。他添加了一些东西,然后提交给回购。回购说这个文件是存在的,并且和之前的版本不一样,我们就存成版本 2。以此类推。Git repo 允许我们进行编辑并保持更改的有序性,所以如果我在某个时候删除了一些东西,我可以说, Git,检查一下之前的点,然后我就可以回去修复我的东西了。

每个提交都有一个所有者,所以我们知道谁做了什么。我可以比较 Beta 版和 Alfa 版,看看有什么变化,更容易发现有什么新的变化。

Git 还允许我创建分支。所以我们在 doc 的第 17 个版本上,但是我想要尝试一些新的东西。我的朋友想继续,所以我创建了一个名为 MiTesoro 的分支,并开始着手于此。这现在是代码的一个单独的路径,而我的朋友继续原来的路径,这通常被认为是主路径。所以 Git 基本上允许多人访问通常是代码的中心部分,并对其进行修改,而不会踩到别人的脚趾。

Git 是什么?

Git 是一个成熟的、积极维护的开源项目,最初由 Linux 操作系统内核的著名创建者 Linus Torvalds 于 2005 年开发。数量惊人的软件项目依赖 Git 进行版本控制,包括商业项目和开源项目。使用过 Git 的开发人员在可用的软件开发人才库中有很好的代表性,它可以在各种操作系统和 ide(集成开发环境)上很好地工作。在这个技术介绍之后,让我们跳转来解释几个关于 Git 的词汇。

Git 中的分支是什么?

在 Git 中,有三个感兴趣的分支,本地分支、远程分支和跟踪分支,它们可能都指向不同的提交:

  1. 本地回购中,分行名为。这是我们工作和承诺的地方。这是当地的分公司。它在下图的左下方。
  2. 远程回购中,名为的分支。这是远程分支,位于下图的顶部。我们通常根本看不到它,因为它通常位于另一台计算机上,需要网络操作才能与之交互。
  3. 本地回购中名为起源/主的分支。这是跟踪分支,在图的右下方。我们自己从不修改跟踪分支。它是由 Git 自动为我们维护的。每当 Git 与远程 repo 通信并了解到一些关于远程主分支的部署情况时,它就会更新本地分支或 origin/master 以反映它所了解到的情况。

Understanding branching in Git.

Git 有哪些状态?

仔细阅读这篇文章,我亲爱的朋友。如果你想在 Git 中取得好的学习效果,这是关于 Git 要记住的主要事情。Git 有三种主要的文件状态:提交、修改和暂存。提交意味着数据安全地存储在您的本地存储库中,这是 git 提交的最终结果。 Modified 表示您已经更改了文件,但是还没有提交到您的数据库中。 Staged 意味着您已经在当前版本中标记了一个修改过的文件,以进入您的下一个提交快照。这是 git add 的最终结果。

Different states of Git.

Git 有哪些领域?

Git 目录是您的本地存储库,是 Git 存储项目的元数据和对象数据库的地方。这是 Git 最重要的部分,当您从另一台计算机上克隆一个存储库时,它就是被复制的内容。

工作目录是项目的一个版本的单次检出。这些文件从 Git 目录下的压缩数据库中取出,放在磁盘上供您使用或修改。

暂存区是一个简单的文件,通常包含在您的 Git 目录中,它存储了关于您下一次提交的内容的信息。它有时被称为索引,但是将它称为临时区域已经成为标准。

基本工作流程是什么?

基本的 Git 工作流程是这样的:

  1. 您可以修改工作目录中的文件。
  2. 您转移文件,将它们的快照添加到您的转移区域。
  3. 您执行一个提交操作,该操作将文件保存在临时区域中,并将快照永久存储到 Git 目录中。

Types of areas inside Git.

所以我希望你喜欢我们的文章,因为在接下来的故事中,我们将讨论 Git 的基本操作,以及还原和重置、拉取和获取、合并和重置之间的区别,Git 的不同工作流,以及如何解决合并冲突。

在 Udemy 上查看我们的免费课程。

感谢阅读。如果你喜欢这篇文章,请点击下面的按钮,这样我们就可以保持联系。

摆脱恐惧,不到五分钟就掌握 Git。第二部分

原文:https://towardsdatascience.com/get-rid-of-your-fear-and-conqueror-git-in-less-than-five-minutes-part-2-49b951cdb8d9?source=collection_archive---------23-----------------------

这是一个由七个部分组成的系列,作为理解 Git 分布式版本控制系统基础的指南。好奇 Git 是怎么工作的?本系列的第二篇文章很好地理解了 Git 中使用的基本命令。你可以在这里 阅读 Part One

在这一部分中,我们将深入了解 Git 的基本命令是如何工作的。在这个故事中,我们将有一个美好的旅程,经历 git 配置、git 初始化、git 添加、git 提交、git 克隆、git 远程、git 推送和 git 状态。如果你有几分钟的宝贵时间,并且你想提高自己,坐下来,和我们一起开始阅读和练习吧,我亲爱的朋友。

但是在进入 Git 的命令之前,我们先来看一下如何在 Ubuntu 18.04 上安装 Git。

How to install Git.

Git 配置

现在您的系统上已经有了 Git,您需要做一些事情来定制您的 Git 环境。在任何给定的计算机上,您应该只需要做一次这些事情;他们会在升级之间逗留。您也可以通过再次运行这些命令来随时更改它们。

你是谁?

首先要做的是告诉 Git 你是谁,自我介绍,互相认识,因为这是一个漫长的旅程,它是以朋友来衡量的,而不是以英里来衡量的。

$ git config --global user.name "nawter"
$ git config --global user.email [4772025+Nawter@users.noreply.github.com](mailto:4772025+Nawter@users.noreply.github.com)

你的编辑是什么?

现在 Git 知道您是谁了,您可以配置默认的文本编辑器,当 Git 需要您输入消息时,将会使用这个编辑器。如果没有配置,Git 使用系统的默认编辑器。如果您想使用不同的文本编辑器,如 Vim,您可以执行以下操作:

$ git config --global core.editor vim

小心这一步,如果你不这样设置你的编辑器,当 Git 试图启动它时,你会进入一个非常混乱的状态。Windows 系统上的一个例子可能包括在 Git 启动的编辑期间过早终止的 Git 操作。

你的设置是什么?

如果您不确定您的配置设置,您可以使用git config --list a 命令列出 Git 可以找到的所有设置:

$git config --list
user.name=nawter
[user.email=4772025+Nawter@users.noreply.github.com](mailto:user.email=4772025+Nawter@users.noreply.github.com)
credential.helper=cache --timeout=3600
http.postbuffer=1757286400
core.editor=vim

Git 初始化

我们到了这个部分,你的第一个想法是我的下一步是什么,我告诉你应该是git init。你正在编写一点代码来创建将改变世界的新视频游戏,或者你正在摆弄一些治疗癌症的新数据,你认为git init

让我们从创建您自己的项目的方法开始。

  • 创建一个新目录来包含项目。

Use of mkdir.

  • 进入新目录。
  • 类型git init

git init sample

  • 检查的内容。git 文件夹

The content of .git folder

  • 写一些东西,比如一个 README.md 文件,以纯文本或带 Markdown 内容的形式,谈论你的项目,这是一个免费的模板来做这件事。
  • 键入git add添加文件git add README.md
  • 类型git commit -m “my first commit”

让我们先检查一些数据,然后再移动到下一部分。如果我们键入git log,我们可以看到该信息,它指示了头部位置和我们的上次提交。

commit 7182a646f28f83767810ee751d50b9808bd62bf7 (HEAD -> master)
Author: nawter <[4772025+Nawter@users.noreply.github.com](mailto:4772025+Nawter@users.noreply.github.com)>
Date: Sun Apr 14 12:46:05 2019 +0100my first commit

最后但同样重要的是,如果我们再次运行tree .git并亲自检查结果,我们会看到目录和文件的数量有一些变化,从 9 个目录和 15 个文件变成了 15 个目录和 23 个文件。

The .git folder after changes.

Git 远程和 Git 推送

什么是远程存储库?

远程 URL 是 Git 对存储代码的地方的别出心裁的说法。那个 URL 可能是你在 Github 上的存储库,或者是另一个用户的分支,甚至是在一个完全不同的服务器上。Git 将一个远程 URL 与一个名称相关联,您的默认远程通常被称为origin

R 远程存储库可以在你的本地机器上。您完全有可能使用一个远程存储库,事实上,它位于您所在的同一台主机上。“远程”一词并不一定意味着储存库在网络或互联网上的某个地方,只是意味着它在某个地方。使用这样的远程存储库仍然会涉及到所有标准的推、拉和取操作,就像使用任何其他远程存储库一样。

如何连接到您的远程存储库?

现在您已经有了一个本地 Git 存储库。如果你愿意,你可以在本地使用 Git。但是如果你想让这个东西在 Github 上有一个家,那么做下面的事情。

  • 转到 Github 网站。
  • 登录您的帐户。
  • 点击右上角的新建存储库按钮。您可以选择用 README.md 文件初始化存储库。
  • 点击创建存储库按钮。

Connecting to our remote repository.

现在,遵循第二组指令,其中您可以看到…或者从命令行推送一个现有的存储库。

$ git remote add origin https://github.com/Nawter/LearningGit.git
$ git push -u origin master

这是我们将更改推送到终端中的新存储库后的结果。

Counting objects: 3, done.
Writing objects: 100% (3/3), 227 bytes | 227.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To [https://github.com/Nawter/LearningGit.git](https://github.com/Nawter/LearningGit.git)
 * [new branch] master -> master
Branch ‘master’ set up to track remote branch ‘master’ from ‘origin’.

结果显示在我们的网络浏览器中。

Result in the Github site.

你能在遥控器里看到什么?

如果你想看到更多关于特定遥控器的信息,你可以使用它们的git remote show <remote>命令。如果您使用一个特定的短名称运行这个命令,比如origin,您会得到如下结果:

$ git remote show origin
* remote origin
  Fetch URL: [https://github.com/Nawter/LearningGit.git](https://github.com/Nawter/LearningGit.git)
  Push  URL: [https://github.com/Nawter/LearningGit.git](https://github.com/Nawter/LearningGit.git)
  HEAD branch: master
  Remote branch:
    master tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up-to-date)

Git 克隆与 Git 初始化

命令git initgit clone很容易混淆。在高层次上,它们都可以用来初始化一个新的 git 库。然而,git clone是依赖于git init的。git clone用于创建一个现有存储库的副本。在内部,git clone首先调用git init创建一个新的存储库,然后调用git remote add ,然后使用git fetch从该 URL 获取所有分支到您的本地存储库,最后使用git checkout.签出一组新的工作文件

Git 状态

在教程的这一部分,我们将使用命令git status探索不同的真实场景

错误的地方

$ git status
fatal: not a git repository (or any of the parent directories): .git

如果我们得到这个错误,我们不在一个有 Git 库的目录中。在我们的终端中使用 cd 命令,或者参考 Git 设置文档来设置您的初始回购。

一切都干净了

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

nothing to commit, working directory clean

这是理想的 Git 状态消息。与“源/主”保持同步。表示没什么可推的。工作目录清理表示当前目录下的所有文件都由 Git 管理,并且文件的最新版本已经提交。

未跟踪的文件

如果git status提到未跟踪文件,我们可能需要添加一个或多个未跟踪文件。

$ git status
On branch masterNo commits yetUntracked files:
  (use "git add <file>..." to include in what will be committed)README.mdnothing added to commit but untracked files present (use "git add" to track)

在这种情况下,我们可能希望添加 README.md。一个好的规则是,如果我们直接用编辑器编辑该文件,该文件就属于它。

承诺还是不承诺

如果您看到消息Changes to commit:…,这意味着我们之前已经运行了git add,但是我们还没有运行git commit

$ git status
On branch masterNo commits yetChanges to be committed:
  (use "git rm --cached <file>..." to unstage)new file:   README.md

通过运行git commit 并附带一条短消息说明我们在文件中所做的更改来修复这个问题。

$ git commit -m "my first commit" 
[master (root-commit) 7182a64] my first commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md

在修复提交之后。

$ git status
On branch master
nothing to commit, working tree clean

在 Udemy 上查看我们的免费课程。

感谢阅读。如果你喜欢这篇文章,请点击下面的按钮,这样我们就可以保持联系。

在 Azure Databricks 上开始使用 Apache Spark 和 TensorFlow

原文:https://towardsdatascience.com/get-started-with-apache-spark-and-tensorflow-on-azure-databricks-163eb3fdb8f3?source=collection_archive---------15-----------------------

现在在 Apache Spark framework 上可以使用 TensorFlow,但是如何开始呢?它叫做张量框架

TL;速度三角形定位法(dead reckoning)

这是一个关于如何在 Azure Databricks 上运行新的 Spark TensorFrame 库的分步教程。

大数据是一个庞大的主题,包含许多领域和专业知识。一路从 DevOps,数据工程师到数据科学家,AI,机器学习,算法开发者等等。我们都在与海量数据作斗争。当我们处理大量数据时,我们需要最好的头脑和工具。这就是阿帕奇火花张量流神奇 组合发生的地方,我们称之为张量框架

Apache Spark 接管了大数据世界,提供答案并支持数据工程师变得更加成功,而数据科学家则不得不设法绕过 Spark 提供的机器学习库 Spark MLlib 的限制。

但是现在,Apache Spark 用户可以使用 TensorFlow 了。这些工具的结合使数据科学家的工作更高效、更准确、更快速。从研究到开发再到生产,比以往任何时候都要快。

在我们开始之前,让我们先整理一下术语:

  • Tensor Flow 是 Google 创建的用于高性能数值计算的开源机器学习框架。它附带了对 AI 的强大支持:机器学习和深度学习。
  • Azure Databricks 是一个基于 Apache Spark 的分析平台,针对微软 Azure 云服务平台进行了优化。Azure Databricks 还充当软件即服务(SaaS) /大数据即服务(BDaaS)。
  • TensorFrames 是一个 Apache Spark 组件,它使我们能够在 Spark 集群上创建自己的可扩展 TensorFlow 学习算法。

-1-工作区:

首先,我们需要创建工作空间,我们正在使用 Databricks 工作空间,这里有一个教程用于创建它。

-2-集群:

有了工作空间之后,我们需要创建集群本身。让我们使用本教程创建我们的 spark 集群,确保您的集群中有以下配置:

  • Apache Spark 的工作版本(2.4 或更高版本)
  • Java 8+
  • (可选)python 2.7+/3.6+如果要使用 python 接口。
  • (可选)python TensorFlow 包(如果要使用 python 接口)。关于如何获得 TensorFlow 的最新版本,请参见官方说明。
  • (可选)如果要使用 python 接口,pandas >= 0.19.1

配置:

使用 Databricks 运行时版本或更高版本:

按 start 启动集群

-3-导入库:

Azure Databricks 下,进入常见任务,点击导入库:

TensorFrame 可以在 maven 资源库上找到,所以选择 maven 标签。在坐标下,插入您选择的库,现在,它将是:

databricks:tensorframes:0.6.0-s_2.11

点击创建按钮。

点击安装

你会看到这个:

嘣。您的 Databricks 集群上有 TensorFrame。

-4-笔记本:

我们使用笔记本作为我们的代码笔记本,在那里我们可以编写代码并直接在我们的 Spark 集群上运行它。

现在我们有了一个正在运行的集群,让我们运行一个笔记本:

点击新笔记本并选择您喜欢的编程语言(这里我们选择了 Scala)

这是 scala 代码在带有 TensorFrames 的笔记本门户上的外观:

代码示例来自 D atabricks git 仓库。

您也可以在这里查看:

-结尾-

现在一切都已启动并运行,在 Apache Spark 集群中创建自己的使用 TensorFrame 的触发/调度作业。

还有…

既然你已经走到这一步了,请点击鼓掌按钮👏和在 Medium 和 Twitter 上关注我,获取更多关于 Scala、Kotlin、大数据、干净代码和软件工程师挑战的帖子。干杯!

Python 面向对象编程入门:类和实例

原文:https://towardsdatascience.com/get-started-with-object-oriented-programming-in-python-classes-and-instances-2c1849e0b411?source=collection_archive---------20-----------------------

OOP 新手?了解如何用 Python 编写类和创建实例

目前有很多关于 Python 面向对象编程的文章。许多数据科学家,包括我自己,发现自己的角色专注于编写功能代码,通常是在小脚本或原型中。我已经做了 3 年的数据科学家(之前做过几年的数据分析师),到目前为止,我几乎没有接触过面向对象编程。

这在数据科学世界中似乎相当普遍——许多数据科学家在行业中工作多年,甚至不需要编写基于面向对象编程概念的代码。

也有相当多的反对实现 OOP 原则的论点。这些通常包括编写具有高维护开销的代码,这变得越来越复杂。

但随着行业的成熟,需要数据科学家编写生产就绪代码,并与工程团队更好地集成。对 OOP 有一些基本的了解,并且能够编写类和方法会非常有帮助。

此外,如果你曾经想为一个开源数据科学项目做贡献,你很可能会处理对象,并且需要一些 OOP 知识!

第一步:用 Python 写你的第一个类

OOP 背后的基本思想是用许多对象来管理简单的任务,所有这些组成了一个复杂的计算机程序。

OOP的起点是理解什么是类。一个广泛使用的关于类的定义是类是“创建对象的蓝图”。 类是数据和方法的逻辑分组(方法类似于函数)。

类通常基于我们在商业世界中发现的对象:客户、产品、员工。

作为一家金融服务公司,我们存储并处理客户信息。我们可以创建一个名为 customer 的简单类:

在 OOP 中,我们有关键字,数据科学家将熟悉功能等同的 def

def 用于定义一个函数(或方法,当它在一个类中的时候),类似的, class 用于定义一个类。

定义 customer 类实际上并没有创建任何客户,我们只是为创建 customer 对象绘制了一个蓝图。

在我们的客户类中,您首先会注意到的是 init 方法。 init 方法是 Python 类中的一个特殊方法,每当构造一个类时都会调用它。

init 是一个类的构造函数

每次你创建一个新的类,你将调用 init 方法,你也将使用 self 参数。

变量代表对象本身的实例。一些 OO 语言会将它作为隐藏参数传递给定义的方法,但是在 Python 中我们需要显式声明它。

自身的参数显式地表示对象的实例**

在我们定义了 init 方法并指定了 self 参数之后,我们列出了将在 init 方法中使用的其他参数/自变量。在这个例子中,这些是第一,最后,移动和每月。

我们现在已经创建了我们的类 customer ,并将继续创建该类的一些实例。

步骤 2:实例和方法

一个 实例 ,在面向对象编程(OOP)中,是任何对象的具体表示。一个 对象 是一个通用的东西,而一个 实例 是已经在内存中创建的单个 对象 。通常情况下,一个 实例 的属性会被赋值,以区别于 对象 类型的其他 实例

创建实例

下面的代码创建了一个名为 cust1 的实例。每次需要存储新的客户信息时,您都会这样做。

*cust1 = Customer('Emilee', 'Smith', '0821231234', 20000)*
  • cust1 是一个实例
  • 顾客是阶级

创建方法

方法类似于函数,除了它们在你的类中。在这个例子中,我们将在我们的客户类中编写一个简单的方法,名为年度。这将简单地获取为客户列出的月薪并计算年薪。

类中的每个方法自动将实例作为第一个参数,这意味着您传递括号中的 self 参数。如果你忽略了 self 参数,那么当你调用它的时候,你会得到一个错误。

要查看我们的年度方法中发生了什么,我们可以简单地打印出来:

*print(cust1.annual())
>> Emilee Smith 240000*

有用的提示:在 Python 中,如果你想调用一个属性,例如 customer 类中的“fullname ”,那么你可以简单地这样做:

*print(cust1.fullname)
>> Emilee Smith*

当你调用一个方法(而不是一个属性)时,你需要像我们调用 annual 时那样使用括号。

您现在已经创建了一个名为 customer、 的新类,一个名为 cust1 的实例和一个名为 annual 的方法。 这些是用 python 编写 OOP 代码的第一批实用的构建块!

如果你打算进一步学习 OOP 编程,你应该仔细阅读 OOP 的四个原则:封装抽象继承多态。这里有一个有用的资源:

* [## 如何向 6 岁的孩子解释面向对象的编程概念

你有没有注意到在求职面试中,同样的老生常谈的问题总是被一遍又一遍地问到?

medium.freecodecamp.org](https://medium.freecodecamp.org/object-oriented-programming-concepts-21bb035f7260)*

所以你想成为一名数据科学家?

原文:https://towardsdatascience.com/get-started-with-python-e50dc8c96589?source=collection_archive---------10-----------------------

PYTHON 入门

到底是什么阻止了你?下面是如何开始!

D 数据一直是做出明智且最终正确决策的关键。但是在过去的十年中,数据生成和数据利用率像前所未有的一样飞速增长。这种现象使得数据素养和数据分析成为几乎每个从事定量学科的人的必备技能。让我们面对现实吧,大多数工作正变得越来越量化和复杂。因为毕竟,平凡的日常工作正在被外包给机器,比我们更快更好。

你可能认为你精心磨练的 Excel 技能会让你退休。好吧,我不想打断你:但是如果你的 60 岁生日不在眼前,你很可能弄错了。

你可能会想:

我真的很想学习 Python,但是我甚至不知道从哪里开始!

他们说第一步总是最难的。但是跟着做,我向你保证,在 15 分钟内,你不仅会写出你的第一行代码,而且会在这个过程中学到一些关于快乐的东西!

提醒一句:为了简单起见,我将跳过并大大简化主题。然而,我们的目标不是让你成为一名成熟的程序员——至少现在还不是——而是让你继续前进!

1.设置 Anaconda

A naconda 是针对科学计算 ( 数据科学、机器学习应用程序、预测分析等的 Python 和 R 编程语言的免费开源发行版。),旨在简化包管理和部署。包版本由包管理系统 康达 管理。超过 1500 万用户使用 Anaconda 发行版,它包含了超过 1500 个适用于 Windows、Linux 和 MacOS 的流行数据科学包

一种非常冗长的说法是:“Anaconda 安装 Python 和几乎所有它的基本包。”

我将带您在 Windows/Mac 上安装 Anaconda,但是它非常简单,甚至不需要截屏。然而,他们提出了一个观点。设置 Anaconda 又快又简单!

窗口:

所以我把生锈的(大约 10 年前的笔记本电脑)重新装上了最新的 Anaconda 版本。咔嚓,咔嚓,咔嚓,搞定!好吧,第六步花了 10 分钟左右,但这都怪我的笔记本电脑。安装对你来说无疑会更快。继续下载 Anaconda 这里(获取 3.7 版本)!这里没什么可怕的。

Installation of Anaconda on Windows

Mac:

我卸载了 Anaconda,在这里下载了最新版本(获得 3.7 版本)重新安装。没有任何打嗝,整个过程花了大约 2 分钟。

Installation of Anaconda on Mac

Unix/Linux:

你在这里做什么?导航您的操作系统比 Anaconda 要复杂得多!

2.开始你的第一个笔记本

安装 Anaconda 之后,打开 Anaconda Navigator。你就快到了!

Anaconda Navigator

点击笔记本(左上第二个)。将打开一个新的浏览器选项卡,如下所示:

Hit the “New” button and select Python 3

Congratulations, you have created your first Jupyter Notebook.

3.开始编码

进口

我们将从进口开始。将以下内容输入您的笔记本。

Imports in the notebook

导入告诉笔记本我们还需要什么模块(特性集合)。Pandas是数据操作,numpy是科学计算,datetime是日期时间相关的功能,matplotlibseaborn是绘图。as XYZ部分为模块定义了一个简短的名称(这样我们就可以通过键入 pd 来引用模块,而不是熊猫)。

现在,通过单击运行按钮或 shift+return 来运行单元。

嘭!你可能会想,这是一个好的开始。

我是故意这么做的,因为错误确实是一件好事,你应该对它们感到舒服。真正阅读和理解错误以有意义的方式解决它们是非常重要的。太多时候,人们在面对错误时会失去理智,尝试随机的事情,直到成功或沮丧地放弃。
例如,这个ModuleNotFoundError非常清楚地告诉我们没有名为 seaborn 的模块。尤普,这个我们能解决。似乎 Anaconda 没有提供这个模块。让我们通过跑步来纠正这一点

!pip install seaborn

在新的牢房里。然后重新运行导入单元格。

精彩!

注意:每当我写“在你的笔记本中运行一个命令”,这意味着你应该创建一个新的单元格,在那里键入命令并运行该单元格。

获取一些数据。它毕竟被称为数据科学

我们来看看《2019 世界幸福报告》中的一些数据。我通过抓取维基百科的一个页面,将各大洲添加到数据中。我还在下载中包含了抓取的代码,但是我将把弄清楚它是如何工作的(只有 15 行代码)留给好奇的读者作为练习。
一个 GitHub Repo 保存数据和代码。如果不熟悉 GitHub,还可以从这个 链接 下载一个打包的 zip 文件!解压文件并将内容(尤其是happiness_with_continent.csv)移动到 Jupyter 笔记本所在的文件夹中!

加载数据(在笔记本上运行以下内容):

data = pd.read_csv('happiness_with_continent.csv')

检查数据(在笔记本上运行以下内容):

data.head(x) previews the first x rows of the data

data.tail(x) previews the last x rows of the data

data.sample(x) previews x randomly selected rows of the data

爽!我们来做一些分析:

我们在这里做了几件事:

  1. 蓝色:groupby为提供的列创建多个组。例如,在这里,我们查看数据集中的每个年份/洲的组合。如果您来自 Excel,请将其视为数据透视表中的行。
  2. 紫色:我们选择感兴趣的列,在我们的例子中就是Life Ladder。如果您来自 Excel,请将其视为数据透视表中的列。
  3. Green:这里,我们应用了mean函数。还有其他功能,像maxminsumcount等等。在某些情况下,您还可以定义自己的自定义函数。如果您来自 Excel,请将其视为数据透视表中的值。
  4. Orange: reset_index按照它说的做,它重置索引,这意味着它展平表格并删除组。

从上一节中您已经知道了sample是做什么的。为了简单起见,我们将整个表达式的结果赋给一个名为grouped_by_year_and_continent的新变量,用于我们随后的绘图。

将数据可视化

运行以下代码以生成可视化效果:

Create a neatly looking line chart with seaborn

很酷吧。我想你可能通过阅读代码就能知道这里发生了什么。我喜欢 Python 的简单性!

好吧,但是如果没有一些直方图就不是数据科学了。所以让我们创造一些。我很想更好地理解一个大陆内部的变化。现在让我们按洲名和国名对数据进行分组,并取一段时间内的平均值。根据我们之前所做的,这对您来说应该不陌生。

现在让我们使用这些数据来绘制一些直方图:

干得好!为自己感到骄傲。你迈出了第一步!

今天到此为止。如果你想多练习一些,看看我的其他文章。

[## 用 Python 从各种工作表中提取数据

或者如何学习统一 Google 工作表、Excel 和 CSV 文件——代码指南

towardsdatascience.com](/replacing-sheets-with-python-f1608e58d2ca) [## 如何使用 Python 浏览和可视化数据集

或者如何学习用 Python——一个代码向导——创建漂亮而有洞察力的图表

towardsdatascience.com](/how-to-explore-and-visualize-a-dataset-with-python-7da5024900ef) [## 使用 Python 进行队列分析

或者如何可视化您的客户保持——代码指南

medium.com](https://medium.com/better-programming/cohort-analysis-with-python-e81d9d740a9b)

强化学习和 Python 入门:如何自动化仓库机器人

原文:https://towardsdatascience.com/get-started-with-reinforcement-learning-and-python-how-to-automatize-a-warehouse-robot-4f996bede325?source=collection_archive---------12-----------------------

在本教程中,我将向您展示如何使用强化学习来自动化自主仓库机器人,以找到不同位置之间的最佳路径。

Photo by Pixabay on Pexels.com

介绍

机器人技术的应用在每个商业领域都在不断扩大。自动化处理重复性任务,旨在消除人工输入,以优化流程和削减成本。

2012 年,亚马逊收购了开发仓库机器人和相关技术的公司 Kiva Systems,Kiva 以 7.75 亿美元被收购。此外,许多其他公司,如阿里巴巴、大众汽车或 Geek+ 不断实现机器人和相关技术。

对于初学者来说,开始这样的话题可能是一场斗争,这就是为什么我认为把事情放到背景中,然后开始深入细节是重要的。

范围

本指南的范围是关于强化学习如何在仓库自动化中使用的 Python 实用实践教程,例如亚马逊等公司。我邀请你打开你最喜欢的编辑器( Jupyter NotebookSpyder 等等……),跟着一起编码。以防你拿不到我的 Google Colab 笔记本。

让我们开始:

在本指南中,我将模拟自主仓库机器人需要采取的行动,以便以最佳方式收集交付的产品,同时考虑机器人的位置、中间位置和最终位置。

此模拟中使用的仓库由不同的 12 个点组成,其形状如下:

该系统需要实时排列在这 12 个位置收集产品的优先级。例如,在特定时间t,系统将返回以下排名:

在这个例子中,位置 G 具有最高优先级,机器人必须以系统计算的最短路线移动到这个位置。

此外,位置KL位于前 3 个优先级中,因此系统将通过在到达其最终最高优先级位置之前“步行”到一些中间位置来计算最短路线。

为了在 Python 中实现这一逻辑,有必要通过定义以下 3 个元素来将这一任务置于上下文环境中:

  • 美国
  • 动作
  • 奖励

状态是机器人在每个时间t可以处于的位置:

动作是机器人从一个位置移动到另一个位置时可能做的动作:

当然,当机器人在一个特定的位置时,有些动作它不能执行。这在模拟中通过奖励的矩阵以及通过对其不能执行的动作给予奖励 0 来指定。

奖励矩阵由状态和动作矩阵组成,0 代表机器人在该状态下不能执行的动作,1 代表机器人可以执行的动作。

A位置开始,根据仓库地图,机器人只能去A位置,而在B位置则有可能移动到ACF位置。

该系统采用奖励矩阵,并向最高优先级位置分配高奖励,返回该位置的最佳路径,该系统基于马尔可夫决策过程,该过程可表示为以下元组:

(S, A, T, R)

其中:

  • S是状态的集合
  • A可以进行的动作集合
  • T定义在时间 t 处于状态 s 的动作 a 将导致在时间t +1 处于状态 s’的概率的转移规则
  • R由于动作A,从状态 s 转换到状态`s``后接收到的奖励函数

系统包含一个策略函数,它给定一个状态S(t)返回动作A(t)

用π表示所有可能的策略动作的集合产生了最优化问题,其中最优策略π∫最大化累积奖励。

每一对动作(s, a)都关联有一个数值,记为Q-value;在t=0 处,当在时间t和状态s(t)处正在进行随机动作时,所有 Q 值被初始化为 0,其带来状态s(t) + 1和奖励R(s(t), a(t))

这个被称为 Q-Learning 的整个算法可以总结如下:

对于所有状态对s和动作对a,Q 值被初始化为 0。

初始状态是s(0),然后,执行一个随机的可能动作,并到达第一状态s(1)

对于每一个t1,直到某个数字(在本案例研究中为 1000 次),重复以下步骤:

这可以应用到我们的例子中,让我们看看到底发生了什么:

从可能的 12 种状态中选择一种随机状态s(t)

  • 播放导致下一个可能状态的随机动作a(t)
  • 到达下一个状态s(t) + 1,并且产生奖励R(s(t), a(t))
  • 时间差TD(t)(s(t); a(t)):计算如下:

  • Q 值通过应用贝尔曼公式进行更新:

实施:

在这一部分中,正在实施 Q-learning 过程以创建位置G的奖励矩阵。

虽然之前已经定义了动作位置-状态,但是现在有必要定义奖励矩阵和参数γ和α:

gamma = 0.75

alpha = 0.9

由于位置G具有最高优先级,因此可以如下定义奖励矩阵,给予位置G较高的奖励:

q 值由零矩阵初始化:

Q = np.array(np.zeroes([12, 12]))

然后实施 Q 学习过程,for 循环迭代 1000 次,重复 1000 次算法步骤:

位置 G 的 Q 值由算法计算,并且可以将它们可视化:

You can change the background color in a pandas dataframe by doing: df.style.background_gradient()

从图中可以看出,位置G的 Q 值最高,而远离G的位置 Q 值较低。

下一步是计算一个函数,该函数能够返回任意位置的最佳路线,而不仅仅是“硬编码”的G位置。

首先,有必要像之前在location_to_state中所做的那样,将每个状态映射到位置:

此时,要计算返回任意位置最佳路径的函数,需要重新定义R矩阵,删除硬编码的奖励:

现在,让我们将计算理想路线的逻辑封装到一个函数中:

以起始位置和结束位置作为参数调用此函数将返回所需的路径:

route("E", "G")

现在可以创建一个额外的函数best_route(),它将起始、中间和结束位置作为输入,它将调用route()函数两次,第一次在起始和中间位置之间,第二次在中间到结束位置之间:

best_route("E", "K", "G")

参考

  • Q-Learning 简介
  • 强化学习
  • Q-Learning 的数学

进一步阅读

另外我想推荐一下这篇文章作者 neptune.ai : 最佳强化学习教程、范例、项目、课程。

在他们的博客中,他们收集了一系列不同的资源来进一步激发你的兴趣,并开始强化学习!

**I have a newsletter 📩.** Every week I’ll send you a brief findings of articles, links, tutorials, and cool things that caught my attention. If tis sounds cool to you subscribe. *That means* ***a lot*** *for me.*

[## 米尔斯形式

编辑描述

无情-创造者-2481.ck.page](https://relentless-creator-2481.ck.page/68d9def351)

开始使用 TensorFlow 2.0 和线性回归

原文:https://towardsdatascience.com/get-started-with-tensorflow-2-0-and-linear-regression-29b5dbd65977?source=collection_archive---------3-----------------------

🤖深度学习

使用新的 TF 2.0 APIs 的线性回归模型

Photo by Joshua Earle on Unsplash

TensorFlow 2.0 是 TensorFlow 家族的重大突破。这是全新的和翻新的,也不那么令人毛骨悚然!我们将在 TensorFlow 2.0 中创建一个简单的线性回归模型来探索一些新的变化。所以,打开你的代码编辑器,让我们开始吧!

此外,打开本笔记本进行互动学习体验。

注意!TensorFlow 2.0 现已在稳定频道上线!

要查看一些基本概念及其更简单的解释,请参见,

  • 机器学习词汇表|谷歌
  • 毫升备忘单

让我们先从数学开始。

First impressions for Calculus

我们首先会得到一些关于线性回归的信息。在线性回归中,我们倾向于为您的数据找到最佳拟合线。

该线可在其斜率截距表中定义为:

The hypothesis function

mc 分别是斜率和 y 截距。其中 Wb 分别是 2ⁿᵈ方程的权重和偏差。

为了优化我们的参数 w 和 b,我们需要一个损失函数。这就是均方误差(L1 / MSE ) 出现的原因。

Mean Squared Error

其中 N 是批次/数据集中的样本数, y 是预测结果,而 y⁻ ( y-hat ) 是目标结果。

此外,我们需要均方误差函数的导数,如下所示:

The derivative of the Mean Squared Error function

其中 N 是批次/数据集中的样本数,y 是预测结果,而 y⁻ ( y-hat ) 是目标结果。

现在,进入梯度下降,通过它我们将更新我们的参数θ。

Gradient Descent update rule

其中 θ 是我们的参数, α 是学习率或步长,损失是我们的损失函数。

我们通过获得 w 和 b 相对于损失函数(MSE)的偏导数来优化 w 和 b。

Partial derivatives w.r.t loss function

其中 wb 是优化的参数, h 是假设函数, loss 是损失函数,MSE’是均方误差损失函数的导数。

钻研代码。获取一些数据!

TensorFlow 2.0!

我们将使用 Kaggle.com 大学研究生招生的数据。它包含 6 个连续特征和 1 个二元特征,总共有 7 个特征。标签或预期结果是学生的入学机会。这是我们的目标变量。

我们将下载数据集并将其解析成我们真正喜欢的东西——训练和验证数据集!

在 TF 2.0 中创建模型

我们使用 TensorFlow 的低级 API 定义了 3 种方法,用于:

  1. 均方误差函数
  2. 均方误差函数的导数
  3. 假设函数/回归函数

我们之前在原始数学中讨论过。

然后,我们初始化一些用于训练的超参数,并创建[tf.data.Dataset](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/data/Dataset)对象来高效地存储和批处理我们的数据。

注意到一个 TF 2.0 的变化?对于 TF 1.x 的早期版本,我们使用了tf.data.Dataset.make_one_shot_iterator()方法来创建迭代器。这已经改变了,现在我们用[tf.data.Dataset.__iter__()](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/data/Dataset#__iter__)

最后,我们用batch_size的批量来训练num_epochs时期的模型,这使得num_samples/batch_size的步长。

变化:我们不需要通过一个tf.Session()对象运行 ops 和 tensors。TensorFlow 2.0 默认启用急切执行。为了得到一个tf.Tensor的值,我们只使用了tf.Tensor.numpy()方法。

此外,我们可以使用matplotlib.pyplt得到历元损失图,

import matplotlib.pyplot as pltplt.plot( epochs_plot , loss_plot ) 
plt.show()

现在为了评估我们模型的准确性,我们测量了平均绝对误差。

变化:tf.metrics现在返回一个 op(运算)而不是张量。不过那很好!

等等,还有呢!

仅此而已。

ope 这是对 TensorFlow 2.0 和线性回归的一个很好的介绍。谢谢大家,机器学习快乐!

开始使用 CNN+LSTM 进行预测

原文:https://towardsdatascience.com/get-started-with-using-cnn-lstm-for-forecasting-6f0f4dde5826?source=collection_archive---------5-----------------------

当您的数据粒度较低且具有循环本地模式时,应该考虑这种方法

预测趋势是一门古老的学科,但它从未失宠。无论是金融市场的股价、电力或能源消耗,还是企业规划的销售预测,一系列基于时间的数据点都可以成为世界在任何给定时刻如何思考的表征,这一直让我着迷。提前预见和反应的能力是在生活的许多方面取得成功的重要因素。

Photo from Unsplash

当数据具有明显的趋势性、季节性或自相关性时,时间序列模型非常有效。然而,现实世界的情况要复杂得多,受到多种因素的影响,包括经济现象、媒体效应、竞争对手的行为,甚至短期波动。这些因素在预测达到小时或分钟等粒度级别时尤为明显。LSTM(长短期记忆)是一种递归神经网络结构,已被用于时间序列预测。我一直在使用有状态 LSTM 进行我的自动实时预测,因为我需要模型在批次之间转移状态。最近,我发现在 LSTM 层上添加卷积层来捕捉本地的时间模式在某些情况下非常有用。在这篇文章中,我将用一个简单的例子来演示这个架构。我也强烈推荐 Jason Brownlee 的博文《时间序列的深度学习》。这个系列我个人受益匪浅。

  1. 数据

在这个演示中,我使用了来自 UCI 机器学习知识库的个人家庭电力消耗数据。我花了几个小时重新采集数据。在这篇文章中,我将重点放在全局活跃功率属性上,忽略其他变量。数据如下所示:

2。问题陈述

在这个问题中,我想使用前一天的 24 小时功耗来生成第二天的 24 小时数。数据是从 2006/12 年到 2010/12 年。我用前两年的数据作为训练,后两年的数据作为验证。所以本质上这是一个序列到序列的预测问题。

3。模型架构

我使用了一个 1D 卷积层,然后是一个最大池层,输出是平坦的,然后馈入 LSTM 层。该模型有两个隐藏的 LSTM 图层,后跟一个密集图层来提供输出。

CNN-LSTM structure

首先对数据进行整形和缩放,以符合 Keras 序列模型的三维输入要求。对于简单的单变量模型,输入形状将是具有 1 个特征的 24 个时间步长。在卷积层中,我没有进一步将序列分成多个子序列,而是将时间步长保持为 24。我选择内核大小为 3。致密层有 24 个神经元产生 24 个输出数。下面是详细的模型总结。

如您所见,我使用的批量输入大小为 24。这是因为,在这个问题中,这也是许多现实世界情况的情况,我想每天预测。批量大小的数目需要能被 24 整除。最后,我拟合了 20 个时期的模型,并输出损失。我用了均方误差损失函数和 Adam 优化(自适应矩估计)。

4。最终想法

你是否应该使用 RNN 或 CNN 或混合模型进行时间序列预测,这实际上取决于数据和你试图解决的问题。我会选择一个简单的模型,如果它符合目的并且不会有过度拟合的风险。这个例子旨在提供一个使用 CNN-LSTM 结构的简单指南。我相信这个特殊的数据可以用多元 LSTM 模型更好地拟合。

参考资料:

  1. https://machine learning mastery . com/how-to-develop-lstm-models-for-time-series-forecasting/
  2. https://www . business-science . io/business/2018/12/04/time-series-forecasting . html
  3. https://stack overflow . com/questions/51344610/how-to-setup-1d-convolution-and-lstm-in-keras
  4. https://jeddy 92 . github . io/jeddy 92 . github . io/ts _ seq 2 seq _ conv/
  5. https://github . com/amirrezaeian/Individual-household-electric-power-consumption-Data-Set-/blob/master/Data _ e _ power . ipynb

获取人工智能的 DL

原文:https://towardsdatascience.com/get-the-dl-on-ai-fda4d9b2fbeb?source=collection_archive---------33-----------------------

人工智能入门

以下是你需要了解的人工智能

Photo by Perfecto Capucine on Unsplash

你可能听说过人工智能(AI)、机器学习(ML)、深度学习(DL)、卷积神经网络(CNN)这些缩写词..现在,你希望了解更多,并理解为什么这些术语会在每个会议、每个新闻报道、每个播客中出现。下面是 AI 上的 3(ish)-分钟下载。

什么是人工智能?

受自然自身智能的启发,人工智能模仿认知行为,如学习和解决问题。

它由通过约束实现的算法组成,由支持以思考、感知和行动为目标的模型的表示公开。

呼!那是一口。让我们把这句话分解一下:

由算法组成— 在构建 AI 时,我们构建人工神经网络。这些受生物学启发的神经网络是一种构建算法的方法,这些算法能够学习并独立地找到数据中的联系。按照经典编程,每个神经元都有一组输入和输出值。

由约束启用,由表示公开 —在构建神经网络时,我们有激活和损失函数,允许我们调整和执行计算,以找到数据中的联系。激活函数计算其输入的加权和,加上偏差,然后决定它是否应该被激发,类似于人脑激发神经元的方式。另一方面,损失函数或误差函数是预测模型在预期结果方面做得有多好的度量。

支持以思维、感知和行动为目标的模型— 这些激活和损失函数的目标是更快地训练、减少过拟合和做出更好的预测。

这使得我们的系统和设备能够基于思考和感知做出数据驱动的行动。

人工、机器、深度学习

在这些术语的含义和差异之间存在很大的误解。深度学习(DL)是机器学习(ML)的一个子领域,机器学习(ML)是人工智能(AI)的一个子领域。总的来说:

人工智能融合了认知功能,比如学习和解决问题。这是一个可以思考、感知并从思考和感知中得出行动的系统。

机器学习涉及的算法可以改善你输入的数据越多,它随着时间的推移获得的上下文感知就越多。

机器学习模型旨在最小化预测和预期结果或基本事实值之间的损失或误差。

这些模型通过反复试验得到优化,直到您得到想要的结果。最大似然模型的好坏取决于它们被训练的数据集。因此,这些模型仅限于具有大量可用于训练的数据的问题。

深度学习,机器学习的一个子领域,涉及神经网络中的多个深层节点,这些节点增强了我们的预测模型,并克服了 ML 的缺点。

这些层自己直接从原始数据的隐式表示中学习。

它执行所谓的特征提取,即提取输入的属性,并基于这些特征对训练数据进行排序。例如,如果我正在创建一个系统来识别一个对象是否是哺乳动物,它可能会提取一些属性,如温血动物和处于生命周期某个阶段的毛发。因此,DL 克服了 ML 的一些限制,因为它的过程更复杂。

TL;博士

人工智能由通过约束实现的算法组成,通过支持以思维、感知和行动为目标的模型的表示来公开。深度学习是机器学习的一个子领域,机器学习是 AI 的一个子领域。

让你的电脑为机器学习做好准备:如何使用 Anaconda,Miniconda 和 conda,为什么要使用它们

原文:https://towardsdatascience.com/get-your-computer-ready-for-machine-learning-how-what-and-why-you-should-use-anaconda-miniconda-d213444f36d6?source=collection_archive---------2-----------------------

蟒蛇?我们在玩什么?蛇和梯子?不。我们正在为机器学习准备我们的电脑。

This big bad beast is what we’re going to cover in this article. Check the full interactive version here.

本文将介绍什么是 Anaconda,什么是 Minconda,什么是 conda,如果您是数据科学家或机器学习工程师,为什么应该了解它们,以及如何使用它们。

您的计算机能够运行许多不同的程序和应用程序。然而,当你想创建或编写自己的程序时,比如构建一个机器学习项目,以正确的方式设置你的计算机是很重要的。

假设您想使用一组患者记录来尝试预测谁有心脏病或没有心脏病。你需要一些工具来做这件事。

一个用于探索数据,另一个用于建立预测模型,一个用于制作图表以向他人展示您的发现,还有一个用于进行实验并将所有其他数据放在一起。

如果你在想,我甚至不知道从哪里开始,不要担心,你不是一个人。很多人都有这个问题。幸运的是,这就是 Anaconda、Miniconda 和 conda 的用武之地。

Anaconda、Miniconda 和 conda 是帮助您管理其他工具的工具。我们将很快讨论每一个的细节。让我们从它们为什么重要开始。

为什么 Anaconda,Miniconda,conda 很重要?

Anaconda, Miniconda and Conda help to create a shareable environment where you can conduct experiments so your colleague (or your future self) can reproduce them later.

很多机器学习和数据科学都是实验性的。你尝试了一些东西,但没有成功,然后你继续尝试其他的东西,直到有些东西成功了或者根本没有成功。

如果你自己在做这些实验,并且最终找到了有效的方法,你可能会希望能够再做一次。

如果你想分享你的作品,也是一样。无论是与同事、团队还是通过由机器学习系统支持的应用程序与世界交流。

Anaconda、Miniconda 和 conda 为您提供了共享您的实验所基于的基础的能力。

Anaconda、Miniconda 和 conda 确保如果其他人想要复制你的作品,他们会拥有和你一样的工具。

因此,无论你是独自工作,破解机器学习问题,还是与数据科学家团队合作,在互联网规模的数据集上寻找见解,Anaconda、Miniconda 和 conda 都为始终一致的体验提供了基础设施。

什么是蟒蛇,迷你蟒蛇,康达?

Anaconda 和 Miniconda 是软件发行版。Anaconda 提供了超过 150 个数据科学包,所有你能想到的都有,而 Miniconda 只提供了一小部分你需要的东西。

包是别人编写的一段代码,它可以运行,通常有特定的用途。您可以将包视为一种工具,用于您自己的项目。

包是有帮助的,因为没有它们,你将不得不写更多的代码来完成你需要做的事情。由于许多人都有类似的问题,你经常会发现一群人编写代码来帮助解决他们的问题,并将其作为一个包发布。

康达是一名包装经理。它通过处理安装、更新和删除来帮助你管理不同的包。

Anaconda contains all of the most common packages (tools) a data scientist needs and can be considered the hardware store of data science tools. Miniconda is more like a workbench, you can customise it with the tools you want. Conda is the assistant underlying Anaconda and Miniconda. It helps you order new tools and organise them when you need.

不止这些。还有 Pip,Pipenv 和其他人。但我们将重点放在蟒蛇,迷你康达和康达。它们足够让你开始了。

  • Anaconda 可以想到数据科学家五金店。它有你需要的一切。从探索数据集的工具,到为数据集建模的工具,再到将你的发现可视化的工具。每个人都可以访问五金店和里面的所有工具。
  • Miniconda 是数据科学家的工作台。每个工作台都是从最基本的必需品开始清洁的。但是随着项目的增长,工作台上的工具数量也在增长。它们被使用,被改变,被交换。每个工作台都可以按照数据科学家的意愿进行定制。一个数据科学家工作台可能与另一个完全不同,即使他们在同一个团队。
  • Conda 帮助整理所有这些工具。尽管 Anaconda 提供了许多现成的,但有时它们需要更改。康达就像盘点所有工具的助理。Miniconda 也是如此。

工具或软件包集合的另一个术语是环境。五金店是一个环境,每个单独的工作台是一个环境。

例如,如果您正在处理一个机器学习问题,并使用您环境中的工具(工作台)找到了一些见解,一位队友可能会要求您与他们共享您的环境,以便他们可以复制您的结果并为项目做出贡献。

应该使用 Anaconda 还是 Miniconda?

Downloading and installing Anaconda is the fastest way to get started with any data science or machine learning project. However, if you don’t have the disk space for all of what comes with Anaconda (a lot, including things you probably won’t use), you might want to consider Miniconda. See the full-size interactive version of this image here.

使用 Anaconda:

  • 如果你在寻找一种适合所有人的方法,这种方法对于大多数项目来说都是现成的,那么在你的电脑上要有 3 GB 的空间。

使用 Miniconda:

  • 如果您的计算机上没有 3 GB 的空间,并且希望设置只包含您需要的空间。

开始使用 Anaconda 或 Miniconda 时,您主要考虑的是计算机上的空间。

如果您选择了蟒蛇,请遵循蟒蛇的步骤。如果您选择了 Miniconda,请按照 Miniconda 的步骤操作。

**Note:** Both Anaconda and Miniconda come with Conda. And because Conda is a package manager, what you can accomplish with Anaconda, you can do with Miniconda. In other words, the steps in the Miniconda section (creating a custom environment with Conda) will work after you’ve gone through the Anaconda section.

使用 Anaconda 快速启动并运行数据科学项目

您可以将 Anaconda 视为数据科学工具的硬件商店。

把它下载到你的电脑上,它会带着你做很多数据科学或机器学习工作所需的工具(包)。如果它没有你需要的套餐,就像五金店一样,你可以订进来(下载)。

好消息是,遵循这些步骤并安装 Anaconda 也将安装 conda。

**Note:** These steps are for macOS (since that's my computer). If you're not using macOS, the concepts will be relevant but the code an images a little different.If you're on Windows, check out [this guide by Anaconda](https://docs.anaconda.com/anaconda/install/windows/).

1。进入蟒蛇分发页面。

What you’ll find on the Anaconda distribution page. Choose the right distribution for your machine.

2。为您的计算机下载合适的 Anaconda 发行版(需要一段时间,取决于您的网速)。除非您有特定的原因,否则最好下载每个版本的最新版本(最高编号)。

在我的例子中,我下载了 macOS Python 3.7 64 位图形安装程序。命令行和图形安装程序的区别在于,一个使用你能看到的应用程序,另一个需要你写代码行。为了简单起见,我们使用图形安装程序。

3。下载完成后,双击下载文件以完成设置步骤,一切保持默认。这将在您的计算机上安装 Anaconda。这可能需要几分钟的时间,并且您需要多达 3 GB 的可用空间。

What the installer looks like on my computer (macOS). I’m installing it on my user account.

Once the installation is complete, you can close this window and remove the Anaconda installer.

4。若要检查安装,如果您在 Mac 上,请打开“终端”,如果您在另一台电脑上,请打开命令行。

如果成功,您会看到(base)出现在您的名字旁边。这意味着我们在base环境中,想象这是在五金店的地板上。

要查看你刚刚安装的所有工具(包),输入代码conda list并按回车键。别担心,你不会弄坏任何东西的。

Opening Terminal on a Mac and typing conda list and hitting enter will return all of the packages (data science tools) Anaconda installed on our computer. There should be a lot.

您应该看到的是四列。名称、版本、内部版本和频道。

名称是包的名称。记住,包是别人写的代码的集合。

版本是这个包的版本号,而版本是这个包的 Python 版本。现在,我们不会担心这些,但是你应该知道一些项目需要特定的版本和内部版本号。

通道是包来自的 Anaconda 通道,没有通道意味着默认通道。

The output of the conda list command. This show the name, version, build and channel of all the packages Anaconda installed.

5。你也可以通过在命令行输入python并按回车键来检查它。这将显示您正在运行的 Python 版本以及 Anaconda 是否存在。

If you downloaded and installed Anaconda, when you type python on the command line, you should see the word Anaconda somewhere appear. This means you're using Anaconda's Python package.

要退出 Python(T4),键入exit()并按回车键。

6。我们刚刚将数据科学工具(包)的整个硬件商店下载到我们的计算机上。

现在,它们位于名为(base)的默认环境中,这是在我们安装 Anaconda 时自动创建的。环境是包或数据科学工具的集合。稍后我们将看到如何创建我们自己的环境。

The current environment (work space). In our case, this indicates we’re using the base environment. (base) is the default environment which gets installed automatically when installing Anaconda.

您可以通过键入conda env list (env 是环境的缩写)来查看您机器上的所有环境。

Running the command conda env list returns all of the environments you have setup on your computer. In my case, I have the environment (base), which I'm in as indicated by the * and I have env, which is in the project_1 folder, we'll look into this later.

好了,现在我们知道我们已经安装了 Anaconda,假设您的目标是为我们的项目做准备,用机器学习来预测心脏病。

在做了一些研究之后,您发现您需要的工具(包)是:

  • Jupyter 笔记本——用于编写 Python 代码、运行实验以及与他人交流您的工作。
  • 熊猫——用于探索和操纵数据。
  • NumPy —用于对数据进行数值运算。
  • Matplotlib —用于创建您的发现的可视化。
  • sci kit-learn——也叫 sklearn,用于构建和分析机器学习模型。

如果你以前从未用过这些,不要担心。重要的是要知道,如果您按照上面的步骤安装了 Anaconda,那么这些包也已经安装了。

Anaconda 自带了许多现成的最流行和最有用的数据科学工具。上面的也不例外。

7。为了真正测试,我们将启动一个 Jupyter 笔记本,看看上面的包是否可用。要打开 Jupyter 笔记本,请在命令行中键入jupyter notebook,然后按回车键。

A command you’ll get very familiar with running during your data science career. This will automatically open up the Jupyter Notebook interface in your browser.

8。您应该会看到 Jupyter 界面出现了。它将包含您当前目录中的所有文件。点击右上角的新建并选择 Python 3,这将创建一个新的 Jupyter 笔记本。

Once the Jupyter Interface has loaded, you can create a new notebook by hitting the new button in the top right and clicking Python 3.

9。现在我们来试试我们需要的其他工具。

您可以通过键入命令import pandas as pd并按 shift+enter 来查看 pandas 是否已安装(这就是 Jupyter 单元中代码的运行方式)。

如果没有错误,感谢 Anaconda,我们现在可以使用 pandas 进行数据操作。

10。使用以下命令对 NumPy、Matplotlib 和 scikit-learn 包执行相同的操作:

  • NumPy — import numpy as np
  • Matplotlib — import matplotlib.pyplot as plt
  • scikit-learn — import sklearn

Installing Anaconda means we’ve also installed some of the most common data science and machine learning tools, such as, Jupyter, pandas, NumPy, Matplotlib and scikit-learn. If this cell runs without errors, you’ve successfully installed Anaconda.

水蟒概述

这可能看起来像是许多开始的步骤,但它们将形成你作为数据科学家或机器学习工程师前进所需的基础。

  • 为什么——我们使用 Anaconda 访问其他人在我们之前编写的所有代码,这样我们就不用自己重写了。
  • What — Anaconda 提供了硬件商店价值的数据科学工具,如 Jupyter 笔记本、pandas、NumPy 等。
  • 我们从网上下载了 Anaconda 到我们的电脑上,并通过一个例子展示了如何开始使用基本工具。

我们采取的步骤:

  1. 从网上下载了巨蟒。
  2. 在我们的电脑上安装了蟒蛇。
  3. 使用conda list在安装终端中测试,它向我们展示了我们安装的所有包(数据科学工具)。
  4. 加载了一个 Jupyter 笔记本(工具之一)。
  5. 通过将 pandas、NumPy、Matplotlib 和 sklearn 导入 Jupyter 笔记本来执行最终检查。

The steps taken in this section. See the full-size interactive version of this image here.

使用 Miniconda 和 conda 创建自定义环境

使用 Anaconda,数据科学工具的整个硬件商店是一个很好的开始。但是对于长期的项目,您可能想要创建自己独特的环境(工作台),其中只有项目所需的工具,而不是所有的东西。

有几种方法可以用 Conda 创建自定义环境。对于这个例子,我们将下载 Miniconda,它只包含最少的数据科学工具。然后,我们将在项目文件夹(文件夹也称为目录)中创建一个自定义环境。

为什么这样?

在每个项目开始时创建一个新的项目目录是一个好主意。然后在这个目录中,保存该项目的所有相关文件,比如数据、代码和您使用的工具。

在接下来的步骤中,我们将建立一个名为project_1的新项目文件夹。在这个目录中,我们将创建另一个名为env(环境的简称)的目录,其中包含我们需要的所有工具。

然后,在env目录中,我们将建立一个环境来处理与上面相同的项目,预测心脏病。所以我们需要 Jupyter 笔记本,熊猫,NumPy,Matplotlib 和 scikit-learn。

这样做可以在将来方便地与他人共享您的项目。

The typical steps you might take when starting a new machine learning project. Create a single project folder and then store all of the other relevant files, such as environment, data and notebooks within it. We’ll go through created an environment folder in this section.

**Note:** If you already have Anaconda, you don’t need Miniconda so you can skip step 1 and go straight to step 2\. Since Anaconda and Miniconda both come with Conda, all of the steps from step 2 onwards in this section are compatible with the previous section.
  1. 首先,我们从 conda 文档网站下载 Miniconda。选择一个适合你的。由于我使用的是 Mac,所以我选择了 Python 3.7,64 位 pkg 版本。

下载完成后,请完成安装步骤。因为 Miniconda 不具备 Anaconda 的所有功能,所以它占用的磁盘空间要少 10 倍(2.15 GB 对 200 MB)。

当安装完成时,您可以在命令行上使用which conda来检查它的安装位置。

Downloading and installing Miniconda means installing Conda as well. You can check where it’s installed using which conda on the command line. In my case, it's stored at /Users/daniel/miniconda3/bin/conda.

2。在桌面上创建一个名为project_1的项目文件夹。在实践中,我们使用这个项目文件夹来完成我们所有的工作,这样就可以很容易地与他人共享。

要在桌面上创建一个名为project_1的文件夹,我们可以使用命令mkdir desktop/project_1mkdir代表制作目录,desktop/project_1表示制作desktop上的project_1

We’re creaitng a new project folder called project_1. Whatever files we use for the project we’re working on will go in here. That way, if we wanted to share our work, we could easily send someone a single file.

3。我们将使用cd desktop/project_1切换到新创建的项目文件夹。cd代表变更目录。

It’s good practice to have separate project folders and environments for each new project. Keeping things separate prevents mixups in the future.

4。进入项目文件夹后,下一步是在其中创建一个环境。

该环境包含我们项目所需的所有基础代码。因此,如果我们想在以后复制我们的工作或与他人分享,我们可以确保我们未来的自己和他人有和我们一样的基础。

我们将创建另一个名为env的文件夹,在这个文件夹中会有所有相关的环境文件。为此,我们使用:

$ conda create --prefix ./env pandas numpy matplotlib scikit-learn

--prefix标签和/env前的.表示将在当前工作目录下创建env文件夹。在我们的例子中是Users/daniel/desktop/project_1/

This line of code says, ‘Hey conda, create a folder called env inside the current folder and install the pandas, NumPy, Matplotlib and scikit-learn packages.' New Conda environments come with a few tools to get started but most of the time, you'll have to install what you're after.

运行上面的代码行后,会询问您是否要继续。按下y

当代码完成时,现在在project_1文件夹中会有一个名为env的文件夹。使用ls可以看到一个目录中所有文件的列表,它是 list 的缩写。

We’ve now created a project_1 folder and an env folder. The project_1 folder will contain all of our project files such as data, Jupyter Notebooks and anything else we need. The env folder will contain all of the data science and machine learning tools we'll be using.

5。环境设置完成后,终端窗口中的输出会告诉我们如何激活新环境。

我的情况是conda activate Users/daniel/desktop/project_1。您可能想在某个地方写下这个命令。

Once an environment is created, it can be activated via conda activate [ENV] where [ENV] is the environment you want to activate.

这是因为我已经在project_1文件夹中的desktop上创建了env文件夹。

运行上面的代码行激活我们的新环境。激活新环境会将(base)更改为(Users/daniel/desktop/project_1),因为这是新环境所在的位置。

When an environment is active, you’ll see its name in brackets next to your command prompt. Activating an environment gives you access to all of the tools stored in it.

6。现在我们的环境已经激活,我们应该可以访问上面安装的包了。让我们看看是否可以像上一节那样启动一个 Jupyter 笔记本。

为此,我们在命令行上运行命令jupyter notebook,激活新环境。

When we created our env folder, we forgot to install the jupyter package. This means we can't run the jupyter notebook command. Not to worry, Conda makes it easy to install new packages with conda install.

7。糟糕…我们忘记安装 Jupyter 了。这是第一次设置新环境时的常见错误。但还是有办法解决的。例如从模板(或 YAML 文件)设置环境。我们将在扩展部分看到如何做到这一点。

要安装 Jupyter 包和使用 Jupyter 笔记本,可以使用conda install jupyter

这类似于我们之前运行来设置环境的内容,除了现在我们关注一个包,jupyter

这就像说,‘嘿,康达,把jupyter包安装到当前环境中’。

If your environment is missing a package, you can install it using conda install [PACKAGE] where [PACKAGE] is your desired package.

运行此命令将再次询问您是否要继续。按下y。然后 Conda 会将jupyter包安装到您激活的环境中。在我们的例子中,它是project_1中的env文件夹。

8。现在我们已经安装了 Jupyter,让我们再次尝试打开笔记本。我们可以使用jupyter notebook来实现。

We’ve just installed the jupyter package into our environment, so now we'll able to run the jupyter notebook command.

9。漂亮,Jupyter 界面加载完毕,我们可以通过点击新建并选择 Python 3 来创建一个新的笔记本。

The Jupyter Interface shows you the files and folders in your current directory. In this case, you should be able to see the env folder you made. And since we're in the project_1 folder, any new files you create with the New button will be stored within the project_1 folder.

然后为了测试我们的其他工具 pandas、NumPy、Matploblib 和 scikit-learn 的安装,我们可以在第一个单元格中输入下面几行代码,然后按 shift+enter。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import sklearn

We can check if our environment has successfully installed the tools we’re after by trying to import them in our Jupyter Notebook.

10。若要停止 Jupyter 笔记本的运行,请在运行它的终端窗口中按 control+c。当它询问您是否要继续时,按下y

When you want to close your Jupyter Notebook, be sure to save it before stopping it running within the terminal.

11。要退出您的环境,您可以使用conda deactivate。这将带您回到(base)环境。

Deactivating your current environment allows you to activate another environment or perform any changes using Conda outside of your environment.

12。要回到您的环境,运行您之前写下的conda activate [ENV_NAME]命令,其中[ENV_NAME]是您的环境。

然后,要重新访问 Jupyter 笔记本,运行jupyter notebook命令。这将加载 Jupyter 接口。

在我的例子中,代码如下所示:

(base) Daniels-MBP:~ daniel$ conda activate \ /Users/daniel/Desktop/project_1/env
(/Users/daniel/Desktop/project_1/env) Daniels-MBP:~ daniel$ jupyter notebook

When you want to resume work on a previous project, the practice is to reactivate the environment you were using and then continue working there. This ensures everything you do is contained in the same place.

Miniconda 概要

这看起来有很多步骤,事实也的确如此。但是了解这些技能很重要。

确保你有一个良好的基础工作环境将有助于在未来节省大量时间。

想象一下在你的工具棚里工作,但是所有的东西都被放错了地方。你可能知道东西在哪里,但是一旦有人来帮忙,他们就会花几个小时去找合适的工具。相反,现在他们有了一个工作环境。

  • 为什么 —当我们不需要 Anaconda 提供的所有东西时,我们使用 Miniconda,并创建我们自己的定制环境,以便与他人共享。
  • 什么 — Minconda 是 Anaconda 的缩小版,conda 是一个完全可定制的包管理器,我们可以用它来创建和管理环境。
  • 如何做 —我们从网上下载了 Miniconda 到我们的电脑上,里面有 conda。然后我们使用 Conda 为project_1 创建了自己的定制环境。

我们设置定制 Conda 环境的步骤(这些步骤也适用于 Anaconda):

  1. 从网上下载了迷你康达。
  2. 在我们的电脑上安装了迷你康达。
  3. 使用mkdir project_1在桌面上创建一个名为project_1的项目文件夹,然后使用cd project_1将其改变。
  4. 使用conda create --prefix ./env pandas numpy matplotlib scikit-learn创建一个名为env的环境文件夹,其中包含 pandas、NumPy、Matplotlib 和 scikit-learn。
  5. 使用conda activate /Users/daniel/Desktop/project_1/env激活我们的环境
  6. 尝试使用jupyter notebook加载 Jupyter 笔记本,但是没有成功,因为我们没有这个包。
  7. 使用conda install jupyter安装 Jupyter。
  8. 使用jupyter notebook启动了一个 Jupyter 笔记本,并通过将 pandas、NumPy、Matplotlib 和 sklearn 导入到 Jupyter 笔记本中来执行最终检查。

Steps we took in this section, downloading, installing and setting up Miniconda. Then we created a project folder as well as a custom environment for our machine learning project. See the full-size interactive version of this image here.

康达摘要

重要的是要记住,Anaconda 和 Miniconda 都是 conda 自带的。所以不管你下载哪一个,你都可以对每一个执行相同的步骤。

其中 Anaconda 是数据科学工具的硬件商店,Miniconda 是工作台(软件分发),conda 是助手(包管理器),帮助您获得新工具和定制您的硬件商店或工作台。

以下是一些你需要记住的有用的 Conda 命令。

扩展:将 Conda 环境导出为 YAML 文件

如果您已经完成了上述所有工作,那么下一步您将想去的地方是如何将您的环境共享为 YAML 文件。YAML 文件是一种常见的文件类型,可以方便地共享和使用。

要将我们之前在/Users/daniel/Desktop/project_1/env创建的环境导出为名为environment.yaml的 YAML 文件,我们可以使用命令:

$ conda env export --prefix /Users/daniel/Desktop/project_1/env > environment.yaml

Exporting your environment to a YAML file is another way of sharing it. You might do it this way if sharing everything in the project_1 folder wasn't an option.

运行 export 命令后,我们可以看到新的 YAML 文件存储为environment.yaml

一个示例 YAML 文件可能如下所示:

name: my_ml_env
dependencies:
  - numpy
  - pandas
  - scikit-learn
  - jupyter
  - matplotlib

实际的 YAML 文件会因环境名称和环境内容的不同而有所不同。

将环境导出为 YAML 文件后,您可能希望与队友共享该文件,以便他们可以重新创建您工作的环境。他们可能会运行下面的命令,使用您发送给他们的environment.yaml文件来创建env2

$ conda env create --file environment.yaml --name env2

Creating env2 like this ensures it will have all of the same tools and packages available within env. Which means your teammate will have access to the same tools as you.

一旦env2被创建,你的队友将能够通过使用conda activate env2激活它来访问其中的工具。

Since env2 has all the same packages and dependencies as env, activating it will mean you'll have access to the same tools as before.

资源

对于 Anaconda、Miniconda 和 conda,您还可以做更多的事情,本文只是触及了皮毛。但是我们在这里介绍的内容已经足够开始了。

如果你想了解更多,我建议查阅文档。通读它帮助我写了这篇文章。

如果你一开始不明白某件事,不要担心,试一试,看看是否可行,如果不行,再试一次。

为帮助我理解蟒蛇、迷你蟒蛇和康达,向下面的人大声呼喊。

  • 用 Conda 拯救环境(以及如何让别人运行你的程序)作者 Sébastien Eustace。
  • 向(数据)科学家介绍 Conda
  • 整个 Anaconda 团队和他们惊人的文档

用四个步骤让你自己的网站上线

原文:https://towardsdatascience.com/get-your-own-website-online-in-four-steps-adef65abe8bd?source=collection_archive---------16-----------------------

使用 R Blogdown 的简单指南

我喜欢收集设计精美或主题有趣的博客网站。吸引我的不仅是网站本身,还有建网站的人。我很佩服他们花时间设计自己的网站,不断发布内容。我总是想象如果有一天我能为自己建一个博客网站该有多好。然而,我总是害怕 HTML、CSS、PHP 和 JavaScript 这些复杂的知识。最近,我重访了 Yihui Xie 的一篇博客,他是 RStudio 的一名活跃的软件工程师,也是许多流行 R 包的作者,包括我们在这篇文章中将要介绍的一个包blogdown。我被他的一句话深深打动了,这句话是他从卡洛斯·沙伊德格中提炼出来的。

“我网,故我在”

我对这个短语的理解有两个文件夹:1)拥有你的个人网站使你跟踪你做了什么和想了什么,因为你网站上的所有内容都在你自己的控制之下。2)最重要的是,这在很大程度上扩大了人们了解你的机会。你可以更有效地向未来的雇主展示你的工作。这对寻找科技相关工作的人非常有帮助。综合来看,我认为是时候把我的长期想象变成现实了。

在这篇文章中,我将分享我在使用blogdown创建我的个人网站时的笔记,这是一个用来显著简化从创建网站到更新网站的整个过程的工具。这篇文章主要由四部分组成:

Github→在RStudio→使用Netlify→自定义域名

在 Github 上创建新的回购

由于 Netlify (一种静态网站服务)将通过 github 源代码库自动呈现您的网站,我们需要首先为您的 github 帐户创建一个新的库来托管您网站的所有源文件。

Create a public repository for your website

之后,让我们在您的机器上创建这个存储库的本地版本。这叫做克隆。为此,单击存储库站点中的绿色“克隆或下载”按钮,然后单击复制图标将存储库 URL(使用 SSH 克隆)复制到剪贴板缓冲区。然后,返回到终端(我使用的是 Mac),并导航到您希望存储库的本地版本所在的目录。在终端中运行以下命令:

git clone <repository_URL>

您应该会看到一个带有您的存储库名称的新文件夹出现。因此,在我的例子中,我应该看到在输入ls后出现博客站点。为了能够从您的机器上与 GitHub 通信,我假设您已经配置了 ssh 密钥并将其添加到您的 Github 帐户中。如果你以前从未使用过git,这里的是一个关于如何建立仓库并克隆它的详细教程。

在 RStudio 中建立一个网站

现在,让我们切换到 R studio(R 的免费 IDE)。我们需要安装blogdown包,然后安装hugo(开源静态站点生成器)。

## Install from CRAN
install.packages("blogdown")
## Or, install from GitHub
if (!requireNamespace("devtools")) install.packages("devtools")
devtools::install_github("rstudio/blogdown")blogdown::**install_hugo**()

然后,让我们在 RStudio 中为您的网站创建一个新项目。选择File > New Project > Existing Directory,然后浏览到 GitHub 库所在的目录,点击创建项目按钮。

Create a R project in RStudio

RStudio 将使用这个新创建的项目打开一个新会话。我们现在需要编辑.gitignore文件。您可以在 RStudio 的文件查看器面板中找到它(通常位于右下面板,Files选项卡)。单击该文件,在 RStudio 中打开它,并按如下方式编辑内容:

.Rproj.user
.Rhistory
.RData
.Ruserdata
blogdown
.DS_Store # if a windows user. Thumbs.db instead
public/ # if using Netlify

一切就绪后,我们就可以开始使用blogdown::new_site()函数来构建我们的网站了(只需在 R 控制台中简单地键入这个即可)。然而,正如这里的详细说明所建议的那样,我们最好现在就决定主题,而不是以后。而且,我们最好从一个简单的主题开始,而不是复杂的,尤其是当你不熟悉 HTML,CSS,或者 JavaScript,没有 Hugo 主题或者模板的经验的时候。我选择了学术主题,因为它处于主动维护中,并且非常灵活地进行定制。只需键入:

blogdown::new_site(theme = "gcushen/hugo-academic", theme_example = TRUE)

您会发现示例网站出现在 RStudio 的Viewer选项卡中,并且会在 blog-site 文件夹中自动创建几个文件夹。这些都是网站运行的文件。

New folders will be created automatically

接下来,我们需要根据这里的建议更新项目选项。Tools > Project Options。基本上,取消选中这两个框。

Updating project options

现在是时候把样本网站变成我们自己的了,按照这里的指示编辑配置。如果你使用的是学术主题,一个快速定制样本网站的方法是进入blog-site > content > home文件夹,所有内容都存储在content子目录下的 markdown ( md)文件中。目录结构反映了站点结构。从那里,有不同部件(即网站上显示的部分)的配置文件。我们可以根据您自己的目的通过将active值更改为false来关闭它们。美化网站和给每个部分添加相应的内容是非常耗时的,为了能够现在在线启动我们的新网站,你可以只让about.md处于活动状态,这意味着你现在只需要为about页面填充内容。一旦这些部分的内容准备好了,我们就可以打开其他小部件。

Markdown file for demo section

使用 Netlify 部署网站

about页面一切正常时,我们可以提交更改并将存储库从您的机器推送到 GitHub,然后联机到 Netlify 。

Git tab in RStudio

从 RStudio 中选择Git选项卡,然后选择Commit。从那里,选择所有已更改的文件,并在Commit message窗口中写下一些消息以保留记录,例如,“关于页面的第一次更改”。然后点击CommitPush。现在,GitHub 中的存储库已经更新。

我们需要向 Netlify 注册,使用您的 GitHub 帐户免费使用其服务。登录后,选择New site from Git -> Continuous Deployment: GitHub,从这里选择包含网站文件的 GitHub 库。然后我们需要配置构建。记得为你用来创建网站的 hugo 版本创建一个新的变量。在终端中输入hugo version。我的hugo版本是 0.61.0,所以这是我输入的。

HUGO_VERSION setting page

Build setting page

完成所有这些设置后,Netlify 将在几秒钟内部署网站,并为其分配一个随机的子域名。这是我网站的域名,[objective-wright-b68557.netlify.com](https://objective-wright-b68557.netlify.com/)。你可以随意更改域名,但需要以netlify.com结尾。现在,我们在网上有了自己的网站。

My first website

自定义域名

如果你的域名是“yourname.com ”,而不是隶属于其他域名,你肯定会看起来像个极客。因此,我更进一步,花了大约 20 美元从一家 DNS 提供商那里购买了我自己的域名(【junye0798.com】)。这使我能够拥有两年的域名。为了保持中立,我不打算在这里为 DNS 提供商提出建议。你会很容易找到一个好的。然后我在 Netlify 中更新了我自己的域名信息,按照它的指示这里。如果你想了解更多关于域名注册的知识,请阅读谢一辉的文章部分,你会被说服拥有自己的域名。

以下是我用来建立网站的一些好资源:

  • 上&下运行
  • blogdown:用 R Markdown 创建网站
  • 页面生成器入门

和往常一样,我欢迎反馈、建设性的批评以及倾听您的数据科学项目。我可以在 LinkedinLinkedin上找到我,现在也可以在我的网站上找到我。

让一台机器帮我做英语作业

原文:https://towardsdatascience.com/getting-a-machine-to-do-my-english-homework-for-me-5d339470fe42?source=collection_archive---------6-----------------------

使用递归神经网络生成文本

Photo by Sharon McCutcheon on Unsplash

我一直不喜欢高中英语课。

可能是作业总是超级主观的事实吧。也许是因为我们被迫读的书又长又无聊。也许是因为莎士比亚是用另一种语言写的。

或者也许我只是不擅长写论文。😢

因为我真的不喜欢英语课,所以最终发生的事情是,我不再注意我的老师在说什么,我不读我们应该读的书。结果,我在作业和考试中得了一个糟糕的分数,我的分数下降了。

所以现在我需要挽回我的平均水平,我能做的两件事是:

  • 上课专心听讲,做老师布置的工作
  • 想办法让我摆脱用人工智能写无聊的文章

此时,第二种选择听起来更酷。

递归神经网络

我以前学过一点关于神经网络的知识,你可以看看我关于卷积神经网络用于图像识别的文章,或者我关于应用 CNN 对皮肤病变进行分类的文章。无论如何,神经网络一直在努力解决的一个问题是顺序数据和时间数据。传统的神经网络需要有固定的输入输出大小。

这就像如果你有一个人从楼梯上摔下来的视频,你想训练一个神经网络来对视频中发生的事情进行分类。一个常规的神经网络可能能够判断出这个人在视频的第一帧是站着的。然后,它可能会查看中间的帧,直到它看到视频的最后一帧,它看到一个人摔倒了。但是一旦到了那里,它就忘记了这个人一开始是不是站着的。

Ouch

由于它们的工作方式,递归神经网络将有助于解决这类问题。从更高的层面来看,rnn 通过相互循环来工作。神经网络进行前向传递,然后在第二次前向传递时,它从第一次迭代中获取一些信息,以获得更多的上下文来进行第二次预测。

A diagram showing an “unfolded” RNN with information being transferred between iterations.

从一开始,信息就可以在整个网络中传递。现在我们的网络可以了解是否有人实际上从楼梯上摔了下来!

递归神经网络的类型

正如我之前提到的,rnn 很酷,因为它们不需要固定的输入或输出,它们可以接受输入并产生序列的输出。

Different types of Recurrent Neural Networks from Andrej Karpathy’s blog post.

  1. 一对一:这基本上是一个常规的神经网络。它接受固定的输入并提供固定的输出。
  2. 一对多:这种 RNN 接受一个输入,提供多个输出。你可以做的是将第一个输出反馈到神经网络,以生成另一个输出,将结果反馈到神经网络,等等。这被称为对神经网络进行采样,通过这样做,你可以生成全新的序列。
  3. 多对一:接收多个输入并给出单个输出的 RNN。这用于像情绪分析这样的应用,你给神经网络提供一段文本,并从中预测情绪或情绪。输出序列可以是句子中的单词,输出可以是神经网络对情感的预测。
  4. 多对多:这种类型的 RNN 接收多个输入序列并产生多个输出。实际上有两种类型的多对多 rnn。当两个序列不一定长度相同时,使用第一种类型。对于诸如机器翻译的应用,输入可以是英语或任何其他语言的句子,输出可以是法语或其他语言的句子。在这种情况下,输入和输出的字数可以不同,这使得这种多对多网络非常有用。当输入和输出同步时使用第二种类型。如果我们要标记视频的每一帧,我们可以输入一帧,输出一个标签,然后继续处理视频的其余部分。

递归神经网络的问题

到目前为止,rnn 看起来很完美,对吧?我们使用这种新型网络对数据序列进行操作,其方式比我们使用传统网络要好得多。但是 RNNs 的一个问题是消失/爆炸梯度问题。

Representation of the vanishing gradient problem from Anish Singh Walia’s article.

当你使用反向传播更新你的模型并计算损耗的梯度时(你的模型是多么的错误),梯度会越来越小。这基本上意味着网络的层数越多,训练的效率就越低。爆炸梯度基本上是相反的,如果梯度非常大,它会像雪崩一样反向传播,并且由于 rnn 经过许多序列和迭代,所以存在消失/爆炸梯度的问题。

长短期记忆

这个问题的一个解决方案是使用 LSTMs,即长短期存储单元。它包含一系列数学公式,帮助 RNNs 解决消失梯度问题,并使预测更加准确。当使用 LSTM 时,想象有四种信息:长期记忆、短期记忆、事件和输出。LSTM 单元基于事件提供输出,并在进行预测时考虑长期记忆和短期记忆。

A diagram showing an example of how information might be updated in an LSTM cell. Source.

从概念上讲,LSTM 包含四个门:遗忘门、学习门、记忆门和使用门。长期记忆进入遗忘门,不需要的信息被遗忘,短期记忆和事件进入学习门,有用的信息被保留。LTM、STM 和事件在记忆门中连接,然后存储在更新的 LTM 中,这三条信息也传递到使用门,在那里进行预测(STM)。

A diagram showing the structure and arrangement of gates in an LSTM cell. Source.

当然,这都是超级简化的。但是主要的收获应该是 LSTMs 在与 rnn 一起工作时非常有用。

用递归神经网络生成论文

现在我们对 RNNs 的工作原理有了基本的了解,让我们回到最初的问题:我如何摆脱做英语作业?

实现这一点的一种方法是利用一对多 RNN。我们可以在一堆不同的文章上训练神经网络,并对模型进行采样,以生成我们从未见过的新文章!

让我们使用 Keras,一个开发深度学习模型的高级 API。这遵循了 Keras Github repo 中使用 LSTMs 生成文本的示例代码。

我们将从导入所有必要的库和模块开始。

任何文本语料库都可以,但对于我的项目,我将使用尼采的著作。我们将导入文本文件,进行一些预处理,并对值进行矢量化。

现在是实际模型的时候了。它由一个 LSTM 组成,并使用 Adam 优化器。

现在定义两个函数,sample:这是一个帮助函数,用于从概率数组中对索引进行采样,on_epoch_end:这是一个函数,在每个 epoch 结束时调用,并打印模型生成的文本。

我们快到了!最后,我们将编写回调函数,在回调函数中我们将看到文本输出,并使模型适合数据。

仅此而已。在我的笔记本电脑上训练所有这些花费了大约三个小时,你也可以在 Google Colab 上用 GPU 运行时训练模型。理论上,生成的文本应该在大约 30 个时代后开始听起来连贯,所以让我们看看模型的一些输出。

“首先培养的是我们的耐心——我们的感觉,即过程的世界对敬畏是同样的形式,是综合的主宰,感觉的节奏也是同样的节奏,是一切驯服的事物,是存在的矛盾的自由的例外——这并不是说,道德和对所有道德领域的人的位置的缺乏”,排除了灵魂对善的追求,总是对他的立场具有对超的危险的恐惧”

“甚至可以把
仇恨的情绪,或做的行为,和一个实例有一个很好地进入灵魂中的宗教状态,压抑和相应,可以是所有宗教的感情和意识的斗争很好地理解站在和可以满足他的主题的灵魂的行为,并依赖于宗教不是作为一种感情谁凌驾于神圣的感觉”

嗯……肯定不惊艳。但这一切都是由神经网络生成的,这难道不酷吗?毫无疑问,有了更好的架构和更广泛的数据,您可能会得到与人类所写的难以区分的结果。

尽管我可能还不能让一个神经网络为我写出我的英语论文,但我认为只要多做一点试验和测试,我就能至少在我的作业的部分中作弊。

一些关键要点

在我看来,自然语言处理目前正在取得一些令人敬畏的突破,并且摆弄文本生成实际上非常有趣。但是如果有什么要点你应该记住的话,下面就是:

  1. 递归神经网络不同于传统神经网络,因为它们能够保留来自先前迭代的数据,以进行更好的预测。
  2. 有许多不同类型的 rnn——包括一对一、一对多、多对一和多对多——每一种都适合特定的任务。
  3. 长短期记忆(LSTM)门用于解决 RNNs 中的消失梯度问题,也用于连接神经网络中的长期信息。

感谢阅读!如果您喜欢,请:

  • 在 LinkedIn 上添加我,关注我的媒体,了解我的旅程
  • 留下一些反馈或者给我发邮件(alex@alexyu.ca)
  • 与你的网络分享这篇文章

谷歌广告报道 Python —逐步指南

原文:https://towardsdatascience.com/getting-adwords-kpis-reports-via-api-python-step-by-step-guide-245fc74d9d73?source=collection_archive---------1-----------------------

Google Adwords 的用户界面非常棒,并且会不断更新,以更加方便用户。它的用户界面功能并不总是能让你解决你的企业特有的问题。我从 SEM 团队的一个问题中受到启发,他们希望按一天中的小时来报告广告支出。

毫无疑问,每小时的广告支出报告可以通过 Adwords UI 创建,但它需要你的团队额外的资源来提取原始数据并生成报告,特别是当你有多个帐户时。内部数据库记录 adwords 的每日数据,但不记录一天中的小时。因此,让我们利用 Adwords API!

Adwords API 客户端库有好几个,像 PHP 、 Ruby 、 Java 等。我选定了 Python 库,因为我没有任何使用其他语言的经验。(有时候,我希望我能有一些网络/软件开发人员的工作经验… LOL)。

通过 OAuth2 进行 API 调用。

如果你是 Adwords API 的初学者,也没有 Adwords 账号,我会推荐跟随官方指南和视频(五集)。因为你需要创建一个测试账户来玩 Adwords APIs,官方指南&视频将带你完成第一次 API 调用。

如果你有 adwords 帐户,让我们开始我们的旅程。总之需要两个脚本:1。第一个脚本—获取刷新的令牌 2。第二个脚本——在活动级别按小时获取广告支出。

如果你以前从未使用过 Adwords API,请不要担心。下一部分将带您从头开始。

步骤:

  1. 通过 OAuth2 设置认证
  2. 为你的 adwords 帐户申请/获得一个开发者令牌
  3. 获取您的刷新令牌并配置您的 adwords 客户端—运行脚本“获取您的刷新令牌”
  4. 进行 API 调用—运行脚本' Get _ ads _ KPIs _ hourofday . py '

现在让我们来看一下每个步骤中的所有细节。

  1. 通过 OAuth2 设置身份验证

这一步的目标:获取客户端 id 和客户端机密。这些是你的应用凭证。你将在谷歌 API 中心创建自己的应用程序后拥有这些。

首先,在谷歌 API 中心创建一个应用程序,可以通过这个链接创建(【https://console.developers.google.com】T4)。请使用您用来访问 adwords 帐户的同一电子邮件。

打开 Google API 控制台凭证页面。点击“选择一个项目”>“新建项目”>输入项目名称>“创建”。

创建项目后,单击“创建凭据”并选择“OAuth 客户端 ID”。

pic-1

pic-2

pic-3

请下载或复制&粘贴您的客户 ID 和客户密码,并保存在安全的地方:)

点击图 3 中的“确定”后。你会看到类似的网页截图如下(图 1)。例如,在 pic-1 中,我的应用程序名称为“Ads-api ”,可以看到客户端 ID。

pic-4

2.获取/请求开发者令牌

转到您的 adwords 帐户,单击右上角的“工具”图标,然后单击“API 中心”。然后,你将登陆一个类似 P2 显示的页面。基本访问级别足以让您进行 API 调用。将开发者令牌信息复制并粘贴到您的“googleleads.yaml”中,您可以在其中存储访问 adwords 帐户的凭据。

pic-2

pic-3

3.获取您的刷新令牌并配置您的 adwords 客户端

将您在步骤 1 中获得的客户端 ID 和客户端密码添加到下面的脚本中。然后通过您的终端(Mac 用户)或注释行(PC 用户)运行“Get_your_refreshed_token.py”下面的脚本。因为我是 Mac 用户,所以我将使用终端来处理其余的步骤。

运行' Get _ your _ refreshed _ token . py '时,您会看到下面的截图

pic-5

按照 pic-5 中的说明,将 URL 从终端复制并粘贴到您的浏览器中。它可能会要求您选择一个 gmail 帐户。请记得选择与您的 adwords 帐户相关的电子邮件。然后你会看到:

pic-5

您可能会在图 5 中看到不同的名称。比如我的 app 名字叫‘Adwords-test’。所以你会看到你的应用程序名称。点击“允许”,然后登陆:

pic-6

再次点击“允许”,您将看到:

pic-7

按照网页上显示的说明,将代码复制回您的终端,然后按键盘上的“enter”或“return”。然后终端会显示:

pic-8

复制和粘贴刷新的令牌并保存它。到目前为止还好吗?我知道第一次它可能仍然令人困惑,但你已经有了所有的部分来建立通过 API 访问 adwords 的关键。

让我们从 Google API Python 库下载“ googleleads.yaml ”(其中存储了您访问账户的凭证)。

在“ googleleads.yaml ”中,有两种配置。根据您的 adwords 帐户类型,您只需要其中一个。在我的例子中,我使用 AdWordsClient 配置。现在,将已经获得的信息输入到“googleleads.yaml”文件中:

开发者令牌(来自步骤 2)

客户端 id &客户端密码(来自步骤 1)

刷新 _ 令牌(来自步骤 3)

完成以下信息后,将“googleleads.yaml”文件保存在本地驱动器的安全位置。完美!您已经完成了访问 Adword 的密钥设置!

4.进行 API 调用—运行脚本“获取每小时广告花费”

运行脚本“Get_ads_KPIs_HourOfDay.py”,为每个 adwords 帐户生成 csv 文件,包括最近 4 周的数据。

注意事项:

  1. 初始化客户端对象时。adwords_client = adwords。AdWords client . LoadFromStorage('…/Google ads . YAML ')这里的' googleads.yaml' 文件包括你的凭证。
  2. 小心 API 报告中的微量。为了得到美元,货币变量/1000000。在我的脚本中,我为 【成本】变量做了这个。 df['成本']=df。成本/1000000
  3. 我在字典中放了三个 adwords 帐户信息( Ad_acc )只是为了同时运行几个帐户的报告。如果你只有一个账号,那么只需在字典中输入一个账号( Ad_acc )。或者,您可以将您的品牌名称作为'键'输入,将 adwords 帐户 ID 作为 'acc_id' 输入,作为函数(run _ hour 0 fday _ kip _ report)的输入变量
  4. 我使用函数根据今天的日期生成过去 28 天的开始日期和结束日期。但你并不真的需要那部分。只需输入任何开始/结束日期格式,如 yymmdd。
  5. 在我的函数( run_Hour0fDay_kip_report)中,报告定义是用 AWQL(AdWords 查询语言)创建的。也可以用 XML 创建报告定义。 查看此处引用的

最后,有许多不同类型的报告可以通过 AdWords API 构建。请检查参考。

通过 5 个简单的步骤获得人口普查数据

原文:https://towardsdatascience.com/getting-census-data-in-5-easy-steps-a08eeb63995d?source=collection_archive---------4-----------------------

Photo by Ishan @seefromthesky on Unsplash

早在 2016 年,在与辛辛那提市合作帮助优化其紧急医疗服务的项目中,我的团队意识到我们需要获得关于该市的详细人口普查数据。我们需要测量,比如按年龄、种族、性别等细分的每个邮政编码的人口。

真的很难得到。我清楚地记得这个过程需要大量的研究、数据搜集和令人头疼的

作为我目前正在撰写的另一篇文章的一部分,我再次发现需要获得人口普查数据,这一次是关于洛杉矶县的邮政编码人口。“又来了”……我想。****

然而,事实证明,在过去的几年里,获取人口普查数据的过程变得极其简单,而且相对来说也不那么痛苦。这里有一个快速的 5 步指南,让你自己得到它。

1.向美国人口普查局请求密钥

为了进行 API 调用(只是一个要求特定数据的 web 请求的花哨名称),您需要从美国人口普查局请求一个密钥。导航到人口普查开发者页面,您应该会看到“请求一个密钥”。

您将被重定向到一个页面,要求输入您的组织名称(我刚刚输入了我的姓名)和您的电子邮件地址。很快,你会收到一封电子邮件,里面有一长串字母和数字,这就是你的 API 密匙。

非常重要:保持这个密钥的秘密。 否则,别人可以以你的名义提出数据请求,而你不一定想要那样。

2.找到正确的数据集

人口普查局有几个数据集,有些可能适合您的项目,有些则不适合。例如,在光谱的一端,我们有美国社区(ACS)调查 1 年数据,它每年都发生,但只针对人口超过 65,000 的地区。

在光谱的另一端,我们有大多数人认为的“人口普查”,官方称为十年一次的人口普查,每 10 年一次,但包括非常详细的地理区域。而且,中间还有几个层次。你可以在这里找到完整的列表。

在这篇文章的其余部分,让我们使用一个具体的例子,假设我们正在试图寻找加利福尼亚州美丽的长滩的邮政编码为 90807 的最近人口统计。

为此,我们将使用 ACS 5 年期数据,其中包括有关小型地理区域的汇总数据,以提高统计可靠性,而不是 1 年期指标(非常适合我们所追求的邮政编码指标)。我们将尽可能使用最新的数据集,来自 2017

导航到 ACS 5 年数据的网页,我们看到我们的 API 调用将以:

https://api.census.gov/data/2017/acs/acs5?key=[YOUR_API_KEY]

3.找到正确的变量

好了,我们有了正确的数据集。现在,我们需要考虑从数据集中需要哪些变量。你可以用你的变量得到相当一般或相当具体的东西。变量的一些例子包括:

  • 总人口
  • 申报加拿大血统的总人数
  • 与祖父母同住的 18 岁以下孙辈总数

而且……这还只是皮毛。ACS 5 年评估的完整变量列表可在这里找到。

对我们来说,我们将保持它的基本性,使用总人口数。我们可以导航到变量网页,Ctrl-F 表示“总人口”,并获得变量名 B01003_001E。

酷!到目前为止,我们的 API 调用如下所示:

https://api.census.gov/data/2017/acs/acs5?KEY =[YOUR _ API _ KEY]&get = b 01003 _ 001 e

上面写着“从 ACS 的 5 年数据中,我想要总人口”。

4.找到正确的地理位置

最后一步是问“哪里”的问题。到目前为止,我们已经从 ACS 5 年的数据中请求了总人口,但是还没有指定我们想要邮政编码为 90807 的这个值。

实现这个结果就像稍微修改一下 API 调用一样简单:

https://api.census.gov/data/2017/acs/acs5?KEY =[YOUR _ API _ KEY]&get = b 01003 _ 001 e&for = zip % 20 code % 20 tabulation % 20 area:90807

如果你想知道, "%20" 只是空格的代码,因为我们不允许在 URL 中放真正的空格。

另请注意,你不仅仅局限于邮政编码作为你的地理位置。你可以用州、县等来代替。您只需要相应地修改 API 调用。我发现找出正确的 API 调用的最好方法是查看人口普查局提供的一些例子,然后修改它们以满足你的需求

5.进行 API 调用

所有艰苦的工作都完成了!

让我们将 API 调用复制/粘贴到浏览器中,看看会得到什么。

这告诉我们 2017 年邮政编码 90807 的总人口是 32395

相当酷!

(6.)可选:将结果存储在电子表格中

您可能想要将您的结果存储在某个地方,这一步将带您通过一个示例了解如何使用 python 来做到这一点。以下脚本将使用包含这些邮政编码列表的 txt 文件(在 my GitHub 这里找到)生成一个 CSV 电子表格,其中包含洛杉矶县内所有邮政编码的人口。

****感谢阅读,我希望这篇文章能让你更容易收集自己的人口普查数据!

发挥数据科学算法的创造力

原文:https://towardsdatascience.com/getting-creative-with-algorithms-c97e2680eb07?source=collection_archive---------21-----------------------

如何在数据科学中不再机械,保持创新优势

Get Creative with Algorithms

1972 年 4 月,《纽约时报》发表了一篇文章《工人越来越反抗流水线上的无聊》。虽然汽车工业被认为是非常创新的,但这种工作是非常机械和重复的。原因是汽车工业是基于装配线的概念,人们应该每天做一系列重复的工作。

同样,数据科学领域也非常有趣和创新,它有时会变得机械和重复。例如,当目标是对数据进行聚类时,通常我们倾向于使用诸如 KMeans 或 DBScan 之类的“常见可疑”算法。就预测而言,这个过程可能非常机械,只是遵循一系列步骤,如数据清理、一键编码、特征工程、机器学习和混淆矩阵。

总是应用相似的算法和方法,有时会导致数据科学疲劳。尽管数据科学被用于创新目的,但数据科学疲劳会导致你的大脑缺乏创新。

那么如何避免过于机械,避免流水线式的工作呢?一种方法是在算法上有所创新。这里有一些例子

先想到客观,然后是算法

当您想到聚类或分段时,我们通常会想到对具有许多特征的表格数据应用聚类算法,如 KMeans、DBScan 和其他算法。然而,让我们在这里看到一种不同于通常做法的聚类方法。

假设您有购物发票列表作为您的数据。它有三个字段发票号码,产品代码,描述和数量。

Invoice data

那么我们如何对这些数据进行聚类呢?首先,我们需要确定集群的目标。一个有用的目标可能是找到一起销售的产品群或细分市场。因此,我们解决这个问题的策略可以分为两步:1 .寻找一起出售的产品。查找一起销售的所有产品的聚类

因此,让我们首先找到一起销售的所有产品。购物篮分析有助于我们发现哪些产品是一起销售的。购物篮分析有各种算法。用于购物篮分析的常用算法之一是 apriori 算法。该算法的结果是经常一起销售的产品对。下面是一些基于购物发票数据集的例子

老式广告牌爱恨杯——&—爱德华七世时代的阳伞红

白色吊心 T 型灯座——白色金属灯笼

现在我们已经确定了一起销售的产品,下一步是找到这些产品的集群。要做到这一点,我们可以从图论中获得灵感,有时也称为网络理论。我们可以把每个产品看作一个节点。如果它们一起出售,我们可以在产品(节点)之间创造一个优势。图表可以如此处所示,显示几个最畅销的产品

Graph Algorithms to make cluster

我们可以清楚地看到一些产品集群。此外,诸如模块化算法的图形算法可以用于提取这些聚类

正如我们所见,我们可以使用 apriori 和图算法进行聚类。当您考虑集群时,您不应该自动总结使用 KMeans、DBScan 或其他类似的算法。人们应该考虑聚类的目的,然后决定使用哪种算法

尝试寻找不同的方法做同一件事

避免重复工作并保持创新优势的一个方法是从不同的角度看待问题。为了说明这一点,让我们以汽车数据集为例。该汽车数据集具有关于汽车的各种技术特征。

Automotive dataset

假设我们的目标是找到所有特征之间的协方差。首先想到的事情之一是在所有特征之间应用协方差算法。重复应用相同的算法总是让你失去创新的优势。

那么另一种寻找协方差的方法是什么呢?一种不同的方法是 PCA(主成分分析)。虽然 PCA 算法的目标是降维,但它是基于发现特征之间的变化。变化最大的特征用于降维。作为该算法的副产品,您还可以获得具有正协方差和负协方差的要素

这里显示的是特征及其对第一主成分的影响(或特征值)之间的图。人们可以得出结论,宽度,长度,高度有正协方差和正相关。mpg、rpm 具有负协方差和负相关

PCA to find variance

这里我们看到我们可以用不同的方法解决问题。这也有助于我们理解不同算法之间的关系。一旦你对算法之间的关系和相似性有了这样的想法,你就可以开始从不同的角度处理问题。这将带您进入数据科学创新的下一个阶段

使用深度学习不是作为最终结果,而是作为数据来源

在执行 YOLO 算法后,我们在图像上看到过多少次绿框。几年前,当 YOLO 被介绍给数据科学家时,那是超级有趣和令人兴奋的。有许多数据科学家使用 YOLO 对各种图像和视频进行对象识别。然而,现在仅仅使用 YOLO 来识别物体已经变得非常机械。所有这些绿色盒子并没有像几年前一样让数据科学家们兴奋。

深度学习非常具有创新性和前沿性。但是它的使用方式已经变得非常机械。保持其创新用法的方法之一是将深度学习视为数据来源。想象一下,你有一个零售店中人们移动的视频分析。我们可以使用深度学习算法来识别人类,如下例所示。这些例子说明了在机场或零售店中识别人

Deep learning YOLO output

现在,如果我们把上面的结果看作一个数据源,而不是一个目的,会怎么样呢?YOLO 可以帮助探测物体,但它也给出了物体的位置。因此,YOLO 的结果可以输入到另一个算法中,比如路径分析。我们可以分析人们的运动。我们可以使用它来查找零售店或机场中有大量活动的区域和不太繁忙的区域。我们还可以找到人们通常走的轨迹。就像在零售店一样,我们可以在来到收银台之前找出哪些区域被光顾过,以及哪些购物者没有经过收银台

如下图所示,是零售商店中所访问区域的路径分析

Path Analysis based on output from YOLO

这就是我们正在超越的仅仅是物体检测和绘制绿色方框。将深度学习算法的输出视为数据来源,将有助于您应用智能算法来得出面向业务和令人兴奋的结果

在本文中,我们看到了一些思考数据科学的有趣方式。使用这些技术,以免陷入机械和流水线式的数据科学研究方式。数据科学专业本质上是创新的。所以,换个角度思考,超越常规,保持你的创新优势

额外资源

网站(全球资讯网的主机站)

你可以访问我的网站进行零编码分析。https://experiencedatascience.com

订阅每当我发布一个新的故事时,请及时通知我。

[## 每当 Pranay Dave 发表文章时,您都会收到电子邮件。

每当 Pranay Dave 发表文章时,您都会收到电子邮件。通过注册,您将创建一个中型帐户,如果您还没有…

pranay-dave9.medium.com](https://pranay-dave9.medium.com/subscribe)

你也可以通过我的推荐链接加入 Medium。

[## 通过我的推荐链接加入 Medium—Pranay Dave

作为一个媒体会员,你的会员费的一部分会给你阅读的作家,你可以完全接触到每一个故事…

pranay-dave9.medium.com](https://pranay-dave9.medium.com/membership)

Youtube 频道
这里是我的 Youtube 频道的链接
【https://www.youtube.com/c/DataScienceDemonstrated

深入研究机器学习的分类编码

原文:https://towardsdatascience.com/getting-deeper-into-categorical-encodings-for-machine-learning-2312acd347c8?source=collection_archive---------3-----------------------

奖励: Catboost 提出的有序目标编码

介绍

根据我在监督学习方面的经验,将模型性能从像样提高到像人一样需要创造性的特征工程。如果特征工程没有做好,从简单算法跳到复杂算法并不总是能提高性能。监督学习的目标是从相关特征中提取所有的汁液,为了做到这一点,我们通常必须丰富和转换特征,以便使算法更容易看到目标变量如何依赖于给定的数据。一种不容易泄露其包含的信息的特征是分类特征。他们一直隐藏信息,直到我们聪明地改变他们。在这篇特别的文章中,我将重点介绍一种叫做目标编码的特殊分类编码技术,这种技术在大多数情况下都非常有效,但是如果操作不正确,就会有目标泄漏的风险。目标泄漏意味着使用来自目标的一些信息来预测目标本身(你看到这里的问题了吗?).因此,这种泄漏增加了过度拟合训练数据的风险,尤其是当数据很小时。类似的目标泄漏也存在于标准梯度提升算法中。 Catboost 实现了一种叫做排序原则的技术,解决了两种情况下的目标泄漏问题。基于这种技术以及许多其他小的改进,Catboost 在一组流行的公开可用数据集上优于其他公开可用的梯度增强库。本文总结了 Catboost 所做的对比实验— CatBoost:具有分类特征的无偏增强。

标准方法

一键编码 —处理分类特征的一种常用技术是一键编码,即对于每一级别的类别,我们创建一个二元特征。然而,在高基数的情况下(例如,城市 ID、地区 ID、邮政编码),这种技术导致不可行的大量特征。基于树的模型尤其受到如此大量的一次性特征的困扰,因为:1)树仅在一个热要素的零的方向上生长(如下图所示),2)如果树想要在一个热要素(0,1)上分割,它的信息增益将会很低,因此如果其他连续的要素也存在,树将无法从根附近的要素中分割。

标签编码 —另一种标准编码技术是数字编码(又名标签编码),我们给每个类别分配一个随机数。这种技术在数据中注入了某种形式的顺序,而这种顺序通常是没有意义的,是随机的。我们需要维护一个类别到数字的映射,以便以后对测试数据应用相同的映射。对于生产中的模型,维护映射有时会变得很困难。基于树的模型也遭受这种编码,因为树基于小于或大于最佳值的值找到最佳分割。在随机排序的情况下,小于或大于没有任何意义。

哈希编码— 这种常用的技术使用哈希函数将字符串类型的特征转换成固定维度的向量。sklearn 中使用的哈希函数是 Murmurhash3 的带符号 32 位版本。一个 32 维向量可以保存 2 个唯一的组合。这对于高基数变量非常有用,在这种情况下,一个热编码将提供大量的特性。我最近注意到这种技术工作得非常好,特别是在类别的字符串模式中有一些信息的情况下。

哈希的优点:1)不需要维护类别到数字的映射。只需要使用相同的哈希函数对测试数据进行编码;2)减少级别,特别是在高基数特征的情况下,这因此使得树更容易分裂;3)可以组合多个特征来创建单个散列。这有助于捕捉特征交互。

哈希的缺点:1)哈希冲突。不同级别的类别可以归入同一个桶。如果这些类别没有同等地影响目标,那么预测得分可能会受到影响;2)需要调整散列向量维数的另一个超参数。

目标编码 —另一个选项,也是这篇博文的主要焦点是目标编码(又名似然编码)。想法是用一个数字替换分类特征的每一级,该数字是从该特定类别级的目标标签的分布计算的。例如,如果分类特征的级别是红色、蓝色和绿色。然后用一些统计集合(平均值、中值、方差等)替换红色。)在训练数据中特征值为红色的所有目标标签中。

下图显示了一个分类特征的决策树是如何构建的,当它是一个热点编码时,与当它是一个数字编码时(每个类别一个随机数)。第三个图显示了带有目标编码特征的决策树。对于所有图,使用仅具有一个分类特征和一个二元目标的 1000 行模拟数据。分类特性具有很高的基数,有 100 个不同的级别,从 0 到 99 (记住顺序没有意义,因为我们将其视为名义分类特性)。目标以这样的方式依赖于特征,即类别是 11 的倍数(0,11,22,33..99)的目标值为 1,对于所有其他情况为 0。该数据具有 897 个阴性标签和 103 个阳性标签)。使用 dtreeviz 库构建图形,用于决策树可视化,树的最大深度限制为 5。 Jupyter 笔记本链接获取生成这些图的代码。

在第一个图中,我们可以看到,具有一个热点编码特征的决策树创建了许多许多分裂,并且树都是左侧的。该树仍在完成工作,并能够分离数据。我们观察到从根到叶的分裂值分别为 66,99,0,88,11。在每次分割时,信息增益很低,因为分割只关注分类特征的一个级别。如果我们引入有噪声的连续特征,树可能会在噪声中找到比某个一次性编码特征更多的信息增益,并在特征重要性图中放弃这些信息,这有时会产生误导。这个问题在这篇博文中有详细的讨论— 分类变量在你的随机森林中迷失了吗?这个 kaggle 讨论页面——为什么一键编码给出的分数更差?

在第二个样地中,树从根到叶分别在 98.5、0、10.5、11.5、88.5 处裂开。所以这棵树也能找到正确的答案,找到接近 11 的倍数的分裂。它假设分配给类别的数字是有序的,这实际上是随机分配。我们看到,即使对于这种基于完美规则的数据,该树也很难达到一个好的决策边界。在实践中,我注意到,只要基数不高,这种技术与随机森林或梯度提升技术配合得很好。如果基数很高,数字编码很可能会在您获得任何好处之前使您的计算成本激增。这个计算成本问题的解决方法是基于该级别的频率分配数字/等级。

在第三个图中,目标均值编码的树在仅仅一次决策践踏/分割中找到了数据的完美分割。我们看到这种编码在我们的玩具例子中非常有效。让我们更深入地研究这一点,并将本文的范围限制在目标编码、目标泄漏/预测偏移、由于这种类型的编码导致的过拟合;最后是 Catboost 对这个问题的解决方案。

目标编码

不同类型的目标编码

目标编码是用等于某个目标统计量(例如,目标的平均值、中值或最大值)的一个数字特征来代替第 k 个训练示例的类别。

  1. 贪婪的
  2. 坚持
  3. k 倍
  4. 有序的(Catboost 提出的)

现在让我们讨论一下每种类型的优缺点。

贪婪目标编码

这是最直接的方法。只需将目标标签的平均值替换到具有相同类别的训练样本上。我们只能看到训练数据的标签。因此,我们从训练数据中找到所有类别的平均编码,并将其映射到测试数据。对于在测试中发现一些新类别而在训练数据中不可用的情况,我们用目标的总体平均值替换该类别的值。只要我们有大量的训练数据、基数较低的分类特征,并且目标分布在训练和测试数据中,这种方法就能很好地工作。但是这在其他情况下不起作用。

Decision tree on greedy target encoded feature

让我们看一个极端的例子来说明这种编码技术的失败。在左边,我们看到一个在 0.5 阈值处具有完美分割的决策树图。用于该模型的训练数据具有 1000 个观察值,其中只有一个分类特征具有 1000 个唯一级别。将用户 ID 视为这种独特分类特征的一个例子。标签(0,1)已被随机分配给训练数据。这意味着目标与特性没有任何关系。但是决策树向我们展示了什么呢?该树向我们展示了在第一个节点上的完美分割,尽管实际上完美分割并不存在。该模型将在训练数据上显示接近完美的分数。这是真的吗?不。测试数据可能有新的用户 id,在训练数据中看不到,我们的模型将吸收测试数据。这就是“在训练数据上过度拟合”的情况。稍后我们将解决这个问题。

k 倍目标编码

这是最常用的方法,解决了训练数据过拟合的问题(“大部分”,不总是)。思路类似于 k 重交叉验证。我们将数据分成 K 层或随机层,用除 M 层之外的所有其他层的数据的平均目标代替 M 层中的观察值。我们基本上是试图 1)使用给我们的所有训练数据,2)通过允许目标信息从其他同伴观察(相同类别但不同折叠)中流出,不泄漏来自自我目标标签的信息。大多数时候,我个人在 K=5 的情况下使用这种方法,到目前为止,这种方法对小型到大型数据集都很有效。

Holdout 目标编码-K = 2 时 K 倍的特例。

另一种选择是将训练数据集分成两部分。第一部分计算目标统计量,第二部分进行模型训练。这样我们就不会从第二部分的目标中泄露任何信息,这些信息实际上是用于训练的。但是这种技术导致了数据减少的问题,因为我们基本上使用的训练数据比我们实际拥有的要少。使用这种方法,我们并没有有效地利用手头的所有训练数据。当我们有大量数据时,仍然不是一个很好的解决方案。

留一目标编码- 当 K =训练数据长度时 K-fold 的特例。

这在我们有小数据集时特别有用。我们通过使用除了特定观察之外的所有观察的标签来计算每个观察的目标统计。但是这种技术在某些情况下也会导致过度拟合。让我们用决策树可视化来看一个这样的失败例子。

Decision tree on leave one out encoded feature

在这个例子中,我们的训练数据有 100 个观察值,只有一个特征;称它为颜色,它总是红色的。很明显这个功能是没用的。如果我们尝试在这个特性上用一个编码来拟合决策树,我们可能会以训练数据的完美分割而结束(如下所示)。这是一种误导,因为这种完美的分割并不存在。它给出这种分割的原因是因为当我们使用留一时,它要么留 0 要么留 1,只给我们两个唯一的编码。当我们在此基础上训练模型时,它使用这两个唯一值来寻找完美的分割。

有序目标编码

这不是常用的方法。但这是 Catboost 库背后的核心思想,它对分类数据非常有效,如这篇论文所示。这种技术源于用于处理时间序列数据的验证技术。当目标的分布与时间不一致时,我们需要特别注意在调整超参数时不要泄漏任何来自未来的信息。在这篇博文中讨论了在时间序列数据中进行超参数调整或分裂验证集的不同方法— 时间序列嵌套交叉验证。基本思想是使用超时验证方法,因为传统的 k-fold 方法在这种情况下效果不佳。类似地,有序目标编码依赖于人工时间依赖性的概念。我们只使用历史记录中的目标来计算每个示例的目标统计数据。为了生成时间的代理概念,我们随机打乱数据。为了简化,我们随机排列行,并对按每个类别分组的目标标签进行移动平均。

但是,取群体的移动平均数有一个问题。对于随机化数据中的最初几行,均值编码将具有较高的方差,因为它只看到历史中的几个点。但随着数据越来越多,移动平均值开始变得稳定。由于随机选择的初始数据点造成的这种不稳定性使得数据集的初始部分具有弱估计。Catboost 通过使用多个随机排列来处理这个问题。它同时训练几个模型,每个模型都根据自己的排列进行训练。所有模型共享相同的树森林,即相同的树结构。但是这些模型的叶值是不同的。在构建下一棵树之前,CatBoost 选择其中一个模型,该模型将用于选择树结构。使用此模型选择结构,然后用于计算所有模型的叶值。

让我们看看有序编码是否解决了我们讨论的遗漏一项和贪婪目标编码技术的失败案例。

Left: No successful split in case of all unique categories. Right: Decision tree construction for case of all same category.

案例 1(左图)。当我们拥有所有独特的类别,贪婪的方法失败了。我们看到,有序编码一开始就不能简单地找到任何好的分割。案例 2(右图)。当我们都有相同的类别时。在这种情况下,如果在第一个节点中给出完美的分割,则省略一个节点会失败。但是有序编码很难找到一个理想的模型。

CatBoost 还对分类要素组合使用有序目标编码,这对于某些数据集很有用。这些组合是在训练期间以贪婪的方式选择的。我们不是在这里讨论程序。但是好奇的读者可以阅读这篇论文来学习组合特性的过程。

排行榜

看过不同类型的编码后,让我们做一些有趣的事情。让我们在几个数据集上比较随机森林在所有这些编码下的性能,看看哪个在排行榜上名列前茅。还增加了 Catboost 在每个数据集上的性能。

以下实验在数据集上运行:
1。随机森林(500 棵树,10 个最大深度)在一个热编码特征
2 上。数字标签上的随机森林(500 棵树,最大深度 10)
3。散列编码特征
4 上的随机森林(500 棵树,10 max_depth)。K 倍目标编码上的随机森林(500 棵树,10 max _ depth)
5。有序/Catboost 目标编码上的随机森林(500 棵树,10 max _ depth)
6。Catboost (500 次迭代,20 轮提前停止);分类索引

数据集 1。

只有一个分类特征的模拟数据集。10,000 个数据点,100 级基数。该功能是创建使用随机字符串生成器。每个字符串的长度为 5,生成 100 个这样的唯一字符串。这 100 个字符串通过替换被重新采样,以给出 10,000 个数据点。以元音开头的字符串的目标标签为 1,其他字符串的目标标签为 0。大约 20%的数据有正面标签。

结果

Left to right. 1–5 are categorical encodings on RF. 6 is Catboost GBM.

我们看到目标编码和数字编码在测试数据上给出了完美的分数。所有情况下的树都被调整到最大深度 10。One hot 编码和 hash 编码不能在测试数据上给出完美的分数。哈希编码肯定遇到了一些冲突,会将一些以元音开头的单词与以辅音开头的单词放在同一个桶中,这就是为什么我们会看到一些分数下降。就时间而言,与随机森林的 500 棵树相比,Catboost 中的 500 次迭代要花费更多的时间。有效使用梯度推进算法的最佳方式是使用早期停止循环和更好的学习速率。

数据集 2。

Kaggle 数据。【Amazon.com 员工准入挑战。该数据集有 8 个特征,所有特征都是基数从低值到高值的分类特征。(0.2%至 22%的独特类别)。

结果

Left to right. 1–4 are categorical encodings on RF. 5 is Catboost GBM.

我们看到 catboost 在性能方面优于随机森林,但速度相对较慢。当我们使用 K-fold 目标编码,然后是 number 和 ordered/catboost 目标编码时,可以获得最佳的随机森林模型。数据集中没有字符串类型特征,所以我们没有使用哈希编码。对于固定深度的 RF,one hot 编码不能提供良好的性能。

Jupyter notebook with comparisons of different encoding techniques

结论

通过实验我们了解到,在实践中,数字编码的特征在随机森林中表现很好。目标编码在数字编码的基础上做了一点改进。就时间效率而言,目标编码特征帮助树找到具有更少分裂的解决方案。传统的贪婪和遗漏一个目标编码有过度拟合的风险。这种过拟合
可以通过使用 5/10 倍目标编码或有序目标编码来解决。有序目标编码通过随机排列行在数据中引入了人为的时间概念。Catboost 创建具有不同随机排列的多个树,以生成没有任何目标泄漏的强模型。

将链接到代码库

关于我:我目前在 AWS 的亚马逊欺诈检测团队担任研究科学家。如果你有兴趣了解 ML 欺诈或与我们合作,请通过 linkedin 联系我。你可以在这里阅读我的其他博客。

推荐读物

  1. 将分类特征转换为数字特征 - Catboost
  2. 激发这篇文章的论文: CatBoost:带有分类特征的无偏增强
  3. 另一篇关于分类特征树可视化的文章:访问:决策树中的分类特征和编码
  4. 由特伦斯·帕尔和杰瑞米·霍华德 : 直截了当地说
  5. 如果不知道梯度推进,阅读这篇简单易懂的文章:从零开始的梯度推进
  6. 让我们从头开始写一个决策树分类器——机器学习方法#8
  7. 一键编码让你的基于树的集合变得更糟,这是为什么?

动手操作数据库

原文:https://towardsdatascience.com/getting-hands-on-with-databases-5ac7b2ae1444?source=collection_archive---------22-----------------------

获得数据科学家最需要的技能之一的经验

Photo by Jan Antonin Kolar on Unsplash

数据科学是一个在过去几年中经历爆炸式增长的领域,并在 2012 年被《哈佛商业评论》评为“21 世纪最性感的工作”。随着高薪和对人工智能的不断炒作,越来越多的人试图转向数据科学。

谷歌快速搜索显示,SQL 和 NoSQL 等数据库查询语言是成为数据科学家所需的顶级编程语言。与其他顶级编程语言相比,这些语言通常更难学习,因为没有多少项目和教程是围绕学习数据库而构建的。这就是我写这篇关于数据库以及如何设置数据库的简介的原因,您可以在学习下游分析时使用它。

那么什么是数据库呢?

数据库,至少是关系数据库,可以被认为是服用了兴奋剂的 Excel 电子表格。每个数据库都由表组成,这些表可以看作是 Excel 中的工作表,每个表都由数据列组成。但是,对存储在数据库中的数据有一些 Excel 中没有的约束。例如,创建数据库表时,必须为每列指定数据类型,并且不能在一列中混合使用。每个表还有一个主键,它是每行的唯一标识符。这些可以指定(用户名),也可以自动生成。它们也用于将桌子连接在一起。这应该是足够的信息,如果你想更深入地了解数据库,我建议查看斯坦福大学这门课的前几堂课,关于数据管理和数据系统。

Instacart 数据集

对于这个数据库,我决定使用 Instacart 在 2017 年发布的数据,作为 Kaggle 上一场比赛的一部分。我选择这个数据是因为它显然是从 SQL 数据库中保存的,而且有些 CSV 文件太大,无法在 Chromebook 上使用。来自 Instacart 的数据可在此处找到以及使用数据的服务条款。为了下载数据,我复制了链接地址,并使用wgetuntar来下载和解压缩数据。

创建数据库

下载完示例数据后,就可以创建数据库了。有许多不同的开源 SQL 数据库可供选择。为此,我决定使用 PostgreSQL,因为它是我在 Heroku 上部署应用程序时开始使用的。如果你还没有安装它,我发现最简单的安装方法是使用 EDB·波斯格里斯提供的安装程序。

在数据库中,每个 CSV 文件都有一个表。如果我们看一下aisles.csv的头部,我们看到有两列,一列是过道 id,另一列是过道名称。

对于靠过道的桌子,我们也需要两列。第一列用integers填充,是表的主键,第二列是长度可变的text。下面的 SQL 将创建这样一个表。

可以为每个表构造类似的语句,并放入名为 create_tables.sql 的文件中。

使用COPY table_name(columns) FROM 'path/to/csv/file.csv';命令,可以用 CSV 文件中的数据填充每个表。同样,我们可以将每个 SQL 语句放入一个名为 add_data.sql 的文件中。

现在我们已经有了创建和填充数据库表的代码,是时候创建实际的数据库了。我们可以通过从命令行首先登录 Postgres,psql -U postgres来做到这一点。我们现在可以运行命令CREATE DATABASE instacart_db;来创建数据库。为了结帐或连接到数据库,我们在终端中输入\c instacart_db。在连接到新创建的数据库后,我们可以创建并填充表\i create_tables.sql;,然后是\i add_data.sql;。请注意,根据处理器的速度,填充表格可能需要一段时间。

用 Python 连接到数据库

我们现在可以用 Python 连接到数据库,并开始做一些分析。要连接到数据库,我们需要安装 psycopg2。我发现用 conda 安装最简单,因为它也可以安装一些需要的库文件。运行conda install psycopg2后,你可以启动一个 Jupyter 笔记本。我已经包含了一个样例笔记本,它演示了如何连接到数据库并执行 SQL 命令。在笔记本里,我看products表,看什么部门和过道的产品最多。

Number of Products in Each Department

Number of Products in the Top 20 Aisles

我希望这有助于您创建一个可以用来练习 SQL 查询和数据分析的数据库。如果您有任何问题或发现任何错误,请联系我。

通过自然语言处理进入机器的灵魂

原文:https://towardsdatascience.com/getting-into-the-soul-of-machines-through-nlp-10316e3d3299?source=collection_archive---------26-----------------------

使用 NLTK 库的 NLP 概览

介绍

自然语言处理,简称 NLP,是计算机用来理解人类语言的人工智能的一个子领域。对自然语言处理的研究始于 20 世纪 50 年代,直到 20 世纪 80 年代,开发人员一直通过编写复杂的手写规则来构建自然语言处理系统。

当机器学习算法被开发用于自然语言处理时,这一切都改变了,一场革命开始了。新的 NLP 系统基于统计和概率模型。

让你的数据科学梦想变成现实

NLP 是如何工作的?

在我们深入 NLP 之前,让我们先看看人类是如何理解语言的。我们人类使用一组单词来组成句子,并通过说和写来表达我们的思想和观点,以便与他人交流。

示例-

我来自法国,我会说 ________?

回答 —法语

人类将根据句子的上下文进行解释,并回答法语,因为法语是法国的官方语言。在自然语言处理中,计算机试图理解句子的上下文,然后像人一样做出决定。

我们有大量原始英语文本或任何其他语言形式的非结构化数据。计算机还不能完全理解英语,但是它们已经可以做很多事情并节省大量时间。

与所有最新技术保持联系

NLTK 库

自然语言处理的基本库是 NLTK(自然语言工具包)。它是用 Python 编写的,支持分类、词干提取、解析、语义推理、标记化等任务。

安装 NLTK

Windows、Linux 和 Mac 用户可以使用 pip 命令直接安装包。

pip install nltk

安装软件包后,编写以下 python 代码

import nltk
nltk.download()

这将打开一个 GUI,您可以从中下载 NTLK 包。你可以下载所有的软件包,因为它们都很小。

现在,让我们开始编写一些代码。

标记文本

记号化是一种将字符串分解成小部分的技术。通常,在 NLP 问题中,我们有一个包含文本的大字符串。第一步,我们把字符串分解成句子。

NLTK 句子分词器

代码:

text = “I seem to have caught cold. I’m a little feverish.”
from nltk import sent_tokenize
sentences = sent_tokenize(text)
print(sentences)

输出:

'我好像感冒了。',“我有点发烧。

为了标记英语以外的句子,我们将语言名称作为第二个参数传递。

代号:

fren = sent_tokenize(“Enchanté, comment allez-vous? Tres bien. Mersi, et vous?”,”french”)
print(fren)

输出:

【‘你好,请问你是哪位?’,'好极了'“梅西,你呢?”】

NLTK 工作标记器

下一步,我们将字符串分解成单词。

代码:

from nltk import word_tokenize
tokens = word_tokenize(“Hello Mr. Roy. How was your day? ”)
print(tokens)

输出:

【‘你好’,‘先生’,‘罗伊’,’、'怎么样'、'曾经是'、'你的'、'一天'、'?'】

:

你注意到“先生”在一个 token 和“罗伊。”被分成两个记号,像“罗伊”和“.”

同义词和反义词

在自然语言中,多个单词可以有相同的意思。所以有一个函数可以给我们一个单词的同义词或反义词是非常方便的。NTLK 图书馆有一个用于此目的的 wordnet 数据库。

同义词

代码:

from nltk.corpus import wordnet
syn=wordnet.synsets(‘fight’)
print(syn)

输出:

【Synset(' battle . n . 01 ')、Synset('fight.n.02 ')、Synset(' competitive . n . 01 ')、Synset('fight.n.05 ')、Synset(' content . v . 06 ')、Synset('fight.v.02 ')、Synset('fight.v.03 ')、Synset(' crusade . v . 01 ')】

我们还可以得到这个词的定义和例子。

print(syn[0].examples())
print(syn[0].definition())

输出:

【‘格兰特在奇卡莫加战役中取得了决定性的胜利’,‘当他真正投入战斗时,他失去了关于战争的浪漫想法’】

战争过程中敌对军事力量的敌对会面

反义词

为了得到反义词的列表,你必须在添加它们之前检查词条。

代码:

from nltk.corpus import wordnet
antonyms=[]
for syn in wordnet.synsets(‘stupid’):
    for l in syn.lemmas():
        if l.antonyms():
            antonyms.append(l.antonyms()[0].name())
print(antonyms)

输出:

[‘智能’,‘智能’]

懂得制造机器的艺术

词干化和词汇化

这也是自然语言处理的重要部分之一。在这些过程中,我们将单词规范化为它们的词根形式。

例如, “吃,吃过,吃”这几个字可以简化为“吃”

词干法使用一种启发式方法,即砍掉单词的末尾来快速达到目标,而词干法通过考虑单词的词汇和形态分析来正确地处理事情。

让我们看看如何实现它们-

词干

代号:

from nltk.stem import PorterStemmer
stem = PorterStemmer()
print(stem.stem(‘swimming’))
print(stem.stem(“cats”))
print(stem.stem(“trouble”))

输出:



词汇化

NLTK 库提供了 wordnet lemmatizer,它查看 wordnet 数据库并返回实际存在的真实单词。

代码:

from nltk.stem import WordNetLemmatizer
lemmatizer=WordNetLemmatizer()
print(lemmatizer.lemmatize(‘believes’))
print(lemmatizer.lemmatize(‘swimming’))
print(lemmatizer.lemmatize(‘trouble’))

输出:

信念
游泳
麻烦

词干化和词汇化都做同样的工作,但方式不同。如果你知道它们之间的区别,那么你就可以决定什么时候用什么。在速度和准确性之间有一个折衷。词干化很快,而词汇化很精确。

停用词

这在预处理步骤中被大量使用,以过滤掉没有提供关于句子的太多信息的无用单词,如(a、an、the 等)。我们可以从 NLTK 库中看到所有停用词的列表。

代码:

from nltk.corpus import stopwords
sw = stopwords.words(‘english’)
print(sw)

输出:

停用字词通过移除不需要的字词来帮助清理标记列表。让我们来看一个例子,如何在构建 NLP 系统之前对文本进行预处理。

代码:

from nltk.corpus import stopwords
from nltk.tokenize import word_tokenizetext = “This is a sample sentence, showing off the stop words filtration.”
stop_words = set(stopwords.words(‘english’))
word_tokens = word_tokenize(text)
filtered_sentence = [w for w in word_tokens if not w in stop_words]
filtered_sentence = []for w in word_tokens:
    if w not in stop_words:
        filtered_sentence.append(w)print(word_tokens)
print(filtered_sentence)

输出:

['这个','是','一个','样本','句子',','显示','关闭','该','停止','词语','过滤','.']
['这个','样本','句子',','显示','停止','词语','过滤','.'】

包装东西

这是自然语言处理的一个快速体验,其中我们理解了 NLP 的一些基础知识,并且实际上使用流行的 NLTK 库实现了一些技术。

希望你喜欢学习新概念!

那你为什么等这么久?
现在成为一名 Python 传教士

最新深度增强算法概述

原文:https://towardsdatascience.com/getting-just-the-gist-of-deep-rl-algorithms-dbffbfdf0dec?source=collection_archive---------5-----------------------

一个不需要浏览大量文档就能获得 RL 算法要点的资源——一个面向学生和研究人员的资源,没有一个公式。

作为一名强化学习(RL)研究人员,我经常需要提醒自己算法之间的细微差别。在这里,我想创建一个算法列表,并为每个算法添加一两句话,使其在子领域与其他算法有所区别。我将此与该领域的简要历史介绍相结合。

Source: Shedding Light on AlphaZero

强化学习植根于最优控制的历史。这个故事始于 20 世纪 50 年代的精确动态规划,从广义上讲,这是一种结构化的方法,将一个受限的问题分解成更小的、可解决的子问题[ 维基百科 ],归功于理查德·贝尔曼。众所周知,克劳德·香农和理查德·贝尔曼在 20 世纪 50 年代和 60 年代革新了许多计算科学。

Richard Bellman — source wikipedia

在 20 世纪 80 年代,出现了一些关于 RL 和控制之间联系的初步工作,第一个值得注意的结果是 1992 年基于时差模型的 Tesauro 的双陆棋程序。在 20 世纪 90 年代,更多的算法分析出现了,并倾向于我们现在所说的 RL。一篇开创性的论文是 Ronald J. Williams 的“用于联结主义强化学习的简单统计梯度跟踪算法”,它介绍了现在的标准策略梯度。请注意,在标题中,他加入了术语“连接主义者”来描述 RL——这是他按照人类认知的设计对模型指定算法的方式。这些现在被称为神经网络,但仅仅在 25 年前还是研究的一个小分支。

Historical application of dynamic programming — trees and other classical computer science data-structures. Source: Cormen et al. “Introduction to Algorithms”

直到 2000 年代中期,随着大数据和计算革命的到来,RL 才转向基于神经网络,以及许多基于梯度的收敛算法。现代 RL 通常分为两种类型,即“自由模型”和“基于模型”的 RL。我也会这么做。

Some core tradeoffs in different types of RL. For deep RL, most algorithms have shallow backups and follows Monte Carlo methods.

无模型 RL:

模型自由 RL 直接生成一个 actor 的策略。我喜欢把它看作是如何行动的端到端学习,所有的环境知识都嵌入在这个政策中。

策略梯度算法:

策略梯度算法修改代理的策略,以跟踪那些为其带来更高回报的行为。这使得这些算法是基于策略的,因此它们只能从算法中采取的动作中学习。

联结主义强化学习的简单统计梯度跟踪算法(强化)——1992:这篇论文启动了政策梯度思想,提出了系统地增加产生高回报的行动可能性的核心思想。

基于值的算法:

基于价值的算法根据给定状态的感知价值修改代理的策略。这使得这些算法脱离策略,因为代理可以通过从任何策略读取奖励函数来更新状态的内部值结构。

Q-Learning—1992:Q-Learning 是现代 RL 中经典的基于值的方法,其中代理存储每个动作的感知值,状态对,然后通知策略动作。

深度 Q-网络(DQN)——2015:深度 Q-学习只是应用一个神经网络来近似每个动作和状态的 Q 函数,可以节省大量的计算资源,并有可能扩展到连续时间的动作空间。

Summary of Actor Critic Algorithms: source — Arulkumaran et al. “A Brief Survey of Deep Reinforcement Learning”

演员-评论家算法:

行动者-批评者算法将基于策略和基于价值的方法结合在一起——通过对价值(批评者)和行动(行动者)进行独立的网络近似。这两个网络共同努力,使彼此规范化,并有望创造更稳定的结果。

Actor Critic Algorithms—2000:本文介绍了使用两个独立但相互关联的模型来生成控制策略的想法。

从基础开始:

十年后,我们发现自己处于深度 RL 算法的爆炸中。请注意,在你阅读的所有报刊中,《核心深处》指的是使用神经网络近似的方法。

策略梯度算法经常受到噪声梯度的影响。我在另一篇文章中谈到了最近提出的梯度计算中的一个变化,当时一堆最新的‘艺术状态’算法试图解决这个问题,包括 TRPO 和 PPO。

Visualization of the TRPO constraint. Green L(theta) is the log probability, or loss. Blue is the lower bound constructed with the KL constraint. The parameters are stepped along eta while maximizing the lower bound on performance. Source of figure. More on TRPO here.

信任区域政策优化(TRPO)——2015:TRPO 的作者基于 actor critic 方法,希望在每次训练迭代中调整政策的变化,他们引入了 KL 散度(***)的硬约束,或新政策分布中的信息变化。在实践中,使用约束而不是惩罚允许更大的训练步长和更快的收敛。

最近的政策优化 (PPO) — 2017 : PPO 建立在与 KL 散度的 TRPO 相似的思想上,并通过使用考虑 KL 散度的替代损失函数,解决了实施 TRPO(涉及共轭梯度以估计 Fisher 信息矩阵)的困难。PPO 使用削波来实现这种替代损失并帮助收敛。

深度确定性策略梯度(DDPG)——2016:DDPG 将 Q 学习的改进与策略梯度更新规则相结合,这使得 Q 学习能够应用于许多连续控制环境。

结合深度 RL 中的改进(Rainbow)——2017:Rainbow 结合并比较了深度 Q 学习(DQN)中的诸多创新。这里引用了许多论文,因此这是了解 DQN 进展的好地方:

  • 优先化 DQN:重放 Q 学习中的转换,在那里有更多的不确定性,即更多的学习。
  • 决斗 DQN:分别估计国家价值和行动优势,以帮助推广行动。
  • A3C:通过多步引导学习,将新知识传播到网络的早期。
  • 分配 DQN:学习奖励的分配,而不仅仅是方法。
  • 嘈杂的 DQN:利用随机层进行探索,这使得行动选择更少剥削。

接下来的两个合并了对演员评论算法的类似改变。注意,SAC 不是 TD3 的继任者,因为它们几乎是同时发布的,但是 SAC 使用了 TD3 中使用的一些技巧。

Twin Delayed Deep Deterministic Policy Gradient(TD3)——2018:TD3 建立在 DDPG 的基础上,有 3 个关键变化:1)“Twin”:同时学习两个 Q 函数,为贝尔曼估计取较低值以减少方差,2)“Delayed”:更新策略的频率低于 Q 函数,3)向目标动作添加噪声以降低剥削策略。

软演员评论家(SAC)——2018:为了在机器人实验中使用无模型 RL,作者希望提高采样效率、数据收集的广度和探索的安全性。使用基于熵的 RL,他们控制探索以及 DDPG 风格的 Q 函数近似连续控制。注意: SAC 也像 TD3 一样实现了裁剪,并且使用随机策略,它受益于规范化的动作选择,这类似于平滑。

随着样本复杂度的下降和结果的增加,许多人对无模型 RL 的应用感到非常兴奋。最近的研究已经将越来越多的这些方法应用到物理实验中,这使得广泛可用的机器人的前景更近了一步。

基于模型的 RL:

基于模型的 RL(MBRL)试图构建环境知识,并利用所述知识采取明智的行动。这些方法的目标通常是降低更接近端到端学习的无模型变量的样本复杂度。

学习控制的概率推理(PILCO)——2011:本文是基于模型的 RL 中的第一篇,它提出了一种基于高斯过程(GP)动力学模型(内置不确定性估计)的策略搜索方法(本质上是策略迭代)。利用 GPs 进行学习的应用有很多,但迄今为止核心算法还不多。

Modeling state transitions with GPs visualization. Left: observed data, middle: multiple plausible function fits, right: uncertainty estimates of the GP. Source.

具有轨迹采样的概率集成(PETS)——2018:PETS 将三个部分组合成一个功能算法:1)由多个随机初始化的神经网络(模型集成)组成的动力学模型,2)基于粒子的传播算法,以及 3)简单的模型预测控制器。这三个部分以潜在的可推广方式利用动力学模型的深度学习。

System flow for PETS algorithm. Fit multiple neural network bootstraps to data, propagate different trajectories through different models, and plan via Model Predictive Control (MPC). Source.

基于模型的元策略优化(m b-MPO)——2018:本文使用元学习来选择集合中的哪个动力学模型能够最佳地优化策略并减轻模型偏差。这种元优化允许 MBRL 在低得多的样本中更接近渐近无模型性能。

模型集合信任区域策略优化(ME-TRPO)——2018:ME-TRPO 是 TRPO 在假设为环境的地面真实的模型集合上的应用。无模型版本的一个微妙的附加是,仅当集合中用户定义比例的模型在策略迭代时不再看到改进时,策略训练的停止条件。

【Atari 的基于模型的强化学习(SimPLe)——2019:SimPLe 结合了基于模型的 RL 领域的许多技巧,以及一个从像素建模动态的变分自动编码器。这展示了 MBRL 在 Atari 游戏中的艺术现状(我个人认为这是一个非常酷的阅读作品,并期待人们很快在它的基础上开发)。

The “SimPLe” experimental setup. I recommend looking at the source for more info, but it is really a fantastic experimental setup.

近年来,基于模型的 RL 背后的宣传越来越多。它经常被忽略,因为它缺乏其无模型对应物的渐近性能。我对它特别感兴趣,因为它已经实现了许多仅用于实验的令人兴奋的应用,包括:四旋翼飞行器和步行机器人。

感谢阅读!我可能会在我认为合适的时候更新这个页面——我希望把它作为提醒自己的资源!干杯。

(***) KL 散度,更少被称为 Kullback-Leibler 散度是两个概率分布之间差异的度量。我最好把它想成两个分布 p (原始)和 q (新) H(p,q) 的交叉熵与原始分布 p,H(p) 的熵之差。它由 KL(P | Q)表示,是信息增益的度量。

参考资料和资源:

一篇回顾截至 2017 年 deep RL 的伟大论文:https://arxiv.org/pdf/1708.05866.pdf

[## CS 294-112

这些讲座将被流式传输和录制。本课程不是以在线课程的形式提供,视频是…

rail.eecs.berkeley.edu](http://rail.eecs.berkeley.edu/deeprlcourse/) [## 在深水中旋转

我们将在 Deep RL 中发布 Spinning Up,这是一个教育资源,旨在让任何人学会成为一名熟练的…

blog.openai.com](https://blog.openai.com/spinning-up-in-deep-rl/)

更多?订阅我关于机器人、人工智能和社会的时事通讯!

[## 自动化大众化

一个关于机器人和人工智能的博客,让它们对每个人都有益,以及即将到来的自动化浪潮…

robotic.substack.com](https://robotic.substack.com/)

为生产准备好机器学习模型

原文:https://towardsdatascience.com/getting-machine-learning-models-ready-for-production-a970b5cfb88d?source=collection_archive---------13-----------------------

银行中的数据科学团队如何将机器学习模型投入生产

The Journey To Production

作为一名科学家,能够通过应用新的研究和快速原型化来自由地进行实验是令人难以置信的满足感。这种满足感在实验室环境中可以保持得很好,但在公司环境中会很快消失。这是因为科学在商业环境中的潜在商业价值动机——如果它不能为员工或客户增加商业价值,就没有它的位置!然而,商业价值不仅仅是向员工或客户展示潜在价值的漂亮实验。在机器学习模型的背景下,唯一[商业]有价值的模型是生产中的模型!

在这篇博文中,我将带您了解我和我的团队在将机器学习模型投入生产的过程中所经历的旅程,以及在此过程中所学到的一些重要经验。

我们的方法

在构建了几个没有转化为 MVP 的概念验证后,我们意识到有 3 件事我们需要做好:

  • 高度集中—团队成员不能同时处理多个项目。分散的焦点和频繁的上下文切换使人们脱离了他们的问题陈述(缺乏解决问题的沉浸感),也导致了大量的技术债务。
  • 软件工程数据科学——从机器学习模型中获取价值既是一个数据科学问题,也是一个软件工程问题。葡萄干面包的比喻在这里响亮地响起:人工智能是葡萄干,软件工程和系统集成是面包。它们一起构成了美味而有价值的产品,但它们本身都不特别或不令人想要。
  • 接近我们的业务!!与你的商业利益相关者保持一致可以成就你的项目,也可以毁掉你的项目——这一点我怎么强调都不为过!

因此,为了做好这三件事,我们制定了一个 8 周的 sprint 计划(从数据科学的角度来看),如下所示。

注:本帖不讨论实际生产部署中涉及的技术细节。我将把它留到另一篇文章中。

8 Week Production Cycle Sprint Plan

冲刺 1:研究/文献综述

AI 是一个极其压倒性的领域!每天都有新的技术、算法和方法被开发和发布。为此,研究是关键!

在我们的环境中,我们正在处理一个异常检测问题,因此团队中的每个数据科学家都在第一个 sprint 中研究可以应用于我们问题的不同异常检测方法。这个研究过程包括阅读论文、博客、观看视频、克隆 Github repos 和玩代码——你能想到的都有!所有这些研究最终形成了与解决我们的问题相关的技术前景的综合视图。

到周末,每个数据科学家都必须写一篇简短的文献综述,并向团队播放他们的研究结果。

冲刺 2:探索性数据分析(EDA)

垃圾进,垃圾出。

这就是做模特的方式!因此,为了防止这种情况发生,您理解您正在处理的数据是至关重要的!要获得这种理解,EDA 是必由之路!

对我们来说,这个过程是相当模型不可知的——我们只是想理解我们的数据。这个过程包括检查我们的数据的清洁度,绘制数据分布图,发现相关性,并提取对特征工程潜在有用的字段。有大量的资源可以帮助 EDA,包括一些非常棒的库,如 熊猫简介

该练习的结果是理解了使用什么数据以及如何将它用于特征工程和模型构建。

冲刺 3–4:特征工程和模型选择

特征工程可以说是建立机器学习模型最重要的一步。不管您有多少数据,也不管您应用什么模型架构,糟糕的特性=糟糕的模型!

我们决定了一个规则:每个模型有一名数据科学家。每个数据科学家都花了这个 sprint 在特定的机器学习算法的上下文中进行功能工程。在特性工程中涉及了相当多的实验,但是在之前的 sprint 中执行的 EDA,以及来自我们业务利益相关者的一些直觉,给了我们一个很好的起点。我们很快意识到,很难决定哪些功能最适合某个特定的型号。为了做出决定,我们运行了各种特性排列的基线模型(默认超参数),并根据适当的成功指标测量了模型性能。

这个 sprint 的输出是向业务和团队回放我们的特性选择,向他们展示基线模型性能结果,并通过所用特性背后的直觉进行讨论。

冲刺 5:模型开发

“性感的东西!”

一个常见的误解是,模型开发占用了数据科学家的大部分时间。正如我们发现的那样,大量数据科学家的时间都花在了清理、探索和操作数据上,以便机器学习算法可以使用这些数据,而不是开发算法本身。

这次冲刺的目的我们很清楚: 找到完美的泡菜!

每个数据科学家都通过尝试不同的模型架构和超参数,在基线模型的基础上进一步开发。适当的成功指标很重要,例如 F1 分数、准确性等。在这个 sprint 之前被选中,因为这是决定你的模型表现如何的因素。

这个冲刺阶段结束时的可交付成果是 完美的泡菜——一个可以投入生产的经过训练的模型文件。

Sprint 6:模型优化和代码重构

一旦我们有了一个训练有素的模型,产生了我们和我们的企业都满意的结果,我们就继续进行模型优化。对我们来说,模型优化过程主要集中在提高模型的预测速度上。我们有一个独特的系统集成限制,要求我们在 100 毫秒内执行端到端预测。

此时,大多数数据科学家会停下来说“好了,我的工作完成了”。

数据科学家:“好的,酷,我已经训练好了我的模型。给你……”

软件工程师:“我必须用这个做什么?”

数据科学家:“拿去生产?”

软件工程师:“怎么做?”

数据科学家:“不知道。那是你的工作,不是吗?”

有点夸张的转换,但信息是明确的:数据科学必须满足工程!这就是代码重构的用武之地。

每个模型都必须有服务代码(代码将获取生产数据,对其进行适当的转换,加载模型文件,并使用它进行预测)。对我们来说,创建了一个标准的模型服务模板,我们的服务代码放在其中。然后,这个服务代码被打包成一个模块,封装并部署到开发环境中。这个重构过程的一个重要部分是要求必须为服务方法编写单元测试,并且在你的代码可以被合并到主代码之前,所有的单元测试都必须通过。

我迄今为止的经验表明,让数据科学家编写生产就绪代码是困难的,但并非不可能。在这一点上,工程师和数据科学家之间有相当多的摩擦,但有一些策略可以让事情变得更顺利(我也将在另一篇博客文章中讨论)。

这个 sprint 的输出是在 Dev 中部署和运行的服务代码和模型文件!

冲刺 7–8:最后冲刺

在我们为期 8 周的生产周期中,最后两次冲刺涉及以下内容:

  • 最终模型培训
  • 端到端测试

在我们的上下文中,我们有一个非常大的数据集(> 200 000 000 行)。在如此大的数据集上进行实验是不可行的,因此,我们将基线模型(在较小的数据子集上进行训练)部署到开发中。这样做的目的是确保与本地环境相比,部署到开发环境的代码和模型能够如预期的那样执行。

运行了几个集成测试,以确保我们架构中的每个组件在开发中都能按预期执行。

一旦我们对 Dev 中的性能感到满意,我们就开始在完整的数据集上进行训练。最终培训中的模型是将要投入生产的模型。

轰!我们现在可以开始生产了!

吸取的教训和遵循的纪律

在生产过程中遇到了许多挑战。下面总结了一些挑战以及我们为实现交付目标而必须遵循的原则:

  • [实际上]运行敏捷——每日站立、每周回顾和业务冲刺计划确保了我们保持高度专注,软件工程符合数据科学,并且存在业务一致性。
  • DevOps 工具——强大的 Git 纪律对我们的部署成功至关重要。是的,数据科学家也必须使用 Git,这是无可避免的!我们利用 JIRA 来管理我们的 sprint 故事, Bitbucket 来管理我们的代码库,以及 Confluence 来管理文档。
  • 文档——为了确保可重复性和连续性,每个团队成员都必须对他们的代码做一定程度的文档记录。这防止了关键人物依赖性的形成。简单文档的一个例子包括简要概述开始特定模型的培训所涉及的步骤。
  • 过早的优化是万恶之源——我们首先关注基线性能,让代码工作起来!如果代码库一开始就不工作,那么投入资源进行优化是没有意义的。我们还很快了解到,企业对技术细节不太感兴趣。他们想看到结果。每周向他们展示逐渐改善的结果,你会赢得他们的信任。
  • 自动化——在数百个需要手动运行的 Untitled.ipynb 笔记本中编写代码所产生的技术债务是惊人的!一般来说,如果某件事需要重复几次,那就自动化吧!这包括数据提取、模型训练和集成测试等活动。自动化为您节省了大量时间,并且可以像参数化 Python 脚本一样简单。

正如我在本文开头提到的,从实验中获得的满足感是巨大的!同样重要的是,或者至少对我来说,看到你的工作实时运行所获得的满足感!

将机器学习模型投入生产绝非易事!重要的是要认识到这确实是一次旅程——一次需要耐心、承诺、纪律和韧性的旅程,但带你到达一个目的地是非常有益的!

从熊猫的价值计数中获取更多价值()

原文:https://towardsdatascience.com/getting-more-value-from-the-pandas-value-counts-aa17230907a6?source=collection_archive---------1-----------------------

在 Python 中有效使用 value_counts()函数的五种方法

Plush Design Studio on Unsplash

数据探索是机器学习管道的一个重要方面。在我们决定训练哪个模型和训练多少之前,我们必须对我们的数据包含什么有一个概念。熊猫库为此配备了许多有用的功能,value_counts就是其中之一。此函数返回熊猫数据帧中唯一项目的计数。然而,大多数时候,我们最终使用带有默认参数的 value_counts。因此,在这篇短文中,我将向您展示如何通过改变默认参数来实现更多。

值计数()

value_counts()方法返回一个包含唯一值计数的Series。这意味着,对于 dataframe 中的任何列,此方法都返回该列中唯一条目的计数。

语法

Series.**value_counts**()

因素

https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.value_counts.html

基本用法

让我们看看这个方法在数据集上的基本用法。我将使用泰坦尼克号数据集进行演示。我还在 Kaggle 上发布了一个附带的笔记本,以防你想直接获得代码。

导入数据集

让我们从导入必要的库和数据集开始。这是每个数据分析过程中的基本步骤。

*# Importing necessary libraries*import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline*# Reading in the data*
train = pd.read_csv('../input/titanic/train.csv')

浏览数据集的前几行

train.head()

计算空值的数量

train.isnull().sum()

因此,AgeCabinEmbarked列具有空值。有了这些,我们对数据集有了一个大概的了解。现在让我们看看如何以五种不同的方式使用value_counts()来进一步探索这些数据。

1.带有默认参数的 value_counts()

让我们调用数据集的Embarked列上的value_counts()。这将返回该列中唯一出现的次数。

train['Embarked'].value_counts()
-------------------------------------------------------------------S      644
C      168
Q       77

该函数以降序返回给定索引中所有唯一值的计数,不包含任何空值。我们可以很快看到最多的人从南安普顿出发,其次是瑟堡然后是皇后镇

2.value_counts()以及唯一值的相对频率。

有时候,得到一个百分比是一个比计数更好的标准。通过设置normalize=True,返回的对象将包含唯一值的相对频率。默认情况下,normalize参数设置为False

train['Embarked'].value_counts(normalize=True)
-------------------------------------------------------------------S    0.724409
C    0.188976
Q    0.086614

知道 72%的人从南安普顿出发比说 644 人从南安普顿出发更好。

3.value_counts()按升序排列

value_counts()返回的序列默认为降序。我们可以通过将ascending参数设置为True来颠倒过来。

train['Embarked'].value_counts(ascending=True)
-------------------------------------------------------------------Q     77
C    168
S    644

4.value_counts()显示 NaN 值

默认情况下,结果中不包括空值的计数。但是,通过将dropna参数设置为False,同样可以轻松显示。

train['Embarked'].value_counts(dropna=False)
-------------------------------------------------------------------S      644
C      168
Q       77
NaN      2

我们很容易看到该列中有两个空值。

5.value_counts()将连续数据绑定到离散区间

这是 value_counts()函数的一个我最喜欢的用法,也是一个未被充分利用的用法。在bin参数的帮助下, value_counts()可用于将连续数据归入离散区间。此选项仅适用于数字数据。它类似于pd.cut功能。让我们使用Fare列来看看它是如何工作的。

*# applying value_counts on a numerical column without the bin parameter*train['Fare'].value_counts()

这并没有传达太多的信息,因为输出包含每个票价值的许多类别。相反,让我们把它们分成七个箱子。

train['Fare'].value_counts(bins=7)

宁滨让人们很容易理解所传达的思想。我们可以很容易地看到,总人口中的大多数人支付的门票费用不到 73.19 英镑。此外,我们可以看到,有五个箱柜服务于我们的目的,因为没有乘客落入最后两个箱柜。

因此,我们可以看到 value_counts()是一个方便的工具,我们可以用这一行代码进行一些有趣的分析。

参考

  • 熊猫。Series.value_counts 文档

使用深度学习预测股票价格

原文:https://towardsdatascience.com/getting-rich-quick-with-machine-learning-and-stock-market-predictions-696802da94fe?source=collection_archive---------0-----------------------

如果人类投资者可以成功,为什么机器不能?

我只想补充一个免责声明——这个项目完全是为了研究目的!我只是一个学习深度学习的学生,该项目是一项正在进行的工作,请不要把任何钱投入到像这样天真的算法中!

算法交易彻底改变了股票市场及其周边行业。现在美国超过 70%的交易都是由机器人处理的。穿着西装的人挥舞着纸片对着电话大喊的日子已经一去不复返了。

这让我开始思考如何开发自己的股票交易算法,或者至少尝试准确预测股票。

结果还不错!

My trading algorithm for the MSFT stock September — October 2019

我在这个夏天学到了很多关于神经网络和机器学习的知识,我学到的最新和最适用的 ML 技术之一是 LSTM 细胞[2]。

An LSTM cell. Credit: https://colah.github.io/posts/2015-08-Understanding-LSTMs/

长短期记忆细胞类似于迷你神经网络,设计用于在更大的神经网络中进行记忆。这是通过使用 LSTM 细胞内的循环节点实现的。这个节点有一个权重为 1 的环回边,这意味着在每一次前馈迭代中,单元可以保存来自上一步以及所有上一步的信息。由于循环连接的权重是 1,旧的记忆不会像在传统的 rnn 中那样随着时间而褪色。

由于它们能够记住过去,因此 LTSMs 和递归神经网络擅长处理时间序列数据。通过在这些循环节点中存储一些旧状态,rnn 和 LSTMs 可以推断当前信息以及网络在一步、十步或一千步之前看到的信息。更好的是,我不必自己编写 LSTM 单元的实现;它们是 Tensorflow 的 Keras 中的默认图层。

所以我有我的计划;利用 LSTMs 和 Keras 预测股市,甚至可能赚点钱。

如果你想直接进入代码,你可以查看一下 GitHub repo 😃

注来自《走向数据科学》的编辑: 虽然我们允许独立作者根据我们的 规则和指导方针 发表文章,但我们不认可每个作者的贡献。你不应该在没有寻求专业建议的情况下依赖一个作者的作品。详见我们的 读者术语

数据集

股票价格历史的好处是,它基本上是一个标记良好的预制数据集。在谷歌搜索了一番后,我找到了一项名为 AlphaVantage 的服务。他们提供了纳斯达克股票过去 20 年的每日价格历史。这包括从今天到 1999 年每天的开盘价、最高价、最低价、收盘价和交易量。更好的是,该服务有一个 python 包装器。我从网站上获得了免费的 API 密匙,并下载了微软的每日股票历史。

由于 AlphaVantage 的免费 API 每分钟只允许 5 次调用(一天最多 500 次),我选择下载数据集并以 CSV 格式保存,这样我就可以随时使用它们。

对于在过去 20 年内首次公开募股上市的股票,由于巨大的交易量,股票交易的第一天通常看起来不正常。这种膨胀的最大体积值还会影响数据集中其他体积值在标准化数据时的缩放方式,因此我选择从每个数据集中删除最旧的数据点。我还删除了日期,因为模型不需要知道任何关于交易何时发生的信息,它需要的只是有序的时间序列数据。

我还记录了我们想要使用的{ history_points }的数量;模型预测所依据的股票历史天数。因此,如果 history_points 设置为 50,模型将继续训练,并要求过去 50 天的股票历史来预测第二天的情况。

现在我们必须将数据标准化——在 0 和 1 之间调整——以提高我们网络的收敛速度。Sklearn 有一个很棒的预处理库能够做到这一点。

数据正常化现在包含正常化的股票价格。

现在让数据集为模型消费做好准备。

训练神经网络时, ohlcv_histories 列表将是我们的 x 参数。列表中的每个值都是一个 numpy 数组,包含 50 个开盘、盘高、盘低、收盘成交量值,从最早到最新排列。这由历史点数参数控制,如切片操作中所示。

所以对于每个 x 值,我们得到[i : i + history_points]个股票价格(记住 numpy 切片是[inclusive:exclusive]),那么 y 值必须是单数的[i + history_points]个股票价格;第二天的股票价格。

在这里,我们还必须选择我们打算预测的值。我决定预测第二天的 open 值,所以我们需要获得数据中每个 ohlcv 值的第 0 个元素,因此 data_scaled[:,0]

还有一个名为 y_normaliser 的变量。这在预测结束时使用,此时模型将吐出一个介于 0 和 1 之间的归一化数,我们希望应用数据集归一化的逆过程,将其按比例放大到真实值。在未来,我们也将使用它来计算我们模型的真实世界(非标准化)误差。

然后,为了获得与 Keras 一起工作的数据,我通过 np.expand_dims() 使 y 数组成为二维数组。最后,我保留未缩放的第二天开放值,以便稍后绘制结果。

在返回数据之前,我们检查 x 的数量= =的数量。

现在,我们可以通过运行以下命令来获取任何具有 csv 文件的数据集:

就是这样!我们的数据集准备好了。

模型

我开始这个项目时只知道如何编写顺序 Keras 代码,但我最终学习了它的函数式 API,因为我想要一个更复杂的网络结构,最终以每个分支中不同层类型的两个输入为特色。

我将首先检查我想出的最基本的模型。

这给了我们一个看起来像这样的模型:

Basic model architecture

输入层具有形状(history_points,5),因为每个输入数据点都是一个形状类似于[history _ points】×OHLCV]的数组。该模型在第一层中有 50 个 LSTM 单元,一个用于防止过度拟合的下降层,以及一些用于将所有 LSTM 数据汇集在一起的密集层。

该网络的一个重要特征是线性输出激活,允许模型精确地调整其倒数第二个权重。

培训

这就是我喜欢 Keras 的原因。只需 3 行代码,您就可以立即知道您的模型在数据集上的表现如何。我得到了 0.00029 的最终评估分数,这看起来非常低,但请记住这是标准化数据的均方误差。缩放后,该值将显著上升,因此它不是一个很好的损失指标。

评估

为了更准确地评估该模型,让我们看看它是如何预测测试集并与真实值进行比较的。首先,我们放大预测值,然后计算均方误差,但为了得出相对于数据集的误差,我们将其除以测试数据的“分布”,即最大测试数据点减去最小值。

这给了我们一个调整后的均方差 7.17 。这样好吗?这并不令人惊讶,这意味着平均预测线偏离实际超过 7%。让我们看看它在图上的样子。

Real and predicted daily opening stock price of MSFT from the last 500 days, basic network

但是还不错!我不确定为什么预测值总是低于实际值,也许这与测试集和训练集的划分方式有关。以及整个数据集的结果:

Real and predicted daily opening stock price of MSFT since 1999, basic network

很难说算法在整个图表中的表现有多好,但正如我们所预期的那样,你肯定可以在训练集中看到更紧密的拟合。

改进

我们可以尝试让我们的模型更复杂,同时增加数据集的大小。让我们从尝试创建一个更复杂的模型开始。

股票市场分析师常用的指标是技术指标。技术指标是对股票价格历史进行的数学运算,传统上被用作视觉辅助工具来帮助识别市场的变化方向。我们可以通过二级输入分支来扩充我们的模型以接受这些技术指标。

现在让我们只使用简单的移动平均线 SMA 指标作为我们网络的额外输入。

要计算股票的简单移动平均线,只需取股票的收盘价格在过去 n 个时间步【5】的平均值。这对我们很有用,因为我们已经在处理固定时间步长的价格历史。为了在我们的模型中包含 SMA,我们必须更改数据集处理代码。

这发生在我们定义了 ohlcv_histories 和 next_day_open_values 数组之后。我们遍历每个 50 个价格的数据块,计算第三列的平均值,即收盘价,并将该值添加到一个技术指标列表中。然后,该列表经过与其余数据相同的转换,被缩放以适应值 0 到 1。然后我们修改 return 语句来返回技术指标,以及之前返回的其他内容。

现在来扩充模型以匹配这个新的数据集。我们希望能够使用我们的旧 LSTM 结构,但在组合中的某个地方纳入 SMA 技术指标。因为 SMA 不是时间序列数据,所以我们不应该通过 LSTM 传递它。相反,我们应该在做出最终预测之前将其混合;我们应该把它输入到倒数第二个 64 节点密集层。所以我们需要一个有两个输入的模型,一个连接层和一个输出。

Model architecture after augmentation to use technical indicators

请注意我们如何使用 technical_indicators.shape[1]作为 tech_input 层的输入形状。这意味着,当我们重新编译模型时,我们添加的任何新的技术指标都会很好地适应。

评估代码也必须更改,以匹配数据集的更改。

我们传入一个[ohlcv,technical_indicators]列表作为模型的输入。这个顺序与我们定义模型输入的方式相匹配。

并且我们得到调整后的均方差 2.25 !低得多,并且当绘制时,预测看起来明显更接近测试集;

Real and predicted daily opening stock price of MSFT from the last 500 days, using SMA

这个模型看起来没有以前的问题,即持续偏离一个固定的量,但似乎也没有捕捉到突然的跳跃。就像在 x 坐标 120 附近,实际价格会出现大幅的跳跃和下降,但模型未能有效地捕捉到这一点。但是越来越好了!看起来技术指标可能是前进的方向。

让我们试着包括一个更高级的技术指标:移动平均线收敛背离。MACD 的计算方法是从 12 期均线中减去 26 期指数移动平均线6。使用以下公式计算均线:

更新我们的技术指标循环,以包括 MACD 指标:

使用 SMA 和 MACD 指标,我们的模型实现了 2.60 的调整均方差。比仅使用 SMA 时略高,这反映在图表中。

Real and predicted daily opening stock price of MSFT from the last 500 days, using SMA and MACD

您可以看到,它不像仅使用 SMA 时那样精确。也许因为我们给了模型更多的数据,它需要更多的层来理解它,但现在我只是要省略 MACD 技术指标的使用。

我们还可以尝试使用更大的数据集。如果我们假设应用于微软股票的股票预测的技术可以推广到所有股票,那么我们就可以结合大量不同股票历史的 csv_to_dataset()函数的结果。例如,我们可以对 AMZN、FB、GOOGL、MSFT、NFLX 的股票历史进行训练,并测试 AAPL 股票的结果。

首先运行 save_dataset 方法,从本文开始的地方开始,对所有你想使用的不同股票进行操作。然后,数据集创建方法看起来像这样:

这基本上就是说对于当前目录下的每一个 csv 文件,如果文件名不是 test_set_name ,从其中加载数据集并追加到整个数据集。然后加载 test_set_name csv 文件,并将其用作测试数据集。使用 AMZN、NFLX、GOOGL、FB 和 MSFT 股票价格作为训练集,我们得到 19854 个训练样本。使用 AAPL 股票作为测试集,我们得到 4981 个测试样本。

在用这个新的、更大的数据集对 SMA 指标进行 50 个时期的训练后,我们得到了调整后的 MSE 值 12.97 ,比我们只对一只股票进行训练时要高。也许股票预测实际上是特定符号的。不同股票的表现可能略有不同。很明显,它们基本上表现相似,因为网络能够从不同的股票中学习和归纳,但为了最准确的预测,最好只训练该股票的历史。毕竟,微软的数据集似乎有足够的训练数据来解决这个问题。

该算法

有了一个不错的股票预测算法,我想到了一个简单的方法来创建一个机器人,根据股票的历史来决定今天买/卖股票。本质上,你只是预测股票第二天的开盘价,如果开盘价超过了阈值,你就买入股票。如果低于另一个阈值,卖出股票。这个非常简单的算法实际上似乎工作得很好——至少在视觉上是这样。

然后绘制交易图。

看起来不错!该算法似乎是正确的低买高卖。请记住,这都是基于测试数据——网络从未见过的数据。没有理由说这些数据不可能是实时的,这些交易实际上是真实的!

给定这些买卖,如果我们说在每一次“买入”时我们买入价值 10 美元的股票,而在每一次“卖出”时我们卖出所有股票,那么该算法将赚得 38.47 美元。但请记住这是跨越 500 天的。计算算法收益的代码在这里;

相反,如果我们在 30 天内尝试这种算法,使用同样的 10 美元购买金额和 0.2 的阈值水平,该算法将获得微不足道的 1.55 美元。但这总比什么都没有好!

Trading algorithm for the MSFT stock over the past 30 days

结论

我认为预测算法还有一定的改进空间。也就是说,所使用的技术指标、历史点数超参数、购买/出售算法/超参数和模型架构都是我希望在未来优化的内容。

我还想通过建立更多的 LSTM 分支机构来为模型提供更多的数据,AlphaVantage 上的每个时间步长都有一个分支机构,这样网络就可以根据短期、中期和长期趋势做出决策。

这个项目的完整代码可以在我的 GitHub 上找到。欢迎在问题页面留下任何反馈/改进!

我确实计划在这个项目上做更多的扩展,以真正推动仅仅使用数字数据来预测股票所能达到的极限。在我的博客上了解我的最新动态!

参考

[1]:https://www . exper fy . com/blog/the-future-of-algorithmic-trading

【2】:【https://colah.github.io/posts/2015-08-Understanding-LSTMs/

[3]:https://jovianlin . io/why-is-normalization-important-in-neural-networks/

【4】:https://www.investopedia.com/terms/t/technicalindicator.asp

【5】:https://www.investopedia.com/terms/s/sma.asp

[7]:https://www . investopedia . com/ask/answers/122314/what-index-moving-average-EMA-formula-and-how-EMA-calculated . ASP

在 PostgresSQL 中进行设置

原文:https://towardsdatascience.com/getting-set-up-in-postgressql-e29db4e6d7fc?source=collection_archive---------28-----------------------

一起使用 PSQL 和 Python 熊猫

在学习了编写结构化查询语言(SQL)查询的入门教程后,我面临的最大挑战之一是如何实际使用这些查询。教程给了我们一个很好的开始环境,但并不总是给我们自己的工作提供一个容易接近的桥梁。下面是 SQL 的快速浏览,以及使用 PSQL 服务器进行查询的教程。

首先,我们需要理解为什么我们需要数据库。当作为学生学习时,我们经常使用相对较小的数据集,这些数据集可以保存在我们自己的机器上。然而,在实践中,我们需要存储和检索对于单个机器的内存来说太大的数据的能力。对数据库的需求源于当时被认为是大数据的结果。

数据库系统地存储信息,以便于存储、操作和管理。数据库管理系统(DBMS)有四种主要类型:层次型、网络型、关系型和面向对象的关系型 DBMS。SQL 用于处理关系数据库管理系统或服务器。

这些服务器有 SQL Server、MySQL、SQLite 和 PostgreSQL 之类的名称,这可能会使 SQL 一词既指语言又指关系数据库的用法变得混乱。有几个数据库平台使用 SQL,但略有不同,每个平台的语法都略有不同(来源)我们还可以在 SQL 服务器中使用 SQL 语言的一种语法演变,称为 SQL Alchemy。

我们既有开源服务器,也有授权服务器。下面简单介绍几种类型的数据库管理系统:例如微软 SQL Server vs MySQL、 PostgreSQL vs MYSQL 和 PostgreSQL vs MongoDB 。

PSQL 是一个很好的选择,因为它已经发展了 30 多年,符合 ACID——它代表原子性、一致性、隔离性、持久性,并意味着松散的错误保护,它已经成为许多组织的开源关系数据库。它用于构建应用程序并受信任以保护数据完整性(来源)。

到开始,我们将使用来自 Kaggle 数据集 Shopify 应用商店的 csv 文件。在工作场所,我们可能不会从 csv 数据文件开始,因为原则上,我们试图处理太大而不能保存在一个简单的 csv 文件中的数据。但是,因为我们是在学习,所以我们将使用一个不需要服务器查看,但可以查询的小数据集进行练习。

我们来看看 Shopify 应用市场的定价数据。加拿大电子商务网站 Shopify 与亚马逊争夺卖家。它通过他们的平台“为超过 60 万家企业提供动力,销售额超过 820 亿美元”。在某些情况下, Shopify 击败亚马逊成为市场上最受欢迎的电子商务平台。

我们可以看到该数据集中有五个表——应用、类别、计划功能、定价计划和评论。我们将首先创建一个实体关系图(ERD)来理解表中数据列之间的关系。这将使我们能够:

确定外键和主键

确定每一列的数据类型——一个好的经验法则是,只有包含我们打算对其进行数学计算的数据的列才应该具有整数类型。

了解表之间的关系类型:一对多、多对一等。

Source (https://www.lucidchart.com/pages/ER-diagram-symbols-and-meaning)

我设置了主键,因为它们是父记录。外键包含子记录。( Source )这可能真的很难计算出我们拥有的表越多。我们知道一个表可以“只有一个主键”,并且“为每个表添加一个主键是一个好的做法”。“主键不接受空值或重复值。”我们可能需要创建一个由两列或更多列组成的主键,这就是所谓的复合主键。这将在中进一步探讨。

为了从 csv 文件中获取数据,我们将从 bash 的命令行开始。我们可以在命令行中进入 PSQL 服务器并创建一个数据库。然后我们可以使用 \connect 导航到我们的数据库。

然后,我们在文本编辑器中创建一个文件,并将其保存为 SQL 文件。我选择使用 Jupyter 笔记本的文本编辑器,但是我们也可以使用 Visual Studio 代码。在这种情况下,我将调用我的文件 create_tables.sql。

/* Drop the apps table if it exists */
DROP TABLE IF EXISTS apps;/* Create skeleton table that supplies the table name, column names, and column types */
#set up our SQL tablesCREATE TABLE apps(
  url text PRIMARY KEY
, title text
, developer text
, developer_link text
, icon text
, rating text
, reviews_count integer
, description text
, description_raw text
, short_description text
, short_description_raw text
, key_benefits_raw text
, key_benefits text
, pricing_raw text
, pricing text
, pricing_hint text
;/* Copy data from CSV file to the table */
COPY apps 
FROM '/Users/sherzyang/flatiron/mod_3/week_7/my_practice/shopify-app-store/apps.csv' 
WITH (FORMAT csv);

现在,我将返回 bash,尝试在数据库中创建我的第一个表。我发现了错误“未加引号的回车”,我了解到这是 csv 文件的错误,而不是来自我们的 end gone 数组的命令。我了解到这是由于\n 出现在我的数据中。这种可能已经发生,因为数据是在 windows 程序中下载的。

我用这个修复文件,很好,它的工作!

Source (http://bit.ly/2JsArGY)

通过编辑我的文本代码,并在 PSQL 中用 \i create_tables.sql 调用 bash 中的文件,我能够将其他 csv 文件移动到表中。对于其他命令,我使用了这个关于中级 PSQL 的伟大教程。我对其他表使用了以下代码:

CREATE TABLE plan_features(
  pricing_plan_id text 
, app_url text 
, feature text
;CREATE TABLE categories(
  app_url text 
, category text 
;CREATE TABLE reviews(
  app_url text 
, url text 
, author text
, body text
, rating text
, helpful_count text
, posted_at text
;CREATE TABLE pricing_plans(
  id text PRIMARY KEY 
, app_url text 
, title text
, price text
, hint text
;

一旦我在 PSQL 的表中有了数据,我就可以移动到我的 Jupyter 笔记本并连接到我的 sqlalchemy 引擎。

import psycopg2
import numpy as np 
import pandas as pd
from sqlalchemy import create_engine#connect to the database and make a cursor
conn = psycopg2.connect("dbname=shopifydb_1")
cur = conn.cursor()#loop through our queries list and execute themfor query in queries_list:
    cur.execute(query)
    conn.commit()#set up a sqlalchemy engineengine = create_engine("postgresql:///shopifydb_1", echo=True)

现在我可以查询我的表了。我想看到的是评论和它们所属的应用程序一起出现在一个数据框架中。连接这些表的有趣之处在于,我们意识到一个应用程序和该应用程序的许多评论之间存在一对多的连接。通过这个查询,我们还可以练习创建别名,这为我们提供了表的全名的昵称,以及将列类型从一种类型转换为另一种类型的转换。

q = """
SELECT 
  r.rating
, r.body
, r.helpful_count
, p_p.price
, a.rating
, a.reviews_count
, a.key_benefits
, a.pricing
, a.url
, a.titleFROM apps AS a
JOIN pricing_plans p_p
    ON cast(a.url as text) = cast(p_p.app_url as text)
    AND a.title = p_p.title

JOIN reviews r
    ON a.url = r.app_url
"""

我们可以使用 SQL 查询一个非常大的数据库来分离出我们需要的数据。如果您犯了一个错误并引入了一个错误,只要您没有提交前面的操作,您总是可以使用下面的代码来回滚光标。

conn.rollback()

现在我们可以运行查询并以熊猫数据帧的形式读取结果。我们希望这样做,以便对我们正在检查的数据切片执行统计测试、转换、可视化等操作。(对于大量数据的计算,我们将需要使用,比方说, Apache Spark ,而不是将数据插入到 pandas 数据帧中。)

#read our query as a DataFrame
df_join = pd.read_sql_query(q,con=engine)

最后,如果需要,我们可以将查询保存回 csv 文件。

#save our selected query back into a CSV file
df_join.to_csv('data.csv')

这是如何使用 psql 及其与 sql 和 python 的 pandas 库的关系的快速浏览。希望这是有用的,并帮助您玩我间谍(比喻)与您的数据更容易一点。

Nvidia Jetson Nano 的人工智能和计算机视觉入门。JetBot 项目的实践方法

原文:https://towardsdatascience.com/getting-started-in-ai-and-computer-vision-with-nvidia-jetson-nano-df2cacbd291c?source=collection_archive---------21-----------------------

Nividia Jetson Nano board 允许您在嵌入式系统中开发定制的 ia 项目。从人脸检测到自动驾驶。

JetBot robot

随着 AI 和 IoT 的兴起,Nvidia 为我们提供了一个简单、廉价、强大的嵌入式人工智能应用开发解决方案。杰特森纳米公司为创造自制机器人、智能系统创造了机会

Jetson Nano 是一款类似覆盆子的主板,但功能更强大,它运行预装 Nvidia 软件的自定义 Ubuntu 映像。它拥有一个四核 ARM Cortex -A57 MPCore 处理器、带有 128 个 NVIDIA CUDA 内核的 NVIDIA Maxwell 架构 GPU 和 4 GB 64 位 LPDDR4 1600MHz 内存。这种硬件使得 Jetson Nano 适用于深度学习问题中的训练和推理阶段。它支持最常见的深度学习框架,如 TensorFlow、Caffe 或 PyTorch。

Jetson Nano performance on different models (source here)

有了这个板子,你就可以做一个叫 JetBot 的教育型 AI 机器人。构建和使用 JetBot 提供了创建全新人工智能项目所需的实践经验,包括硬件和软件阶段。构建 JetBot 不是本文的目标。在 GitHub 官方页面你可以找到所有的信息和需求。【https://github.com/NVIDIA-AI-IOT/jetbot 号

使用 Jetson Nano board,你可以轻松高效地运行大多数深度学习框架,如 TensorFlow、Caffe 或 PyTorch。

JetBot perspectives

让我们让喷气机器人工作。拍照,训练我们的网络

运行这个项目的所有必要代码都可以在上面提到的 JetBot GitHub 页面上找到。不过,你可以利用我修改过的笔记本,它有一些改进,比如动态拍照,而用 Xbox 控制器远程移动你的 JetBot(很容易扩展到其他控制器)。

第一步。-收集数据以支持您的模型

https://github . com/davidRetana/jetbot/blob/davidRetana/notebooks/collection _ remote operation . ipynb

为了训练我们的神经网络,我们需要从相机中收集图像。我们需要两种图像:封锁和自由。注意以平衡的方式(50-50%)从两个类别中收集图像,并尝试同一遮挡物体或畅通路径的不同位置。一个好的数据集是机器人正常运行的关键。

如果路径受阻,JetBot 将向左转,相反,如果路径畅通,JetBot 将继续直行。

步骤 2: 训练网络

https://github . com/davidRetana/jetbot/blob/davidRetana/notebooks/collision _ avoidance/train _ model . ipynb

从这项工作中选择的网络架构是 AlexNet ,但稍加修改,以完成我们的要求。

AlexNet architecture

这个架构是为 ImageNet LSVRC-2010 竞赛设计的,有 1000 个不同的类。然而,我们的网络只需要区分一个图像是自由的还是阻塞的来移动 JetBot,所以最后一层只有 2 个输出。此外,PyTorch 允许我们下载预训练的 AlexNet 网络,这对于解决我们的问题是一个巨大的优势,因为在训练阶段,我们不需要随机启动网络权重。这些层拥有在 ImageNet LSVRC-2010 竞赛中从 1000 个不同班级学到的知识。为任务开发的模型被重用为模型完成不同任务的起点。这种技术被称为迁移学习。

import torch
import torchvision.models as models
model = models.alexnet(pretrained=True)
model.classifier[6] = torch.nn.Linear(model.classifier[6].in_features, 2)
print(model)

PyTorch representation of AlexNet

您可以在 JetBot 本身或外部系统中训练网络。笔记本准备将模型的权重导出到一个文件中,您可以稍后在 JetBot 中导入该文件。

第三步:运行你的模型

https://github . com/davidRetana/jetbot/blob/davidRetana/notebooks/collision _ avoidance/live _ demo . ipynb

现在,是时候运行您的模型,看看它是如何工作的。

机器学习和数据科学入门:社会科学家指南

原文:https://towardsdatascience.com/getting-started-in-machine-learning-data-science-a-guide-for-social-scientists-d4cdd6332eb0?source=collection_archive---------20-----------------------

我生命中最大的爱好之一是数据;然而,操纵和理解数据所需的知识和技能对我来说并不总是自然而然的。我已经做了几年的数据科学家,但是我的编程和机器学习技能来之不易。与我共事的大多数数据科学家不同,我获得了心理学和神经科学的博士学位。我的学术研究确实需要我发展一些编码技能和应用统计学知识,但我绝对不是我的实验室中应用机器学习来理解大脑的酷孩子之一。如果你和我一样,你可能会认为学习使用机器学习或其他数据科学技术是不可能的。你错了。一旦我离开学术界进入工业界,我发现只要给我足够的时间、精力和资源,我可以很好地学习任何东西。

假设你有一些时间并且愿意付出一些努力,剩下的问题是,你如何找到合适的资源?许多机器学习和数据科学的书籍和教程都预先假定了大量的软件工程和数学知识,而这些知识是我开始尝试闯入该领域时所没有的。如果你是一名心理学家、社会学家、人类学家或其他一些与社会科学相关的“学家”,你的研究生培训可能没有包括很多理论数学或计算机科学。然而,这并不意味着你不能自学大部分你需要知道的东西。你所需要的是一些社会科学家友好的资源作为出发点。

多年来,我和许多社会科学家谈论过向数据科学领域转型的问题。为了更好地促进这些对话,我列出了我最喜欢的数据科学和机器学习资源,并描述了我认为每个资源是如何有用的。许多和我分享过这个列表的人都觉得它非常有用,所以我想我也应该和你分享一下。但在我进入之前,让我澄清一件事:我不认为你需要投入所有这些资源来开始使用机器学习或追求数据科学的职业生涯。选择几个就可以开始了。你能做到的!

机器学习

  • 如果你需要复习统计学或者想了解 R 中的分析,我真的很喜欢用 R 发现统计学。DSUR 本质上并不是真正关于机器学习的,因为这本书的大部分内容都集中在推理统计学上。同样,这本书可以帮助你尝试分析中稍微数学化的部分,如果你以前没有真正做过的话。DSUR 很大——就像严肃的门挡书一样大——但我保证它真的很容易理解。自从几年前这本书出版以来,一些代码不得不到处更新,许多 R 包也已经更新了。如果您在完成示例时遇到 R 错误,不要惊慌。在栈溢出上快速搜索通常可以解决任何问题。如果你想在进入机器学习之前加强你的统计知识,我会从这里开始。
  • 数据学校对使用 Python 的机器学习有非常浅显的介绍。我说的“非常轻”指的是轻得可笑,所以这些教程只是让一些代码工作是很好的,但没有太多的内容。无论如何,这些视频为使用 Python 进行机器学习提供了一个不可怕的介绍。
  • Lantz 的机器学习与 R 是一本关于机器学习基础介绍的好书,特别是如果你知道一点 R(甚至一点 SAS)和/或有点害怕从 Python 开始。这本书没有深入细节,但它不仅仅是一个没有任何数学解释的概述。你可能会很快地完成解释和示例问题,并对人们用于一般机器学习问题的最常用算法有一个相当好的入门掌握。如果你之前没有机器学习的经验和/或数学背景不扎实,我建议从这里开始。
  • 如果你想要一些超越基本介绍的东西,库恩约翰逊的应用预测模型非常棒。它更深入算法如何工作的细节,但不会深到让你陷入优化或类似的事情。我喜欢这本书。如果您已经对大多数常用的监督学习算法有了一个概述,并且想要扩展这些知识,这将是非常棒的。此外,它有相当一部分关于数据清理和特征工程的内容,大多数机器学习书籍都跳过了(见这个的反例)。主要的缺点是,它在无监督学习方面没有给你太多的东西,代码是 r 语言的。尽管如此,我还是经常把这本书作为参考,即使我实际上是在用 Python 开发。
  • 如果你真的想让疯狂,试试统计学习的元素。就我个人而言,我只浏览了其中的一部分,并认为我真的没有这个能力。但是如果你是那些想要宣称你读过这个坏男孩的人之一,无论如何,请自便。我绝对不建议初学者从这里开始。
  • 很多人建议以 Coursera 上的吴恩达的机器学习课程为起点,但我认为如果你先从其他一些不涉及算法背后的线性代数的书籍开始,这门课会更容易跟上。如果你已经对线性代数有了一定的了解,或者对机器学习有了一定的了解,这是一个很好的资源。吴恩达是一位非常冷静的老师,她让你觉得一切都会好的。

Python 等编码的东西

如果你想成为一名数据科学家,除了统计学和机器学习之外,你可能还需要学习一些东西。许多招聘数据科学家的雇主更喜欢懂 Python 而不是 R 的人(尽管很多人用 R)。几乎没有人使用 MATLAB/SAS/SPSS,所以如果其中一个是你唯一的语言/分析工具,不幸的是,你可能需要再学一两个。(注意,一旦你创建了一个账户,Udemy 课程的价格通常是 15 美元,而不是点击下面的链接时显示的高昂价格)。

  • 如果你没有大量的 Python 经验,我认为何塞·波尔蒂利亚的 Udemy 基础 Python 课程相当不错。这是一个简单的介绍,但是您会对 Python 中的许多数据类型和常见功能有所熟悉,并且练习/家庭作业非常有趣。此外,教练善于给初学者友好的解释。我会从这里开始学习用 Python 编码。
  • 同样,这位教授有一门关于 SQL 的课,这门课相当容易掌握和学习。几乎业内的每个人都希望你了解一些 SQL,所以一个基本的概述会很有帮助。
  • 如果你已经很好地掌握了 Python,但是对面向对象编程不是很了解,我发现 Febin George 的课程真的很有帮助。此外,总共只有 5 个小时的讲座,所以你不会花太多时间来完成核心内容。根据我的经验,大多数工作并不期望刚从学校毕业的数据科学家能够真正熟练地使用面向对象编程。然而,如果你真的得到了一份数据科学的工作,你最终可能不得不学习。如果“面向对象编程”这个短语让你胆战心惊,那就忘了你读过这个要点吧。
  • 大多数数据科学工作认为拥有一些分布式计算的经验是一种“很好的要求”,而不是一项严格的要求,所以如果你总是时间紧张,我不会太担心。也就是说,教我上面列出的 SQL 和 Python 课程的那个家伙也有一个用于 Python 的 Spark 类。PySpark 的文档非常非常糟糕,来自 Spark 的错误消息通常完全难以理解,所以当我真正开始使用 Spark 时,我发现这个类非常有用。

有用的播客

我是播客迷。当我刚开始学习机器时,我用播客来把遛狗/通勤/家务变成学习时间。我最喜欢的两个关于数据科学的播客是数据怀疑论者和线性离题。我从这两个播客中学到了很多机器学习的概念,甚至认为我通过了解我第一次在播客上听到的东西给一些面试的人留下了深刻的印象。

  • 数据怀疑论者:《数据怀疑论者》的主持人是一位经验丰富的数据科学家。在大多数较长的播客中,他在采访数据科学领域的其他人。这些全长播客很有趣,但我想说迷你播客更有趣,也更有用。在这些文章中,他试图向他的妻子解释一些数据科学的概念,他的妻子不是很懂技术,通常也不关心数据科学。他不断处理信息,直到她得到它。如果她得到了,你可能也会得到。显然,这些迷你播客并没有给你细节,但它们确实以一种容易理解的方式让你意识到有哪些技术,并带有一些喜剧效果。
  • 线性题外话:线性题外话的主持人是一位数据科学家,她正在向她的软件工程师朋友解释一些东西。这些解释比《数据怀疑论》中的解释更具技术性,但它们仍然是可以理解的,并且以一种有趣的方式呈现。此外,如果你想了解更多,该展览还链接了大量有助于阅读的论文和资源。另外,这是一个女人运行一个关于数据科学的播客,这是一个意外收获。

几个数学问题

对于数据科学的起步来说,这一整节并不是真正必要的,您的时间最好花在阅读上述书籍和课程上;然而,如果你在想,“嘿,艾米,所有这些东西都很好,但我真的只想认真对待基本的数学。其他的都是废话,”我想我有一些话要说。第一,如果你成为一名数据科学家,请不要成为那些数学让其他所有人都感到羞耻的人。没人喜欢那家伙。其次,我遇到了一些资源,它们对复习和学习数据科学相关的数学概念很有帮助。

  • 不废话的线性代数指南有一个非常棒的“数学基础”介绍,你甚至可以在这里免费下载。数学基础一章讲述了一大堆你可能已经忘记的高中数学知识。然后,这本书的其余部分以一种我认为大体上可以理解的方式进入线性代数(至少对于我阅读的章节来说)。此外,柯克·贝克为写了一篇关于奇异值分解(SVD)的教程(不要惊慌,这有点像 PCA),这是专门为线性代数新手量身定制的。事实上,前 10 页左右是入门书,在进入 SVD 之前会先复习一些基础知识。
  • 大约半年前,我注册成为了 Brilliant.org 的正式会员。网上的人似乎给出了辉煌的褒贬不一的评价,但迄今为止我很喜欢它。基本上,它通过一堆动画和互动材料教你数学概念。然后,它实际上让你解决了很多问题,这显然比只是坐在 Coursera 上看视频更难,但我认为你会对你学到的东西有更好的理解。此外,您可以查看他们问您的每个测验问题的详细解释。我一直在学习微积分基础课程,甚至复习了基础代数和几何课程中的一些内容来快速复习。移动应用程序也很好,所以如果你可以在通勤时集中注意力,这是一个在途中学习的好方法。

好了,就这样吧!我知道这份清单很长,所以如果你没有钻到桌子底下哭着读完了整本书,我会印象深刻的!如果你现在感到不知所措,我道歉,我感同身受。深呼吸,回到顶端。重读机器学习的第一节,就此打住。当你准备好了,你就可以开始新的工作了。底线是:如果你足够优秀,能够进入社会科学的研究生项目,并且有足够的自虐倾向,能够在那里呆上几年,那么你绝对有能力学习所有这些东西。

音频数据深度学习入门

原文:https://towardsdatascience.com/getting-started-on-deep-learning-for-audio-data-667d9aa76a33?source=collection_archive---------11-----------------------

尽管随着梯度推进方法的兴起,传统的机器学习算法仍然在结构化数据上取得了胜利,但在处理非结构化数据方面,没有什么比深度学习更好了。

Photo by Hitesh Choudhary on Unsplash

让我们回到标题。

音频数据,你确定?

好吧,不管是不是有意的,我想我们大多数人已经在基于音频的深度学习系统中尝试了一些解决方案。

Ok, Google!

我可以肯定地假设我们大多数人都尝试过这个东西。

你有没有想过那个功能是怎么建立的?

非结构化数据的深度学习

是的,非结构化数据是迄今为止最适合深度学习的数据。虽然你也可以在结构化数据上使用它,但传统的机器学习可以在中等数量的数据上轻松击败性能。

像自动驾驶汽车、人脸识别或几个月前传播开来的臭名昭著的 FaceApp 这样的东西,都是图像数据深度学习系统的副产品。

图像数据=像素颜色=非结构化数据

基本上,非结构化数据意味着一堆数据点,没有对它们进行统计分析的手段。你不能在像素上使用任何形式的标准差,所以图像是非结构化的。

文本和音频也是如此。

音频数据是一串一个接一个排序的波形信号。你不可能分析均值对模型的影响。

我们去找音频数据

你知道非结构化数据的概念。现在,你想知道“好吧,谷歌!”正在建造的东西。

通俗地说,流程应该是这样的:

你的手机听周围的话→有人说关键词“好的,谷歌!”→助手应用程序激活。

什么!

我手机每次都听我的?那不是侵犯隐私吗?

嗯,这篇文章我不想谈那个问题。让我们继续第 2 步和第 3 步。

如果你的手机听到关键词,它会打开应用程序。

因此,在这个特别的教程中,我想分享你如何建立一个算法,能够区分关键词和其他声音。

音频数据深度学习教程

让我们来看看 Kaggle ,

有一个关于如何区分火鸡(动物)的声音和其他声音的比赛。为什么是土耳其?我不知道。至少,它符合我们的需求。关键词不一定要人声吧?Lol。

下载数据,可以看到训练数据(train.json)

train.json data

您将看到一个包含 1195 个项目的 JSON 列表,这意味着您有 1995 个项目作为训练数据。

每个项目将有 5 个属性,

  1. 视频 id,即来自 YouTube 的视频的 ID
  2. 剪辑的开始时间
  3. 剪辑的结束时间(因此,没有使用所有视频,只有 10 秒的视频)
  4. 是火鸡,确定那是不是火鸡
  5. 音频嵌入,这是从音频嵌入的 10 秒钟。他们使用https://github . com/tensor flow/models/tree/master/research/audioset中的脚本将音频波转换成数字。我们可以只使用处理后的结果。

例如,你可以看这个超赞的火鸡视频,

美味的火鸡

从第 30 秒到第 40 秒观看。你知道有火鸡,尽管背景音乐扰乱了宁静。

准备工作

等等,我有点不知所措了。

看起来很复杂。我想从头说起。我不懂深度学习,连火鸡都不懂。

你可以在网上找到很多资源,从书籍、讲座到课程。去谷歌一下。

或者你可以从我之前策划的开始。

所以,现在你已经熟悉了术语和其他种类的东西,你已经准备好了。

Python 和包

当然,Python。需要先从 Python 官网安装。您需要安装 3.6+版以保持库的最新状态。

并从终端安装其他东西,

pip install numpy
pip install pandas
pip install seaborn
pip install matplotlib
pip install tensorflow
pip install keras
pip install jupyter

让我们从终端键入 jupyter notebook ,我们就可以开始了!

import numpy as np
import pandas as pd 
import os
import seaborn as sns
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use('fivethirtyeight')
from tqdm import tqdm
print(os.listdir("../input"))

准备好库,您可以看到输出

['train.json', 'sample_submission.csv', 'test.json']

导入您需要的 Keras 包

from keras import Sequential
from keras import optimizers
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential,Model
from keras.layers import LSTM, Dense, Bidirectional, Input,Dropout,BatchNormalization,CuDNNLSTM, GRU, CuDNNGRU, Embedding, GlobalMaxPooling1D, GlobalAveragePooling1D, Flatten
from keras import backend as K
from keras.engine.topology import Layer
from keras import initializers, regularizers, constraints
from sklearn.model_selection import KFold, cross_val_score, train_test_split

当然,还要准备好你的数据

train = pd.read_json('../input/train.json')
display(train.shape)

它会显示

(1195, 5)

是的,你有 1195 个数据要处理。

让我们看看数据的内部

train.head()

让我们为训练准备数据。您需要拆分其中的一些进行验证,这样您就可以确保模型能够很好地处理看不见的数据。

train_train, train_val = train_test_split(train, random_state = 42)
xtrain = [k for k in train_train['audio_embedding']]
ytrain = train_train['is_turkey'].valuesxval = [k for k in train_val['audio_embedding']]
yval = train_val['is_turkey'].values

train_test_split 方法默认情况下,将数据按 3:1 分割意味着 75%的数据进入定型集,而剩余的 25%进入验证集。

为了在数据上创建一个标准,让我们用零填充所有音频嵌入,直到它们都具有相同的 10 秒长度。

# Pad the audio features so that all are "10 seconds" long
x_train = pad_sequences(xtrain, maxlen=10)
x_val = pad_sequences(xval, maxlen=10)y_train = np.asarray(ytrain)
y_val = np.asarray(yval)

让我们创建模型!

model = Sequential()
model.add(BatchNormalization(momentum=0.98,input_shape=(10, 128)))
model.add(Bidirectional(CuDNNGRU(128, return_sequences = True)))
model.add(Flatten())
model.add(Dense(1,activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer = optimizers.Nadam(lr=0.001), metrics=['accuracy'])
print(model.summary())

详细情况如下:

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
batch_normalization_7 (Batch (None, 10, 128)           512       
_________________________________________________________________
bidirectional_7 (Bidirection (None, 10, 256)           198144    
_________________________________________________________________
flatten_2 (Flatten)          (None, 2560)              0         
_________________________________________________________________
dense_7 (Dense)              (None, 1)                 2561      
=================================================================
Total params: 201,217
Trainable params: 200,961
Non-trainable params: 256
_________________________________________________________________

看一下这段代码

model.add(Bidirectional(CuDNNGRU(128, return_sequences = True)))

那是什么鬼东西?

Photo by Sean O. on Unsplash

在继续之前,让我们看看美丽的日出。当然也能提神醒脑。哈哈

处理音频数据

这是你必须知道的事情。音频数据是一系列声波。将一个连接到另一个。

有了这个属性,音频数据基本上就是一个数字序列。

当然,对于数字,你可以用格鲁的 LSTM

这两种算法都非常擅长处理数列。基本上,他们可以保存他们“阅读”的内容,并在处理下一个数字时使用该信息。这种“短期记忆”让他们比其他算法更有优势。

在这个教程中,我用了 GRU

让我们回到代码上来

model = Sequential()
model.add(BatchNormalization(momentum=0.98,input_shape=(10, 128)))
model.add(Bidirectional(CuDNNGRU(128, return_sequences = True)))
model.add(Flatten())
model.add(Dense(1,activation='sigmoid'))

我在 Keras 上创建了一个简单的模型,

  1. 添加 BatchNorm 层以标准化输入数字(音频输入尚未标准化)
  2. 添加双向 GRU 来处理输入
  3. 拉平结果
  4. 为“对-错”或二元问题创建一个 sigmoid 密集层。

训练时间!

#fit on a portion of the training data, and validate on the rest
from keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateaureduce_lr = ReduceLROnPlateau(monitor='val_acc', factor=0.1, patience=2, verbose=1, min_lr=1e-8)early_stop = EarlyStopping(monitor='val_loss', verbose=1, patience=20,  restore_best_weights=True)history = model.fit(x_train, y_train,batch_size=512, epochs=16,validation_data=[x_val, y_val],verbose = 2,callbacks=[reduce_lr,early_stop])

它会显示这个结果

Epoch 16/16
 - 0s - loss: 0.1037 - acc: 0.9710 - val_loss: 0.1694 - val_acc: 0.9231

它在验证测试中有 92.31%的准确率!厉害!

让我们绘制培训历史

def eva_plot(History):
    plt.figure(figsize=(20,10))
    sns.lineplot(range(1, 16+1), History.history['acc'], label='Train Accuracy')
    sns.lineplot(range(1, 16+1), History.history['val_acc'], label='Test Accuracy')
    plt.legend(['train', 'validaiton'], loc='upper left')
    plt.ylabel('accuracy')
    plt.xlabel('epoch')
    plt.show()
    plt.figure(figsize=(20,10))
    sns.lineplot(range(1, 16+1), History.history['loss'], label='Train loss')
    sns.lineplot(range(1, 16+1), History.history['val_loss'], label='Test loss')
    plt.legend(['train', 'validaiton'], loc='upper left')
    plt.ylabel('loss')
    plt.xlabel('epoch')
    plt.show()eva_plot(history)

这个简单的模型实际上可以做一些伟大的事情。我们甚至没有对它做任何优化。

好吧,如果你想优化,欢迎你来做。

虽然,我想做另一种形式的优化。不知道结果如何,何乐而不为。

求关注!

不,我是说,注意力机制。看看下面的图片

Photo by Zdeněk Macháček on Unsplash

你看到了什么?

当然,那只鸟

而不是图像中的绿色背景。

这就是人类的感知方式。我们想在机器上模拟这个机制。

Attention! Attention!

上图向你展示了注意力机制。这是一种机制,它迫使网络在处理新事物的同时关注某些事物。

每一行都意味着一步一步的处理。红色的字是当前正在处理的字。而蓝色的,越蓝意味着越多的机器关注这个词。

这将使机器与上下文保持一致。

实施

感谢我们在 kaggle 的朋友,我们可以使用这个令人敬畏的类,

class Attention(Layer):
    def __init__(self, step_dim,
                 W_regularizer=None, b_regularizer=None,
                 W_constraint=None, b_constraint=None,
                 bias=True, **kwargs):
        self.supports_masking = True
        self.init = initializers.get('glorot_uniform')self.W_regularizer = regularizers.get(W_regularizer)
        self.b_regularizer = regularizers.get(b_regularizer)self.W_constraint = constraints.get(W_constraint)
        self.b_constraint = constraints.get(b_constraint)self.bias = bias
        self.step_dim = step_dim
        self.features_dim = 0
        super(Attention, self).__init__(**kwargs) def build(self, input_shape):
        assert len(input_shape) == 3 self.W = self.add_weight((input_shape[-1],),
                                 initializer=self.init,
                                 name='{}_W'.format(self.name),
                                 regularizer=self.W_regularizer,
                                 constraint=self.W_constraint)
        self.features_dim = input_shape[-1] if self.bias:
            self.b = self.add_weight((input_shape[1],),
                                     initializer='zero',
                                     name='{}_b'.format(self.name),
                                     regularizer=self.b_regularizer,
                                     constraint=self.b_constraint)
        else:
            self.b = None self.built = True def compute_mask(self, input, input_mask=None):
        return None def call(self, x, mask=None):
        features_dim = self.features_dim
        step_dim = self.step_dim eij = K.reshape(K.dot(K.reshape(x, (-1, features_dim)),
                        K.reshape(self.W, (features_dim, 1))), (-1, step_dim)) if self.bias:
            eij += self.b eij = K.tanh(eij) a = K.exp(eij) if mask is not None:
            a *= K.cast(mask, K.floatx()) a /= K.cast(K.sum(a, axis=1, keepdims=True) + K.epsilon(), K.floatx()) a = K.expand_dims(a)
        weighted_input = x * a
        return K.sum(weighted_input, axis=1) def compute_output_shape(self, input_shape):
        return input_shape[0],  self.features_dim

不要强迫自己去理解这件事。让我们只是改变我们的模型

model = Sequential()
model.add(BatchNormalization(momentum=0.98,input_shape=(10, 128)))
model.add(Bidirectional(CuDNNGRU(128, return_sequences = True)))
model.add(Attention(10))
model.add(Dense(1,activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer = optimizers.Nadam(lr=0.001), metrics=['accuracy'])
print(model.summary())

改变扁平化层注意。你会看到

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
batch_normalization_6 (Batch (None, 10, 128)           512       
_________________________________________________________________
bidirectional_6 (Bidirection (None, 10, 256)           198144    
_________________________________________________________________
attention_2 (Attention)      (None, 256)               266       
_________________________________________________________________
dense_6 (Dense)              (None, 1)                 257       
=================================================================
Total params: 199,179
Trainable params: 198,923
Non-trainable params: 256
_________________________________________________________________

它减少了大约 2000 个可训练参数。嗯,这是好事。让我们试试训练

培训 v2

early_stop = EarlyStopping(monitor='val_loss', verbose=1, patience=20,  restore_best_weights=True)model.fit(x_train, y_train,batch_size=512, epochs=16,validation_data=[x_val, y_val],verbose = 2,callbacks=[reduce_lr,early_stop])

现在你得到了:

Epoch 16/16
 - 0s - loss: 0.1037 - acc: 0.9710 - val_loss: 0.1680 - val_acc: 0.9331

耶!1%增长到 93.31%

不多,但肯定是增加了!

Photo by Warren Wong on Unsplash

结论

创建音频数据的深度学习系统非常容易。

你只需要知道怎么做。变得更好,以创造真正的“好吧,谷歌!”。

去试试吧。当然,你可以尝试教程,并改变你想要的参数或网络。

祝你好运!

Python 熊猫数据分析入门

原文:https://towardsdatascience.com/getting-started-to-data-analysis-with-python-pandas-with-titanic-dataset-a195ab043c77?source=collection_archive---------5-----------------------

动手练习(使用 Titanic 数据集)

在本文中,我将重点介绍导入数据集、处理缺失值、更改数据类型过滤排序选择特定列、处理重复值删除添加行计数值计算唯一值

在我的毕业设计中,我在没有使用任何库的情况下处理了许多数据预处理的东西。我刚刚使用了 if 语句和 for 循环。简直要了我的命。在我开始学习熊猫后,我决定写这篇文章来帮助学生和初学者入门。我将尽我所能向你介绍熊猫在探索性数据分析阶段的一些最有用的能力。先说蟒蛇熊猫的定义。

Pandas 是一个为 Python 编程语言编写的软件库,用于数据操作和分析。

  • 用于集成索引的数据操作的 DataFrame 对象。
  • 用于在内存数据结构和不同文件格式之间读写数据的工具。
  • 数据对齐和缺失数据的综合处理。
  • 数据集的整形和旋转。
  • 大型数据集的基于标签的切片、花式索引和子集化。
  • 数据结构列的插入和删除。
  • 按引擎分组,允许对数据集进行拆分-应用-组合操作。
  • 数据集合并和连接。
  • 层次轴索引用于在低维数据结构中处理高维数据。
  • 时间序列-功能:日期范围生成和频率转换,移动窗口统计,移动窗口线性回归,日期移动和滞后。
  • 提供数据过滤。( Ref-1

数据集

我们将使用 Kaggle 上著名的泰坦尼克号数据集。要下载并使用它,请点击此处的。在你点击给定的链接后,你必须点击“全部下载”。如果找不到下载按钮,如下所示。

Downloading the dataset

该网站可能会引导你到竞争选项卡,你所要做的就是点击“加入竞争”。之后,您将能够下载数据集。

先说进口熊猫。

import pandas as pd

熊猫常见的捷径是 pd。而不是写“熊猫”我们可以写“pd”现在。所以,在“pd”后面有一个点,用来从 Pandas 库中调用一个方法。

使用 read_csv 导入数据集

为了读取数据集,我们将使用 read_csv

df = pd.read_csv("train.csv")

检查数据帧的第一个元素。头()方法

运行上面的代码后,什么都不会出现。所以你要写 df 才能看到你的数据。但是我们不是看到所有的数据,而是使用“”。头()"方法查看第元素的数据。在运行 read_csv 代码之前,可以编写下面的 df.head()。所以会是这样的:

.head() to see first 5 elements of the dataframe

在括号内,我们可以写下我们想要看到的元素的数量。如果我们将其留空,它将显示五个元素中的第一个。如果我们在括号内写 25,它将显示数据帧的前 25 个元素。****

.head(25) to see first 25 elements of the dataframe

用检查数据帧的最后元素。tail()方法

还有一种方法可以查看最后 n 个元素。该方法称为。尾巴()

同样的规则也适用于此。如果我们将括号留空,它将被设置为 5,如果我们在括号内写 25,它将显示数据帧的最后 25 个元素。

df.tail(25)

.tail(25) to see last 25 elements of the dataframe

总结。头()和。尾部()

总而言之,这些方法返回数据帧的顶部和底部。默认行数设置为 5。但是,您可以通过在括号内写入您希望看到的行数来更改它。

读取具有特定列的 CSV 文件

假设您不想要 CSV 文件中的所有列。你只是想要三个,你想一开始就摆脱他们。怎么做呢?好消息!有一个非常简单的方法可以做到这一点。我们将使用 usecols 参数来指定我们想要使用的列名。让我们只使用 PassengerId、Survived、Pclass 列。

df = pd.read_csv("train.csv", usecols= ["PassengerId", "Survived", "Pclass"]) 
df.head() #and add this to see if our code worked

Reading only three columns with usecols argument

这只是一个例子。我们将处理全部数据。

获取有关数据集的一些信息。描述()和。信息()

在我们用 read_csv,加载数据集之后,我们希望获得一些关于列的信息。为此,我们将使用。描述()和。信息()

。describe()方法

此方法用于获取数据集中数值的汇总。它计算带有数值的列的平均值、标准差、最小值、最大值、第 1 个百分点、第 2 个百分点、第 3 个百分点。它还计算数据集中变量的数量。因此,我们将能够看到列中是否有丢失的值。

df.describe()

Summary of statistics with .describe() method

我们可以看到年龄栏的计数是 714,均值是 29.6,标准差是 14.52 等等。多亏了 count,我们才能明白这一列中有一些缺失的值。我们稍后会处理它们。

。信息()方法

这个方法打印关于数据帧的信息,包括索引数据类型和列数据类型、非空值和内存使用情况。( Ref-2

df.info()

我们还可以看到带有的列的数据类型。数据类型****

基于列对数据帧进行排序

排序数字数据

在我们的数据框架中有一列表示乘客购买的机票价格。让我们假设我们希望看到最低的票价。为此,我们必须使用。sort_values()** 方法。不管要排序的列是字符串还是数字。如果包含字母,它将按字母顺序排序。**

df.sort_values("Fare")

.sort_values without any arguments

我们曾经。head()方法只能看到排序后的前 10 个结果。我们可以看到最低的“票价”值是 0。如果我们想看最高票价呢?我们所要做的就是使用法尾()。不,只是开玩笑。我们必须将升序参数设置为 False 。但是使用。tail()** 是替代:p。**

df.sort_values("Fare", ascending = False).head(10)

.sort_values with ascending argument

由于这一点,我们可以看到乘客支付的最高票价。如果我们想保存数据帧的排序版本,有两种选择。一种是老方法,那就是

df = df.sort_values("Fare", ascending = False)

另一种方法是使用代替参数。如果我们把这个论点设为真,它就会改写它。

df.sort_values("Fare", ascending = False, inplace = True)

执行完上面的代码后,我们将使用。head()** 方法来检查我们的 DataFrame 的新版本。**

.sort_values and save it with inplace argument

用字符串对列进行排序

我们要对【小屋】列进行排序。此列中有许多缺失(NaN)值。我们该如何对付他们?幸运的是,有一个名为 na_position 的参数可以帮助我们设置 NaN 值在数据集中的位置。

df.sort_values("Cabin", ascending = True, na_position ='last')

通过使用。tail(20),我们可以看到数据集的最后 20 个元素。如果我们查看 Cabin 列,我们可以看到所有的值都是 NaN。

总结 ,我们学会了用读取 csv 文件。read_csv** 方法(选择和不选择特定列),使用。头()。tail() 查看顶部和底部的元素,用获取关于数据集的信息。形容()。info(),包含字符串或数值的已排序列(有和没有 NaN 值)**

计算变量的出现次数

在某些情况下,知道一列中有多少唯一变量,或者一列中每一项的出现次数可能非常有用。我们用来统计一下男女乘客的数量。value_counts()****

使用。value_counts()计算一列中每个变量的出现次数

要计算变量的出现次数,我们必须首先选择列。您可以用两种不同的方式选择列:

df.Sex
df["Sex"]

自从。value_counts()是一个方法,我们所要做的就是将这个方法附加到上面的代码中。它看起来会像这样:

df[“Sex”].value_counts()

Counting the occurences of elements in “Sex” column with .value_counts()

使用。nunique()计算数据集或列中出现的唯一值的数量

如果我们想查看一个数据集或一个列中唯一记录的数量,我们必须使用。nunique()方法。

df.nunique() #by typing this, we can see the counts of unique numbers in each column

Counting the number of unique records in each column with .nunique()

我们还可以用统计唯一记录。nunique()** 为一列。我们所要做的就是添加列名。**

df["Embarked"].nunique()

Counting unique records in a column with .nunique()

如果您想要查看多列的唯一记录的数量,您必须再添加一个方括号。

df[["Embarked", "Sex"]].nunique()

Counting unique records for more than one column with .nunique()

更改数据类型

我们检查了 Titanic 数据集中列的数据类型。我们看到搭载的列的类型是 object。对栏中的唯一值进行计数后,用。unique(),我们可以看到该列中有 3 个唯一值。所以我们可以认为数据类型应该是分类的。要更改该列的数据类型,必须执行下面的代码:****

df["Embarked"] = df["Embarked"].astype("category")
df["Embarked"].dtype

输出是:

Converting the data type of Embarked column to Category

过滤

在一个条件下过滤

Python 中的比较符号是 == (双等号)。所以你应该仔细检查你是否使用了两个等号。如果你只使用一个等号,你可能会破坏你的数据。假设我想看看“已上船”一栏是否等于“C”。比较的真实版本是:

df["Embarked"] == "C" 

输出将是:

Checking if Embarked column is C for each row in data with double equal sign

如果我像这样写代码

df["Embarked"] = "C"

它会将已装载列中的所有值设置为“C”。

Wrong usage of equal signs

如果我们不想只看到真和假呢?如果我们想看到所有 C 语言用户的信息怎么办?为此:

df[df["Embarked"] == "C"]

如果我们这样写,熊猫会理解我们希望看到那些有真正价值的行。输出是:

另一种方法可能是:

embarked_c_mask = df["Embarked"] == "C"
df[embarked_c_mask]

如果我们想过滤我们的数据,反之亦然:

df[df[“Embarked”] != “C”]

它将向行显示它们的已装载列不是“C”。输出是

Not equal to filtering

在两个或多个条件下过滤

逻辑积算符

我们将使用 AND 和 OR 运算符来过滤多个条件。假设我们想要查看票价小于 100 且为女性的乘客。我们将创建 2 个新的遮罩来完成此操作。

df_fare_mask = df["Fare"] < 100
df_sex_mask = df["Sex"] == "female"
df[df_fare_mask & df_sex_mask]

输出是:

Those passengers whose fare is less than 100 and who are female

OR 运算符

让我们用 OR 运算符做另一个例子。我们将使用|符号来实现这一点。让我们看看票价在 500 以上或 70 岁以上的乘客。

df_fare_mask2 = df[“Fare”] > 500
df_age_mask = df["Age"] > 70
df[df_fare_mask2 | df_age_mask]

输出是:

用查找空值。isnull()

数据科学中最常见的问题之一是缺少值。要检测它们,有一个很好的方法,叫做。isnull()。用这种方法,我们可以得到一个布尔数列(真或假)。正如我们之前所做的,通过屏蔽条件,我们可以提取空值。例如

null_mask = df["Cabin"].isnull()
df[null_mask]

有了这个代码,我们就是在说“给我看看客舱未知的乘客”。输出是:

除了在列上使用这种方法,它还可以在整个数据集上使用。如果我们想计算一个数据帧中所有列的空值,我们只需编写下面的代码

df.isnull().sum()

It is possible to see all sum of the missing values in all columns in a dataset with .isnull().sum()

处理缺失值

有很多处理缺失值的方法,但在本文中,我们将使用“忽略元组”和“用中位数填充它”。我们将忽略“栏,因为该栏的 %70缺失。我们将用该列的中值填充缺失的年龄。****

删除一列

要删除“Cabin”列,我们必须执行下面的代码。

df.drop(labels = ["Cabin"], axis=1).head()

我们曾经。空投舱柱的空投方法。上面有一个 2 的论点。在 labels 参数中,我们必须指定要删除的列名,在 axis 参数中,我们指定按列删除。

如果你想删除不止一列的,你所要做的就是把它添加到方括号中。例如:****

df.drop(labels = ["Cabin", "Name"], axis=1).head()

我们将同时删除客舱列和名称列。正如我之前提到的,如果我们知道我们不会使用这些列,我们就会使用usecols 参数。read_csv** 方法去掉开头的列。**

用填充缺少的值。菲尔娜

为了填充数据帧中缺失的值,有一个叫做的方法。菲尔娜()

让我们假设在一列中有许多缺失值,我们想用 0 来填充它们。我们要做的就是写下面的代码

df["columnname"].fillna(0, inplace = True) #with inplace argument, we don't have to write it as
df["columnname"] = df["columnname"].fillna(0, inplace = True)

我们也可以用一个特定的值来填充它。让我们在泰坦尼克号数据集上举个例子

df["Age"].fillna("Unknown", inplace = True)

但是,我们不是用“未知”来填充年龄列中缺少的值,而是使用该列的中值。为此:

df['Age'] = df['Age'].fillna((df['Age'].median()))

如果我们想用均值或其他东西填充缺失的值,我们要做的就是在最后改变方法。执行完这段代码后,我们应该检查年龄列中是否还有空值。

如果你有任何问题,不要犹豫地问。非常感谢你的评论。

你可以通过 LinkedIn 联系我:https://www.linkedin.com/in/sukruyavuz/

或电子邮件:sukruyavuz96@gmail.com

谢谢你的时间。

Apache Cassandra 和 Python 入门

原文:https://towardsdatascience.com/getting-started-with-apache-cassandra-and-python-81e00ccf17c9?source=collection_archive---------2-----------------------

在这篇文章中,我将谈论 Apache Cassandra,它的用途、用法、配置和设置集群,最后,你如何在你的 Python 应用程序中访问它。在这篇文章的最后,你应该对 Cassandra 有了一个基本的了解,以及如何在你的 Python 应用中使用它。

什么是阿帕奇卡珊德拉?

根据维基百科:

Apache Cassandra 是一个免费的开源分布式宽列存储 NoSQL 数据库管理系统,旨在处理许多商用服务器上的大量数据,提供无单点故障的高可用性。Cassandra 为跨多个数据中心的集群提供了强大的支持,[1]异步无主机复制允许所有客户端进行低延迟操作。

两位脸书工程师开发的 Cassandra 用于处理收件箱的搜索机制。后来,脸书将其作为谷歌代码的开源项目发布,过了一段时间,它被移交给阿帕奇基金会。许多知名公司都在使用 Cassandra,比如网飞、苹果、天气频道、易贝等等。它的分散性(无主系统)、容错性、可伸缩性和持久性使其优于竞争对手。让我们讨论一下它的架构,如果你愿意,你可以跳到安装和设置部分。我建议你浏览一下架构部分,因为它会让你知道为什么你会想使用它。

卡桑德拉建筑

Cassandra 架构由以下组件组成:

结节

它是数据的基本组成部分,是存储数据的机器

资料处理中心

相关节点的集合。它可以是物理数据中心或虚拟数据中心

一个集群包含一个或多个数据中心,它可以跨越多个位置。

提交日志

每个写操作首先存储在提交日志中。它用于崩溃恢复。

记忆表

将数据写入提交日志后,它会存储在 Mem-Table(内存表)中,直到达到阈值。

Sorted-String Table 或 SSTable 是一个磁盘文件,它在 MemTable 达到阈值时存储其中的数据。表按顺序存储在磁盘上,并为每个数据库表进行维护。

写操作

Write Operation Flow

  • 一旦收到写请求,它首先被转储到提交日志中,以确保数据被保存。
  • 数据还被写入 MemTable,这是一个内存系统,它保存数据直到填满。
  • 一旦 MemTable 达到其阈值,其数据就会被刷新到 SS 表中。

接受写请求的节点被称为用于特定操作的协调器。它充当发送请求的客户端和其他节点之间的代理。然后,协调器根据集群配置确定环中的哪个节点应该接收该数据。

一致性级别决定了有多少节点会用成功确认来回应。

读取操作

协调器可以向副本发送三种类型的读取请求:

  1. 直接请求:- 协调器节点向其中一个副本发送读取请求。之后,向其他副本发送一个摘要请求,以确定返回的数据是否是更新的数据。
  2. 摘要请求:协调器联系由一致性级别指定的复制品。被联系的节点用所需数据的摘要请求来响应。每个副本中的行在内存中进行比较,以确保一致性。如果它们不一致,协调器将使用具有最新数据(时间戳)的副本将结果转发回客户端。
  3. 读取修复请求:如果节点上的数据不一致,将启动后台读取修复请求,以确保节点上的最新数据可用。

数据复制策略

数据复制是一项必不可少的功能,以确保不会因硬件或网络故障而丢失数据。复制策略决定在哪些节点上放置副本。Cassandra 提供了两种不同的复制策略。

简单策略

当您只有一个数据中心时,使用 SimpleStrategy。它将第一个副本放在由分区器选择的节点上。分割器决定数据如何在集群中的节点之间分布(包括副本)。之后,剩余的副本以顺时针方向放置在节点环中。

网络拓扑策略

当您跨多个数据中心进行部署时,会用到它。该策略通过顺时针遍历环,直到到达另一个机架中的第一个节点,将副本放置在同一数据中心。这是因为机架中有时会出现故障或问题。那么其他节点上的副本可以提供数据。出于可伸缩性和未来扩展的目的,强烈建议采用这种策略。

好了,理论讨论够了,来点实际的吧。

安装和设置

你可以从官方网站下载该软件包,并以单一模式运行用于开发目的,但它不会帮助你了解 Cassandra 的真正实力,因为它的行为就像任何其他数据库一样。因此,我将使用它的 docker 版本,其中我将设置一个包含两个节点的集群。

注意:在开始之前,请确保将 Docker 内存设置为至少 4GB,否则容器会以错误代码 137 退出。由于内存资源不足,我花了一个小时才发现这个错误。

在你的机器上创建一个文件夹,就像我创建的/Development/PetProjects/CassandraTut/data。在这个文件夹中,我创建了两个子文件夹来存储两个节点的数据。完成后,它将如下所示:

➜  data tree -a.├── node1└── node22 directories, 1 file

留在同一个文件夹,运行命令docker pull cassandra下载官方镜像。如果你是 docker 的新手,那么你应该看看我在 Docker 系列的帖子。一旦下载完毕,docker images命令就会显示在你的终端上。确保 docker 已安装并正在运行。此外,您必须给 Cassandra 存储数据的文件夹写权限。

我们将设置两个节点: Node1 为主节点, Node2种子节点。种子在启动过程中用于发现集群。让我们运行第一个节点。

docker run --name cas1 -p 9042:9042 -v /Development/PetProjects/CassandraTut/data/node1:/var/lib/cassandra/data -e CASSANDRA_CLUSTER_NAME=MyCluster -e CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch -e CASSANDRA_DC=datacenter1 -d cassandra

许多环境变量是不言自明的,我将讨论CASSANDRA_ENDPOINT_SNITCH

告密者决定卡珊德拉如何分发复制品。这个飞贼推荐生产。GossipingPropertyFileSnitch在添加新节点时使用八卦协议自动更新所有节点,建议用于生产。运行以下命令了解节点的状态。

➜  data docker exec -it cas1  nodetool status
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
--  Address     Load       Tokens       Owns (effective)  Host ID                               Rack
UN  172.17.0.2  103.67 KiB  256          100.0%            bcb57440-7303-4849-9afc-af0237587870  rack1

UN表示状态为 U p 和 N 正常。当其他节点加入时,您可能会看到状态 UJ,这意味着 U p 和 J 正在加入。我正在使用docker run-d开关在后台运行它。另外,请注意节点 1 文件夹的内容。它创建默认的系统数据库,类似于 MySQL。

➜  node1 ls
system             system_auth        system_distributed system_schema      system_traces
➜  node1

现在让我们运行第二个节点:

docker run --name cas2 -v /Development/PetProjects/CassandraTut/data/node2:/var/lib/cassandra/data -e CASSANDRA_SEEDS="$(docker inspect --format='{{ .NetworkSettings.IPAddress }}' cas1)" -e CASSANDRA_CLUSTER_NAME=MyCluster -e CASSANDRA_ENDPOINT_SNITCH=GossipingPropertyFileSnitch -e CASSANDRA_DC=datacenter1 -d cassandra:latest

在设置了相关的容器名和数据中心后,您还可以将这里的CASSANDRA_SEEDS 设置为节点cas1的 IP 地址,该节点可以使用docker inspect命令获取。过一会儿,当您在cas1中运行nodetool status命令时,您应该会看到如下所示的内容:

如您所见,我们的第二个节点正在加入集群,我们从状态UJ中了解到这一点。

如果你查看挂载的卷,node2文件夹,你也会看到系统文件夹。

从终端运行命令很烦人,因此我创建了一个docker-compose.yaml文件来运行集群,没有任何麻烦。

为了确保cas1启动并运行,我让cas2依赖于cas1,并设置一个 60 秒的sleep

我得到 RPC 错误INFO [main] 2019-05-14 01:51:07,336 CassandraDaemon.java:556 - Not starting RPC server as requested. Use JMX (StorageService->startRPCServer()) or nodetool (enablethrift) to start it,所以我也调用CASSANDRA_START_RPC环境参数,并将其设置为真。

让我们运行docker-compose up -d以在分离模式下运行。

正如您可以看到的,第一个节点没有启动,第二个节点启动过程也没有启动。

过了一会儿,两个节点都使用各自独特的 IP 启动。

所有 Cassandra 配置文件都位于容器内的/etc/cassandra/文件夹中。

让我们运行 CQL 外壳。

➜  CassandraTut docker exec -it cas2  cqlsh          
Connected to MyCluster at 127.0.0.1:9042.
[cqlsh 5.0.1 | Cassandra 3.11.4 | CQL spec 3.4.4 | Native protocol v4]
Use HELP for help.
cqlsh>

它类似于 MySQL shell。CQL,Cassandra 查询语言在语法上与 SQL 相似,但其用法与 RDBMS 系统不同。我们将很快对此进行更深入的研究。坚持住!

如果你注意到我已经在docker rundocker compose命令中公开了默认的 Cassandra 端口9042。使用终端 like 并不吸引人,使用 GUI 客户端怎么样?我使用的是 SQL/NoSQL 客户端 TablePlus 。

一旦连接,您将看到默认的系统数据库。

让我们在节点cas1上创建一个测试密钥空间、数据库的 Cassandra 版本和一个表。别担心,我稍后会详细讨论。现在,我们的目的是告诉您数据是如何复制的。

将复制因子设置为 2,这意味着将有 2 份数据拷贝,每个节点一份。

让我们连接到第二个节点。

请注意端口 9043。9042 已经分配给cas1

瞧啊!我的密钥空间在这里也存在,它被很好地从案例 1 复制到案例 2

无论您在 Cas1 或 Cas2 上进行更改,它最终都会被传播。这并不类似于典型的主/从概念,而是被称为无主,因为整个系统是分散的,P2P 连接是在环中建立的(它让你想起区块链了吗?)

接下来是数据建模概念和在 CQL 创建实体。

卡珊德拉数据建模和 CQL

Cassandra 是一头野兽,不可能在这里涵盖数据建模的每个方面。因此,我将介绍一些基础知识,让您了解它与典型的关系数据库系统有何不同。尽管 CQL 看起来非常类似于 SQL 或基于 MySQL 的 SQL,但它根本不是 SQL。让自己做好准备,忘掉 RDBMS 的东西。

术语

下面是 Cassandra 和 RDBMS world 的一点对比。

Keyspace :-它是列族的容器集合。你可以把它想象成 RDBMS 世界中的一个数据库

列族:- 列族是行的有序集合的容器。每一行又是列的有序集合。可以把它想象成 RDBMS 世界中的一个

行:- 行是列的集合,按列排序。

列:- 列是键/值对的集合。

行键:- 主键叫做行键。

复合主键:- 主键由多列组成。该密钥一部分被称为分区密钥和剩余的簇密钥

分区键:-Cassandra 中的数据分布在各个节点上。分区键的目的是识别存储了被请求的特定行的节点。名为 partition 的函数用于在写入行时计算分区键的哈希值。例如,节点 1* 的键值范围从1–10节点 2 包含11–20节点 3 包含范围21–30。当执行带有 WHERE 子句的 SELECT 命令时,使用分区键的哈希值来查找所需的节点,一旦找到该节点,它就会获取数据并返回给客户端。例如,查询是SELECT * FROM users where id = 5,假设分区键的哈希值(在本例中是 5)是 15,那么将会是节点 2 获得该行。下面是它的图示。*

我们来举个例子。您正在开发一个保存网站用户及其所在城市信息的系统。我们将创建一个名为 CityInfo 的密钥空间。你可以使用 CQLSH 或 TablePlus GUI,由你决定。

create keyspace CityInfo with replication = {'class' : 'SimpleStrategy', 'replication_factor':2}

因为我有 2 个节点,所以我将replication_factor设置为2

设计模型

在 RDBMS 中,我们有一个类似 JOINs 的工具,而编写并不便宜,因此我们通过在相关表中使用外键来避免重复。《卡珊德拉》就不是这样的。Cassandra 是一个分布式系统,编写起来很便宜,因此非常欢迎你在需要的地方去规范化数据。这有助于检索通常通过连接获取的数据。另一方面,数据读取可能会很昂贵,因为数据跨越多个节点并通过分区键检索。设计模型时,您应该记住以下目标:

  1. 在集群中均匀分布数据:- 如果主键由单列组成,则主键是分区键,如果是复合主键,则主键是分区键和集群键。要平均分布数据,您必须为 PK 选择一个具有唯一性的列,这样就可以跨节点分布。像 ID、用户名、email 这样的东西具有唯一性,会充分利用节点的集群。但是如果您使用像名字/姓氏性别等这样的键,那么分区键的选择将会非常少,尽管有 100 个节点,但总是只有少数几个会被使用,从而使一个分区变得臃肿,性能降低。
  2. 尽量减少读取次数:- 正如我提到的,读取是很昂贵的。如果您以一种单个查询从多个分区获取的方式建模,将会使系统变慢。

因此,与 RDBMS 不同,在 RDBMS 中,您首先设计模式,然后根据您的需求自由地创建查询,而 Cassandra 却不是这样。你必须预先知道系统中需要的查询,然后相应地设计模型。

示例使用案例

我们有一个系统,不同城市的用户访问一个网站。管理层要求提供以下信息:

  1. 所有用户的列表
  2. 所有城市的列表。
  3. 按城市列出的用户列表

让我们首先创建cities表。

*CREATE TABLE cities (
 id int,
 name text,
 country text,
 PRIMARY KEY(id)
);*

然后users

*CREATE TABLE users (
 username text,
 name text,
 age int,
 PRIMARY KEY(username)
);*

插入几个城市。

*INSERT INTO cities(id,name,country) VALUES (1,'Karachi','Pakistan');
INSERT INTO cities(id,name,country) VALUES (2,'Lahore','Pakistan');
INSERT INTO cities(id,name,country) VALUES (3,'Dubai','UAE');
INSERT INTO cities(id,name,country) VALUES (4,'Berlin','Germany');*

并插入一些用户

*INSERT INTO users(username,name,age) VALUES ('aali24','Ali Amin',34);
INSERT INTO users(username,name,age) VALUES ('jack01','Jack David',23);
INSERT INTO users(username,name,age) VALUES ('ninopk','Nina Rehman',34);*

这些插入满足了我们的前两个要求,但是第三个要求呢?在 RDBMS 世界中,我们将使用city_id作为users表中的 FK,连接将很容易返回数据,但这是 Cassandra,我们不能这样做,剩下的是我们创建另一个表来满足我们的需求。

*CREATE TABLE users_by_cities (
 username text,
 name text,
 city text,
 age int,
 PRIMARY KEY(city,age)
);*

这个主键有两个组成部分:第一个成为分区键,第二个成为簇键。它将查找 w . r . t . city,所有记录都按年龄分组。

现在插入一些记录:

*INSERT INTO users_by_cities(username,name,city,age) VALUES ('aali24','Ali Amin','Karachi',34);
INSERT INTO users_by_cities(username,name,city, age) VALUES ('jack01','Jack David','Berlin',23);
INSERT INTO users_by_cities(username,name,city, age) VALUES ('ninopk','Nina Rehman','Lahore',34);*

通常情况下,在两个表中的这些插入会在“添加用户”界面中一次完成,从 CQL 端,您可以做类似这样的事情来添加用户信息。

*BEGIN BATCH
INSERT into users(username,name,age) VALUES('raziz12','Rashid Aziz',34);
INSERT INTO users_by_cities(username,name,city, age) VALUES ('raziz12','Rashid Aziz','Karachi',30);
APPLY BATCH;*

在继续之前,我想提醒您一下我之前讨论过的散列令牌。首先,在 CQL shell 上运行EXPAND ON命令。一旦你这样做了,你会看到如下结果:

看起来不错,不是吗?好了,现在我们将看到我们的主键的令牌值。它返回以下结果:

*cqlsh:cityinfo> select token(username) from users;@ Row 1
------------------------+----------------------
 system.token(username) | -7905752472182359000@ Row 2
------------------------+----------------------
 system.token(username) | 2621513098312339776@ Row 3
------------------------+----------------------
 system.token(username) | 6013687671608201304*

有道理,令牌是唯一的,因为用户名是唯一的。这些令牌将跨节点传播。当用户运行命令SELECT * FROM users where username = 'raziz12'时,它将根据这个令牌值选择节点。我已经在上面几行中展示过了。

下面的查询显示了来自users_by_cities表的令牌值。

*cqlsh:cityinfo> select token(username),username,city from users_by_cities;@ Row 1
------------------------+----------------------
 system.token(username) | 2621513098312339776
 username               | jack01
 city                   | Berlin@ Row 2
------------------------+----------------------
 system.token(username) | 6013687671608201304
 username               | ninopk
 city                   | Lahore@ Row 3
------------------------+----------------------
 system.token(username) | -882788003101376442
 username               | raziz12
 city                   | Karachi@ Row 4
------------------------+----------------------
 system.token(username) | -7905752472182359000
 username               | aali24
 city                   | Karachi*

Select * from users_by_cities where city = 'Karachi';返回以下内容:

*cqlsh:cityinfo> select * from users_by_cities where city = 'Karachi';@ Row 1
----------+-------------
 city     | Karachi
 username | aali24
 name     | Ali Amin@ Row 2
----------+-------------
 city     | Karachi
 username | raziz12
 name     | Rashid Aziz*

该模型还服务于查询select * from users_by_cities where city = 'Karachi' and age = 34

但是,如果您想根据字段选择一条记录,该怎么办呢?

SELECT * from users_by_cities where name = 'Ali Amin';

您会得到下面的错误。

*Error from server: code=2200 [Invalid query] message="Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability*

这是因为没有提到分区键,Cassandra 要求在所有节点中搜索所需的名称,是的,所有节点,想象一下如果节点是 10 或 100,返回数据需要时间。因此不建议这样做。如果您想在 w.r.t 字段中找到一些东西,要么创建另一个表(强烈推荐),要么创建一个二级索引(不推荐)

数据按城市分区,在查找时,一个节点用城市的令牌响应,一旦发现该节点,它就获取该分区中属于卡拉奇城市的用户的所有记录。对于与卡拉奇相关的数据聚类,也可以看到类似的情况。数据根据年龄列进行聚类。

所以对于一个保存所有 Karachiites 记录的分区,你会看到记录的集群。

你的脑袋一定在打转,会想念你心爱的 MySQL,但我告诉你,这是值得学习的东西,我也在学习,我只是触及了这个野兽的表面。

你可能想知道这篇文章的标题提到了 Python,但是我听说到目前为止还没有写 Python 代码。有必要准备一个基础,因为您将只是在 Python 应用程序中执行查询。主要工作在别的地方,就在上面。

好了,在我转向开发之前,我讨论过 Cassandra 最初在 Commitlog 中写数据。

Cassandra CommitLog 的路径可以从/etc/cassandra/cassandra.yaml获得,也就是从/var/lib/cassandra/commitlog获得,这里它创建了带有时间戳的日志文件。这是不可读的,但当我搜索一些插入的记录,然后发现一些痕迹。检查下面的屏幕:

你可以在这里找到杰克 01阿力、尼诺普的踪迹。你也可以找到与修复机制相关的文字。

/var/lib/cassandra/data/<keyspacename>可以找到桌子。我的情况是cityinfo

对于每个表/列族,它生成manifest.json文件,一些*.db和一些其他类型的文件,下面是表users_by_cities表的文件。

*./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/manifest.json
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/md-1-big-CompressionInfo.db
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/md-1-big-Data.db
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/md-1-big-Digest.crc32
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/md-1-big-Filter.db
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/md-1-big-Index.db
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/md-1-big-Statistics.db
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/md-1-big-Summary.db
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/md-1-big-TOC.txt
./users_by_cities-62cea5f0788e11e9b568e709cd27ef9f/snapshots/truncated-1558089482008-users_by_cities/schema.cql*

你可以在这里了解更多。

从 Python 访问 Cassandra

好的,首先,我们需要安装驱动程序。我在 docker shell 之外,因为我将从我的主机访问它。运行命令pip install cassandra-driver

构建驱动程序需要一段时间:

*Requirement already satisfied: six>=1.9 in /anaconda3/anaconda/lib/python3.6/site-packages (from cassandra-driver) (1.11.0)
Building wheels for collected packages: cassandra-driver
  Building wheel for cassandra-driver (setup.py) ... done
  Stored in directory: /Users/AdnanAhmad/Library/Caches/pip/wheels/df/f4/40/941c98128d60f08d2f628b04a7a1b10006655aac3803e0e227
Successfully built cassandra-driver
Installing collected packages: cassandra-driver
Successfully installed cassandra-driver-3.17.1*

下面是从 Docker 中运行的 Python 脚本连接到 Docker 中的 Cassandra 集群的代码。

*from cassandra.cluster import Clusterif __name__ == "__main__":
    cluster = Cluster(['0.0.0.0'],port=9042)
    session = cluster.connect('cityinfo',wait_for_all_pools=True)
    session.execute('USE cityinfo')
    rows = session.execute('SELECT * FROM users')
    for row in rows:
        print(row.age,row.name,row.username)*

返回了以下输出:

*➜  CassandraTut python cassandra_connect.py
34 Ali Amin aali24
34 Rashid Aziz raziz12
23 Jack David jack01
34 Nina Rehman ninopk
➜  CassandraTut*

你可以在这里了解更多信息

结论

所以在这篇文章中,你学习了一些关于 Cassandra 的知识,以及如何使用 CQL 并在你的 Python 脚本中连接它。请在下面留下您的评论,以便提出意见、更正或反馈。和往常一样,代码在 Github 上。

本帖原载 此处

Apache Spark 入门

原文:https://towardsdatascience.com/getting-started-with-apache-spark-ad9d59e71f6f?source=collection_archive---------7-----------------------

Java 中 Spark 的体系结构及应用

Photo by Markus Spiske on Unsplash

Apache Spark 被解释为“大规模数据处理的快速通用引擎”然而,这甚至没有开始概括它成为大数据领域如此突出的参与者的原因。Apache Spark 是一个分布式计算平台,大数据公司对它的采用一直在以令人瞩目的速度增长。

火花建筑

spark 的架构如下所示:

Spark Eco-System — Image by Author

Spark 是一个分布式处理引擎,但是它没有自己的分布式存储和资源集群管理器。它运行在现成的集群资源管理器和分布式存储之上。

Spark core 由两部分组成:

  • 核心 API:非结构化 API(rdd),结构化 API(数据帧,数据集)。在 Scala、Python、Java 和 r 中可用。
  • 计算引擎:内存管理、任务调度、故障恢复、与集群管理器交互。

注意:我们将在文章末尾看到核心 API 的 Java 实现。

在核心 API 之外,Spark 提供了:

  • Spark SQL:通过类似 SQL 的查询与结构化数据进行交互。
  • 流:消费和处理连续的数据流。
  • 机器学习库。但是,我不会推荐在这里训练深度学习模型。
  • GraphX:典型的图形处理算法。

以上四个都直接依赖于 spark 核心 API 进行分布式计算。

Spark 的优势

  • Spark 为批处理、结构化数据处理、流等提供了一个统一的平台。
  • 与 Hadoop 的 map-reduce 相比,spark 代码更容易编写和使用。
  • Spark 最重要的特性,它抽象了并行编程方面。Spark core 抽象了分布式存储、计算和并行编程的复杂性。

Apache Spark 的主要用例之一是大规模数据处理。我们创建程序并在 spark 集群上执行它们。

程序在集群上的执行

在 spark cluster 上执行程序主要有两种方法:

  1. 互动客户端如py-spark,笔记本等。
  2. 提交作业。

大多数开发过程发生在交互式客户机上,但是当我们必须将应用程序投入生产时,我们使用提交作业方法。

对于长时间运行的流作业或定期批处理作业,我们将应用程序打包并提交给 Spark cluster 执行。

Spark 是一个分布式处理引擎,遵循主从架构。在 spark 术语中,主人是 驱动者 ,奴隶是 执行者

Image by Author

司机负责:

  1. 分析
  2. 分发。
  3. 监控。
  4. 日程安排。
  5. 在 spark 进程的生命周期内维护所有必要的信息。

执行者只负责执行驱动程序分配给他们的那部分代码,并将状态报告给驱动程序。

每个 spark 进程都有一个单独的驱动程序和独占的执行器。

执行方式

  1. 客户端模式:驱动程序是本地虚拟机,您可以在这里提交应用程序。默认情况下,spark 以客户端模式提交所有应用程序。由于驱动程序是整个 spark 流程中的主节点,因此在生产设置中,这是不可取的。对于调试,使用客户端模式更有意义。
  2. 集群模式:司机是集群中的执行者之一。在 spark-submit 中,您可以如下传递参数:
*--deploy-mode cluster*

集群资源管理器

Image by Author

Yarn 和 Mesos 是常用的集群管理器。

Kubernetes 是一个通用容器编制器。

注意:在撰写本文时,Kubernetes 上的 Spark 还没有做好生产准备。

Yarn 是 spark 最受欢迎的资源管理器,让我们看看它的内部工作原理:

在客户端模式应用程序中,驱动程序是我们的本地虚拟机,用于启动 spark 应用程序:

步骤 1: 一旦驱动程序启动,spark 会话请求就会发送到 yarn 以创建一个 Yarn 应用程序。

步骤 2: 纱线资源经理创建一个应用程序主程序。对于客户机模式,AM 充当执行器启动器。

第 3 步: AM 将联系纱线资源经理,要求提供更多容器。

步骤 4: 资源管理器将分配新的容器,AM 将启动每个容器中的执行器。之后,执行者直接与司机沟通。

Image by Author

注意:在集群模式下,驱动程序在上午启动。

执行器和内存调优

硬件— 6 个节点,每个节点 16 个内核,64 GB RAM

让我们从核心的数量开始。核心的数量代表一个执行器可以运行的并发任务。研究表明,任何具有 5 个以上并发任务的应用程序都会导致糟糕的表现。因此,我建议坚持 5。

注意:上面的数字来自于一个执行器的性能,而不是来自于系统有多少内核。因此,对于 32 核系统来说也是一样的。

操作系统和 Hadoop 守护程序需要 1 个内核和 1 GB RAM。因此,我们只剩下 63 GB 内存和 15 个内核。

对于 15 个内核,每个节点可以有 3 个执行器。我们总共有 18 个遗嘱执行人。AM 容器需要 1 个执行器。因此我们可以得到 17 个遗嘱执行人。

回到内存,我们得到每个执行器 63/3 = 21 GB。但是,在计算完整的内存请求时,需要考虑少量的开销。

*Formula for that over head = max(384, .07 * spark.executor.memory)Calculating that overhead = .07 * 21 = 1.47*

因此,内存下降到大约 19 GB。

因此,该系统得出:

*--num-executors 17 --executor-memory 19G --executor-cores 5* 

注意:如果我们需要更少的内存,我们可以减少内核的数量来增加执行器的数量。

火花核心

现在我们来看看 spark 提供的一些核心 API。Spark 需要一个数据结构来保存数据。我们有三种选择 RDD、数据帧和数据集。从 Spark 2.0 开始,建议只使用数据集和数据帧。这两个内部编译到 RDD 本身。

这三个是弹性的、分布式的、分区的和不可变的数据集合。

Image by Author

Task:Spark 中最小的工作单元,由一个执行者执行。

数据集提供两种类型的操作:

  • 转换:从现有的数据集创建新的数据集。它是懒惰的,数据仍然是分布式的。
  • 动作:动作向驱动返回数据,本质上是非分布式的。数据集上的操作触发作业。

混洗和排序:对数据集进行重新分区,以便对其执行操作。它是 spark 中的一个抽象,我们不需要为它编写代码。这项活动需要一个新的阶段。

常见操作和转换

1) lit,geq,leq,gt,lt

lit:创建一个文字值列。可用于与其他列进行比较。

geq(大于等于),leq(小于等于),gt(大于),lt(小于):用于与其他列值进行比较。例如:

2)加入

Spark 允许我们以各种方式连接数据集。我将试着用一个例子来解释

结果看起来像这样:

3)工会

Spark 联合函数让我们在两个数据集之间建立一个联合。数据集应该具有相同的模式。

4)窗户

Spark 的基本功能之一。它允许您基于一组行(称为)计算表中每个输入行的返回值。

Spark 提供了翻滚窗口、希望窗口、滑动窗口和延迟窗口的 API。

我们用它来排序、求和、普通的窗口等等。一些使用案例包括:

其他函数,如 laglead 等等,允许您进行其他操作,使您能够对数据集进行复杂的分析。

但是,如果您仍然需要对数据集执行更复杂的操作,您可以使用 UDF。UDF 的用法示例:

注意:使用 UDF 应该是最后的手段,因为它们不是为 Spark 优化的;他们可能需要更长的时间来执行死刑。建议在 UDF 上使用本机 spark 函数。

这只是 Apache Spark 的冰山一角。它的应用扩展到各个领域,不仅限于数据分析。请关注此空间了解更多信息。

参考

  • https://www.youtube.com/watch?v=AYZCpxYVxH4&list = plkz 1 SCF 5 IB 4d xipdfd 4 hxwhergrwhmd 6k
  • https://stack overflow . com/questions/37871194/how-to-tune-spark-executor-number-cores-and-executor-memory
  • https://medium . com/@ farox 2q/UDFs-vs-map-vs-custom-spark-native-functions-91 ab 2c 154 b 44
  • https://stack overflow . com/questions/45990633/what-the-variable-join-types-in-spark

使用 AWS Glue、RDS 和 S3 在 Amazon EMR 上开始使用 Apache Zeppelin

原文:https://towardsdatascience.com/getting-started-with-apache-zeppelin-on-amazon-emr-using-aws-glue-rds-and-s3-2b5d231a788a?source=collection_archive---------21-----------------------

使用一系列预制的 Zeppelin 笔记本,探索在 Amazon EMR 上使用 Apache Zeppelin 进行数据分析和数据科学。

介绍

毫无疑问,大数据分析、数据科学、人工智能 (AI)和机器学习 (ML),人工智能的一个子类,在过去 3-5 年里都经历了巨大的受欢迎程度。在炒作周期和营销热潮的背后,这些技术正在对我们现代生活的各个方面产生重大影响。由于其受欢迎程度,商业企业、学术机构和公共部门都争相开发硬件和软件解决方案,以降低进入门槛并提高 ML 和数据科学家和工程师的速度。

(courtesy Google Trends and Plotly)

技术

所有三大云提供商,亚马逊网络服务(AWS)、微软 Azure 和谷歌云,都拥有快速成熟的大数据分析、数据科学以及人工智能和人工智能服务。例如,AWS 在 2009 年推出了Amazon Elastic MapReduce(EMR),主要作为基于 Apache Hadoop 的大数据处理服务。据亚马逊称,从那时起,EMR 已经发展成为一种服务,它使用 Apache Spark 、 Apache Hadoop 和其他几个领先的开源框架来快速、经济高效地处理和分析大量数据。最近,在 2017 年末,亚马逊发布了 SageMaker ,这是一项提供快速安全地构建、训练和部署机器学习模型的能力的服务。

同时,组织正在构建集成和增强这些基于云的大数据分析、数据科学、人工智能和 ML 服务的解决方案。一个这样的例子是阿帕奇齐柏林飞艇。类似于非常受欢迎的项目 Jupyter 和新近开源的网飞的 Polynote ,Apache Zeppelin 是一个基于网络的多语言计算笔记本。Zeppelin 使用大量的解释器,如 Scala、Python、Spark SQL、JDBC、Markdown 和 Shell,实现了数据驱动的交互式数据分析和文档协作。Zeppelin 是亚马逊 EMR 原生支持的核心应用之一。

Example of an Apache Zeppelin Notebook Paragraph

在接下来的文章中,我们将使用一系列 Zeppelin 笔记本,探索在 EMR 上使用 Apache Zeppelin 进行数据分析和数据科学。这些笔记本电脑使用了 AWS Glue ,这是一种完全托管的提取、转换和加载(ETL)服务,可以轻松准备和加载数据以进行分析。这些笔记本还采用了针对 PostgreSQL 的亚马逊关系数据库服务 (RDS)和亚马逊简单云存储服务 (S3)。亚马逊 S3 将作为一个数据湖来存储我们的非结构化数据。鉴于目前 Zeppelin 的二十多个不同的解释器的选择,我们将为所有笔记本使用 Python3 和 Apache Spark ,具体来说就是 Spark SQL 和 PySpark 。

Featured Technologies

我们将构建一个经济的单节点 EMR 集群来进行数据探索,以及一个更大的多节点 EMR 集群来高效地分析大型数据集。亚马逊 S3 将用于存储输入和输出数据,而中间结果存储在 EMR 集群上的 Hadoop 分布式文件系统 (HDFS)中。亚马逊提供了一个很好的概述 EMR 架构。下面是我们将为本次演示构建的基础架构的高级架构图。

High-level AWS Architecture

笔记本功能

下面是每个 Zeppelin 笔记本的简要概述,并带有链接,可以使用 Zepl 的免费笔记本浏览器进行查看。Zepl 由开发阿帕奇齐柏林飞艇的同一批工程师创建,包括阿帕奇齐柏林飞艇的首席技术官兼创造者 Moonsoo Lee。Zepl 的企业协作平台建立在 Apache Zeppelin 的基础上,使数据科学和 AI/ML 团队能够围绕数据进行协作。

笔记本 1

第一个笔记本使用一个小的 21k 行 kaggle 数据集,来自面包店的交易。该笔记本展示了 Zeppelin 与 Helium 插件系统的集成能力,用于添加新的图表类型,使用亚马逊 S3 进行数据存储和检索,使用 Apache Parquet ,一种压缩和高效的列数据存储格式,以及 Zeppelin 与 GitHub 的存储集成,用于笔记本版本控制。

笔记本 2

第二本笔记本演示了使用单节点和多节点亚马逊 EMR 集群,使用 Zeppelin 探索和分析从大约 100k 行到 27MM 行的公共数据集。我们将使用最新的 GroupLens MovieLens 评级数据集,在单节点和多节点 EMR 集群上使用 Spark 来检查 Zeppelin 的性能特征,以便使用各种 Amazon EC2 实例类型来分析大数据。

笔记本 3

第三个笔记本展示了亚马逊 EMR 和 Zeppelin 的集成能力,其中一个 AWS Glue 数据目录作为兼容 Apache Hive 的metastoreforSpark SQL。我们将使用 AWS Glue 数据目录和一组 AWS Glue 爬虫创建一个基于亚马逊 S3 的数据湖。

笔记本 4

第四个笔记本展示了 Zeppelin 与外部数据源集成的能力。在这种情况下,我们将使用三种方法与 Amazon RDS PostgreSQL 关系数据库中的数据进行交互,包括用于 Python 的 Psycopg 2 PostgreSQL 适配器、Spark 的原生 JDBC 功能和 Zeppelin 的 JDBC 解释器。

示范

首先,作为一名数据操作工程师,我们将使用 AWS Glue 数据目录、Amazon RDS PostgreSQL 数据库和基于 S3 的数据湖,创建和配置演示在 EMR 上使用 Apache Zeppelin 所需的 AWS 资源。设置完成后,作为数据分析师,我们将使用预构建的 Zeppelin 笔记本电脑探索 Apache Zeppelin 的功能以及与各种 AWS 服务的集成能力。

源代码

演示的源代码包含在两个公共的 GitHub 存储库中。第一个存储库, zeppelin-emr-demo ,包括四个预建的 zeppelin 笔记本,根据 Zeppelin 的可插拔笔记本存储机制的惯例进行组织。

.
├── 2ERVVKTCG
│   └── note.json
├── 2ERYY923A
│   └── note.json
├── 2ESH8DGFS
│   └── note.json
├── 2EUZKQXX7
│   └── note.json
├── LICENSE
└── README.md

齐柏林 GitHub 存储

在演示过程中,当提交发生时,对运行在 EMR 上的 Zeppelin 笔记本副本所做的更改将自动推回到 GitHub。为了实现这一点,不仅仅是克隆 zeppelin-emr-demo 项目存储库的本地副本,您还需要在您的个人 GitHub 帐户中有自己的副本。您可以派生 zeppelin-emr-demo GitHub 存储库,或者将一个克隆拷贝到您自己的 GitHub 存储库中。

要在您自己的 GitHub 帐户中创建项目的副本,首先,在 GitHub 上创建一个新的空存储库,例如,“my-zeppelin-emr-demo-copy”。然后,从您的终端执行以下命令,将原始项目存储库克隆到您的本地环境,最后,将其推送到您的 GitHub 帐户。

GitHub 个人访问令牌

为了在提交时自动将更改推送到 GitHub 存储库,Zeppelin 将需要一个 GitHub 个人访问令牌。创建一个个人访问令牌,其范围如下所示。一定要保守令牌的秘密。确保不要意外地将令牌值签入 GitHub 上的源代码。为了最大限度地降低风险,请在完成演示后立即更改或删除令牌。

GitHub Developer Settings — Personal Access Tokens

第二个存储库 zeppelin-emr-config ,包含必要的引导文件、CloudFormation 模板和 PostgreSQL DDL(数据定义语言)SQL 脚本。

.
├── LICENSE
├── README.md
├── bootstrap
│   ├── bootstrap.sh
│   ├── emr-config.json
│   ├── helium.json
├── cloudformation
│   ├── crawler.yml
│   ├── emr_single_node.yml
│   ├── emr_cluster.yml
│   └── rds_postgres.yml
└── sql
    └── ratings.sql

使用以下 AWS CLI 命令将 GitHub 存储库克隆到您的本地环境中。

要求

为了进行演示,您将需要一个 AWS 帐户、一个现有的亚马逊 S3 桶来存储 EMR 配置和数据,以及一个 EC2 密钥对。您还需要在您的工作环境中安装最新版本的 AWS CLI 。由于我们将使用特定的 EMR 功能,我建议使用us-east-1 AWS 区域来创建演示资源。

S3 的配置文件

首先,将三个配置文件, bootstrap.sh 、 helium.json 和 ratings.sql ,从zeppelin-emr-demo-setup项目目录复制到我们的 S3 存储桶。更改ZEPPELIN_DEMO_BUCKET变量值,然后使用 AWS CLI 运行下面的s3 cp API 命令。这三个文件将被复制到 S3 存储桶内的引导目录中。

下面是将本地文件复制到 S3 的示例输出。

Copy Configuration Files to S3

创建 AWS 资源

我们将首先使用三个 AWS CloudFormation 模板创建演示所需的大部分 AWS 资源。我们将创建一个单节点 Amazon EMR 集群、一个 Amazon RDS PostgresSQL 数据库、一个 AWS Glue 数据目录数据库、两个 AWS Glue 爬虫和一个 Glue IAM 角色。由于在集群中运行大型 EC2 实例的计算成本,我们将等待创建多节点 EMR 集群。在继续之前,您应该了解这些资源的成本,并确保在演示完成后立即销毁这些资源,以最大限度地减少您的开支。

单节点 EMR 集群

我们将从创建单节点 Amazon EMR 集群开始,它只包含一个主节点,没有核心或任务节点(一个集群)。所有操作都将在主节点上进行。

默认 EMR 资源

以下 EMR 说明假设您过去已经在当前 AWS 区域使用带有“创建集群—快速选项”选项的 EMR web 界面创建了至少一个 EMR 集群。以这种方式创建集群会创建几个额外的 AWS 资源,比如EMR_EC2_DefaultRole EC2 实例概要、默认的EMR_DefaultRole EMR IAM 角色和默认的 EMR S3 日志存储桶。

EMR — AWS Console

如果您过去没有使用 EMR 的“创建集群-快速选项”功能创建任何 EMR 集群,请不要担心。您还可以使用一些快速的 AWS CLI 命令来创建所需的资源。更改下面的LOG_BUCKET变量值,然后使用 AWS CLI 运行aws emraws s3api API 命令。LOG_BUCKET变量值遵循aws-logs-awsaccount-region的惯例。比如aws-logs-012345678901-us-east-1

可以在 IAM 角色 web 界面中查看新的 EMR IAM 角色。

IAM Management Console

我经常看到从 AWS CLI 或 CloudFormation 引用这些默认 EMR 资源的教程,而没有对它们是如何创建的任何理解或解释。

EMR 引导脚本

作为创建 EMR 集群的一部分,云模板 emr_single_node.yml 将调用我们之前复制到 S3 的引导脚本 bootstrap.sh 。bootstrap 脚本预装了所需的 Python 和 Linux 软件包,以及 PostgreSQL 驱动程序 JAR 。引导脚本还会克隆您的 zeppelin-emr-demo GitHub 存储库副本。

EMR 应用程序配置

EMR CloudFormation 模板还将修改 EMR 集群的 Spark 和 Zeppelin 应用程序配置。在其他配置属性中,模板将默认 Python 版本设置为 Python3,指示 Zeppelin 使用克隆的 GitHub 笔记本目录路径,并将 PostgreSQL 驱动程序 JAR 添加到 JVM 类路径中。下面我们可以看到应用于现有 EMR 集群的配置属性。

EMR — AWS Console

EMR 应用程序版本

截至本文发布之日(2019 年 12 月),EMR 的版本为 5.28.0 。如 EMR web 界面所示,下面是可安装在 EMR 上的当前(21)个应用程序和框架。

对于这个演示,我们将安装 Apache Spark v2.4.4、 Ganglia v3.7.2 和 Zeppelin 0.8.2。

Apache Zeppelin: Web Interface

Apache Spark: DAG Visualization

Ganglia: Cluster CPU Monitoring

创建 EMR 云信息堆栈

更改以下(7)个变量值,然后使用 AWS CLI 运行emr cloudformation create-stack API 命令。

您可以使用 Amazon EMR web 界面来确认 CloudFormation 堆栈的结果。集群应该处于“等待”状态。

EMR — AWS Console

亚马逊 RDS 上的 PostgreSQL

接下来,使用包含的 CloudFormation 模板 rds_postgres.yml ,创建一个简单的、单 AZ、单主、非复制的 Amazon RDS PostgreSQL 数据库。我们将在笔记本 4 中使用该数据库。对于演示,我选择了当前通用的db.m4.large EC2 实例类型来运行 PostgreSQL。您可以轻松地将实例类型更改为另一个支持 RDS 的实例类型,以满足您的特定需求。

更改以下(3)个变量值,然后使用 AWS CLI 运行cloudformation create-stack API 命令。

您可以使用 Amazon RDS web 界面来确认 CloudFormation 堆栈的结果。

RDS — AWS Console

AWS 胶水

接下来,使用包含的 CloudFormation 模板 crawler.yml 创建 AWS Glue 数据目录数据库、Apache Hive 兼容的 metastore for Spark SQL、两个 AWS Glue Crawlers 和一个 Glue IAM 角色(ZeppelinDemoCrawlerRole)。AWS 胶水数据目录数据库将在笔记本 3 中使用。

更改以下变量值,然后使用 AWS CLI 运行cloudformation create-stack API 命令。

您可以使用 AWS Glue web 界面来确认 CloudFormation 堆栈的结果。注意数据目录数据库和两个 Glue Crawlers。我们不会在后面的文章中运行这两个爬虫。因此,数据目录数据库中还不存在任何表。

AWS Glue Console

AWS Glue Console

至此,您应该已经成功创建了一个单节点 Amazon EMR 集群、一个 Amazon RDS PostgresSQL 数据库和几个 AWS Glue 资源,所有这些都使用了 CloudFormation 模板。

CloudFormation — AWS Console

EMR 创建后配置

RDS 安全性

为了让新的 EMR 集群与 RDS PostgreSQL 数据库通信,我们需要确保从 RDS 数据库的 VPC 安全组(默认的 VPC 安全组)到 EMR 节点的安全组的端口 5432 是开放的。从 EMR web 界面或使用 AWS CLI 获取ElasticMapReduce-masterElasticMapReduce-slave安全组的组 ID。

EMR — AWS Console

使用 RDS web 界面访问 RDS 数据库的安全组。将端口 5432 的入站规则更改为包含两个安全组 id。

EC2 Management Console

到 EMR 主节点的 SSH

除了引导脚本和配置之外,我们已经应用于 EMR 集群,我们需要对 EMR 集群进行一些 EMR 创建后配置更改,以便进行演示。这些变化需要使用 SSH 连接到 EMR 集群。使用主节点的公共 DNS 地址和 EMR web 控制台中提供的 SSH 命令,SSH 进入主节点。

EMR — AWS Console

如果您无法使用 SSH 访问节点,请检查相关 EMR 主节点 IAM 安全组(ElasticMapReduce-master)上的端口 22 是否对您的 IP 地址或地址范围开放。

EMR — AWS Console

EC2 Management Console

Git 权限

我们需要更改在 EMR 引导阶段安装的 git 存储库的权限。通常,对于 EC2 实例,您作为ec2-user用户执行操作。使用 Amazon EMR,您经常以hadoop用户的身份执行操作。使用 EMR 上的 Zeppelin,笔记本执行操作,包括作为zeppelin用户与 git 存储库交互。作为 bootstrap.sh 脚本的结果,默认情况下,git 存储库目录/tmp/zeppelin-emr-demo/的内容归hadoop用户和组所有。

Git Clone Project Permissions on EMR Master Node

我们将把他们的所有者改为zeppelin用户和组。我们无法将此步骤作为引导脚本的一部分来执行,因为在脚本执行时不存在zeppelin用户和组。

cd /tmp/zeppelin-emr-demo/
sudo chown -R zeppelin:zeppelin .

结果应该类似于下面的输出。

Git Clone Project Permissions on EMR Master Node

预安装可视化软件包

接下来,我们将预装几个 Apache Zeppelin 可视化软件包。据 Zeppelin 网站介绍,Apache Zeppelin 可视化是一个可插拔的包,可以在运行时通过 Zeppelin 中的氦框架加载和卸载。我们可以像使用笔记本中的任何其他内置可视化一样使用它们。可视化是一个 javascript npm 包。例如,这里有一个公共 npm 注册表上的最终饼状图的链接。

我们可以通过用之前复制到 S3 的 helium.json 版本替换/usr/lib/zeppelin/conf/helium.json文件,并重启 Zeppelin 来预加载插件。如果您有很多可视化或包类型,或者使用任何 DataOps 自动化来创建 EMR 集群,这种方法比每次创建新的 EMR 集群时使用 Zeppelin UI 手动加载插件更有效且可重复。下面是helium.json文件,它预加载了 8 个可视化包。

运行以下命令来加载插件并调整文件的权限。

创建新的 JDBC 解释器

最后,我们需要创建一个新的齐柏林 JDBC 解释器来连接到我们的 RDS 数据库。默认情况下,Zeppelin 安装了几个解释器。您可以使用以下命令查看可用解释器的列表。

sudo sh /usr/lib/zeppelin/bin/install-interpreter.sh --list

List of Installed Interpreters

新的 JDBC 解释器将允许我们使用 Java 数据库连接 (JDBC)连接到我们的 RDS PostgreSQL 数据库。首先,确保安装了所有可用的解释器,包括当前的齐柏林 JDBC 驱动程序(org.apache.zeppelin:zeppelin-jdbc:0.8.0)到/usr/lib/zeppelin/interpreter/jdbc

创建一个新的解释器是一个两部分的过程。在这个阶段,我们使用下面的命令在主节点上安装所需的解释器文件。然后,在 Zeppelin web 界面中,我们将配置新的 PostgreSQL JDBC 解释器。注意,我们必须为解释器提供一个唯一的名称(即‘postgres’),我们将在解释器创建过程的第二部分中引用这个名称。

为了在主节点上完成后 EMR 创建配置,我们必须重新启动 Zeppelin 以使我们的更改生效。

sudo stop zeppelin && sudo start zeppelin

根据我的经验,重启后 Zeppelin UI 可能需要 2-3 分钟才能完全响应。

Restarting Zeppelin

Zeppelin Web 界面访问

随着所有 EMR 应用程序配置的完成,我们将访问运行在主节点上的 Zeppelin web 界面。使用 EMR web 界面中提供的 Zeppelin 连接信息来设置 SSH 隧道到 Zeppelin web 界面,在主节点上运行。使用 SSH 隧道,我们还可以访问 Spark 历史服务器、Ganglia 和 Hadoop 资源管理器 web 界面。所有链接都是从 EMR web 控制台提供的。

EMR — AWS Console

为了建立到 EMR 集群上安装的应用程序的 web 连接,我使用了 FoxyProxy 作为 Google Chrome 的代理管理工具。

EMR — Enable Web Connection

如果到目前为止一切正常,您应该会看到 Zeppelin web 界面,其中包含了从克隆的 GitHub 存储库中获得的所有四个 Zeppelin 笔记本。您将作为anonymous用户登录。Zeppelin 为访问 EMR 集群上的笔记本提供了身份验证。为了简洁起见,我们将不讨论在 Zeppelin 中使用 Shiro 认证来设置认证。

Apache Zeppelin Landing Page

笔记本路径

要确认 GitHub 笔记本存储库的本地克隆副本的路径是否正确,请检查笔记本存储库界面,该界面可在屏幕右上角的设置下拉菜单(anonymous用户)下访问。该值应该与我们之前执行的EMR _ single _ node . ymlcloud formation 模板中的ZEPPELIN_NOTEBOOK_DIR配置属性值相匹配。

Apache Zeppelin GitHub Notebook Repository

氦可视化

为了确认氦可视化已正确预安装,使用氦. json 文件,打开氦界面,可在屏幕右上角的设置下拉菜单(anonymous用户)下访问。

Apache Zeppelin — Available Helium Visualizations

请注意启用的可视化。而且,通过 web 界面启用附加插件也很容易。

Apache Zeppelin — Enabled Helium Visualizations

新的 PostgreSQL JDBC 解释器

如果您还记得,在前面,我们使用下面的命令和引导脚本在主节点上安装了所需的解释器文件。我们现在将完成配置新的 PostgreSQL JDBC 解释器的过程。打开口译员界面,可通过屏幕右上角的设置下拉菜单(anonymous用户)进入。

新解释器的名称必须与我们用来安装解释器文件的名称“postgres”相匹配。解释器组将是“jdbc”。我们至少需要为您的特定 RDS 数据库实例配置三个属性,包括default.urldefault.userdefault.password。这些值应该与前面创建 RDS 实例时使用的值相匹配。确保在default.url中包含数据库名称。下面是一个例子。

我们还需要提供 PostgreSQL 驱动程序 JAR 依赖项的路径。这个路径是我们之前使用 bootstrap.sh 脚本/home/hadoop/extrajars/postgresql-42.2.8.jar放置 JAR 的位置。保存新的解释器并确保它成功启动(显示绿色图标)。

Configuring the PostgreSQL JDBC Interpreter

Configuring the PostgreSQL JDBC Interpreter

将解释器切换到 Python 3

我们需要做的最后一件事是改变 Spark 和 Python 解释器,使用 Python 3 而不是默认的 Python 2。在用于创建新解释器的同一个屏幕上,修改 Spark 和 Python 解释器。首先,对于 Python 解释器,将zeppelin.python属性改为python3

Setting Interpreters to Python 3

最后,对于 Spark 解释器,将zeppelin.pyspark.python属性更改为python3

Setting Interpreters to Python 3

祝贺您,随着演示设置的完成,我们已经准备好开始使用我们的四个笔记本中的每一个来探索 Apache Zeppelin。

笔记本 1

第一个笔记本使用一个小的 21k 行 kaggle 数据集,来自面包店的交易。该笔记本展示了 Zeppelin 与 Helium 插件系统的集成能力,用于添加新的图表类型,使用亚马逊 S3 进行数据存储和检索,使用 Apache Parquet ,一种压缩和高效的列数据存储格式,以及 Zeppelin 与 GitHub 的存储集成,用于笔记本版本控制。

解释程序

当您第一次打开一个笔记本时,您可以选择绑定和解除绑定到笔记本的解释器。下面显示的列表中的最后一个解释器postgres,是我们在帖子前面创建的新的 PostgreSQL JDBC Zeppelin 解释器。我们将在笔记本 3 中使用这个解释器。

应用程序版本

笔记本的前两段用来确认我们正在使用的 Spark、Scala、OpenJDK、Python 的版本。回想一下,我们更新了 Spark 和 Python 解释器以使用 Python 3。

氦可视化

如果你记得在这篇文章的前面,我们预装了几个额外的氦可视化,包括终极饼状图。下面,我们看到使用 Spark SQL ( %sql)解释器来查询 Spark 数据帧,返回结果,并使用最终的饼图来可视化数据。除了饼图之外,我们还可以在菜单栏中看到其他预安装的氦可视化,它们位于五个默认可视化之前。

有了 Zeppelin,我们所要做的就是针对之前在笔记本中创建的 Spark 数据帧编写 Spark SQL 查询,Zeppelin 将处理可视化。您可以使用“设置”下拉选项对图表进行一些基本控制。

构建数据湖

笔记本 1 演示了如何向 S3 读写数据。我们使用 Spark (PySpark)将面包店数据集读写为 CSV 格式和 Apache Parquet 格式。我们还将 Spark SQL 查询的结果写入 S3 的 Parquet 中,如上图所示。

S3 Management Console

使用 Parquet,数据可以被分割成多个文件,如下面的 S3 桶目录所示。Parquet 比 CSV 更快地读入 Spark 数据帧。Spark 支持读写拼花文件。我们将把我们所有的数据写到 S3 的 Parquet 上,这使得未来数据的重复使用比从互联网上下载数据(如 GroupLens 或 kaggle)或从 S3 消费 CSV 文件更有效率。

Paquet-Format Files in S3

预览 S3 数据

除了使用 Zeppelin 笔记本,我们还可以使用亚马逊 S3 选择 T2 功能在 S3 木桶网络界面上预览数据。这个就地查询特性有助于快速理解您想要在 Zeppelin 中与之交互的新数据文件的结构和内容。

Previewing Data in S3 using the ‘Select from’ Feature

Previewing Data in S3 using the ‘Select from’ Feature

Previewing Data in S3 using the ‘Select from’ Feature

将更改保存到 GitHub

之前,我们将 Zeppelin 配置为从您自己的 GitHub 笔记本存储库中读取和写入笔记本。使用“版本控制”菜单项,对笔记本所做的更改可以直接提交到 GitHub。

在 GitHub 中,注意提交者是zeppelin用户。

Commits in GitHub

笔记本 2

第二本笔记本演示了使用单节点和多节点 Amazon EMR 集群,使用 Zeppelin 探索和分析从大约 100k 行到 27MM 行的公共数据集。我们将使用最新的 GroupLens MovieLens 评级数据集,在单节点和多节点 EMR 集群上使用 Spark 来检查 Zeppelin 的性能特征,以便使用各种 Amazon EC2 实例类型来分析大数据。

多节点 EMR 集群

如果您还记得,我们等待创建多节点集群是因为运行集群的大型 EC2 实例的计算成本。在继续之前,您应该了解这些资源的成本,并确保在演示完成后立即销毁这些资源,以最大限度地减少您的开支。

标准化实例小时数

理解 EMR 的成本需要理解标准化实例时间的概念。EMR AWS 控制台中显示的集群包含两列,“运行时间”和“标准化实例小时数”。“已用时间”列反映了使用集群的实际挂钟时间。“标准化实例小时数”列指示群集已使用的计算小时数的近似值,四舍五入到最接近的小时数。

EMR — AWS Console: Normalized Instance Hours

标准化实例小时数的计算基于一个标准化因子。规范化因子的范围从小型实例的 1 到大型实例的 64。根据我们多节点集群中实例的类型和数量,我们将每一个小时的挂钟时间使用大约 56 个计算小时(也称为标准化实例小时)。请注意我们的演示中使用的多节点集群,上面以黄色突出显示。集群运行了两个小时,相当于 112 个标准化实例小时。

创建多节点集群

使用 CloudFormation 创建多节点 EMR 集群。更改以下九个变量值,然后使用 AWS CLI 运行emr cloudformation create-stack API 命令。

使用 Amazon EMR web 界面来确认 CloudFormation 堆栈的成功。准备就绪时,完全调配的群集应处于“等待”状态。

EMR — AWS Console

配置 EMR 集群

继续之前,请参考前面的单节点集群说明,了解准备 EMR 集群和 Zeppelin 所需的配置步骤。重复用于单节点集群的所有步骤。

使用 Ganglia 进行监控

之前,我们在创建 EMR 集群时安装了 Ganglia。 Ganglia ,据其网站介绍,是一个可扩展的分布式监控系统,用于集群和网格等高性能计算系统。Ganglia 可用于评估单节点和多节点 EMR 集群的性能。使用 Ganglia,我们可以轻松查看集群和单个实例的 CPU、内存和网络 I/O 性能。

Ganglia Example: Cluster CPU

Ganglia Example: Cluster Memory

Ganglia Example: Cluster Network I/O

纱线资源经理

我们的 EMR 集群也提供纱线资源管理器网络用户界面。使用资源管理器,我们可以查看集群上的计算资源负载,以及各个 EMR 核心节点。下面,我们看到多节点集群有 24 个 vCPUs 和 72 GiB 可用内存,平均分布在三个核心集群节点上。

您可能还记得,用于三个核心节点的 m5.2xlarge EC2 实例类型,每个包含 8 个 vCPUs 和 32 GiB 内存。然而,通过默认,尽管每个节点的所有 8 个虚拟 CPU 都可用于计算,但是节点的 32 GiB 内存中只有 24 GiB 可用于计算。EMR 确保每个节点上都有一部分内存保留给其他系统进程。最大可用内存由纱线内存配置选项yarn.scheduler.maximum-allocation-mb控制。

YARN Resource Manager

上面的纱线资源管理器预览显示了 Notebook 2 在 27MM 评级的大型 MovieLens 数据帧上执行 Spark SQL 查询时代码节点上的负载。请注意,24 个 vCPUs 中只有 4 个(16.6%)正在使用,但 72 GiB (97.6%)可用内存中有 70.25%正在使用。根据 Spark 的说法,由于大多数 Spark 计算的内存性质,Spark 程序可能会受到集群中任何资源的瓶颈:CPU、网络带宽或内存。通常,如果数据适合内存,瓶颈是网络带宽。在这种情况下,内存似乎是最受限制的资源。使用内存优化的实例,比如 r4 或 r5 实例类型,对于核心节点可能比 m5 实例类型更有效。

电影镜头数据集

通过更改笔记本中的一个变量,我们可以使用最新的、更小的 GroupLens MovieLens 数据集,包含大约 100k 行(ml-latest-small)或更大的数据集,包含大约 2700 万行(ml-latest)。对于本演示,请在单节点和多节点集群上尝试这两个数据集。比较四个变量中每个变量的 Spark SQL 段落执行时间,包括 1)小数据集的单节点,2)大数据集的单节点,3)小数据集的多节点,以及 4)大数据集的多节点。观察 SQL 查询在单节点集群和多节点集群上的执行速度。尝试切换到不同的核心节点实例类型,例如 r5.2xlarge。计算时间是如何实现的?

在继续笔记本 3 之前,终止多节点 EMR 群集以节省您的费用。

aws cloudformation delete-stack --stack-name=zeppelin-emr-prod-stack

笔记本 3

第三个笔记本展示了亚马逊 EMR 和 Zeppelin 与AWS Glue数据目录的集成能力,作为 Apache Hive 兼容 metastore 用于 Spark SQL 。我们将使用 AWS Glue 数据目录和一组 AWS Glue 爬虫创建一个基于亚马逊 S3 的数据湖。

胶粘履带车

在继续使用 Notebook 3 之前,使用 AWS CLI 启动两个 Glue 爬虫。

aws glue start-crawler --name bakery-transactions-crawler
aws glue start-crawler --name movie-ratings-crawler

这两个爬行器应该在 Glue 数据目录数据库中创建总共七个表。

AWS Glue Console: Crawlers

如果我们检查 Glue 数据目录数据库,我们现在应该观察几个表,每个表对应于在 S3 桶中找到的一个数据集。每个数据集的位置显示在表视图的“位置”列中。

AWS Glue Console: Data Catalog Tables

从 Zeppelin 笔记本中,我们甚至可以使用 Spark SQL 来查询 AWS Glue 数据目录本身,以获得其数据库和其中的表。

根据亚马逊的说法,粘合数据目录表和数据库是元数据定义的容器,这些元数据定义定义了底层源数据的模式。使用 Zeppelin 的 SQL 解释器,我们可以查询数据目录的元数据并返回底层的源数据。下面的 SQL 查询示例演示了如何跨数据目录数据库中的两个表执行连接,这两个表代表两个不同的数据源,并返回结果。

笔记本 4

第四个笔记本展示了 Zeppelin 与外部数据源整合的能力。在这种情况下,我们将使用三种方法与 Amazon RDS PostgreSQL 关系数据库中的数据进行交互,包括用于 Python 的 Psycopg 2 PostgreSQL 适配器、Spark 的原生 JDBC 功能和 Zeppelin 的 JDBC 解释器。

心理战

首先,使用 Psycopg 2 PostgreSQL adapter for Python 和 SQL 文件为 RDS PostgreSQL movie ratings 数据库创建一个新的数据库模式和四个相关的表,我们之前已经将该文件复制到了 S3。

RDS 数据库的模式如下所示,近似于我们在笔记本 2 中使用的 GroupLens MovieLens 评级数据集的四个 CSV 文件的模式。

MovieLens Relational Database Schema

由于 PostgreSQL 数据库的模式与 MovieLens 数据集文件相匹配,我们可以将从 GroupLens 下载的 CVS 文件中的数据直接导入到 RDS 数据库中,再次使用PsycopgPostgreSQL adapter for Python。

火花 JDBC

根据 Spark 文档,Spark SQL 还包括一个数据源,可以使用 JDBC 从其他数据库读取数据。使用 Spark 的 JDBC 功能和我们之前安装的 PostgreSQL JDBC 驱动程序,在安装期间,我们可以使用 PySpark ( %spark.pyspark)对 RDS 数据库执行 Spark SQL 查询。下面,我们看到一个使用 Spark 读取 RDS 数据库的movies表的例子。

Zeppelin PostgreSQL 解释程序

作为查询 RDS 数据库的第三种方法,我们可以使用我们之前创建的定制 Zeppelin PostgreSQL JDBC 解释器(%postgres)。尽管 JDBC 解释器的默认驱动程序被设置为 PostgreSQL,并且相关的 JAR 包含在 Zeppelin 中,但是我们用最新的 PostgreSQL JDBC 驱动程序 JAR 覆盖了旧的 JAR。

使用%postgres解释器,我们查询 RDS 数据库的public模式,并返回我们之前在笔记本中创建的四个数据库表。

动态表单

使用笔记本段落中的%postgres解释器,我们查询 RDS 数据库并返回数据,然后使用 Zeppelin 的条形图可视化这些数据。最后,注意这个例子中 Zeppelin 动态形式的使用。动态表单允许 Zeppelin 动态地创建输入表单,然后可以通过编程使用表单的输入值。笔记本使用两个表单输入值来控制从我们的查询返回的数据和结果可视化。

结论

在这篇文章中,我们了解了 Apache Zeppelin 如何有效地与 Amazon EMR 集成。我们还学习了如何使用 AWS Glue、亚马逊 RDS 和亚马逊 S3 作为数据湖来扩展 Zeppelin 的功能。除了这篇文章中提到的,还有几十个 Zeppelin 和 EMR 特性,以及几十个与 Zeppelin 和 EMR 集成的 AWS 服务,供您探索。

本文表达的所有观点都是我个人的,不一定代表我现在或过去的雇主或他们的客户的观点。