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

原文:TowardsDataScience Blog

协议:CC BY-NC-SA 4.0

借助递归神经网络生成分子

原文: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和我预约时间

参考

通过生成密码来揭开生成模型的神秘面纱—第 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 内核的趋势,并作为编写新内核和获得奖牌的灵感。在本文中:

这个小项目的完整代码可以在 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

谢谢大家!

—埃里克·克莱本

生成,风格: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 ©, 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 纹理,因为我认为它可以对游戏进行一些非常酷的修改,并给我们老前辈一些新的理由来重播我们的最爱,但我仍在研究这样做是否合法。

到那时,感谢阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值