TowardsDataScience 博客中文翻译 2020(三百九十九)

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

使用神经网络生成 Eminem 歌词

原文:https://towardsdatascience.com/generating-eminem-lyrics-using-neural-networks-96e7f9c45e8a?source=collection_archive---------28-----------------------

我如何使用递归神经网络实现歌词生成器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

阿姆途经脸书

深度学习不仅仅是对猫和狗进行分类或预测泰坦尼克号乘客是否幸存,这不是什么秘密。无论是将文本从一种语言翻译成另一种语言,同时保留语义(像人类一样),还是比以往任何时候都更准确地识别人脸,深度学习已经取得了无数奇迹。

这篇文章是使用 TensorFlow 实现 Eminem 歌词生成器(更正式地说,是无监督文本生成器)的分步指南。先来偷看一下主要内容:

内容:

  1. 递归神经网络简介
  2. 使用 RNNs 生成文本
  3. 实施
  4. 结论

递归神经网络简介

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一个典型的 RNN via Colah 的博客

在本节中,我们将对 RNNs 及其几种风格进行高度概括。

神经网络的基本操作是通过由许多嵌套加权和组成的非常复杂的数学函数将输入(自变量)映射到输出(因变量)。这很好,但对于序列或系列数据,因变量在序列或系列中任何给定点的值(通常称为时间步长)不仅是定义它的自变量的函数,也是该序列中因变量的先前值。这可以用任何特定的文本片段的例子来最好地解释,其中任何给定的单词都取决于它添加到句子以及上下文中之前的单词的含义,这给文本添加了语法意义(是的,正是我们要如何生成文本)。

这种建模是通过递归神经网络实现的。这里,输出与输入的加权和一起,还有一个来自先前输出的额外存储单元。前面提到的图表清楚地描绘了 RNN 的架构。在任何给定的时间步长,输入都经过隐藏层,其输出是通过将先前的隐藏层值与当前输出相结合来计算的。该计算值也被保存以在下一个时间步中被组合,因此是“存储元素”。

rnn 工作正常,但是有一些问题,

  • 消失梯度问题
  • 长期依赖

对这些问题的解释超出了本文的范围,但简而言之,消失梯度意味着在计算权重校正的梯度时,当我们返回时间步长时,梯度往往会减小,最终“消失”。而长期依赖性是普通(普通)RNNs 不能记住更长序列的限制。这些问题由 RNNs 的“后代”——长短期记忆网络或 LSTMs 解决。这些基本上有一个更复杂的单元,具有一个门控结构,确保保存更长的序列,并解决消失梯度问题。LSTM 的一个众所周知的特色是门控循环单元(GRU ),它是 LSTM 的一个增强,用于更快的计算。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

LSTM 通过科拉的博客

Colah 的博客是迄今为止对 RNNs 最好的解释之一(在我看来)。如果您有兴趣了解 RNNs 背后的数学原理,可以考虑阅读一下。

使用 RNNs 的文本生成

在这一节中,我们将讨论如何在我们的文本生成问题中使用 RNNs,并对实际工作原理有一个粗浅的了解。

模型的训练输入是给定歌词中的单词,目标是歌词中的下一个单词。以下是相同的图示描述:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

文本生成英尺。说唱上帝

所以,这到底是怎么回事?

众所周知,神经网络可以学习输入和输出之间的一般模式。我的意思是,当我训练一个神经网络来预测“look”的“I”和“go”的“easy”+许多不同歌曲的 RNNs 的记忆元素时,神经网络倾向于学习这些歌词中相似的模式。这种模式正是阿姆写作的方式,也就是他写歌的风格,如果你仔细观察的话,这是独一无二的(我们也有自己独特的风格)。现在,经过训练后,如果我们让模型自己预测单词,它将根据他的歌词生成由单词组成的文本,并遵循他的写歌风格(还不如放弃自己的阿姆热门歌曲谁知道呢!).这概括了模型的主要思想。

履行

我们终于开始真正的交易了。密码!

我已经手动收集了阿姆的 15 首歌曲到文本文件中,我们认为每首歌曲都是一个单独的训练样本

首先,我们读取文件并清理数据,使其能够被模型处理:

歌词的最小预处理

正如上一节所解释的,我们训练模型来预测歌词中的下一个词,给定前一个词和最近的一些上下文。有两种方法可以实现这一点:

  1. 取歌曲的第一个词,获得输出,计算预测的损失,使用该预测来预测下一个词,等等。在这种方法中,如果第一个预测的字不正确,那么丢失将导致大量丢失值的级联,因为输入远远不正确。
  2. 取歌曲的第一个词,获得输出,计算预测的损失,在下一个时间步,我们不使用预测的词作为输入,而是使用实际的词作为输入。这确保了没有级联损失,并且每个时间步长的损失是相互独立的。这种方法被称为**‘老师强迫’。**

为了更好更快的收敛,我们将继续进行教师强制。为此,我们将原始歌词作为输入,并将原始歌词的偏移量 1 作为目标。这意味着,如果输入是“看,我要去”,那么目标将是“我要去容易”(偏移 1)。

分离输入和输出

接下来,我们将执行一般的 NLP 步骤,以确保我们对模型的输入是数字。我们将单词标记为整数,然后将序列填充或截断为固定长度,因为模型的所有输入都应该是固定长度的。

标记化和填充

作为一个可行性工具,我们有一个词汇表,可以在令牌和相应的单词之间互换。此外,我们定义了一些常量,可以根据型号和硬件资源的可用性进行调整(我已经考虑了最小值)。

词汇和其他超参数

现在,我们将最终建立模型

训练文本生成器的最简模式

我已经训练了一个极简模型来展示这个概念,它可能会根据要求进行调整。模型调优再次超出了本文的范围。然而,我将描述基本组件。

  • 稀疏分类交叉熵损失 可以与具有一个热编码输出序列的分类交叉熵互换使用(在这种情况下,这将是一个巨大的数组,因此计算量大)。

关于 tensorflow 预定义损失的更多信息:https://www.tensorflow.org/api_docs/python/tf/keras/losses

关于损失函数的更多信息:https://towardsdatascience . com/common-loss-functions-in-machine-learning-46 af 0 ffc 4d 23

  • 亚当 优化器 增加收敛速度。

更多关于 tensorflow 优化器:https://www . tensor flow . org/API _ docs/python/TF/keras/optimizer

关于亚当优化器的更多信息:【https://arxiv.org/abs/1412.6980

更多关于优化者的一般信息:【https://ruder.io/optimizing-gradient-descent/

以下是模型培训中的一些冗长内容:

Epoch 45/50
1/1 [==============================] - 0s 2ms/step - loss: 0.0386
Epoch 46/50
1/1 [==============================] - 0s 1ms/step - loss: 0.0381
Epoch 47/50
1/1 [==============================] - 0s 1ms/step - loss: 0.0375
Epoch 48/50
1/1 [==============================] - 0s 2ms/step - loss: 0.0369
Epoch 49/50
1/1 [==============================] - 0s 6ms/step - loss: 0.0364
Epoch 50/50
1/1 [==============================] - 0s 2ms/step - loss: 0.0359

对于极简主义者来说相当不错!现在让我们测试结果。

由于我们已经使用教师强制进行训练,对于未知输出的预测,我们需要使用第一种方法,因为我们不知道“实际”输出,我们所拥有的只是下一个预测的单词。我们称之为“推理步骤”。

推理步骤,“无需”教师强迫

将“slim”作为输入传递给生成器,我得到了以下输出:

shady is alright because i am frozen would know sometimes things have tried ideas gonna stand upi am frozen would know sometimes things have tried ideas gonna stand upi am frozen would know sometimes things have tried ideas gonna stand up

结论

正如我前面提到的,这个模型是用最少的参数和 15 首歌来训练的。一个模型很有可能用如此少量的数据过度拟合,并且它显示;一些短语被重复多次。这可以通过适当的调优和更大的数据语料库来解决。

这篇文章的主要内容是文本生成的概念。该模型是通用的,并且可以在任何类型的语料库(比如一本书)上被训练,以生成期望流派或模式的文本。

这里的是指向 github 代码库的链接。随意分叉它,微调模型,训练更多的数据,提出拉请求(如果可以的话)。

参考

  1. https://colah.github.io/posts/2015-08-Understanding-LSTMs/
  2. https://www.tensorflow.org/api_docs/python/tf/keras
  3. https://ruder.io/optimizing-gradient-descent/
  4. https://arxiv.org/abs/1412.6980

我为数据科学制作了 1000 多份假的约会资料

原文:https://towardsdatascience.com/generating-fake-dating-profiles-for-data-science-cd3b929972bc?source=collection_archive---------15-----------------------

我如何使用 Python Web Scraping 创建约会档案

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Yogas 设计Unsplash 上拍摄的照片

D ata 是世界上最新、最珍贵的资源之一。公司收集的大部分数据都是私有的,很少与公众分享。这些数据可能包括一个人的浏览习惯、财务信息或密码。对于 Tinder 或 Hinge 等专注于约会的公司来说,这些数据包含用户的个人信息,他们自愿在约会档案中披露这些信息。因为这个简单的事实,这些信息是保密的,公众无法访问。

但是,如果我们想创建一个使用这些特定数据的项目,该怎么办呢?如果我们想创建一个使用机器学习和人工智能的新约会应用程序,我们需要大量属于这些公司的数据。但是可以理解的是,这些公司将用户数据保密,远离公众。那么我们如何完成这样的任务呢?

嗯,基于交友档案中缺乏用户信息,我们需要为交友档案生成虚假的用户信息。我们需要这些伪造的数据,以便尝试将机器学习用于我们的约会应用。这个应用程序的想法起源可以在以前的文章中读到:

[## 可以用机器学习来寻找爱情吗?

medium.com](https://medium.com/@marcosan93/applying-machine-learning-to-find-love-3558dafcc4a1)

前一篇文章讨论了我们潜在的约会应用程序的布局或格式。我们将使用一种叫做 K-Means 聚类 的机器学习算法,根据他们对几个类别的回答或选择,对每个约会档案进行聚类。此外,我们会考虑他们在简历中提到的另一个因素,这也是对个人资料进行聚类的一个因素。这种形式背后的理论是,一般来说,人们更容易与拥有相同信仰(政治、宗教)和兴趣(体育、电影等)的人相处。)。

有了约会应用的想法,我们可以开始收集或伪造我们的假资料数据,以输入我们的机器学习算法。如果以前已经创建了类似的东西,那么至少我们会学到一些关于自然语言处理( NLP )和 K-Means 聚类中的无监督学习的知识。

伪造假档案

我们需要做的第一件事是找到一种方法来为每个用户配置文件创建一个假的个人资料。没有可行的方法可以在合理的时间内编写成千上万的假 bios。为了构建这些假的 bios,我们将需要依靠第三方网站来为我们生成假的 bios。有很多网站会为我们生成虚假的个人资料。然而,我们不会显示我们选择的网站,因为我们将实施网络抓取技术。

使用 BeautifulSoup

我们将使用 BeautifulSoup 来浏览假的生物发生器网站,以便抓取生成的多个不同的 bios,并将它们存储到熊猫数据帧中。这将使我们能够多次刷新页面,以便为我们的约会档案生成必要数量的假 bios。

我们做的第一件事是导入所有必要的库来运行我们的 web-scraper。我们将解释 BeautifulSoup 正常运行的特殊库包,例如:

  • 允许我们访问我们需要抓取的网页。
  • 为了在网页刷新之间等待,需要使用time
  • tqdm只是为了我们的缘故才需要作为装货港。
  • bs4需要使用 BeautifulSoup。

抓取网页

代码的下一部分涉及为用户 bios 抓取网页。我们首先创建一个从 0.8 到 1.8 的数字列表。这些数字表示我们在两次请求之间等待刷新页面的秒数。我们创建的下一个东西是一个空列表,用于存储我们将从页面中抓取的所有 bios。

接下来,我们创建一个将刷新页面 1000 次的循环,以生成我们想要的 bios 数量(大约 5000 个不同的 bios)。这个循环被tqdm所环绕,以创建一个加载或进度条来显示我们还剩多少时间来完成这个站点的抓取。

在循环中,我们使用requests来访问网页并检索其内容。使用try语句是因为有时用requests刷新网页不会返回任何结果,并且会导致代码失败。在那些情况下,我们将简单地pass到下一个循环。try 语句中是我们实际获取 bios 并将它们添加到我们之前实例化的空列表中的地方。在当前页面中收集了 bios 之后,我们使用time.sleep(random.choice(seq))来决定要等多久才能开始下一个循环。这样做是为了使我们的刷新基于从我们的数字列表中随机选择的时间间隔而被随机化。

一旦我们从网站上获得了所有需要的 bios,我们将把 bios 列表转换成熊猫数据框架。

为其他类别生成数据

为了完成我们的假约会档案,我们需要填写宗教、政治、电影、电视节目等其他类别。下一部分非常简单,因为它不需要我们从网上抓取任何东西。本质上,我们将生成一个随机数列表,应用于每个类别。

我们要做的第一件事是为我们的约会档案建立分类。这些类别然后被存储到一个列表中,然后被转换成另一个熊猫数据帧。接下来,我们将遍历我们创建的每个新列,并使用numpy为每行生成一个从 0 到 9 的随机数。行数由我们在之前的数据帧中能够检索到的 bios 数量决定。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

包含每个假约会简介的个人资料和类别的数据框架

一旦我们有了每个类别的随机数,我们就可以将生物数据框架和类别数据框架连接在一起,以完成我们的假约会资料的数据。最后,我们可以将最终的数据帧导出为一个.pkl文件,以备后用。

走向

现在我们已经有了我们的假约会档案的所有数据,我们可以开始探索我们刚刚创建的数据集。使用 NLP ( 自然语言处理),我们将能够深入了解每个约会档案的 bios。在对数据进行了一些探索之后,我们实际上可以开始使用 K-Mean 聚类进行建模,以将每个配置文件相互匹配。请关注下一篇文章,它将讨论如何使用 NLP 来探索 bios 以及 K-Means 集群。

[## 我在约会档案上使用了机器学习 NLP

medium.com](https://medium.com/swlh/using-nlp-machine-learning-on-dating-profiles-1d9328484e85)

资源

[## Marcos an 93/人工智能媒婆

github.com](https://github.com/marcosan93/AI-Matchmaker) [## 可以用机器学习来寻找爱情吗?

medium.com](https://medium.com/@marcosan93/applying-machine-learning-to-find-love-3558dafcc4a1)

用混合器和动画节点生成分形

原文:https://towardsdatascience.com/generating-fractals-with-blender-and-animation-nodes-3ae79d02bf40?source=collection_archive---------11-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这是一个使用 Blender 生成分形视觉效果的教程、例子和资源的集合。我将涵盖递归、n-flakes、L-系统、Mandelbrot/Julia 集和导子等主题。

**为什么:**如果你对分形图案着迷,对 Blender 中的过程化生成感兴趣,想对动画-节点和着色器节点有更好的理解和动手体验。

**谁:**此处所有内容均基于 Blender 2.8.2 和动画-节点 v2.1 。我还依赖了一些简短的代码片段(Python ≥ 3.6)。

分形

“美丽复杂,却又如此简单”

分形是具有分形维数的形状。这源于我们在它们扩展时测量它们的方式。理论分形在不同的尺度上是无限自相似的。

对于我们的设置,我们不关心纯理论分形,因为除非在非常特殊的情况下,否则在 Blender 中是无法实现的。我们最关心的是精细结构(不同尺度的细节)和自相似的自然外观(由明显更小的自身副本组成)。

了解分形更多信息的其他建议资源:

n-薄片

n-flake(或 polyflake) 是一种分形,通过用自身的多个缩放副本替换初始形状来构建,通常放置在对应于顶点和中心的位置。然后对每个新形状递归重复该过程。

递归

这是我们探索分形的一个很好的起点,因为它允许我们通过一个简单的动画节点设置来涵盖递归和其他重要概念。

这就引出了我们的主要问题:动画节点(目前)不支持纯递归。我们需要一些变通办法。一种选择是始终依赖纯 Python 脚本,正如我在上一篇文章中解释的那样,但我希望这篇文章的重点更多地放在动画节点上,所以我们可以做的是通过迭代和循环队列来近似递归。

这个想法是依靠循环输入 重新分配选项来保存一个结果队列,我们可以在下一次迭代中处理这些结果。

让我们考虑正多边形的 n 片情况。给定若干线段n(多边形的边数)、半径r和中心c,我们计算以c为中心、半径rn-多边形的点。对于每个新计算的点p,我们重复这个过程(即,找到以p为中心的多边形),但是通过一些预定义的因子调整半径r

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

n 多边形动画-实际的节点设置

所有主要的逻辑都在下面的循环中,它负责计算多边形点和新的半径,并重新分配它,以便下一次迭代可以处理它们。理解这一部分是很重要的:在第一次迭代中,循环处理给予Invoke Subprogram节点的任何东西,而对于所有后续的迭代,循环将处理它在前一次迭代中更新的值。每次这些都被清理,这就是为什么我们维护两个队列(centers_queueall_centers),前者是我们还没有处理的中心,后者是到目前为止计算的所有中心的集合,它将被用作输出来创建我们的样条列表。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

带有缩放和重新分配逻辑的主循环

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这两个子程序都是 Python 脚本。这些例子让我觉得编码更简洁,不需要翻译成纯粹的节点。

计算正多边形的点:

points = []
# compute regular polygon points for each given center
for center in centers:
    angle = 2*pi/segments  # angle in radians
    for i in range(segments):
        x = center[0] + radius*cos(angle*i)
        y = center[1] + radius*sin(angle*i)
        z = center[2]  # constant z values
        points.append((x, y, z))
    #points.append(points[-segments])  #  close the loop

获取比例因子:

from math import cos, pi# compute scale factor for any n-flake
# [https://en.wikipedia.org/wiki/N-flake](https://en.wikipedia.org/wiki/N-flake)
cumulative = 0
for i in range(0, segments//4):
    cumulative += cos(2*pi*(i+1) / segments)
scale_factor = 1 / (2*(1 + cumulative))

额外的循环设置是分割点,以便将每个多边形转化为单独的样条线。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

转向 3D 规则多面体

我们可以很容易地调整这种设置来处理常规的固体。这一次,我们不是自己计算形状顶点,而是依赖于场景中已经存在的对象,获取它的顶点并递归地变换它们。我们利用矩阵属性和Compose Matrix节点来最小化所需的工作量或节点。这是设置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Out matrix_queue用恒等式变换矩阵(无平移、无旋转和单位比例)初始化,而我们的transformation列表是我们的目标/输入对象顶点位置,由任意比例因子组成,当用于变换另一个矩阵时,这相当于说“在那里移动一切,并按给定因子缩放”。
这里是执行转换循环和重新分配操作的改编递归部分。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

柏拉图立体的示例结果(介于四次和五次迭代之间)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我讨厌二十面体

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

然后,可以更新原始平移矩阵,使得新实体不精确地放置在前身顶点上,而是放置在穿过前身中心和新顶点的线的任何点上,如侧面动画中所示。

虽然之前的转换矩阵仅仅是顶点的位置,但是我们现在做了一些矢量数学来将这些点从原始位置转移。如果我们从它们中减去物体中心,我们就得到感兴趣的方向向量。然后,我们可以将它除以任意值,以相应地放置新的递归实体。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

如果我们只实例化最后一次迭代的对象,我们会得到正确的柏拉图立体分形。众所周知的例子是 Sierpinski 四面体和 Menger 海绵。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Eevee 中渲染的示例,增加了布尔运算符以增加趣味性

要尝试的事情

  • 在递归步骤中任意/随机更改 polyflake 类型
  • 使用置换贴图来模拟额外的递归步骤,而无需创建更精细的额外几何体
  • 体积和纯着色器节点设置

l 系统

一个 L-系统(或林登迈耶系统)是一个文法;指定如何通过一组规则、字母表和初始公理生成文本字符串的东西。它伴随着将这种字符串转换成几何图形的转换机制。

我们对 L 系统感兴趣,因为它们可以用来生成自相似分形,也因为我们可以通过LSystem节点免费获得它们。这里是一个将结果实例化为 object 的示例设置。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

边上的是由公理X(初始状态)和两条规则X=F[+X][-X]FXF=FF定义的分形图形。节点负责使系统进化到指定的代数,这可以是很好的分数,允许平滑过渡。它还将文本结果转换为网格。由于这个原因,你必须遵循公理和字母用法的特定惯例。

另一个需要考虑的重要参数是高级节点设置中的Symbol Limit,它指定了生成的字符串的最大长度。如果超过这个限制,系统将抛出一个错误。

例子

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

龙曲线,分形植物,sierpinski 三角形

dragon curve - axiom: FX, rules: (X=X+YF, Y=-FX-Y), angle: 90fractal plant - axiom: F, rules: (F=FF-[-F+F+F]+[+F-F-F]), angle: 22.5sierpinski triangle - axiom: F-F1-F1, rules: (X=X+YF, Y=-FX-Y), angle: 120

要尝试的事情

  • 3D L 系统(例如方位角+倾斜度)和随机 L 系统。(见 Python 代码)
  • 步长规则,与增长成比例,这样视图可以在增加代数时保持不变

曼德尔布罗特

作为分形之父,最常见和最频繁展示的分形以他的名字命名也就不足为奇了。Mandelbrot 集合与 Julia 集合一起为一种现象提供了理论基础,这种现象也是由简单的规则定义的,但能够产生一幅美丽和复杂的无限画面。

我们可以把这些集合看作是“用坐标形式表示的函数的迭代”,其中我们处理的是复数的平面。Jeremy Behreandt 的这篇文章提供了关于复数、Mandelbrot 集合和更多内容的令人印象深刻的详细介绍,所有这些都包含在 Blender 的 Python API 和开放着色语言(OSL)中。

我们完全可以在 Blender 节点中实现类似的结果(没有脚本),但是像往常一样,我们受到设置中缺少的迭代/递归功能的限制。基本思想是围绕复数平面移动,如公式所示

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

根据每个点收敛到无穷大的速度给每个点着色。这里z是我们的起点,c可以是任意选择的复数。该公式可以用纯笛卡尔平面坐标形式改写为

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这里我们现在用(x,y)作为我们的点,用ab作为我们的控制值(之前c的实部和虚部)。
这里是着色器节点设置中公式的翻译

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

坐标形式函数的节点设置

iterations_count 部分用于跟踪有效的迭代,那些点没有分叉的迭代。出于实用目的,这可以通过检查向量幅度是否小于 2 来近似计算。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Mandelbrot 集合的设置

然后我们可以插入我们的纹理坐标,通过分离xy如图所示。为ab重用它们给了我们 Mandebrot 集合,或者我们可以传递自定义值来探索其他集合和结果。现在是丑陋的部分:我们必须通过非常不优雅的复制粘贴混乱来近似函数迭代,对我来说最终看起来像这样。100 次迭代是提供良好结果的合理估计,你添加的越多,你得到的细节就越多,但是设置会很快变得很慢。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

是…

但至少我们现在有东西可以玩了

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

曼德尔布尔

Mandelbulb 是 Mandelbrot 集合的 3D 投影。另外已经有一个很棒的教程Jonas Dichelle 编写,解释了如何在 Blender nodes 和 Eevee 中模拟 Mandelbulb。鉴于这种方法依赖于体积学,也值得参考一下 Gleb Alexandrov 在 Blender 会议上关于 3D 星云的演讲。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

玩弄公式和颜色

结论

我总是被那些从简单规则中展现出复杂性的现象所吸引,而将它们可视化的能力让这一切变得更加有趣。Blender 只是让它变得如此简单,而 animation-nodes 只是已经存在的一组令人惊叹的工具/实用程序的又一个补充,特别是从过程的角度来看。

我承认远离纯粹的编码对我来说有点可怕,就像一种发自内心的感觉,我没有做正确的事情,但是从迭代和实验的角度来看,毫无疑问我可以通过使用节点来实现效率。我仍然相信一些部分更适合作为单独的脚本,并且人们应该总是首先用代码构建/理解基础,因为它为复杂性分解和组织以及解决问题的一般化提供了更好的框架。

我计划探索更多类似的主题,完善理论理解和实践能力,以令人信服的方式再现它们。

具体来说,这些是当前最热门的条目:

  • 超越三维
  • 元胞自动机
  • 形态发生
  • 反应扩散
  • 奇怪的吸引子
  • 棋盘形布置
  • 本轮

我欢迎任何建议、批评和反馈。

你可以在 Instagram 上看到更多我“润色”的图形结果,在 Twitter 上阅读更多技术/故障解释,在 Github 上试用我的代码。

使用 LSTMs 和混合密度网络生成手写序列

原文:https://towardsdatascience.com/generating-handwritten-sequences-using-lstms-and-mixed-density-networks-c3a2b4a65539?source=collection_archive---------16-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由于每个人都在年初提出了一个解决方案,所以我会尽量少在博客上发帖😀。已经过去一个多月了,我想在这里分享一些话😀。在这篇博客中,我们将讨论一篇由 Alex Graves(DeepMind)提出的关于用递归神经网络生成序列的有趣论文。我还将使用 Tensorflow 和 Keras 来实现这篇论文。

问题定义

这里的数据集是手写笔画的数学表示形式。所以笔画序列中的一个点是一个长度=3 的向量。第一个值是一个二进制数字,表示笔是否在该点上升起。第二个值是 x 坐标相对于序列中前一个 x 值的偏移量,同样,第三个值是 y 坐标的偏移量。问题是,给定数据集,我们需要一个可以无条件生成手写笔画的模型(通过给定一个种子值随机生成,就像 GANs 一样)。

混合密度网络

在进入实现部分之前,我想讨论一种特殊的网络,称为 MDNs 或混合密度网络。监督问题的目标是对要素和标注的生成器或联合概率分布进行建模。但是在大多数情况下,这些分布被认为是时不变的,例如在图像或文本分类的情况下。但是,当概率分布本身不稳定时,比如手写笔画或汽车的路径坐标,正常的神经网络在这种情况下表现很差。混合密度网络假设数据集是各种分布的混合物,并倾向于学习这些分布的统计参数,从而获得更好的性能。迷茫?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:https://media1.giphy.com/media/3o7btPCcdNniyf0ArS/giphy.gif

好吧,好吧,我们会进入更多的细节。

让我们举一个下图所示的例子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:https://cedar . buffalo . edu/~ Sri Hari/CSE 574/chap 5/chap 5.6-mixdensitynetworks . pdf

在第一张图中,给定θ1 和θ2,当被问及预测机械臂的位置时,我们有一个独特的解决方案。现在看第二个图,问题反过来了。给定 x1 和 x2,当被问及预测θ参数时,我们得到两个解。在大多数情况下,我们会遇到像第一张图这样的问题,其中数据分布可以被假设为来自单个高斯分布。而对于像第二幅图这样的情况,如果我们使用传统的神经网络,它的性能不会下降。我很快会告诉你为什么。

这并不是说具有均方损失或交叉熵损失的神经网络不考虑(混合分布)的事情。它考虑了这一点,但给出了一个结果分布,它是所有这些混合物的平均值,这篇论文建议我们不需要平均值,而是最可能的混合物成分来模拟统计参数。因此 MDN 进入了画面。

它看起来怎么样?

因此,MDN 只不过是一个预测统计参数的神经网络,而不是预测回归问题的类或值的概率。让我们假设数据是 M 正态分布的混合物,因此最终预测将是混合物的 M 概率权重、 M 平均值和 M 方差。取样时,我们取最可能的混合物成分的参数。我们将在后面详细讨论其结构和实现。

长短期记忆网络

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:https://i.stack.imgur.com/SjiQE.png

虽然这不是什么新鲜事,但我可能会遇到一些新人。因此,我将在这里给出一个关于 LSTMs 的基本概念。因此,LSTMs 只不过是一种特殊的神经网络,具有三个门,分别是输入门、遗忘门和输出门。LSTM 细胞中最重要的东西是它的记忆——如上图所示。

**遗忘门:**一个 LSTM 细胞会输出隐藏状态和本细胞的记忆,反馈给它旁边的细胞。一个遗忘门决定了从前一个存储器传入当前单元的信息量。它基本上采用以前的输出和当前的输入,并输出一个遗忘概率。

**输入门:**它接受与遗忘门相同的输入,并输出一个概率,该概率决定了有助于记忆的单元状态的信息量。

**输出门:**它再次接受与上述相同的输入,并给出一个概率,该概率预测决定要传递给下一个单元的信息量的概率。

LSTMs 非常擅长处理顺序输入,如前面讨论的文本、时间序列数据集或笔画数据集,并为样本数据序列提供健壮的特征向量。Alex Graves 因此建议将它们用于手写笔画,以找到笔画序列的特征向量,然后将该特征向量馈送到 MDN 网络,以找到统计参数,如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我希望我们现在可以进入实施阶段了。我将使用 Keras 来创建网络,并在其后端使用 Tensorflow 来定义损失函数。

假设 x 和 y 点偏移遵循二元正态分布的混合,笔抬起遵循伯努利分布(很明显,对吗?).我将使用两个二元正态分布的混合来演示解决方案,伯努利分布可以用一个概率值来表示,对吗?

哦!我忘了告诉你损失函数。它由下面给出的等式定义:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中,π是混合物成分的概率,e 是确定伯努利分布参数的冲程终点的概率。

现在让我们完成我们被雇来的任务😮….🤫….😃代码代码代码:

输入将是 3 个长度向量的序列,每个点的输出是笔画序列中的下一个点,如下图所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:https://image . slidesharecdn . com/rnne Rica-180423124525/95/rnn-and-its-applications-31-638 . jpg?cb=1524487703

车型(LSTM + MDN)

import numpy **as** np
import numpy
import tensorflow **as** tf
import tensorflow.keras **as** keras
import tensorflow.keras.backend **as** K
import keras.layers.Input **as** Input
import keras.layers.LSTM **as** LSTM
from tensorflow.keras.models import Model

*# nout = 1 eos + 2 mixture weights + 2*2 means \
# + 2*2 variances + 2 correlations for bivariates* 
**def** **build_model**(ninp**=**3, nmix**=**2):
    inp **=** Input(shape**=**(None, ninp), dtype**=**'float32')
    l,h,c **=** LSTM(400, return_sequences**=**True, \
    return_state**=**True)(inp)
    l1 ,_,_**=** LSTM(400, return_sequences**=**True, \
    return_state**=**True)(l, initial_state**=**[h,c])

    output **=** keras**.**layers**.**Dense(nmix*****6 **+** 1)(l1)
    model **=** Model(inp,output)

    **return** model

损失函数

**def** **seqloss**():
    **def** **pdf**(x1, x2, mu1, mu2, s1, s2,rho):
        norm1 **=** tf**.**subtract(x1, mu1)
        norm2 **=** tf**.**subtract(x2, mu2)
        s1s2 **=** tf**.**multiply(s1, s2)
        z **=** tf**.**square(tf**.**div(norm1, s1)) **+** \
            tf**.**square(tf**.**div(norm2, s2)) **-** \
            2 ***** tf**.**div(tf**.**multiply(rho, tf**.**multiply(norm1, norm2)), s1s2)
        negRho **=** 1 **-** tf**.**square(rho)
        result **=** tf**.**exp(tf**.**div(**-**z, 2 ***** negRho))
        denom **=** 2 ***** np**.**pi ***** tf**.**multiply(s1s2, tf**.**sqrt(negRho))
        result **=** tf**.**div(result, denom)
        **return** result

    **def** **loss**(y_true, pred):

        prob **=** K**.**sigmoid(pred[0][:,0]); pi **=** K**.**softmax(pred[0][:,1:3])

        x **=** y_true[0][:,1]; y **=** y_true[0][:,2]; penlifts **=** y_true[0][:,0]

        m11 **=** K**.**sigmoid(pred[0][:,3]); m12 **=** K**.**sigmoid(pred[0][:,4])
        s11**=** K**.**exp(pred[0][:,5]); s12 **=** K**.**exp(pred[0][:,6])
        rho1 **=** K**.**tanh(pred[0][:,7])
        pdf1 **=** tf**.**maximum(tf**.**multiply(pdf(x, y, m11, m12, s11, s12, rho1),pi[:,0]), K**.**epsilon())

        **for** i **in** range(1,2):
            m11 **=** K**.**sigmoid(pred[0][:,3**+**5*****i]); m12 **=** K**.**sigmoid(pred[0][:,4**+**5*****i])
            s11 **=** K**.**exp(pred[0][:,5**+**5*****i]); s12 **=** K**.**exp(pred[0][:,6**+**5*****i])
            rho1 **=** K**.**tanh(pred[0][:,7**+**5*****i])
            pdf1 **+=** tf**.**maximum(tf**.**multiply(pdf(x, y, m11, m12, s11, s12, rho1),pi[:,i]), K**.**epsilon())

        loss1 **=** tf**.**math**.**reduce_sum(**-**tf**.**log(pdf1))
        pos **=** tf**.**multiply(prob, penlifts)
        neg **=** tf**.**multiply(1**-**prob, 1**-**penlifts)
        loss2 **=** tf**.**math**.**reduce_mean(**-**tf**.**log(pos**+**neg))
        final_loss **=** loss1**+**loss2

        **return** final_loss

    **return** loss

我在一个小的笔画数据集上随机训练了 2 个时期的模型,因为笔画的长度是变化的。我得到的结果如下所示:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我认为,如果你增加混合、数据集和时期的数量,你会得到更好的结果。我希望我的博客是一个愉快的阅读,如果你有任何疑问或建议,请联系我。

参考

  1. 【https://arxiv.org/abs/1308.0850
  2. https://cedar . buffalo . edu/~ Sri Hari/CSE 574/chap 5/chap 5.6-mixdensitynetworks . pdf
  3. https://github.com/Grzego/handwriting-generation

生成图像分割蒙版——简单的方法

原文:https://towardsdatascience.com/generating-image-segmentation-masks-the-easy-way-dd4d3656dbd1?source=collection_archive---------1-----------------------

…不到 5 分钟

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

米歇尔·胡贝尔在 Unsplash 上拍摄的图片。作者编辑

如果你正在读这篇文章,那么你可能知道你在寻找什么🤷。所以我就开门见山了,假设你熟悉图像分割是什么意思,语义分割和实例分割的区别,以及 U-Net、Mask R-CNN 等不同的分割模型。如果没有,我强烈推荐阅读这篇关于分析的优秀文章 Vidhya,全面介绍这个主题,最后用一个例子完成使用 Mask R-CNN。

大多数在线图像分割教程使用预处理和标记的数据集,并生成地面真实图像和掩膜。在实际项目中,当您想要处理类似的任务时,几乎不会出现这种情况。我也面临过同样的问题,在一个实例分割项目中,我花了无数个小时试图找到一个足够简单和完整的例子。我不能,因此决定写自己的:)

下面是我们将在本文中做的事情的一个简单的可视化:)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

VGG 图像注释器(VIA)

VIA 是一个非常轻量级的注释器,支持图像和视频。可以通过项目首页了解更多。使用 VIA 时,您有两种选择:V2 或 V3。我会试着解释下面的区别:

  1. V2 要老得多,但足以完成基本任务,而且界面简单
  2. 与 V2 不同,V3 支持视频和音频注释器
  3. 如果您的目标是使用 JSON 和 CSV 等多种导出选项进行图像分割,那么 V2 是更好的选择
  4. V2 项目与 V3 项目不兼容

在这篇文章中,我将使用 V2。你可以在这里下载需要的文件。或者,如果您想通过在线试用,您可以在这里进行

操作方法

我将使用 ka gglenucleus 数据集并注释其中一幅测试图像,以生成分割蒙版。充分披露,我是而不是认证的医学专家,我做的注释只是为了这篇文章。您也可以快速调整该过程以适应其他类型的对象。

根文件夹树如下所示。via.html是我们将用来注释图像的文件。它位于上面提供的 VIA V2 ZIP 下载链接中。将所有要添加注释的图片放在images文件夹中。maskGen.py是一个将注释转换成遮罩的脚本。

├── images
│   └── test_image.png
├── maskGen.py
└── via.html

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图一。作者图片

1.打开 via.html:会在你默认的浏览器中打开。在区域形状下,选择折线工具(最后一个选项)并给你的项目命名。然后点击添加文件并选择您想要添加注释的所有图像。此时,您的屏幕应该如图 1 所示。

2.开始标注:点击一个对象的边框,在对象周围画一个多边形。你可以通过按回车来完成多边形,或者如果你犯了一个错误,按退格键。对所有对象重复此操作。完成后,您的屏幕应该如图 2 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图二。作者图片

3.导出注释:完成后,点击顶部的注释选项卡,选择*导出注释(作为 JSON)。*一个 JSON 文件将被保存到您的设备中。按照上面给出的树,找到这个文件并将其转移到根文件夹。

4.生成遮罩:现在,你的根文件夹应该看起来像这样。

├── images
│   └── test_image.png
├── maskGen_json.json
├── maskGen.py
└── via.html

maskGen.py给出了下面的大意。它读取 JSON 文件,记住每个遮罩对象的多边形坐标,生成遮罩,并将其保存在中。png 格式。对于images文件夹中的每个图像,脚本会以该图像的名称创建一个新文件夹,该文件夹包含原始图像和生成的遮罩文件的子文件夹。确保将 json_path 变量更新为您的 json 文件名,并设置遮罩高度和宽度。几个生成的掩码显示在要点之后。

如果你做的一切都是正确的,你的根文件夹树应该看起来像这样。每个mask文件夹中的文件数量对应于你在地面真实图像中标注的对象数量。

├── images
│   └── test_image
│       ├── images
│       │   └── test_image.png
│       └── masks
│           ├── test_image_10.png
│           ├── test_image_11.png
│           ├── test_image_12.png
│           ├── test_image_13.png
│           ├── test_image_14.png
│           ├── test_image_15.png
│           ├── test_image_1.png
│           ├── test_image_2.png
│           ├── test_image_3.png
│           ├── test_image_4.png
│           ├── test_image_5.png
│           ├── test_image_6.png
│           ├── test_image_7.png
│           ├── test_image_8.png
│           └── test_image_9.png
├── maskGen_json.json
├── maskGen.py
└── via.html 

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一些最终的分割蒙版。作者图片

结论

我希望这篇文章对你的项目有所帮助。请联系我们寻求任何建议/澄清:)

你可以通过以下方式联系我:邮箱LinkedInGitHub

[## 印度口音的自动语音识别

谷歌语音识别 API 的最佳开源替代方案——现在是第二大英语国家……

towardsdatascience.com](/automatic-speech-recognition-for-the-indian-accent-91bb011ad169) [## 使用 Mozilla DeepSpeech 自动生成字幕

对于那些嘴里薯条的噪音让你无法看电影的时候:)

towardsdatascience.com](/generating-subtitles-automatically-using-mozilla-deepspeech-562c633936a7)

用可变自动编码器生成新的人脸

原文:https://towardsdatascience.com/generating-new-faces-with-variational-autoencoders-d13cfcb5f0a8?source=collection_archive---------6-----------------------

一个关于使用可变自动编码器生成新面的综合教程。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 Vidushi RajputUnsplash 拍摄

介绍

深度生成模型在行业和学术研究中都获得了极大的欢迎。计算机程序生成新的人类面孔或新的动物的想法是非常令人兴奋的。与我们很快将讨论的监督学习相比,深度生成模型采用了一种稍微不同的方法。

本教程涵盖了使用可变自动编码器的生成式深度学习的基础知识。我假设你相当熟悉卷积神经网络和表示学习的概念。如果没有,我会推荐观看安德烈·卡帕西的 CS231n 演讲视频,因为在我看来,它们是在互联网上学习 CNN 的最佳资源。你也可以在这里找到课程的课堂讲稿。

这个例子演示了使用 Keras 生成新脸来构建和训练 VAE 的过程。我们将使用来自 Kaggle 的名人面孔属性(CelebA)数据集Google Colab 来训练 VAE 模型。

生成模型

如果你开始探索生成性深度学习领域,一个变化的自动编码器(VAE)是开启你旅程的理想选择。VAE 的建筑很直观,也很容易理解。与诸如 CNN 分类器的判别模型相反,生成模型试图学习数据的基本分布,而不是将数据分类到许多类别中的一个。一个训练有素的 CNN 分类器在区分汽车和房子的图像时会非常准确。然而,这并没有实现我们生成汽车和房屋图像的目标。

判别模型学习从数据中捕捉有用的信息,并利用该信息将新数据点分类为两个或更多类别中的一个。从概率的角度来看,判别模型估计概率𝑝(𝑦|𝑥,其中𝑦是类别或级别,𝑥是数据点。它估计数据点𝑥属于𝑦.类别的概率例如,图像是汽车或房子的概率。

生成模型学习解释数据如何生成的数据的底层分布。本质上,它模拟了底层分布,并允许我们从中取样以生成新数据。它可以被定义为估计概率𝑝(𝑥),其中𝑥是数据点。它估计在分布中观察到数据点𝑥的概率。

简单自动编码器

在深入研究变型自动编码器之前,分析一个简单的自动编码器是至关重要的。

一个简单或普通的自动编码器由两个神经网络组成——一个编码器和一个解码器。编码器负责将图像转换成紧凑的低维向量(或潜在向量)。这个潜在向量是图像的压缩表示。因此,编码器将输入从高维输入空间映射到低维潜在空间。这类似于 CNN 分类器。在 CNN 分类器中,这个潜在向量将随后被送入 softmax 层,以计算各个类别的概率。然而,在自动编码器中,这个潜在向量被送入解码器。解码器是一个不同的神经网络,它试图重建图像,从而从较低维度的潜在空间映射到较高维度的输出空间。编码器和解码器执行完全相反的映射,如图 img-1 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

img-1(资料来源:en.wikipedia.org/wiki/Autoencoder)

考虑下面的类比来更好地理解这一点。想象你正在和你的朋友通过电话玩游戏。游戏规则很简单。你会看到许多不同的圆柱体。你的任务是向你的朋友描述这些圆柱体,然后他将尝试用粘土模型重新制作它们。禁止您发送图片。你将如何传达这一信息?

因为任何圆柱体都可以用两个参数来构造——高度和直径,所以最有效的策略是估计这两个尺寸,并把它们传达给你的朋友。你的朋友收到这个信息后,就可以重建圆筒。在这个例子中,很明显,你通过将视觉信息压缩成两个量来执行编码器的功能。相反,你的朋友正在执行一个解码器的功能,利用这个浓缩的信息来重建圆筒。

家政

下载数据集

数据集可以使用如下所示的 Kaggle API 直接下载到您的 Google Colab 环境中。更多细节可以参考这个在 Medium 上的帖子

上传从您注册的 Kaggle 帐户下载的 Kaggle.json。

!pip install -U -q kaggle
!mkdir -p ~/.kaggle

从 Kaggle 下载数据集。

!cp kaggle.json ~/.kaggle/
!kaggle datasets download -d jessicali9530/celeba-dataset

定义项目结构。

注意(针对 Colab 用户) :不要试图使用左边的查看器浏览目录,因为数据集太大,页面会变得没有响应。

进口

数据

由于数据集非常大,我们将创建一个 ImageDataGenerator 对象,并使用其成员函数 flow_from_directory 来定义直接来自磁盘的数据流,而不是将整个数据集加载到内存中。ImageDataGenerator 还可用于动态应用各种图像增强转换,这在小数据集的情况下特别有用。

我强烈建议你参考文档来理解数据流函数的各种参数。

模型架构

构建编码器

如下所示,编码器的架构由一堆卷积层组成,后面是一个密集(全连接)层,输出大小为 200 的矢量。

注意:padding = 'same '和 stride = 2 的组合将产生一个在高度和宽度上都是输入张量一半大小的输出张量。深度/通道不受影响,因为它们在数字上等于过滤器的数量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

构建解码器

回想一下,解码器的功能是从潜在向量中重建图像。因此,有必要定义解码器,以便通过网络逐渐增加激活的大小。这可以通过上采样 2D 层或 Conv2DTransponse 层来实现。

这里采用了 Conv2DTranspose 层。这一层产生的输出张量在高度和宽度上都是输入张量的两倍。

注意:在这个例子中,解码器被定义为编码器的镜像,这不是强制性的。

将解码器连接到编码器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

汇编和培训

使用的损失函数是简单的均方根误差(RMSE)。真正的输出是在输入层提供给模型的同一批图像。Adam 优化器正在优化 RMSE 误差,用于将一批图像编码到它们各自的潜在向量中,并随后解码它们以重建图像。

ModelCheckpoint Keras 回调保存模型权重以供重用。它在每个时期后用一组新的权重覆盖文件。

注意:如果你正在使用 Google Colab,要么下载重量到光盘,要么安装你的 Google Drive。

提示:这是我在 Reddit(arvind 1096)上找到的一个非常有用的提示——为了防止 Google Colab 由于超时问题而断开连接,请在 Google Chrome 控制台中执行以下 JS 函数。

function ClickConnect(){console.log(“Working”);document.querySelector(“colab-toolbar-button#connect”).click()}setInterval(ClickConnect,60000)

重建

第一步是使用顶部“数据”部分中定义的 ImageDataGenerator 生成一批新图像。图像以数组的形式返回,图像的数量等于 BATCH_SIZE

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

第一行显示直接来自数据集的图像,第二行显示已经通过自动编码器的图像。显然,该模型已经很好地学会了编码和解码(重建)。

注意:图像缺乏清晰度的一个原因是 RMSE 损失,因为它平均了单个像素值之间的差异。

缺点

将从标准正态分布采样的噪声向量添加到图像编码

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以观察到,随着编码中加入一点噪声,图像开始失真。一个可能的原因是模型没有确保编码值周围的空间(潜在空间)是连续的。

尝试从从标准正态分布采样的潜在向量生成图像

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

显然,从标准正态分布采样的潜在向量不能用于生成新的人脸。这表明由模型生成的潜在向量不是以原点为中心/对称的。这也加强了我们的推论,即潜空间不是连续的。

因为我们没有一个明确的分布来采样潜在向量,所以我们不清楚如何生成新的面孔。我们观察到在潜在向量中加入一点杂讯并不会产生新的面孔。我们可以编码和解码图像,但这并不符合我们的目标。

基于这种想法,如果我们可以从标准正态分布的潜在向量中生成新的面孔,那不是很好吗?这基本上就是变分自动编码器能够做到的。

变分自动编码器

变型自动编码器解决了上面讨论的大多数问题。他们被训练来从从标准正态分布采样的潜在向量中生成新的面孔。简单的自动编码器学习将每个图像映射到潜在空间中的固定点,而变分自动编码器(VAE)的编码器将每个图像映射到 z 维标准正态分布。

如何修改简单的自动编码器,使编码器映射到 z 维标准正态分布?

任何 z 维正态分布都可以用平均矢量𝜇和协方差矩阵σ来表示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因此,在 VAE 的情况下,编码器应该输出均值向量( 𝜇 )和协方差矩阵(σ)来映射到正态分布,对吧?

是的,但是,需要对协方差矩阵σ进行细微的修改。

修改 1) 假设潜在向量的元素之间没有相关性。因此,代表协方差的非对角线元素都是零。因此,协方差矩阵是一个对角矩阵。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

因为这个矩阵的对角元素代表方差,所以它被简单地表示为𝜎2,一个 z 维方差向量。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

修改 2) 回想一下方差只能取非负值。为了保证编码器的输出无界,编码器实际上映射到均值向量和方差向量的对数。对数确保输出现在可以取范围内的任何值,(∞,∞)。这使得训练更容易,因为神经网络的输出自然是无界的。

现在,如何确保编码器映射到标准正态分布(即平均值为 0,标准偏差为 1)?

输入 KL 散度。

KL 散度提供了一个概率分布与另一个概率分布不同程度的度量。具有平均𝜇和标准偏差𝜎的分布与标准正态分布之间的 KL 散度采用以下形式:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过稍微修改损失函数以包括除 RMSE 损失之外的 KL 发散损失,VAE 被迫确保编码非常类似于多元标准正态分布。因为多元标准正态分布的平均值为零,所以它以原点为中心。将每个图像映射到与固定点相对的标准正态分布确保了潜在空间是连续的,并且潜在向量以原点为中心。

看一下图像 img-2 以便更好地理解。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

img-2(来源:blog . Bayes labs . co/2019/06/04/All-you-need-to-know-about-Vae)

如果编码器映射到𝜇和𝜎,而不是 z 维的潜在向量,那么在训练期间给解码器的输入是什么?

解码器的输入,如 img-2 所示,是从编码器输出——𝜇和𝜎.——表示的正态分布中采样的向量这种采样可以按如下方式进行:

𝑍=𝜇+𝜎𝜀

其中𝜀是从多元标准正态分布中取样的。

我们如何生成新面孔?

由于 KL 散度确保编码器映射尽可能接近标准正态分布,因此我们可以从 z 维标准正态分布进行采样,并将其提供给解码器以生成新图像。

解码器需要修改吗?

不,解码器保持不变。它等同于简单的自动编码器。

VAE 建筑模型

编码器架构有微小的变化。它现在有两个输出:mu(均值)和 log_var(方差的对数),如下所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

构建解码器

由于解码器保持不变,简单自动编码器的解码器架构被重用。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

将解码器连接到编码器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

汇编和培训

损失函数是 RMSE 和 KL 散度之和。RMSE 损耗被赋予一个权重,称为损耗因子。损耗因子乘以 RMSE 损耗。如果我们使用高损耗因子,简单的自动编码器的缺点就开始出现了。然而,如果我们使用的损耗因子太低,重建图像的质量将会很差。因此,损耗因子是一个需要调整的超参数。

重建

重建过程与简单自动编码器的过程相同。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

重建结果与简单的自动编码器非常相似。

从标准正态分布采样的随机向量生成新面孔。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

VAE 显然有足够的能力从标准正态分布的样本向量中产生新的面孔。神经网络能够从随机噪声中生成新面孔的事实表明,它在执行极其复杂的映射方面是多么强大!

由于不可能可视化 200 维向量,潜在向量的一些元素被单独可视化,以查看它们是否接近标准正态分布。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

观察到 Z 维向量的前 30 个元素非常类似于标准正态分布。因此,增加 KL 散度项是合理的。

结论

正如我们所观察到的,变分自动编码器实现了我们创建生成模型的目标。VAE 已经学会模拟数据的基本分布,并在多元标准正态分布和表面数据之间执行非常复杂的映射。换句话说,我们可以从多元标准正态分布中采样一个潜在向量,我们的 VAE 模型将该向量转换成一个新的面孔。

本教程的笔记本可以从我的GitHub 资源库 访问。

为了进一步阅读,我推荐卡尔·多施的关于变分自动编码器 教程。

LinkedInGitHub 上随时联系我。

感谢阅读!

在没有数据集的情况下生成新内容

原文:https://towardsdatascience.com/generating-novel-content-without-dataset-544107da4cc8?source=collection_archive---------28-----------------------

重写 GAN 中的规则:上下文相关的复制和粘贴特性

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

编辑样式为马添加头盔【来源】

介绍

GAN 架构一直是通过人工智能生成内容的标准,但它真的能在训练数据集中可用的内容之外发明新的内容吗?还是只是模仿训练数据,用新的方式混合特征?

在本文中,我将讨论“重写深度生成模型”论文,该论文支持直接编辑 GAN 模型以给出我们想要的输出,即使它与现有数据集不匹配。上面的图像是一个编辑的例子,其中您复制头盔特征并将其粘贴到马的上下文中。我相信这种可能性将在数字行业中开辟许多新的有趣的应用程序,例如为动画或游戏生成虚拟内容,这些内容可能不存在现有的数据集。您可以通过下面的链接观看演示视频。

[## 重写深度生成模型(ECCV 2020)——cross minds . ai

重写深度生成网络,发表于 ECCV 2020(口头)。在本文中,我们展示了如何深生成…

crossminds.ai](https://crossminds.ai/video/5f3b29e596cfcc9d075e35f0/?utm_campaign=5edc3d3a07df2164&utm_medium=share)

【甘】

生成对抗网络(GAN)是一种生成模型,这意味着它可以生成与训练数据相似的真实输出。例如,在人脸上训练的 GAN 将能够生成看起来相似的真实人脸。GAN 能够通过学习训练数据的分布来做到这一点,并生成遵循相同分布的新内容。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

甘建筑[图片由作者提供]

甘通过一个试图区分真实和虚假图像的鉴别器和一个创建虚假数据来欺骗鉴别器的生成器来“间接”学习分布。这两个网络将不断竞争和相互学习,直到它们都能够分别生成和区分真实的图像。

GAN 限制

尽管 GAN 能够学习一般的数据分布并生成数据集的不同图像。它仍然局限于训练数据中存在的内容。举个例子,我们来看一个在人脸上训练的 GAN 模型。虽然它可以生成数据集中不存在的新面孔,但它不能发明一个具有新颖特征的全新面孔。你只能期望它以新的方式结合模型已经知道的东西。

因此,如果我们只想生成正常的脸,这是没有问题的。但是如果我们想要长着浓密眉毛或者第三只眼睛的脸呢?GAN 模型无法生成这一点,因为在训练数据中没有眉毛浓密或第三只眼睛的样本。快速的解决方法是用照片编辑工具简单地编辑生成的人脸,但是如果我们想要生成大量这样的图像,这是不可行的。因此,GAN 模型更适合这个问题,但是在没有现有数据集的情况下,我们如何让 GAN 生成我们想要的图像呢?

改写甘规则

2020 年 1 月,MIT 和 Adobe Research 发表了一篇名为“重写深度生成模型”的有趣论文,使我们能够直接编辑 GAN 模型,生成新颖的内容。模型重写是什么意思?我们没有让模型根据训练数据或标签来优化自己,而是直接设置我们希望保留的规则(参数),以获得所需的结果。想要马背上的头盔吗?没问题。我们可以复制头盔的特征,并将其放在马头特征上。然而,这需要了解内部参数及其如何影响输出,这在过去是一个相当大的挑战。虽然,论文已经证明是可行的。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

通过重写模型,根据上下文复制和粘贴特征[图片由作者提供]

训练重写之间的区别类似于自然选择和基因工程之间的区别。虽然培训可以有效地优化整体目标,但它不允许直接指定内部机制。相比之下,重写允许一个人直接选择他们希望包含的内部规则,即使这些选择碰巧不匹配现有的数据集或优化全局目标。

-大卫·鲍尔(论文主要作者)

正如大卫·鲍尔所说,重写一个模型就像基因工程。这就像把发光水母的 DNA 植入猫体内,制造出一只在黑暗中发光的猫。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

发光的猫【图片由阿纳希德·巴拉瓦尼亚

它是如何工作的

你实际上如何重写一个生成模型?本文提出了将生成器的权值视为最优线性联想记忆(OLAM)的思想。OLAM 的作用是存储一个键值对关联。我们将选择某一层 L,它表示值 V ,该值表示图像的输出特征,例如微笑表情。然后,层 L 之前的前一层将表示键 K ,其表示有意义的上下文,例如嘴的位置。这里,层 L 和层 L-1 之间的权重 W 充当存储 K 和 v 之间的关联的线性关联存储器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

权重作为联想记忆[图片由作者提供]

我们可以认为 K🠖V 协会是模型中的一个规则。例如,想象一下,如果我们有一个在马身上训练的 StyleGAN 模型,我们想重写这个模型,给马戴上头盔。我们将我们想要的特征头盔标记为 V* ,将我们想要粘贴特征的上下文马头标记为 K* 。因此,为了得到我们想要的特征,我们想把原来的规则 K 🠖 V 改为我们想要的规则 K* 🠖 V* 。为此,我们以这样的方式更新权重,以将规则更改为目标 K* 🠖 V* 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

模型重写[图片由作者提供]

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

【来源】

数学细节

我们如何更新 W 来得到目标 K* 🠖 V* ?我们想要设定新规则 K* 🠖 V* 同时最小化旧 k🠖v.的变化因此,

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

上面的表达式是一个约束最小二乘问题,可以用

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这可以被简化

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其中 C = K*KT,λ和 c^−1 k∫都是简单矢量。

因此,我们的更新将有两个分量,幅度λ和更新方向 c^−1 k*。我们将更新方向 c^−1 k∫表示为 d 更新方向 d 仅受密钥 k 影响,且仅λ取决于值 v 。为了简化,更新方向确保只有影响所选上下文 k*的权重将被更新,以最小化与其他规则的干扰,同时λ确保我们实现期望的 v。关于数学的更多细节,我推荐阅读论文本身。*

总之,获得更新的权重 W1 的步骤是

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

【来源】

结果

本研究通过重写预先训练好的 StyleGAN 和 ProGAN 模型来验证其能力。一些演示是给马戴上头盔,把圆顶变成树顶,把皱眉变成微笑,去掉耳环,加上浓密的眉毛,加上眼镜。我推荐观看 David Bau 的演示视频,他展示了如何使用研究制作的接口工具重写模型。

[## 重写深度生成模型(ECCV 2020)——cross minds . ai

重写深度生成网络,发表于 ECCV 2020(口头)。在本文中,我们展示了如何深生成…

crossminds.ai](https://crossminds.ai/video/5f3b29e596cfcc9d075e35f0/?utm_campaign=5edc3d3a07df2164&utm_medium=share) 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

给马戴帽【来源】

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加浓眉【来源】

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

把教堂顶改成树顶【来源】

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

变皱眉为微笑【来源】

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

取下耳环【来源】

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

添加眼镜【来源】

该界面工具易于使用,并且可以在 Jupyter 笔记本上运行。您可以使用这个 Colab 笔记本或从源代码中使用该工具。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接口工具重写模型【来源】

感谢您的阅读,如果您喜欢我的文章,请随时查看我的其他文章!

[## 带有可变自动编码器的创成式建模(VAE)

理解变分自动编码器背后的直觉(VAE)

medium.com](https://medium.com/vitrox-publication/generative-modeling-with-variational-auto-encoder-vae-fc449be9890e) [## 使用 StyleGAN2 生成动画角色

了解如何生成这个很酷的动画人脸插值

towardsdatascience.com](/generating-anime-characters-with-stylegan2-6f8ae59e237b)

参考

[1] Bau,d .,Liu,s .,Wang,t .,Zhu,J. Y .,& Torralba,A. (2020)。重写深度生成模型。arXiv 预印本 arXiv:2007.15646 。

https://rewriting.csail.mit.edu/

在 Python 中生成帕累托分布

原文:https://towardsdatascience.com/generating-pareto-distribution-in-python-2c2f77f70dbf?source=collection_archive---------15-----------------------

概率统计/帕累托分布

让我们更好地理解帕累托分布

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 iambipin 拍摄

1.帕累托分布

P areto 分布是一种幂律概率分布,以意大利土木工程师、经济学家、社会学家维尔弗雷多·帕累托的名字命名,用于描述社会、科学、地球物理、精算以及其他各种类型的可观测现象。帕累托分布有时被称为帕累托原则或“80-20”规则,因为该规则表明,80%的社会财富掌握在 20%的人口手中。帕累托分布不是自然规律,而是一种观察。它在许多现实世界的问题中是有用的。这是一个偏斜的重尾分布。

看完定义,你一定在疑惑什么是幂律?幂律是两个量之间的函数关系,使得一个量的变化触发另一个量的成比例变化,而不管两个量的初始大小。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 iambipin 拍摄

80-20 法则在很多情况下都适用。例如,维尔弗雷多·帕累托发现意大利 80%的土地被 20%的人口占有。他还发现,从他的菜园里采购的 80%的豌豆来自 20%的豌豆植株。全球 82.7%的收入被 20%的人口控制。微软 2002 年的一份报告表明,Windows 和 MS Office 80%的错误和崩溃是由 20%的检测到的错误造成的。80%的销售额来自 20%的产品。80%的客户只使用 20%的软件功能。这种 80-20 分布经常出现。

2.在 Python 中生成帕累托分布

可以使用 Scipy.stats 模块或 NumPy 在 Python 中复制 Pareto 分布。Scipy.stats 模块包含各种概率分布和不断增长的统计函数库。Scipy 是用于科学计算和技术计算的 Python 库。NumPy 是一个用于科学计算的 Python 库,除了科学用途之外,它还可以用作通用数据的多维容器。

2.1 使用 Scipy.stats

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import pareto
x_m = 1 #scale
alpha = [1, 2, 3] #list of values of shape parameters
samples = np.linspace(start=0, stop=5, num=1000)for a in alpha:
    output = np.array([pareto.pdf(x=samples, b=a, loc=0, scale=x_m)])
    plt.plot(samples, output.T, label='alpha {0}' .format(a))plt.xlabel('samples', fontsize=15)
plt.ylabel('PDF', fontsize=15)
plt.title('Probability Density function', fontsize=15)
plt.grid(b=True, color='grey', alpha=0.3, linestyle='-.', linewidth=2)
plt.rcParams["figure.figsize"] = [5, 5]
plt.legend(loc='best')
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 iambipin 拍摄

x_mα帕累托分布的两个参数。x_m 是标度参数,代表帕累托分布随机变量可以取的最小值。α是形状参数,等于 n/SUM{ln(x_i/x_m)}。

np.linspace() 返回特定间隔[开始,停止]内间隔均匀的样本(样本数等于 num)。在上面的代码中,linspace()方法返回范围[0,5]内 1000 个均匀分布的样本。

shape values -alpha 列表被迭代以绘制每个值的线条。 np.array() 创建一个数组。 scipy.stats.pareto() 方法返回 pareto 连续随机变量。 pareto.pdf() 创建概率密度函数(pdf)。参数 x、b、loc 和 scale 分别是类数组分位数、类数组形状参数、类数组可选位置参数(默认值=0)和类数组可选比例参数(默认值=1)。

plt.plot() 绘制均匀间隔的样本和 PDF 值数组。该图是为每个α值绘制的。这里,输出。T 正在变换输出。输出是具有 3 行的 Pareto 分布值的数组,每个形状参数一行。在转置时,输出被转换成 1000 行的数组。

剩下的代码行几乎是不言自明的。 plt.xlabel()plt.ylabel() 用于标注 x 轴和 y 轴。 plt.title() 给图形指定标题。 plt.grid() 配置网格线。

plt.rcParams['figure.figsize'] = [width, height]

plt.rcParams[] 设置当前 rc 参数。Matplotlib 使用 matplotlibrc 配置文件自定义各种属性,称为‘RC 设置’或‘RC 参数’。Matplotlib 中几乎每个属性的默认值都可以控制:图形大小和 DPI、线条宽度、颜色和样式、轴、轴和网格属性、文本和字体属性等等。

plt.legend() 显示图例,plt.show()显示所有图形。想进一步了解如何让你的情节更有意义,请访问这里。

2.2 使用 Numpy

import numpy as np
import matplotlib.pyplot as plt
x_m, alpha = 1, 3.
#drawing samples from distribution
samples = (np.random.pareto(alpha, 1000) + 1) * x_m
count, bins, _ = plt.hist(samples, 100, normed=True)
fit = alpha*x_m**alpha / bins**(alpha+1)
plt.plot(bins, max(count)*fit/max(fit), linewidth=2, color='r')
plt.xlabel('bins', fontsize=15)
plt.ylabel('probability density', fontsize=15)
plt.title('Probability Density Function', fontsize=15)
plt.grid(b=True, color='grey', alpha=0.3, linestyle='-.', linewidth=2)
plt.rcParams['figure.figsize'] = [8, 8]
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 iambipin 拍摄

np.random.pareto() 从指定形状的 Pareto II 或 Lomax 分布中抽取随机样本。帕累托 II 分布是一种转移的帕累托分布。通过加 1 并乘以标度参数 x_m,可以从 Lomax 分布得到经典的 Pareto 分布。

samples = (np.random.pareto(alpha, 1000) + 1) * x_m

帕累托 II 分布的最小值是零,而经典帕累托分布的最小值是μ,其中标准帕累托分布的位置μ= 1。

plt.hist() 绘制直方图。当参数 density 或 normed 设置为 True 时,返回的元组将把第一个元素作为计数规范化以形成概率密度。因此直方图下的面积将是 1。这是通过将计数除以观察数量乘以箱宽度而不是除以观察总数来实现的。因此,y 轴将具有样本密度。

count,bin,_ 中的 ‘_’ 表示返回的元组的最后一个值不重要( plt.hist() 将返回一个具有三个值的元组)。

我们将在分箱的数据上绘制曲线,

我们将通过计算 Pareto 分布在由具有参数 x_m 和 alpha 的条柱定义的 x 值处的概率密度,使 Pareto 分布符合我们的随机采样数据,并在我们的数据之上绘制该分布。

fit = alpha*x_m**alpha / bins**(alpha+1)

3.验证帕累托分布

Q-Q 图(分位数-分位数图)用于判断连续随机变量是否遵循帕累托分布。

import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as statsx_m = 10 
alpha = 15 
size = 100000 #the size of the sample(no. of random samples)
samples = (np.random.pareto(alpha, size) + 1) * x_m
stats.probplot(samples, dist='pareto', sparams=(15, 10), plot=pylab)
plt.show()

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

照片由 iambipin 拍摄

stats . proplot根据指定理论分布(帕累托分布)的分位数,生成从分布(样本数据)中抽取的随机样本的概率图。由于绝大多数蓝点(样本数据)几乎与红线(理论分布)对齐,我们可以得出分布遵循帕累托分布的结论。

在得出结论之前,必须了解帕累托分布在现实世界中的应用。

4.帕累托分布的应用

  • 人类住区的规模(更少的城市和更多的村庄)。
  • 沙粒的大小。
  • 遵循 TCP 协议通过互联网分发的数据的文件大小。
  • 油田(几个大油田和许多小油田)的石油储量值
  • 在 Tinder 中,80%的女性争夺 20%最有魅力的男性。
  • 用户在 Steam 中玩各种游戏所花费的时间(很少有游戏玩得很多,比大多数很少玩的游戏更频繁)。

帕累托分布及其概念非常简单而强大。它总是有助于收集重要的线索,以了解广泛的人类行为,科学和社会现象。我希望你能更好地理解帕累托分布,以及如何从中抽取样本并使用 Pyplot、Numpy、Scipy 和 Python 绘图。编码快乐!!!

参考

[## scipy.stats.pareto — SciPy v1.4.1 参考指南

scipy.stats. pareto( *args,**kwds) = [source]一个 pareto 连续随机变量。作为 rv_continuous 的一个实例…

docs.scipy.org](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.pareto.html) [## NumPy . random . Pareto—NumPy 1.10 版手册

numpy.random. pareto ( a,size=None)从指定形状的 Pareto II 或 Lomax 分布中抽取样本。的…

docs.scipy.org](https://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.random.pareto.html)

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

https://docs . scipy . org/doc/numpy-1 . 10 . 1/reference/generated/numpy . random . Pareto . html

https://stack overflow . com/questions/19525899/how-to-generate-random-numbers-in-specific-range-using-Pareto-distribution-in-py

用扩张卷积神经网络生成钢琴音乐

原文:https://towardsdatascience.com/generating-piano-music-with-dilated-convolutional-neural-networks-d81d02e1dda6?source=collection_archive---------20-----------------------

如何建立完全卷积的神经网络,能够以惊人的成功模拟复杂的钢琴音乐结构

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

介绍

由扩展 1D 卷积组成的完全卷积神经网络易于构建、易于训练,并且可以生成逼真的钢琴音乐,例如:

通过 100 小时古典音乐训练的完全卷积网络产生的示例性能。

动机

大量的研究致力于训练可以创作钢琴音乐的深度神经网络。例如,OpenAI 开发的 Musenet 已经训练出能够创作长度为许多分钟的逼真钢琴曲的大规模变形金刚模型。Musenet 使用的模型采用了许多技术,比如最初为 NLP 任务开发的注意力层。参见上一篇 TDS 文章,了解更多关于将注意力模型应用于音乐生成的细节。

虽然基于 NLP 的方法非常适合基于机器的音乐生成(毕竟,音乐就像一种语言),但 transformer 模型架构有些复杂,并且适当的数据准备和训练可能需要极大的关注和经验。这种陡峭的学习曲线促使我探索更简单的方法来训练可以创作钢琴音乐的深度神经网络。特别是,我将重点关注基于扩展卷积的全卷积神经网络,它只需要几行代码来定义,需要最少的数据准备,并且易于训练。

历史关联

2016 年, DeepMind 研究人员推出了 WaveNet 模型架构,在语音合成方面产生了最先进的性能。他们的研究表明,具有指数增长膨胀率的堆叠 1D 卷积层可以极其有效地处理原始音频波形序列,从而产生可以合成来自各种来源的令人信服的音频的生成模型,包括钢琴音乐

在这篇文章中,我以 DeepMind 的研究为基础,明确专注于创作钢琴音乐。我没有从录制的音乐中向模型输入原始音频,而是显式地向模型输入在乐器数字接口(MIDI)文件中编码的钢琴音符序列。这有助于数据收集,大大减少计算量,并允许模型完全集中于数据的音乐方面。这种高效的数据编码和数据收集的便利性使得快速探索完全卷积网络能够多好地理解钢琴音乐成为可能。

这些模特“弹钢琴”的水平如何?

为了让大家了解这些模型听起来有多逼真,我们来玩一个模仿游戏。以下哪一段是由人类创作的,哪一段是由模特创作的:

钢琴作曲 A:人还是模特?

钢琴作曲 B:人还是模特?

也许你预料到了这个诡计,但是这两个作品都是由这篇文章中描述的模型产生的。生成上述两个片段的模型仅用了四天时间在一台 NVIDIA Tesla T4 上进行训练,训练集中有 100 小时的古典钢琴音乐。

我希望这两个表演的质量为你提供动力,继续阅读并探索如何构建你自己的钢琴音乐创作模型。这个项目中描述的代码可以在 piano et 的 Github 中找到,更多示例作品可以在 piano et 的 SoundCloud 中找到。

现在,让我们深入了解如何训练一个模型像上面的例子一样产生钢琴曲的细节。

方法

当开始任何机器学习项目时,很好的做法是明确定义我们试图完成的任务,我们的模型将从中学习的体验,以及我们将用来确定我们的模型是否在任务中改进的性能度量。

工作

我们的首要目标是生成一个模型,有效地逼近数据生成分布 P(X)。这个分布是一个函数,它将钢琴音符的任意序列 X 映射到一个范围在 0 和 1 之间的实数。本质上,P(X)赋予更可能由熟练的人类作曲家创作的序列更大的值。举个例子,如果 X 是由 200 个小时随机选取的音符组成的曲子,X 是莫扎特的奏鸣曲,那么 P(X ) < P(X)。此外,P(X)将非常接近零。

实际上,分布 P(X)永远无法精确确定,因为这需要将所有可能存在的人类作曲家聚集在一个房间里,让他们永远创作钢琴曲。然而,对于更简单的数据生成分布,也存在同样的不完整性。例如,精确确定人类身高的分布需要所有可能的人类存在并被测量,但这并不阻止我们定义和近似这样的分布。在这个意义上,上面定义的 P(X)是一个有用的数学抽象,它包含了决定钢琴音乐如何产生的所有可能的因素。

如果我们用一个模型很好地估计了 P(X ),我们就可以用这个模型随机抽样出新的、现实的、从未听过的作品。这个定义仍然有点抽象,所以让我们应用一些合理的近似,使 P(X)的估计更容易处理。

**数据编码:**我们需要用计算机可以理解的方式对钢琴音乐进行编码。为此,我们将把一首钢琴作品表示为一个可变长度的二进制状态时间序列,每个状态跟踪在一个时间步长内手指是否按下了键盘上的给定音符:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 1:数据编码过程,展示了如何将钢琴音乐表示为二进制按键状态的 1D 序列,其中一个状态表示在特定的时间步长内按下了一个按键。

数据处理不等式告诉我们,只有当我们处理信息时,信息才会丢失,我们选择的钢琴音乐编码方法也不例外。在这种情况下,信息丢失有两种方式。首先,必须通过使时间步长有限来限制时间方向上的分辨率。幸运的是,0.02 秒的相当大的步长仍然会导致音乐质量的可忽略不计的降低。第二,我们不能代表按键的速度,因此,音乐的力度就丧失了。

尽管有重要的近似,这种编码方法以简洁和机器友好的形式捕获了大量的底层信息。这是因为钢琴实际上是一个大型的有限状态机。有效地编码其他更微妙的乐器的音乐,如吉他或长笛,可能会困难得多。

既然我们有了编码方案,我们可以用更具体的形式来表示数据生成分布:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

等式 1:在 88 键钢琴上演奏的钢琴作品的联合概率分布。有 T 个时间步长,或 88 个按键状态的集合,每个 x 变量可以是 1(按键)或 0。

作为一个例子,在第一时间步,如果钢琴上的第一个音符被按下,在 t =1, x ₁ = 1。

**分解分布:**另一种简化涉及使用概率链规则分解(1)中的联合概率分布:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

等式 2:将编码数据生成分布因式分解成条件概率。

类似于 n -gram 语言模型,我们可以做出马尔可夫假设,即在过去发生超过 N 个时间步的音符对在时间 t=n 的音符是否被按下没有影响。这允许我们最多使用最后一个 N 音符来重写(2)中的每个因子:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

等式 3 😦 2)中的每一项可以使用该表达式来近似,该表达式假设只有键状态的最后 N 个时间步长影响下一个键被按下的概率。

请注意,在一首歌曲的开头,音符历史可以用多达 N 个零来填充,以便总是有至少 N 个音符的历史。此外,请注意 N 必须在数百个时间步长(许多秒的历史)内,这种近似才能很好地适用于钢琴音乐。我们将在后面看到 N 是由我们模型的感受野决定的,并且是表演质量的关键决定因素。

最后,我们已经涵盖了足够的数学背景,以严格定义这个项目的任务:使用真实钢琴音乐的编码序列数据集,训练一个估计器 ,给出最后 N 个音符状态下下一个音符被按下的概率。然后,我们可以使用 重复采样下一个音符,在每次采样后更新音符历史,自动回归创建一个全新的乐曲。

在这个项目中,我们的估计器 将是一个完全卷积的深度神经网络。但是,在我们谈论模型架构或培训之前,我们需要收集一些数据。

经验

我们的模型在训练期间看到的数据将在很大程度上决定其生成的音乐的质量和风格。此外,我们试图估计的联合概率分布是非常高维的,并且容易出现数据稀疏的问题。这可以通过使用足够大量的训练数据和适当的模型选择来克服。关于前者,钢琴音乐很容易收集和预处理,原因有二。

首先,互联网上有大量 MIDI 格式的钢琴音乐。这些文件本质上是钢琴键状态的序列,并且需要最少的预处理来获得我们期望的训练数据的编码。第二,我们试图完成的任务是自监督学习,其中我们的目标标签可以从数据中自动生成,无需人工标注:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 2:输入和目标音符序列由相同的数据组成,目标相对于输入向前移动一个音符。该任务的自我监督性质排除了手动贴标的需要。

图 2 显示了如何收集这个任务的训练实例。首先,从一首歌曲中选择一个二元密钥状态序列。然后,这些状态被分成两个子序列;一个输入序列,然后是一个大小相等的目标序列,但索引向前移动一个音符。总而言之,构建我们的数据集就像从互联网上下载高质量的钢琴 midi 文件并操作数组一样简单。

值得注意的是,我们在训练集中包含的音乐风格将在很大程度上决定我们最终估计的数据生成分布 P(X)的子空间。如果我们喂巴赫和莫札特的模式序列,它显然不会学习产生塞隆尼斯·蒙克的爵士乐。出于数据收集的考虑,我将重点放在最著名的古典作曲家的输入数据上,包括巴赫、肖邦、莫扎特和贝多芬。然而,将这项工作扩展到不同风格的钢琴音乐只需要用这些附加风格的代表性例子来扩充数据集。

绩效指标

PianoNet 本质上是一个自我监督的二进制分类器,它被反复调用来预测下一个键状态是向上还是向下。对于任何概率二进制分类器,我们可以通过最小化训练数据上的交叉熵损失来最大化模型对数据集的预测可能性:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

等式 4:交叉熵损失,针对具有参数θ的概率模型 p̂,在一组 m 个实例的训练集上计算。如果第 I 个训练实例的实际目标音符被按下,yᵢ = 1,否则为 0。

在训练过程中,我们的模型被输入长序列的音符状态输入和从人类创作的钢琴音乐中采样的目标。在每个训练步骤,该模型使用有限的音符历史来预测下一个钢琴键状态被按下的概率。如果当真键状态被按下时预测概率接近于零,或者当真键状态未被按下时预测概率接近于 1,则模型将根据(4)受到强烈惩罚。

这个损失函数有一个潜在的问题。我们的最终目标不是创建一个基于人类创作的作品中的过去音符来预测单个下一个音符的模型,而是基于模型本身生成的音符历史来创建扩展的音符序列。在这个意义上,我们做了一个非常强有力的假设:当给定一个人为生成的音符状态的历史时,随着模型在预测下一个钢琴音符的状态方面的改进,它通常也会在使用其自己的输出作为音符历史自动回归地生成扩展的演奏方面有所改进。

事实证明,这个假设并不 而不是总是成立的,因为验证损失相对较低的模型在生成表演时听起来仍然很不悦耳。下面,我表明这个假设不适用于浅层网络,但对于足够深的网络,它在实践中适用。

模型架构

我们现在知道如何定义任务,并可以收集大量正确编码的数据,但我们应该根据数据训练什么模型才能更好地完成钢琴作曲的任务?作为一个好的起点,我们的模型应该有几个属性,这些属性应该能够提高它对看不见的数据进行归纳的能力:

  • **该模型对于调的移调应该是不变的,也就是说,将按下的音符向上或向下移动固定数量的键:**为了更好地近似,以 c 大调和弦开始的莫札特奏鸣曲应该具有与以 G 大调和弦开始的奏鸣曲相同的相对音符分布。调式并不完全对称,但是音调的相对频率在很大程度上决定了作品的音乐语义。这种现象就是为什么一个乐队可以用主唱更舒服的音调来覆盖汤姆·佩蒂的自由落体,而观众不会注意到。
  • **该模型对于节奏的微小变化应该是不变的:**如果一首歌曲播放快了或慢了 2%,这应该不会对下一个音符的分布产生太大影响。事实证明,我们不能直接强加这种不变性,但我们可以通过使用数据增强来教授模型速度不变性。
  • **当数据流经网络时,模型不应降低输入分辨率:**未来音符的分布可能对音乐中的高分辨率细微差别非常敏感,尤其是时间方向上的节奏变化,因此我们不应破坏这些信息。在这方面,假定像池化这样的技术会损害模型性能。
  • **模型参数的数量应与感受野的大小成比例:**总感受野是模型输入的大小。该值越大,可用于影响未来票据概率的票据历史就越多。在钢琴曲中,这必须至少有几秒钟长。对于几秒钟的感受野,模型参数的数量应该保持在几百万或更少。

由堆叠的扩展卷积层组成的全卷积神经网络是满足上述特性的简单而有效的选择。除了在内核输入之间可能有一个或多个长度的间隙之外,扩展卷积类似于传统卷积。见这篇 TDS 博客文章了解膨胀卷积的更详细的概述,虽然我们在这种情况下使用 1D 卷积,而不是 2D。

与 WaveNet 论文中使用的方法类似,我们将在每个“块”中使用指数增长的膨胀率来构建我们的模型,并堆叠多个块来创建完整的网络。下面是构建两个块模型的 Tensorflow 代码示例,每个块有七层。整个网络变得越来越宽,因此第二个块的每一层比第一个块有更多的滤波器。最后,该模型以单个滤波器结束,其输出通过 sigmoid 激活运行,并且该输出将是下一个音符状态为 1 的预测概率。

from tensorflow.keras.layers import Input, Conv1D, Activation
from tensorflow.keras.models import Model

filter_counts = [
    [4,  8,  12, 16, 20, 24, 28], *# block one's filter counts* [32, 36, 38, 42, 46, 50, 54], *# block two's filter counts* ]

inputs = Input(shape=(None, 1)) *# None allows variable input lengths* conv = inputs

for block_idx in range(0, len(filter_counts)):
    block_filter_counts = filter_counts[block_idx]

    for i in range(0, len(block_filter_counts)):
        filter_count = block_filter_counts[i]
        dilation_rate = 2**i *# exponentially growing receptive field*conv = Conv1D(filters=filter_count, kernel_size=2,
                      strides=1, dilation_rate=dilation_rate,
                      padding=**'valid'**)(conv)
        conv = Activation(**'elu'**)(conv)

outputs = Conv1D(filters=1, kernel_size=1, strides=1,
                 dilation_rate=1, padding=**'valid'**)(conv)
outputs = Activation(**'sigmoid'**)(outputs)

model = Model(inputs=inputs, outputs=outputs)

线dilation_rate = 2**i导致每个块中的膨胀率从 1 开始(类似于核大小为 2 的传统卷积),然后随着块中的每个后续层呈指数增加。一旦第二个区块开始,这个膨胀率重置为大小 1,并开始像以前一样以指数方式增加。

我们可以让扩张率继续呈指数增长,而无需重置,但这将导致感受野在每个模型深度增长过快。我们也不必为每个新层增加过滤器的数量。我们可以让每一层的过滤器计数总是等于某个大的数字,比如 64。然而,在实验过程中,我发现从少量的过滤器开始,慢慢地增加数量会产生一个统计效率更高的模型。图 3 显示了一个包含两个模块的示意模型:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3:模型架构,包括堆叠的扩张 1D 卷积层,每增加一层,扩张率增加两倍。当第二个块开始时,膨胀率重置为 1。每个节点代表一个向量,该向量包含每个后续层的越来越多的元素。

需要对每个Conv1D层实例化的padding='valid'参数做最后的说明。我们希望我们的模型输入只看到在当前预测音符之前发生的音符——否则我们将允许在推理时不存在的未来信息泄漏到我们的预测中。我们也不想在输入的音符序列中填充零(静音)。输入序列可以在歌曲中间开始,用无声填充会产生一种人为的输入状态,其中无声突然被内部歌曲片段打断。“有效”设置以满足上述两个要求的方式填充序列。

训练的技巧和诀窍

尽管获取大型数据集很容易,并且我们讨论的模型架构构建起来也相当简单,但训练一个产生真实音乐的模型仍然是一门艺术。这里有一些技巧可以帮助你克服我面临的许多挑战。

深度的重要性

当我开始训练模型时,我从单块浅层网络架构开始,大约有 15 层,每层有大量的权重。虽然验证损失表明这些模型正在从数据中学习,而不是过度拟合,但听到如下表现时,我感到沮丧:

来自太浅(13 个卷积层)的网络的示例性能。

浅层网络的表现开始有点音乐,但随着它离人类产生的种子越来越远,它最终陷入混乱,最终让位于大部分沉默。

令人惊讶的是,当我通过添加更多块来增加网络深度,但保持参数数量不变时,即使验证损失没有减少,性能质量也显著提高:

深层网络(36 层)的性能示例。这种表演在音乐上与种子相去甚远。

产生上述表演的浅层和深层网络在验证集上的损失几乎相同,然而深层网络能够形成连贯的音乐短语,而浅层网络是……前卫。请注意,上述两个网络相对较小,具有 2.6 秒的狭窄感受野和 10-40 层。本文开头显示的更高级的模型有接近 100 层和几乎 10 秒的感受域。同样,这些结果也不是随机的。我已经听了很多分钟的音乐,这些音乐来自浅层和深层模型,使用了许多不同的种子,模式保持一致。

为什么验证损失不能说明全部情况?请记住,我们使用的损失衡量的是模型预测下一个音符的能力,因为人类生成了大量音符。这将涉及,但不完全捕获,一个模型的能力,使用它的 自己的生成的音符历史自动回归一个干净的性能,在很长一段时间内,没有下降到 P(X)内的一个空间,它没有被给予代表性的训练数据。(4)中给出的交叉熵损失是便于训练的内在度量,但是表演的主观质量才是真正的外在度量。

我支持为什么低验证损失并不意味着良好的音响性能,但为什么增加我们的网络深度往往会提高相同损失的音乐性?很可能统计效率是这里的决定性因素。深而薄的卷积神经网络很可能代表了我们试图比浅而宽的卷积神经网络更有效地估计的函数家族。作曲的过程,像许多人类的任务一样,似乎更好地表现为一系列简单功能的组合,而不是一些相对复杂的功能。很可能浅层网络正在“记忆”笔记历史中的常见模式,而深层网络正在将这些模式编码成更有意义的表示,这些表示随着输入的小变化而变化。

我发现了最后一个关于深度的启发,它可以提高表现,减少训练时间。每个附加块的感受野应该相对于最后一个块缩小两倍。这需要每个后续块比上一个少一层。这大大减少了卷积运算的次数,因为最宽的层(靠近输出层的层)具有最小的感受野。同时,如果第一层具有相当大的感受野,模型的整体感受野不会受到很大影响。

应该训练多久?更久。

添加到网络中的每一个额外的块都增加了显著的深度——每个块大约十层。因此,让这些深层网络接受训练可能会很快变得棘手。为了对抗训练期间的爆炸梯度,学习率需要相当小,通常在 0.0001 左右,这意味着模型在收敛到好的解决方案之前必须训练更多的步骤。

然而,也有一线希望。因为我们可以访问如此多的数据(数十亿个注释状态),所以对于一个具有大约一百万个参数的中等规模的模型来说,很难适应数据集。这实际上意味着,你让你的模型训练的时间越长,它听起来就越好。随着训练的进行,验证损失将越来越少,但是模型在训练后期继续学习音乐的极其重要的元素。

为了证明让模型训练足够长的时间是多么重要,这里有一组迷你表演,展示了给定模型在训练过程中是如何学习的。每场迷你演出都有相同的人类作曲种子,由贝多芬的 Für Elise 的片段组成。W 随着每一次重复,模型在被要求完成 seed 之前被给予越来越多的训练时间:

随着模型训练时间的延长,它可以更令人信服地完成音乐短语。

我们看到,直到最后 20%的训练时间,模型才产生音乐上合理的乐句。

为了加快训练速度,我经常从一个批量开始,慢慢增加到 32 个。这鼓励了跨参数空间的探索,并限制了所需的计算资源量。我们可以不考虑初始批量大小为 1 的情况,因为每个单独的训练样本可以包含歌曲片段中的数百个预测(参见图 2 中的输入和目标序列)。

战略偏差初始化

大多数时候,钢琴键没有被按下。只有最具实验性的艺术家才会在任何时候按下几个以上的键。这使得在输出层中正确设置偏置非常重要:

output_bias_init = tensorflow.keras.initializers.Constant(-3.2)outputs = Conv1D(filters=1, kernel_size=1, strides=1,
                 dilation_rate=1, padding=**'valid'**,
                 bias_initializer=output_bias_init)(conv)outputs = Activation(**'sigmoid'**)(outputs)

通过将偏差设置为-3.2,我们的模型从一开始就预测了平均被按压的音符的正确基本比率(大约 0.04)。该模型不再需要花费许多训练步骤来弄清楚钢琴键只是没有被经常按下。这消除了曲棍球杆的学习曲线,并加快了训练速度。

数据扩充

同样,旋转和缩放图像可以帮助模型在计算机视觉任务中更好地概括,我们可以将钢琴音符的 1D 序列拉伸和压缩几个百分点,以进一步增加训练数据。其思想是,给定的钢琴作品可以演奏得快一点或慢一点,而不改变其从数据生成分布中被采样的机会。这在对抗数据稀疏性方面有很大帮助,并且它还帮助模型学会对节奏的微小变化保持不变。我通常为每首输入歌曲创建五个克隆,随机拉长 15%到 15%的速度。

安全创建验证数据集

在构建训练集和验证集时,我们不应该对所有歌曲的随机片段进行采样。钢琴曲经常重复整个部分,所以如果我们使用随机抽样的方法,我们可能会无意中在验证集上结束训练。

为了避免这种情况,我们必须确保在将训练集和验证集分成样本片段之前,为它们分配完全不同的歌曲。只要从每个作曲家那里采样的歌曲数量是数百首,我们仍然会得到模型对未知音乐的泛化误差的合理估计。

作曲家和熵

一般来说,不同的作曲家会有更高或更低的音乐熵。也就是说,作曲家的作品或多或少是不可预测的,因为在前一个音符之后可能会有或多或少的不确定性。一般来说,早期作曲家,如巴赫或海顿,在其数据生成分布中具有较低的不确定性,而后期作曲家,如普罗科菲耶夫或拉威尔,在给定音符历史的情况下,将具有更多可能的音符。

由于这种不同程度的熵,如果您的模型需要更多的模型容量、训练时间和/或训练数据来重现更不可预测的风格,请不要感到惊讶。根据我的经验,这篇文章中描述的模型通常可以轻松地用一百首歌曲复制巴赫的作品,而让一个模型产生引人注目的肖邦音乐似乎需要更多的输入数据。

使用训练模型生成性能

朴素模型推理

一旦你有了一个训练好的模型,你会想用它来生成新的作品。为了生成一个性能,我们从一个长度等于模型感受域的输入种子开始。这颗种子可以是人类写的一首歌的一部分,或者只是沉默。然后我们可以调用这个输入种子上的model.predict来生成下一个时间步长中第一个键的状态被按下的概率。如果这个预测是 0.01,那么我们将以 1%的概率对下一个被按下的键进行采样。

如果我们从输入种子中删除第一个音符,并将模型的最后一个采样音符状态添加到末尾,那么我们再次得到长度等于模型感受域的输入向量。我们可以使用新的输入来生成另一个键状态,这次使用模型的最后一个输出作为输入的一部分。最后,我们可以无限地重复这个过程,在某一点上,输入完全由我们的模型生成。这是自回归背后的核心思想。

快速波网生成算法

虽然上述方法可以很好地工作,但制作一分钟的音乐可能需要几个小时。这是因为每个model.predict(input)调用需要非常大量的连续卷积运算来计算最终输出,并且计算时间与模型深度的比例很差。

事实证明,如果我们将过去卷积运算的一些信息存储在一个队列中,我们可以大大加快这些计算的速度。这就是快速波网生成算法背后的思想。这个算法如何工作超出了本文的范围,但是请放心,我已经在下面更详细描述的 PianoNet 包中实现了一个纯 Python 版本。如果你使用这个软件包,即使有一个包含数百万参数的非常大的网络,生成一分钟的钢琴音乐也需要五分钟的时间,而不是几个小时。

边缘厌恶

关于性能生成的最后一个细节包括限制模型漂移。因为我们的架构相对于按键变化是不变的,所以它不编码按键状态处于哪个八度音阶。这意味着该模型将键盘上的所有八度音程视为同等可能性,并且可以向钢琴键状态的边缘漂移。我们不希望这种情况发生,因为作曲家倾向于将按下的键放在更靠近钢琴中间的位置。

为了用最简单的方法来对抗这种漂移,我使用了我称之为边缘厌恶的方法。这种方法是在表演过程中使模型偏离边缘的一种方式,而不会过多地改变模型的输出分布。本质上,边缘厌恶强制钢琴键盘上非常高和非常低的音符仅在模型预测到非常高的概率时被演奏。例如,如果模型预测钢琴上最高的键将以 0.05 的概率被按下,则该键仍然不会被随机采样为被按下。

使用 PianoNet Python 包

此时,您可能会兴奋地开始训练自己的模型来生成钢琴曲。为了使这个过程尽可能简单,我创建了 PianoNet ,这是一个 Python 包,用于轻松复制我上面描述的工作。

有关如何使用该软件包的完整端到端教程,请参见链接报告中包含的自述文件。在下面的小节中,我将简要地讨论用于控制数据收集、模型训练和性能生成的抽象。任何工作流程的基本步骤都是:

  • 使用 piano net/scripts/master _ note _ array _ creation . py 脚本创建培训和验证 MasterNoteArray 文件
  • 创建一个目录来保存您的计算并包含一个 run_description.json 文件,该文件指定了用于训练的超参数以及到输入数据文件的链接
  • 使用 pianonet/scripts/runner.py 脚本在同一目录中启动运行
  • 一旦训练完成,使用 piano net/model _ inspection/performance _ tools . py 中的get_performance方法生成表演

收集和预处理数据

第一步是找到一些 midi 文件,其中包含您希望模型学习的风格的钢琴演奏。互联网是找到各种作曲家的免费钢琴 midi 文件的好地方。一旦你收集了这些文件,把它们都移到你选择的目录下。在本例中,我假设它们位于/path/to/midi/

为了使用 PianoNet 包训练模型,我们需要将所有的 midi 文件提取到保存到磁盘的训练和验证 MasterNoteArray 实例中。MasterNoteArray 对象实质上是所有输入歌曲的 1D 数组,这些歌曲以一种易于训练的方式连接在一起。我们可以创建一个数据描述 json 文件来生成 MasterNoteArray,如下所示:

{
  "file_name_prefix": "dataset_master_note_array",
  "min_key_index": 31,
  "num_keys": 72,
  "resolution": 1.0,
  "end_padding_range_in_seconds": [
    4.0,
    6.0
  ],
  "num_augmentations_per_midi_file": 5,
  "stretch_range": [
    0.85,
    1.15
  ],
  "time_steps_crop_range": [],
  "midi_locator": {
    "paths_to_directories_of_midi_files": ["/path/to/midi/"],
    "whitelisted_midi_file_names": []
  },
  "validation_fraction": 0.2
}

确保将上面的/path/to/midi/路径更改为存储 midi 文件的位置。对于更多的增强(每首歌曲的拉伸),将num_augmentations_per_midi_file从 5 增加到一个更大的数字。

最后,我们可以使用以下命令生成输入数据集:

*python pianonet/scripts/master_note_array_creation.py /path/to/data_description.json /path/to/output/directory*

这个脚本将生成两个.mna_jl文件,一个包含训练数据,一个包含验证数据。

培训模型

一旦我们有了 MasterNoteArray 数据集,我们就可以开始模型训练课程或运行。每个运行都位于自己的目录中,并且有一个 run_description.json 文件来描述运行应该如何执行:

{
  "data_description": {
    "training_master_note_array_path": "./dataset_train.mna_jl",
    "validation_master_note_array_path": "./dataset_val.mna_jl"
  },
  "model_description": {
    "model_path": "",
    "model_initializer": {
      "path": "pianonet/scripts/model_generators/basic_convolutional_with_blocks.py",
      "params": {
        "filter_increments": [
          [ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
          [ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4],
          [ 6, 6, 6, 6, 6, 6, 6, 6, 8, 8],
        ],
        "default_activation": "elu",
        "use_calibrated_output_bias": true
      }
    }
  },
  "training_description": {
    "batch_size": 8,
    "num_predicted_time_steps_in_sample": 24,
    "epochs": 10000,
    "checkpoint_frequency_in_steps": 250,
    "fraction_data_each_epoch": 0.1,
    "loss": "binary_crossentropy",
    "optimizer_description": {
      "type": "Adam",
      "kwargs": {
        "lr": 0.0001,
        "beta_1": 0.9,
        "beta_2": 0.999,
        "epsilon": 1e-07,
        "decay": 0.0
      }
    }
  },
  "validation_description": {
    "batch_size": 1,
    "num_predicted_time_steps_in_sample": 512,
    "fraction_data_each_epoch": 1.0
  }
}

重要的是training_master_note_array_pathvalidation_master_note_array_path都指向。在数据集创建步骤中创建的 mna_jl 文件。

model_description参数描述了应该如何生成模型。filter_increments中的每个列表控制一个块,每个数字代表当前层的过滤器数量相对于前一层的过滤器数量的增加。添加更多的列表将通过增加深度(更多的块)来增加模型容量,而增加过滤器增量幅度将增加模型的宽度。其余的描述符字段都是不言自明的,它们允许您控制超参数,比如批量大小、每个输入样本序列包含多少个预测音符以及优化器的参数。以上数字都代表了理智的默认。

一旦创建了 run_description.json 文件并将其放在运行目录中,就可以使用以下命令开始培训:

*python pianonet/scripts/runner.py /path/to/run/directory*

这将在您的终端中启动一个培训会话。要查看运行的输出日志,在运行目录中启动另一个终端,并使用tail -f training_output.txt在训练过程中实时查看日志。

模型将定期保存在运行路径内的 Models 目录中,文件名类似于0_trained_model。如果训练停止,可以使用上述命令重新开始,并从最后保存的模型开始。

产生性能

最后一步,一旦你对模型进行了充分的训练,就是听听它的声音。这包括输入您的训练模型的文件路径和性能工具方法的种子。我已经创建了一个 jupyter 笔记本,概述了如何一步一步地做到这一点,可以在pianonet/examples/pianonet_mini/get_performances.ipynb找到。

结论

基于扩张卷积的全卷积神经网络在正确训练时可以成功地生成令人信服的钢琴音乐。这些模型可以输入原始的音符序列,易于构建,并且在一些技巧的帮助下易于训练。最棒的是,如果使用 Fast-WaveNet 算法,他们几乎可以实时生成音乐。 PianoNet 是一个 python 包,可以轻松重现所有这些特性。

虽然这些全卷积网络的性能听起来相当不错,但与简介中提到的基于变压器的架构相比,它们在某些方面有所欠缺。因为全卷积网络被有效地限制为具有短于 20 秒的感受域,所以它们不能学习超过这个时间尺度的歌曲模式,例如奏鸣曲式的重复结构。卷积模型也很难学习旋律,而基于 NLP 的 transformer 模型似乎做得很好。

尽管有这些缺点,本帖中描述的全卷积架构相对简单,易于使用,并且是探索机器生成艺术可能性的一种快速方式。

参考

[1]波网论文:https://arxiv.org/abs/1609.03499

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

[3]快波网论文:https://arxiv.org/abs/1611.09482

用闪亮的 Web 应用生成泊松分布

原文:https://towardsdatascience.com/generating-poisson-distributions-with-shiny-web-apps-9c3352a006ab?source=collection_archive---------47-----------------------

使用闪亮的网络应用程序进行交互式概率分析

泊松分布使我们能够想象在给定的时间间隔内一个事件发生的概率。这些事件必须相互独立。

这方面的一些例子可能是:

  • 一个人每周收到的电子邮件数量(假设电子邮件相互独立到达)
  • 给定时间间隔内极端天气事件的数量,例如一个国家每 10 年发生一次异常寒潮的概率
  • 一家公司在一周内的产品销售数量

例子

让我们以酒店取消为例(Antonio、Almeida 和 Nunes 的数据和研究,可从下面的参考资料部分获得)。

假设在给定的一周内,酒店会有一定数量的预订取消。根据研究中的第一个数据集(H1),酒店预计每周平均有 115 次预订取消。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:闪亮的网络应用

从上面我们可以看到,酒店预计每周最少有 90 次取消预订,最多有 150 次取消预订。

然而,一个闪亮的 Web 应用程序的优势在于,它允许我们动态地分析一系列不同的场景,由此可以操纵 l (我们的λ值)。

例如,研究中的另一家酒店(H2)平均每周有 287 次取消预订。让我们更改 lambda 值,看看这会如何影响分析。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:闪亮的网络应用

在这种情况下,我们看到每周大约有 230–330 次取消。这将允许酒店经理对每周可预期的酒店取消的大致数量进行概率评估。

也就是说,上述泊松分布可用于分析任何问题——只需知道λ值,并在必要时调整 x 轴,以说明特定数据集的整体值范围。

你为什么不自己试试这个模拟?

创建您自己的闪亮网络应用程序

要生成闪亮的 Web 应用程序,请执行以下操作:

  1. 打开 RStudio,点击文件- >新文件- >闪亮 Web App
  2. 选择多文件并为您的应用程序指定一个名称。
  3. ui 中。R ,粘贴以下内容:
library(shiny)# Define UI for application that draws a Poisson probability plot
shinyUI(fluidPage(

  # Application title
  titlePanel("Poisson Distribution"),

  # Sidebar with a slider input for value of lambda
  sidebarLayout(
    sidebarPanel(
      sliderInput("l",
                  "l:",
                  min = 1,
                  max = 400,
                  value = 1)
    ),

    # Show a plot of the generated probability plot
    mainPanel(
      plotOutput("ProbPlot")
    )
  )
))

4.在服务器中。R ,粘贴以下内容:

library(shiny)
library(ggplot2)
library(scales)# Shiny Application
shinyServer(function(input, output) {

  # Reactive expressions
  output$ProbPlot <- renderPlot({

    # generate lambda based on input$lambda from ui.R
    l = input$l
    x <- 0:400

    # generate trials based on lambda value
    muCalculation <- function(x, lambda) {dpois(x, l=lambda)}
    probability_at_lambda <- sapply(input$x, muCalculation, seq(1, 400, 0.01))
    # draw the probability
    plot(x, dpois(x, l), type='h',lwd=3)
    title(main="Poisson Distribution")
  })

})

5.完成后,点击控制台右上角的运行应用:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

资料来源:RStudio

现在,您将看到一个动态泊松分布,其中 l (lambda) 可以动态调整:)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:闪亮的网络应用

现在,假设你想调整音阶。如果您正在处理一个小得多的问题,例如,您平均每天收到 10 封电子邮件,并且想知道这个时间间隔的最小值和最大值,该怎么办?

在 ui 中。r,我们把最大 lambda 值设为 20。

# Sidebar with a slider input for value of lambda
  sidebarLayout(
    sidebarPanel(
      sliderInput("l",
                  "l:",
                  min = 1,
                  max = 20,
                  value = 1)

在服务器中。r, x 的值和顺序可以调整。让我们将最大范围设置为 20。

x <- 0:20
probability_at_lambda <- sapply(input$x, muCalculation, seq(1, 20, 0.01))

假设 l = 10 ,下面是现在的分布图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来源:闪亮的网络应用

结论

泊松分布在分析给定时间间隔内一定数量的事件发生的概率时非常有用——当我们可以使用闪亮的 Web 应用程序进行动态分析时甚至更有用!

非常感谢您阅读本文,感谢您的任何问题或反馈。

您还可以找到我的 GitHub(MGCodesandStats/shiny-we b-apps)的链接,其中包含下面的代码脚本,以及其他有用的参考资料。

免责声明:本文是在“原样”的基础上编写的,没有担保。本文旨在提供数据科学概念的概述,不应以任何方式解释为专业建议。

参考

使用 Python 在数据库中生成随机数据

原文:https://towardsdatascience.com/generating-random-data-into-a-database-using-python-fd2f7d54024e?source=collection_archive---------4-----------------------

使用 Pandas 用虚拟数据填充 MySQL 数据库

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

来自 pixabay艾托夫的照片

在本文中,我们将演示如何为 MySQL 数据库生成虚拟数据和输入。大多数情况下,我们需要创建一个数据库来测试我们构建的一些软件。为此,我们可以使用结构化的 Q 查询 L 语言(SQL)来创建一个模拟数据库系统。但是,如果我们要测试数百甚至数千条记录,可能会出现问题。我们绝对不可能在我们的 SQL 脚本中编写这么多的 insert 语句来满足产品部署的测试截止日期,那将是非常乏味和耗时的。

为了帮助解决这个问题,我们值得信赖的朋友 Python 来帮忙了!

巨蟒来救援了!

您可能知道也可能不知道,python 是一种脚本语言,以其丰富的库而闻名。Python 还以其使用非常简单的语法自动执行任务的能力而闻名。

必备知识:

  • 使用 pip 安装 python 包。
  • 对什么是数据库以及它们如何使用 SQL 有基本的了解。

即使您不具备上述要求,本文也将确保您理解其内容,以帮助您进一步发展您的 Python 事业。

所以让我们开始吧!

我们将在这个项目中使用的 python 库是:

  • Faker这是一个可以为你生成伪数据的包。我们将用它来生成我们的虚拟数据。
  • 熊猫 —这是一个数据分析工具。这将用于封装我们的虚拟数据,并将其转换为数据库系统中的表格。
  • SQLAlchemy —这是一个用于 SQL 的对象关系映射器(ORM)。ORM 将被用作我们的数据库引擎,因为它将为我们的数据库提供连接。

我们将使用的其他工具包括:

  • XAMPP —这是一个包含 MariaDB、PHP 和 Perl 数据库管理系统的发行版。我们将使用 MariaDB,这是我们的 SQL 数据库。

注意:然而,可以使用不同类型的数据库,因为本文将关注 MySQL 连接。所以,对于任何其他数据库如 PostgreSQL、微软 SQL Server、Oracle 等。将需要替代配置。

入门指南

我们开始吧!

首先,我们需要前面提到的那些 python 库。Pip—PIPIinstallsPpackages(简称 Pip)。PIP 是 python 的包管理器,也是我们用来安装 python 包的工具。

注:康达也可以用于那些森蚺发行爱好者。

*pip install **pandas Faker sqlalchemy mysqlclient***

我们现在已经使用上面的代码安装了所有相关的包。

导入库

首先,我们需要导入相关的库。

*import pandas as pd
from faker import Faker
from collections import defaultdict
from sqlalchemy import create_engine*

defaultdict(默认字典)来自 collections 包。这将作为我们的字典,因为它将提供比普通字典更多的功能,我们将在本文后面看到。

生成虚拟数据

为了生成我们的虚拟数据,我们将首先初始化我们将用来获取虚拟数据的Faker实例。

*fake = Faker()*

我们将使用fake_data 来创建我们的字典。defaultdict(list)将创建一个字典,该字典在被访问时将创建当前没有存储在字典中的键值对。本质上,您不需要在字典中定义任何键。

*fake_data = defaultdict(list)*

现在,让我们决定从Faker实例中获取哪种数据,并存储在fake变量中。这种数据的一个例子包括:

  1. 西方人名的第一个字
  2. 职业
  3. 出生日期
  4. 国家

我们可以在伪数据实例中通过不同的方法访问这些数据。

我们将要访问的方法是first_name()last_name()job()date_of_birth()country()

我们将循环一千次来访问这些方法,然后将它们添加到我们的字典中。

*for _ in range(1000):
    fake_data["first_name"].append( fake.first_name() )
    fake_data["last_name"].append( fake.last_name() )
    fake_data["occupation"].append( fake.job() )
    fake_data["dob"].append( fake.date_of_birth() )
    fake_data["country"].append( fake.country() )*

注意:因为使用了 **defaultdict(list)** ,所以每当我们访问一个不是我们创建的键时,就会自动添加一个空 list []作为它的值。

现在,因为我们的字典fake_data中有所有的随机数据。我们需要将这些数据打包到我们的熊猫数据框架中。

*df_fake_data = pd.DataFrame(fake_data)*

pandas 数据框架提供了许多分析和操作数据的功能。为了这个项目的目的,我们将操纵这个数据帧作为一个数据库条目。

向数据库添加虚拟数据

首先,让我们建立数据库连接!我们将使用前面提到的 XAMPP 来启动我们的 SQL 实例。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我们已经成功启动了我们的数据库。现在,我们将创建一个数据库,其中包含由 python 脚本使用下面的代码生成的表。

*mysql -u root
create database testdb;*

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

看啊!我们启动了我们的 MySQL 数据库(这里是 MariaDB ),并创建了我们的testdb数据库。

注意:Root 是我的用户名。没有为我的帐户配置(创建)密码。但是,如果您创建了密码,在 **mysql -u root** 后可能会有提示,要求您输入密码。

如你所见,我使用的是命令行版本的 MySQL。GUI 版本也是一个备选选项。

现在,我们的下一步是将我们创建的数据库连接到我们的 python 代码。为此,我们将使用来自sqlalchemy 库的引擎。

*engine = create_engine('mysql://root:[@localhost/](http://twitter.com/localhost/foo)testdb', echo=False)*

create_engine中的琴弦遵循driver://username:password**@host**:port/database的结构。如你所见,我没有密码,所以它是空白的。可以指定端口,但是如果您使用 MySQL 的默认配置,就没有必要了。

现在我们已经创建了我们的连接,我们现在可以将熊猫数据帧直接保存到我们的数据库testdb

*df_fake_data.to_sql('user', con=engine,index=False)*

当执行上面的代码时,将在我们的数据库中创建一个用户表,并向其中添加一千条记录。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者截图

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者截图

通过查看数据和屏幕截图左下角的行号,您可以看到,我们刚刚生成了 1000 条记录!

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

按作者显示表中行数的屏幕截图。

获取代码

该项目的完整代码位于以下要点中:

奖金!

让我们生成十万(100,000)条记录!

一个可以完成的任务是通过增加循环中的迭代次数来增加生成的假记录的数量。

注意。我们首先需要使用查询 *drop table user;*删除之前由我们的脚本创建的用户表

*for _ in range(**100000**):
    fake_data["first_name"].append( fake.first_name() )
    fake_data["last_name"].append( fake.last_name() )
    fake_data["occupation"].append( fake.job() )
    fake_data["dob"].append( fake.date_of_birth() )
    fake_data["country"].append( fake.country() )*

由于我的终端输出的记录太多,我将只说明行数:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

下面的时间戳显示了在我的机器上生成十万条记录所用的时间:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

不错的成绩对吧!

我们在短短 31 秒内就在数据库中创建了 100,000 条记录。31 秒!你能相信吗,疯狂的权利!

摘要

我们能够创建一个由普通用户数据填充的数据库,如他们的名字、姓氏、出生日期、职业和国家。我们不仅创造了它,而且在很短的时间内创造了它。这个解决方案的一个好处是,它比我遇到的许多其他解决方案都要快。请随意使用 faker 库。它还可以用来生成许多其他类型的数据。

加入我们的邮件列表

如果您喜欢这篇文章,请注册,以便在我们发布新文章时收到电子邮件。使用此链接输入您的电子邮件,完全免费!

用 LSTM 的生成简短的星球大战文本

原文:https://towardsdatascience.com/generating-short-star-wars-text-with-lstms-c7dc65e252c4?source=collection_archive---------42-----------------------

“会说话并不会让你变得聪明”——绝地大师魁刚·金。

毫无疑问,我是那些被称为“星球大战迷”的人中的一员。我记得小时候在电视上看《幽灵的威胁》时被它震撼了(我知道,这不是一部伟大的电影)。后来,我看了《T2》中的《克隆人的进攻》和《T4》中的《西斯的复仇》(这是影院上映的最后一部电影),接着又看了原版三部曲的 DVD,那时这些电影还在上映。作为一个成年人,我在右臂上纹了一个 Tie 战士的纹身,这让我达到了高潮。

对《星球大战》的热情很好地回答了“我应该做什么样的 NLP 项目?”;我想开发一个完整的自然语言处理项目,边做边练习一些技能。

这是一个关于 LSTM 氏症的项目实验的简要文档,以及如何训练一个语言模型来在字符级别上生成特定域内的文本。给定一个种子标题,它通过一个 API 编写一个简短的描述。该模型是使用 Tensorflow 从零开始构建的,没有迁移学习。它使用了来自 Wookiepedia.com 的文本,Fandom.com 的团队(负责管理网站)非常友好地允许我使用网络抓取器收集数据并发表这篇文章。

最终产品

下面可以看到工作模型的演示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作者图片

要求

为了复制这个模型,你需要从这里下载代码。然后,安装所有需要的依赖项(强烈建议创建一个新的虚拟环境,并在其上安装所有软件包),如果您使用的是 Linux,则:

pip install -r requirements-linux.txt

但是,如果您使用的是 Windows,只需使用:

pip install -r requirements-windows.txt

在安装了所有依赖项之后,您需要经过训练的模型能够生成任何文本。由于 GitHub 上的大小限制,模型必须从这里下载。只需下载整个模型文件夹,并将其放在部署文件夹下。最后,激活安装了所有依赖项的环境,并在下载项目的文件夹中打开终端,键入:

python deploy/deploy.py

该项目

下面是所有使用的重要库的列表:

  • 美丽的声音
  • 要求
  • Lxml
  • 熊猫
  • Numpy
  • MatplotLib
  • 张量流
  • 超文本标记语言
  • 半铸钢ˌ钢性铸铁(Cast Semi-Steel)

我们现在将检查项目的所有主要部分。

数据处理

用于训练模型的文本是使用网络报废从伍基人百科网站(一种星球大战维基百科)中挖掘出来的。用于该任务的所有代码都在 wookiescraper.py 文件中,并且创建了一个类Article来构造文本,每篇文章都包含一个标题、主题描述(这将是文章页面上的第一个简要描述)以及它们所属的类别。提取数据的主要库是 beautifulsoup、requests 和 Pandas(在数据帧中存储文本)。

为了列出所有可能的文章,调用了函数create_complete_database。它创建了一个所有佳能文章的 URL 列表(在《星球大战》宇宙中,所有在书籍、漫画和视频游戏等替代媒体中产生的故事都被重新启动;旧的故事被贴上“传说的标签,而仍然是官方的故事和新的故事被认为是经典。然后,它通过使用 Article 类自己的函数下载并创建列表中的每篇文章。然后创建一个包含所有下载文章的数据框架,并保存在一个完整的 Database.csv 文件中。

为了给模型提供信息,我们还必须处理获得的数据;文件 data_processor.py 包含该任务使用的所有代码。函数clean_data获取文本的数据帧,并通过删除不需要的字符和缩短文本对其进行格式化(这是必须要做的,因为我们正在创建一个在字符级别上工作的模型,该模型将很难从较长的句子中学习模式和上下文)。该文件还包含将给定的文本语料库转换成单热点向量的函数,反之亦然,以及数据集生成器函数;函数build_datasets将构建一个 training_dataset 和一个 validation_dataset ,而不是在训练期间将所有数据加载到内存中,每一个都是 Tensorflow Dataset 对象,它们在训练期间处理数据并将数据作为块馈送到模型中。

模型和培训

LSTM 是一种递归神经网络细胞,在长数据序列中具有更高的信息保持能力。因为这个特性,它在处理 NLP 问题时非常有用。对于这个项目,使用了一个序列到序列架构来生成输出句子。在这种方法中,输入字符串(文章的标题)被提供给编码器,编码器按顺序逐个字符地处理数据,并传递包含输入信息的编码向量。然后,解码器将使用此信息再次按顺序逐个字符地生成新的嵌入向量,该向量将进入 softmax 层以生成概率向量,每个可能的字符一个值。每个输出字符在前一个字符之后生成,总是使用包含编码器生成的输入信息的向量。创建和训练模型的代码在文件 run.py 中。

在 GPU 初始化和词汇定义之后,创建了一个config字典,以使超参数调整更容易:

# enable memory growth to be able to work with GPU
GPU = tf.config.experimental.get_visible_devices('GPU')[0]
tf.config.experimental.set_memory_growth(GPU, enable=True)# set tensorflow to work with float64
tf.keras.backend.set_floatx('float64')# the new line character (\n) is the 'end of sentence', therefore there is no need to add a '[STOP]' character
vocab = 'c-y5i8"j\'fk,theqm:/.wnlrdg0u1 v\n4b97)o36z2axs(p'
vocab = list(vocab) + ['[START]']config = {  # dictionary that contains the training set up. Will be saved as a JSON file
    'DIM_VOCAB': len(vocab),
    'MAX_LEN_TITLE': MAX_LEN_TITLE,
    'MAX_LEN_TEXT': MAX_LEN_TEXT,
    'DIM_LSTM_LAYER': 512,
    'ENCODER_DEPTH': 2,
    'DECODER_DEPTH': 2,
    'LEARNING_RATE': 0.0005,
    'BATCH_SIZE': 16,
    'EPOCHS': 100,
    'SEED': 1,
    # 'GRAD_VAL_CLIP': 0.5,
    # 'GRAD_NORM_CLIP': 1,
    'DECAY_AT_10_EPOCHS': 0.9,
    'DROPOUT': 0.2,
}

为了使结果具有可重复性,还将使用种子:

tf.random.set_seed(config['SEED'])

之后,最后,采集的数据被加载到数据帧中,进行清理,现在可以设置新的配置选项,如训练/验证分割:

data = pd.read_csv('Complete Database.csv', index_col=0)data = clean_data(data)config['STEPS_PER_EPOCH'] = int((data.shape[0] - 1500) / config['BATCH_SIZE'])
config['VALIDATION_SAMPLES'] = int(
    data.shape[0]) - (config['STEPS_PER_EPOCH'] * config['BATCH_SIZE'])
config['VALIDATION_STEPS'] = int(
    np.floor(config['VALIDATION_SAMPLES'] / config['BATCH_SIZE']))

然后定义学习率。在这个项目中,一个指数衰减的学习率被证明可以给出最好的结果:

# configures the learning rate to be decayed by the value specified at config['DECAY_AT_10_EPOCHS'] at each 10 epochs, but to that gradually at each epoch
learning_rate = ExponentialDecay(initial_learning_rate=config['LEARNING_RATE'],
                                decay_steps=config['STEPS_PER_EPOCH'],
                                decay_rate=np.power(
                                    config['DECAY_AT_10_EPOCHS'], 1/10),
                                staircase=True)

加载数据后,现在可以构建训练数据集和验证数据集:

training_dataset, validation_dataset = build_datasets(
    data, seed=config['SEED'], validation_samples=config['VALIDATION_SAMPLES'], batch=config['BATCH_SIZE'], vocab=vocab)

以训练后保存模型为目标,将选择一条路径。该文件夹将以通用名称命名,然后更改为模型完成训练的具体时间。此外,词汇和模型配置都将保存为json文件。

folder_path = 'Training Logs/Training'  # creates folder to save traning logs
if not os.path.exists(folder_path):
    os.makedirs(folder_path)# saves the training configuration as a JSON file
with open(folder_path + '/config.json', 'w') as json_file:
    json.dump(config, json_file, indent=4)

# saves the vocab used as a JSON file
with open(folder_path + '/vocab.json', 'w') as json_file:  
    json.dump(vocab, json_file, indent=4)

为了监控模型,使用了一些回调函数(在训练期间以指定的时间间隔调用的函数)。这些函数包含在 callbacks.py 文件中。创建了一个自定义类CallbackPlot,以便在整个训练过程中绘制训练误差。Tensorflow 回调类ModelCheckpointCSVLogger的对象也被实例化,以便分别保存训练时的模型和训练日志:

loss_plot_settings = {'variables': {'loss': 'Training loss',
                                    'val_loss': 'Validation loss'},
                    'title': 'Losses',
                    'ylabel': 'Epoch Loss'}last_5_plot_settings = {'variables': {'loss': 'Training loss',
                                    'val_loss': 'Validation loss'},
                        'title': 'Losses',
                        'ylabel': 'Epoch Loss',
                        'last_epochs': 5}plot_callback = CallbackPlot(folder_path=folder_path,
                            plots_settings=[
                                loss_plot_settings, last_5_plot_settings],
                            title='Losses', share_x=False)model_checkpoint_callback = ModelCheckpoint(
    filepath=folder_path + '/trained_model.h5')csv_logger = CSVLogger(filename=folder_path +
                    '/Training logs.csv', separator=',', append=False)

最后,可以构建、编译和训练模型:

###### BUILDS MODEL FROM SCRATCH WITH MULTI LAYER LSTM ###########
tf.keras.backend.clear_session()  # destroys the current graphencoder_inputs = Input(shape=(None, config['DIM_VOCAB']), name='encoder_input')
enc_internal_tensor = encoder_inputsfor i in range(config['ENCODER_DEPTH']):
    encoder_LSTM = LSTM(units=config['DIM_LSTM_LAYER'],
                        batch_input_shape=(
                            config['BATCH_SIZE'], MAX_LEN_TITLE, enc_internal_tensor.shape[-1]),
                        return_sequences=True, return_state=True,
                        name='encoder_LSTM_' + str(i), dropout=config['DROPOUT'])
    enc_internal_tensor, enc_memory_state, enc_carry_state = encoder_LSTM(
        enc_internal_tensor)  # only the last states are of interestdecoder_inputs = Input(shape=(None, config['DIM_VOCAB']), name='decoder_input')
dec_internal_tensor = decoder_inputsfor i in range(config['DECODER_DEPTH']):
    decoder_LSTM = LSTM(units=config['DIM_LSTM_LAYER'],
                        batch_input_shape=(
                            config['BATCH_SIZE'], MAX_LEN_TEXT, dec_internal_tensor.shape[-1]),
                        return_sequences=True, return_state=True,
                        name='decoder_LSTM_' + str(i), dropout=config['DROPOUT'])  # return_state must be set in order to retrieve the internal states in inference model later
    # every LSTM layer in the decoder model have their states initialized with states from last time step from last LSTM layer in the encoder
    dec_internal_tensor, _, _ = decoder_LSTM(dec_internal_tensor, initial_state=[
                                            enc_memory_state, enc_carry_state])decoder_output = dec_internal_tensordense = Dense(units=config['DIM_VOCAB'], activation='softmax', name='output')
dense_output = dense(decoder_output)model = Model(inputs=[encoder_inputs, decoder_inputs], outputs=dense_output)model.compile(optimizer=optimizer, loss='categorical_crossentropy')history = model.fit(x=training_dataset,
                    epochs=config['EPOCHS'],
                    steps_per_epoch=config['STEPS_PER_EPOCH'],
                    callbacks=[plot_callback, csv_logger,
                            model_checkpoint_callback],
                    validation_data=validation_dataset,
                    validation_steps=config['VALIDATION_STEPS'])

训练后,文件夹将包含与本次训练相关的所有数据,如损失函数图、不同时间步长的误差以及模型本身。

model.save(folder_path + '/trained_model.h5', save_format='h5')
model.save_weights(folder_path + '/trained_model_weights.h5')
plot_model(model, to_file=folder_path + '/model_layout.png', show_shapes=True, show_layer_names=True, rankdir='LR') timestamp_end = datetime.now().strftime('%d-%b-%y -- %H:%M:%S')# renames the training folder with the end-of-training timestamp
root, _ = os.path.split(folder_path)timestamp_end = timestamp_end.replace(':', '-')
os.rename(folder_path, root + '/' + 'Training Session - ' + timestamp_end)print("Training Successfully finished.")

部署

为了服务于该模型,使用 Flask 包构建了一个简单的接口,其代码可以在 deploy 文件夹下找到。

结论

经过训练后,该模型能够在给定种子字符串的情况下生成句子。下面是生成句子和用于生成句子的种子字符串的一些示例(我将使用我的猫的名字作为示例,但是因为它们已经被称为 Luke、Han 和 Leia,所以它们已经存在于训练数据集中):

  • 佩德罗:佩德罗是一名男性人类,在瑞博·l·阿拉内特·奥尼号上担任指挥官。
  • 佩德罗·恩里克:佩德罗·欧索农是一名人类女性,在银河共和国的加巴尔形态中担任指挥官。
  • 奇科是一名塔姆泰德人,作为银河帝国的指挥官为银河帝国服务。
  • 莎拉:莎拉是一名人类男性,在银河内战期间,他在共和军中担任指挥官。

从上面可以看出,该模型学习了如何合理地形成一些单词,如何确定这些单词的大小,如何正确地结束一个句子,以及如何形成某种上下文。然而,它似乎严重偏向于总是描述在《星球大战》宇宙中的一个派系下服务的人类。这可以用这样一个事实来解释,即模型的架构不是使用单词嵌入构建的(这将允许更复杂的上下文学习),因为有几个单词是《星球大战》独有的。我对未来项目的一个好主意将是为星球大战宇宙生成一个特定的单词嵌入,然后使用它来生成新的文本。

通过无监督学习生成 Spotify 播放列表

原文:https://towardsdatascience.com/generating-spotify-playlists-with-unsupervised-learning-abac60182022?source=collection_archive---------25-----------------------

数字音乐

人工智能能区分愚蠢的朋克和混蛋吗?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片— Stas Knop on Pexels

这个系列之前的博客中,我们探索了音乐流媒体巨头 Spotify 如何创建算法,完全基于其波形自动描述任何歌曲的音乐质量。这些算法可以计算一些显而易见的音乐属性(例如,一首歌有多快,它的调是什么)。然而,他们也可以得到更微妙的措施;一首歌有多快乐?是冰镇还是高能?你能随着它跳舞吗?

为了看看这是如何工作的,我创建了一个播放列表,比如说,一些折衷的内容——Kendrick Lamar 到黑色安息日,通过披头士和 Billie Eilish。当然,还有德帕西托。

让我们看看 Spotify 如何根据各种音频特征指标对这些歌曲进行分类(这些指标的完整描述可以在之前的博客中找到)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

节奏稳定、不间断的歌曲被认为更适合跳舞——因此像《真正的苗条阴影》和《卑微》这样的说唱歌曲得分很高。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

正如我们在之前的博客中提到的,可跳舞性和能量并不像我们预期的那样高度相关。《黑桃 a》是最有活力的曲目,看过 motrhead 现场演出的人都不会感到惊讶。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

回忆——高价曲目是‘快乐和欣快’,低价曲目是‘阴郁和悲伤’。看到比莉·埃利什在这个排名中垫底,我们不应该感到惊讶。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

在这里,Spotify 给出了一个从 0 到 1 的置信度,来判断该曲目是否是原声的。“多灾多难的水上桥梁”被正确识别。黑色安息日的重金属敏感性也在排名中垫底。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

“Speechiness”试图在音频文件中查找口语单词。播客得分接近 1,说唱音乐通常在 0.2 到 0.5 之间。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Spotify 正确地指出了播放列表中的一首器乐歌曲(蠢朋克),尽管也认为 Joy Division 是器乐歌曲(可能是因为伊恩·柯蒂斯的演唱风格,以及它在整体混音中的位置)。

当然,我们可以用这些方法来思考哪些歌曲在发音上相似。让我们暂时保持简单,并假设歌曲只有两个特征——舞蹈性和效价。这两个度量都取 0 到 1 之间的值,所以我们可以通过它们在散点上的两点之间的(欧几里德)距离来推断两首歌有多相似。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

由红色箭头分隔的歌曲比由黄色箭头分隔的歌曲更“相似”,尽管第二对歌曲具有非常相似的舞蹈性。

我们可以扩展这个逻辑。给定播放列表中的一首歌曲,我们可以通过在散点上找到最近的 n 点来计算出 n 最相似的曲目。但是我们可以做得更复杂——假设我们想把这 32 首歌分成给定数量的播放列表(比如 5 首)。然后,我们需要某种方法来获取上面的散点图,并将这些点分成五个不同的组,其中组内的歌曲彼此“最佳相似”。

如果这听起来很像集群的用例,那是因为它是。具体来说,我们可以部署“分层聚集聚类”(HAC)。用外行人的话来说,HAC 首先将每个单独的点视为其自身的一组点。然后,它合并两个彼此“最接近”的现有集群(注意;在这种情况下,“距离”的定义是可变的——我们稍后将对此进行探讨)。HAC 算法将反复合并“闭合”聚类,直到得出所有数据点都属于一个聚类的自然结论。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

HAC 阶段的示例-请记住,每个点都被视为一个“集群”,因此各个集群的数量随着每个阶段而减少

如前所述,算法如何考虑两个现有集群之间的“距离”是可变的。sci kit-lean 提供了三种“连锁标准”作为其 HAC 包的一部分:

  • 沃德(默认):选择两个聚类合并,使所有聚类内的方差增加最小。一般来说,这导致了大小相当的集群。
  • 平均:合并所有点间 平均 距离最小的两簇。
  • 完成(或称最大联动):合并两个点间 最大 距离最小的聚类。

考虑到 HAC 处理的是“距离”——抽象的或其他的——我们需要在将数据输入聚类算法之前对其进行标准缩放。这确保了我们的最终结果不会被特征单元扭曲。例如,速度通常在每分钟 70 到 180 拍之间,而大多数其他小节在 0 到 1 之间。如果没有缩放,两首节奏非常不同的歌曲将总是“相距甚远”,即使它们在其他指标上完全相同。

幸运的是,使用 Scikit-Learn 的标准缩放和 HAC 非常简单:

**from** sklearn.preprocessing **import** StandardScalersclaer = StandardScaler()
X_scaled = scaler.fit_transform(X)***#This scaled data can then be fed into the HAC alorithm* from** sklearn.cluster **import** AgglomerativeClustering***#We can tell it how many clusters we're aiming for***
agg_clust = AgglomerativeClustering(n_clusters=3)
assigned_clusters = agg_clust.fit_predict(X_scaled)

让我们将 HAC 应用到我们的播放列表中(记住,我们仍然将自己限制在两个维度上——水平轴上是 danceability,垂直轴上是 valence)。我们可以看到不同颜色的数量随着星团的融合而减少。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

当然,由于两点之间的距离可以用二维来定义,所以也可以用三维来定义——下图显示了当我们添加第三个度量(“能量”)时,HAC 算法如何创建四个聚类。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来,我们可以继续添加维度,以同样的方式计算点之间的“距离”,我们只是失去了在“网格”上可视化结果的能力。然而,我们可以通过树状图来查看结果。按照下图从左到右,我们看到不同的歌曲是如何链接在一起成为越来越大的集群。

注意——水平距离表示两个链接的簇有多“接近”,较长的线表示歌曲“相距较远”。如果我们想要创建 n 个集群,我们可以使用树状图来完成。我们只需要在图表的适当位置画一条垂直的直线——不管相交多少条直线,都是创建的集群数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

可以说,这种聚类分析得出了一些有趣的结果。北极猴子和电台司令是显而易见的伙伴,杜阿·利帕和贾斯汀·比伯,莫特海德和黑色安息日也是如此。鲍伊、披头士、平克·弗洛伊德和埃尔维斯·普雷斯利听起来也是一个合理的组合,尽管迈克尔·杰克逊和阿姆是一个令人惊讶的组合。不过,总而言之,我们可以说,Spotify 的 metrics 结合 HAC,在对类似歌曲进行分组方面做得相当不错。

在接下来的几篇博客中,我们将看看如何用数学方法测量聚类结果的质量。然后,我们将从数千首歌曲中制作相似歌曲的播放列表,并研究如何使用 Spotify 的 API 将这些新的播放列表直接上传到用户的个人资料中。

这是我的“ Music By Numbers ”专栏中的最新博客,它使用数据来讲述关于音乐的故事。我很乐意听到对以上分析的任何评论——欢迎在下面留言,或者通过 LinkedIn 联系我!

使用 Mozilla DeepSpeech 为任何视频文件生成字幕

原文:https://towardsdatascience.com/generating-subtitles-automatically-using-mozilla-deepspeech-562c633936a7?source=collection_archive---------10-----------------------

对于那些嘴里薯条的噪音让你无法看电影的时候:)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

玛利亚·特内娃在 Unsplash 上拍摄的照片

在 OTT 平台时代,仍然有一些人喜欢从 YouTube/脸书/Torrents 下载电影/视频(嘘🤫)过流。我就是其中之一,有一次,我找不到我下载的某部电影的字幕文件。然后, AutoSub 的想法打动了我,因为我以前和 DeepSpeech 合作过,我决定用它来为我的电影制作字幕。

给定一个视频文件作为输入,我的目标是生成一个**。srt** 文件。字幕可以导入任何现代视频播放器。在本文中,我将带您浏览一些代码。你可以在我的 GitHub 上找到这个项目,这里有关于如何在本地安装的说明。

先决条件:对 Python 的中级理解,对自动语音识别引擎的一些熟悉,以及对信号处理的基本理解将会很棒。

注意:这是我第一篇关于媒体的文章。如果你有任何建议/疑问,请写下来。快乐阅读:)

Mozilla DeepSpeech

DeepSpeech 是基于百度原创深度语音研究论文的开源语音转文本引擎。鉴于其多功能性和易用性,它是最好的语音识别工具之一。它是使用 Tensorflow 构建的,可以使用自定义数据集进行训练,在庞大的 Mozilla Common Voice 数据集上进行训练,并在 Mozilla Public License 下获得许可。最大的好处是我们可以下载模型文件并在本地执行推理只需几分钟!

虽然,DeepSpeech 确实有它的问题。该模型与非母语英语口音的语音进行斗争。对此有一个解决方法——使用我们想要预测的语言中的自定义数据集来微调模型。我将很快就如何做到这一点写另一篇文章。

如果你正在处理语音识别任务,我强烈建议你看看 DeepSpeech。

自动 Sub

让我们从安装一些我们需要的包开始。所有命令都已经在 Ubuntu 18.04 的 pip 虚拟环境中进行了测试。

  1. FFmpeg 是领先的多媒体框架,能够解码、编码、转码、复用、解复用、流式传输、过滤和播放人类和机器创造的几乎任何东西。我们需要它从我们的输入视频文件中提取音频。
$ sudo apt-get install ffmpeg
  1. DeepSpeech :从 PyPI 安装 python 包,下载模型文件。记分员文件是可选的,但大大提高了准确性。
*$* pip install deepspeech*==0.8.2**# Model file (~190 MB)* 
$ wget https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.pbmm*# Scorer file (~900 MB)* $ wget [https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer](https://github.com/mozilla/DeepSpeech/releases/download/v0.8.2/deepspeech-0.8.2-models.scorer)

现在我们都设置好了,让我们首先使用 FFmpeg 从我们的输入视频文件中提取音频。我们需要创建一个子进程来运行 UNIX 命令。DeepSpeech 期望输入音频文件以 16kHz 采样,因此 ffmpeg 的参数如下。

现在,假设我们的输入视频文件有 2 小时长。通常不建议对整个文件运行 DeepSpeech 推断。我试过了,效果不太好。解决这个问题的一个方法是将音频文件分割成无声片段。分割后,我们有多个小文件包含我们需要推断的语音。这是使用 pyAudioAnalysis 完成的。

以下函数使用 pyAudioAnalysis 中的函数 read_audio_file()silenceRemoval() ,并从语音开始和结束的位置生成分段限制。参数以秒为单位控制平滑窗口大小,以(0,1)为单位控制权重因子。使用段限制,较小的音频文件被写入磁盘。

我们现在需要分别对这些文件运行 DeepSpeech 推断,并将推断的文本写入一个 SRT 文件。让我们首先创建一个 DeepSpeech 模型的实例,并添加 scorer 文件。然后,我们将音频文件读入一个 NumPy 数组,并将其送入语音转文本功能以产生推断。如上所述,pyAudioAnalysis 保存的文件具有以秒为单位的段限制时间。在写入 SRT 文件之前,我们需要提取这些限制并将其转换成合适的形式。这里的定义了写功能

整个过程不应超过原始视频文件持续时间的 60%。这里有一个视频,展示了在我的笔记本电脑上运行的一个例子。

自动 Sub 演示

还有一个领域我希望在未来改进。推断的文本是无格式的。我们需要添加适当的标点符号,纠正单词中可能的小错误(一个字母之外),并将很长的片段分成较小的片段(尽管这很难自动化)。

就是这样!如果您已经到达这里,感谢您的坚持:)

你可以在这里找到我: LinkedInGitHub

用 WGANs 生成合成金融时间序列

原文:https://towardsdatascience.com/generating-synthetic-financial-time-series-with-wgans-e03596eb7185?source=collection_archive---------18-----------------------

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

寻找稳定的平衡——泰勒·米利根在 Unsplash 上的照片

Pytorch 代码的首次实验

介绍

过度拟合是研究人员在尝试将机器学习技术应用于时间序列时遇到的问题之一。出现这个问题是因为我们使用我们已知的唯一时间序列路径训练我们的模型:实现的历史。毕竟,我们一生只见过这个世界的一种状态:无聊,不是吗?=)

特别是,并非所有可能的市场机制或事件都能在我们的数据中得到很好的体现。事实上,极不可能发生的事件,如异常高波动时期,通常会被低估,这使得模型无法得到足够好的训练。所以,当这些经过训练的算法面对新的场景时,它们可能会失败;如果我们在没有任何预防措施的情况下让它们生产足够长的时间,这种情况就会发生。

现在,如果我们可以教一个模型为相同的资产生成新的数据,会怎么样呢?如果我们有一种工具,可以产生与原始时间序列具有相同统计特性的替代现实时间序列,会怎么样?有了这样的工具,我们可以用关于不可能发生的事件或罕见的市场机制的数据来扩充我们的训练集;因此,研究人员将能够建立更好的模型,从业者将执行更好的模拟和交易回测。在这方面,最近在《金融数据科学杂志》上发表的论文的作者展示了在合成数据上训练深度模型如何减轻过度拟合并提高性能。

事实证明,生成对抗网络(GANs)可以做到这一点。GANs 是一个机器学习框架,其中两个神经网络,一个生成器(G)和一个鉴别器(D),互相玩游戏,前者试图欺骗后者生成类似真实事物的假数据。当我说“游戏”时,我指的是这里的博弈论!

然而,没有人应该获胜:GAN 的研究人员总是在 G 和 D 之间寻找纳什均衡,希望——GAN 可能很难训练——生成器已经学会如何产生虚假但真实的样本,鉴别器的最佳选择是随机猜测。

本文的目的

我在这里的目的不是深入研究 GANs 的理论(网上有很好的论文和资源),而是简单地触及基础,分享我和我的队友兼朋友 Andrea Politano 的实验结果。

虽然我们的最终目标是使用一个或多个经过训练的生成器一次生成多个时间序列,但我们选择从简单开始,逐步进行。在这方面,我们首先检查 GANs 是否能够学习我们完全理解的数据生成过程(DGP)的系列。当然,只有少数人——如果有的话——理解金融资产回报的 DGP;因此,我们开始产生假正弦波。

我们的模型

我们首先对 Pytorch 数据集进行编码,以产生不同的正弦函数。Pytorch 数据集是方便的实用程序,它使数据加载更容易,并提高了代码的可读性。点击查看

Pytorch 数据集生成正弦

然后,我们选择了 Wasserstein GAN (WGAN),因为这种特殊类型的模型具有坚实的理论基础,并显著提高了训练稳定性;此外,损失与生成器的收敛和样本质量相关-这非常有用,因为研究人员不需要不断检查生成的样本来了解模型是否在改进。最后,WGANs 比标准的 gan 对模式崩溃和架构变化更健壮。

WGANs 和 gan 有什么不同?

标准 GAN 中的损失函数量化了训练和生成的数据分布之间的距离。事实上,GANs 基于这样的思想,随着训练的进行,模型的参数逐渐更新,并且 G 学习的分布收敛到真实的数据分布。这种收敛必须尽可能平滑,重要的是要记住这个分布序列收敛的方式取决于我们如何计算每对分布之间的距离。

现在,WGANs 与标准 gan 在量化距离的方式上有所不同。常规 gan 使用Jensen–Shannon divergence(JS),而 WGANs 使用 Wasserstein distance ,其特征在于更好的属性。特别是,Wasserstein 度量是连续的,在任何地方都有良好的梯度,因此即使当真实分布和生成分布的支持位于非重叠低维流形中时,也允许更平滑的分布收敛**。**查看这篇好的文章了解更多细节。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图片直接取自 WGANs 的原始文件。它显示了标准 GAN 的鉴别器如何饱和并导致梯度消失,而 WGAN critic 在空间的所有部分提供非常干净的梯度。

李普希茨约束

简单的 Wasserstein 距离是相当棘手的;因此,我们需要运用一个聪明的技巧——Kantorovich-Rubinstein 对偶——来克服这个障碍,获得我们问题的最终形式。按照理论,我们的瓦瑟斯坦度量的新形式中的函数 f_w 必定是 K-Lipschitz 连续的f_w 由我们的评论家学习,属于参数化函数序列; w 代表一组参数,即权重。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

目标函数的最终形式——瓦瑟斯坦度量。相对于真实分布计算第一期望,而相对于噪声分布计算第二期望。z 是潜在张量,g_theta(z)代表 g 产生的伪数据。这个目标函数表明,t 批评家并不直接归因于一个概率。相反,它被训练来学习 K-Lipschitz 连续函数,以帮助计算我们的 Wasserstein 距离的最终形式。

我们说一个可微函数是 K-Lipschitz 连续的当且仅当它在任何地方都有范数至多为 K 的梯度。k 称为李普希茨常数。

Lipschitz 连续性是一种很有前途的改善 GANs 训练的技术。不幸的是,其实施仍然具有挑战性。事实上,这是一个活跃的研究领域,有几种方法可以加强约束。最初的 WGAN 论文提出了权重裁剪,但是我们采用了一种“梯度惩罚”(GP)方法,因为权重裁剪会导致容量问题,并且需要额外的参数来定义权重所在的空间。另一方面,GP 方法能够在几乎没有超参数调整的情况下实现更稳定的训练。

第一架构

我们的第一个架构来自这篇论文,其中提出了一个 WGAN-GP 架构来生成单变量合成金融时间序列——不从零开始总是一个好主意。所提出的架构混合了 G 和 D 中的线性层和卷积层,并且开箱即用。不幸的是,尽管最初的 WGAN-GP 论文明确规定**“无批判批次归一化”**,但使用这种设置训练看起来并不十分稳定,并且 D 是通过批次归一化(BN)实现的。

因此,我们摆脱了 BN,转而采用频谱归一化(SN)。简单来说,SN 确保 D 是 K-Lipschitz 连续的。为此,它逐步作用于你的批评家的每一层,以限制它的李普希兹常数。更多细节参见这篇伟大的文章和这篇论文

虽然从理论上讲 SN 可以消除损失中的 GP 项——SN 和 GP 应该被认为是加强 Lipschitz 连续性的替代方法——但我们的测试并不支持这一观点。然而,SN 提高了训练的稳定性并使收敛更快。因此,我们在 G 和 d 中都采用它。

最后,最初的 WGAN-GP 论文建议对 G 和 D 都使用 Adam 优化器,但是我们根据经验发现 RMSprop 更适合我们的需要。

批评家和生成器的 Pytorch 代码

要尝试一下,你还需要一段代码来计算损失,反向传递,更新模型权重,保存日志,训练样本等。你会在下面找到它。如果你需要更多关于如何使用这个代码的细节,请参考这个回购

培训师代码

结果

好消息是,我们的模型学会了生成真实的正弦样本;坏消息是正弦不是资产回报!=)那么,下一步如何增加我们对这种模式的信任呢?

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用训练过的模型生成不同的真实正弦波

为什么我们不去掉简单的正弦信号,用来自一个我们知道参数的 ARMA 工艺的样本来填充 GAN 呢?!

我们选择一个简单的 ARMA(1,1)过程,其中 p =0.7 和 q =0.2,使用新的 Pytorch 数据集生成真实样本并训练模型。

Pytorch ARMA 数据集

我们现在生成一百个假样本,估计 pq看看下面的结果。pT22q是我们 DGP 唯一的参数。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

用训练模型生成的合成 ARMA(1,1)样本

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

对合成 ARMA 样本进行的参数估计的分布。可以看出,模型很好地学习了 DGP。事实上,这些分布的模式接近 DGP 的真实参数 p 和 q,它们分别是 0.7 和 0.2。

这些结果加强了我们的信任,并鼓励进一步的研究。

奖金部分

亏损应该是什么样的?

在我们的第一次实验中,我们不停地问自己会从损失中得到什么。当然,一切都取决于训练数据、优化算法和你选择的学习率,但我们根据经验发现,成功的训练的特点是损失,尽管在开始时不稳定,但随后会逐渐收敛到较低的值。在其他条件相同的情况下,降低学习率可以稳定训练。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

发电机损耗示例

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

评论家的损失例子

如何检查模式崩溃?

为了检查模式崩溃,我们在训练期间每次生成假样本时都使用不同的潜在张量。通过这样的程序,我们可以检查对噪声空间的不同部分进行采样时会发生什么。如果你对不同的随机张量进行采样,而 G 一直产生相同的序列,那么你正在经历模式崩溃。=(

GANs 比其他发电机制更有优势吗?

这是一个重要的问题,我想通过进一步的实验来回答:GANs 的复杂性必须通过明显更好的性能来证明。

GP 限值

我们必须提到,根据这篇论文的作者,标准 GP 方法可能不是 Lipschitz 正则化的最佳实现。此外,频谱归一化可能会不必要地限制评论家,并削弱其为 g 提供声音梯度的能力。当标准方法失败时,作者提出了一种替代方法。我们将很快试验他们的建议。

为什么要训练 D 多于 G?

一个训练有素的 D 在 WGAN 环境中至关重要,因为评论家估计真实和虚假分布之间的 Wasserstein 距离。一个最佳的评论家将提供我们的距离度量的良好估计,这反过来将导致梯度是健康的!

文献学

  • 【2019】在 GANs 中实现 Lipschitz 连续性的高效和无偏实现—周,沈等
  • 【2019】用生成式对抗网络丰富金融数据集,de Meer Pardo
  • 【2018】生成性对抗网络的谱归一化——宫藤,片冈等
  • 【2017】改善了 Wasserstein GANs — Gulrajani、Ahmed 等人的培训
  • 【2017】wasser stein GAN—Arjovsky,Chintala 等人
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值