在 Ampere 架构上使用 NVIDIA StyleGAN2-ADA for PyTorch 生成您自己的图像
来自:《我的世界》,70 年代的科幻艺术,假日照片和鱼
StyleGAN2 ADA 允许您训练神经网络,以基于一组训练图像生成高分辨率图像。这方面最经典的例子就是 StyleGAN2 经常用来生成的化妆脸。直到 2021 年 2 月的最新版本,你必须安装旧的 1.x 版本的 TensorFlow,并使用 CUDA 10。这一要求使得很难在 NVIDIA 最新的基于安培的 GPU 上利用 StyleGAN2 ADA。在这篇文章中,我将向你展示如何在 Windows 中使用这个新版本的 StyleGAN,不需要 Docker 或者 Linux 的 Windows 子系统(WSL2 )!
我已经训练过 GANs 产生各种不同的图像类型,你可以从上面我的 GANs 中看到一些例子。我在 GitHub 上提供预先训练的模型来制作这些图像:
你可以利用上述网络,只使用谷歌在线 Colab,为自己生成这些图像。
硬件先决条件
gan 是计算密集型的,这是无法回避的。英伟达的研究人员在 DGX 系统上扔了 8 个 V100s 来训练人脸。StyleGAN 还可以跨多个 GPU 进行线性扩展,因此,StyleGAN 可以在一台机器上使用任何硬件。我在这里展示的图像是在一台双 Quadro RTX 8000 上训练的。
ThinkStation P920 中的双 Quadro RTX 8000
对于本文,我假设我们将使用最新的 CUDA 11 和 PyTorch 1.7.1。NVIDIA 建议 GPU 上 12GB RAM;但是,如果您使用较低的分辨率,例如 256x256,也可以使用更低的分辨率。分辨率较高的 gan 一般以 1024x1024 训练。单个强劲的 GPU,比如一个英伟达 RTX A6000 也做得很好。
我们将在 WSL2 或 Docker 之外安装 StyleGAN2。这提供了最高的性能。相信我,有了 GANs,你想要你机器能提供的每一点计算!
首先,确保您的显卡安装了最新的 NVIDIA 驱动程序:
第二,安装最新版本的 CUDA 11。如果 CUDA 12 已经发布,而我还没有更新这篇文章,那么就要谨慎行事。查看 StyleGAN2 ADA PyTorch 说明,了解版本的最新更新。
还需要安装 Visual C++,这样 StyleGAN 就可以编译定制的 CUDA 内核。可以在以下 URL 找到 Visual Studio Community edition。确保你安装的是 C++,在微软的安装程序中默认是不启用的。
- 【https://visualstudio.microsoft.com/vs/
安装 Visual Studio 后,您必须向系统路径和环境变量中添加几项。您可以通过运行以下批处理程序来实现这一点:
- c:\ Program Files(x86)\ Microsoft Visual Studio <version>\ Community \ VC \ Auxiliary \ Build \ VC vars 64 . bat
我建议打开一个 power shell 窗口,进入该目录并运行命令“vcvars64”
PyTorch 装置
要安装 PyTorch,您需要在系统上安装 Python。我建议要么安装 Miniconda,要么安装 Anaconda。Miniconda 很小,你必须安装需要的软件包。Anaconda 很大,但是包含了你所需要的大部分东西。
如果您甚至在争论安装哪个,或者您从未听说过 Anaconda 和 Miniconda 之间的区别,那么几乎可以肯定,Anaconda 是您的正确答案。
StyleGAN 团队推荐 PyTorch 1.7.1 用于 StyleGAN。根据 PyTorch 引入的“突破性变化”的数量,以后的版本可能会起作用。PyTorch 的安装过程令人惊叹,请浏览以下 URL 并选择您的选项:
我选择:
- 稳定
- Windows 操作系统
- 点
- 计算机编程语言
- CUDA 11
这导致了以下命令:
pip install torch===1.7.1+cu110 torchvision===0.8.2+cu110 torchaudio===0.7.2 -f https://download.pytorch.org/whl/torch_stable.html
NVIDIA StyleGAN2 ADA PyTorch 安装
实际的 NVIDIA StyleGAN2 ADA 包通过 GitHub 在以下存储库分发:
您可以选择下载一个 ZIP 文件,该文件应该被解压缩到一个目录中。还可以用命令行 git 命令获得 StyleGAN。
git clone [https://github.com/NVlabs/stylegan2-ada-pytorch.git](https://github.com/NVlabs/stylegan2-ada-pytorch.git)
在撰写本文时,StyleGAN 还没有提供 requirements.txt 文件来指定所需的包。当您运行 Python 脚本时,您会看到关于缺少包的错误,只需 pip 安装它们。为了让你开始,这些是我找到的:
pip install click
pip install tqdm
pip install requests
pip installimageio
pip installpsutil
pip installscipy
训练 GAN
为了训练 GAN,您必须将所有图像转换为具有相同大小和维度的 PNG,并且具有非常具体的目录结构。这可以通过 StyleGAN 提供的 dataset_tool 脚本来完成。在这里,我转换所有的 JPEG 图像,我获得了训练甘生成鱼的图像。
python dataset_tool.py --source c:\jth\fish_img --dest c:\jth\fish_train
接下来,您将实际训练 GAN。这是通过以下命令完成的:
python train.py --data c:\jth\fish_train --outdir c:\jth\results
训练可能需要很长时间,在训练过程中,您会看到在训练过程中创建的图像,这些图像显示了当前的效果。下图显示了我的《我的世界》GAN 在 2,800 kimg 时的情况,这意味着它在这一点上已经对超过 2800 张图像(包括真实图像和增强图像)进行了训练。
图像设置检查点为《我的世界》甘在 2800 公斤
生成图像
随着培训的进行,pickle 快照将由您的生成器和鉴别器组成,以与生成的每个映像集检查点相对应。例如,network-snapshot-002800.pkl 生成了上面的映像检查点。要从该网络生成图像,请使用以下命令。
python generate.py --outdir=out --trunc=1 --seeds=85,265,297,849 \
--network=network-snapshot-002800.pkl
种子指定要生成的单个图像,每个种子是一个单独的图像。
YouTube 视频
如果你想看这些步骤的执行,我也有同样材料的 YouTube 视频。
结论
如果你有培训的硬件,NVIDIA StyleGAN2 ADA 是一个生成你自己的图像的好方法。新的 PyTorch 版本使其易于在 Windows 环境下运行。按照本文中的步骤,您可以快速建立一个环境来训练您自己的 GANs。
生成性对抗性模仿学习:优势与局限
与强化学习和非穷举用例列表的区别
Alex Perri 在 Unsplash 上的照片
越来越多的人工智能项目依赖于学习观察和行动之间的映射。出于战略和技术原因,从演示中学习将在开发几个用例(机器人、视频游戏、自动驾驶汽车)中发挥至关重要的作用。
在我最近的项目中,我有机会对生成性对抗性模仿学习(GAIL)有了深入的了解。作为团队的一员,我的目标是利用 GAIL 帮助机器人预测和理解人类的安全行为。
在这篇文章中,我将解释生成性对抗性模仿学习,介绍它的优势,并解释这种方法的局限性。
学习人类决策策略的重要性
正如几位计算机科学研究人员所解释的那样,“为了做决定,人类创造了特定的规则/习惯。例如,我们中的一些人根据首选的路线或交通方式来决定。出于这个原因,机器准确地模仿人类在各种场景中的行为是非常重要的,例如,玩视频游戏等。
通过模仿学习有助于用最少的任务专家知识来教授复杂的任务。
通过模仿学习的能力可以为许多需要实时感知和反应的潜在人工智能应用打开大门,如机器人、自动驾驶汽车、人机交互和视频游戏。
然而,需要专门的算法来有效地学习模型。事实上,通过模仿来学习也带来了一系列挑战。不幸的是,对于复杂的任务,这往往是具有挑战性的描述,强化学习(RL)方法有局限性。
模仿教学的概念并不新鲜。由于计算技术的进步和智能应用需求的增长,这个想法最近受到了关注。
一些“最近”的算法,如生成对抗模仿学习,证明了使用深度神经网络(DNNs)从人类的行为数据中学习人类决策策略的成功。
然而,“这种基于 DNN 的模型在本质上是“黑盒”模型,很难解释这些模型从人类那里学到了什么知识”( 2 )以及它们如何做出这样的决定,这在模仿学习文献中没有涉及。
模仿学习技术“旨在在给定的任务中模仿人类行为”( 3 )。
通用模仿学习方法( 4 )可以减少教授任务以提供演示的问题,而不需要显式编程或设计特定于任务的奖励函数。
正如各种研究论文中提到的那样,生成对抗模仿学习展示了“在有限数量的用例中取得了巨大的成功,尤其是在与神经网络参数化相结合时”( 5 )。与强化学习不同,GAIL 从专家(人)的演示中学习策略和奖励函数。
生成性对抗性模仿学习
简单来说,GAIL 是一种逆向强化学习(IRL)算法。顾名思义,它是基于生成对抗网络(GANs)的。 GAIL 可以定义为一种无模型的模仿学习算法。与其他无模型方法相比,该算法在模拟复杂行为方面表现出了令人印象深刻的性能增益,尤其是在大型高维环境中。
逆向强化学习 (IRL)是通过观察代理的行为来学习其目标、价值观或报酬的领域。
在 GAN ( 6 )中,我们有两个网络:发生器和鉴别器。生成器的作用是通过学习输入数据集的分布来生成新的数据点。鉴别器的部分是对给定的数据点是由生成器生成的(学习分布)还是真实的数据分布进行分类。
由于 IRL 和 GAN 概念的结合,GAIL 可以从少量专家轨迹中学习。事实上,GAIL 的目标是训练具有与给定专家相似行为的生成器。同时,鉴别器可以作为强化学习的奖励函数,用来判断行为是否像专家。
GAIL 代表了学习顺序决策策略的一种有前途的方法。与强化学习(RL)不同,GAIL 使用专家(例如,人类)的演示数据,并学习未知环境的政策和奖励函数。
作为一种无模型的模仿学习方法,生成性对抗模仿学习(GAIL)能够很好地概括未知情况,并处理复杂问题。
正如在一个实验( 6 )中提到的,“将 GANs 应用于模仿学习的一个基本属性是,生成器永远不会接触到真实世界的训练示例,只会接触到鉴别器。这种情况允许 GAIL 最小化将专家演示翻译到目标代理领域的问题”。
在 GAIL 的案例中,鉴别者学会了从专家的演示中辨别生成的表演。同时,发生器试图模仿专家来愚弄鉴别器,使其认为它的表现是专家的演示。
盖尔和逆强化学习 由于不同的原因,盖尔并不完全是 IRL。因为 GAIL 是直接从数据中学习策略,而不是奖励函数。尽管有这个因素,GAIL 比行为克隆表现得更好,有时甚至比专家更好,因为它在进行强化学习,并且它不会被限制总是接近专家。
RL 方法需要明确定义的奖励函数,它告诉代理他们做得有多好。不幸的是,在大多数现实世界的情况下,奖励函数通常很难定义。
引入 IRL 来帮助 RL 学习专家的策略,并从给定的专家轨迹中获取奖励函数来解释专家的行为。然而,对于大多数经典的 IRL 方法,需要提供大量的专家轨迹,但在很多情况下,这些轨迹并不容易得到。
其他一些模仿学习方法的局限性
行为克隆
(从状态到动作的映射)。此外,小错误会随着时间的推移而加剧(级联错误)。此外,行为克隆通常具有较差的泛化能力,精确地复制动作,即使它们与最终任务无关,并且可能无法理解专家的动作是有目的的并且有最终目标。
逆向强化学习 这种方法学习一种成本函数,该函数将整个轨迹优先于其他轨迹。主要问题是“许多现有的 IRL 方法需要解决一系列计算量大的强化学习问题,因为它们具有双层优化的性质。因此,它们通常无法扩展到大型和高维度环境”( 7 )。最后但同样重要的是,IRL 的运营成本很高。
用例
尽管深度强化学习已成功应用于各种任务,但为复杂任务手动设计合适的奖励函数仍具有挑战性且成本高昂。
大多数涉及 GAIL 的项目目前都应用于简单的环境中( 8 ),在这些环境中,具有手工制作功能的全连接神经网络已经工作得很好了。
具体地说,代理从专家演示和自我探索中学习“接近最优”行为而无需显式奖励函数设计的想法已经应用于几个机器人操作( 9 )或运动任务( 10 )。
再者,GAIL 也被用于电子游戏行业,尤其是在相对复杂的没有手工制作特色的游戏中模仿特定玩家( 11 )。
盖尔的问题
尽管结果很有希望,盖尔背后的理论仍然鲜为人知。根据我的经验,GAIL 很难从多模态演示中学习到好的策略。事实上,它似乎假设所有的演示都来自单个专家,无法提取演示。
对抗性模仿学习在许多环境中都取得了成功。然而,“对抗方法被证明是不稳定的,并且在低数据量的情况下,可能需要很长时间才能收敛”( 12 )。
一些作者( 13 )介绍了逆向 RL 技术 AIRL ,认为“盖尔未能推广到不同环境的动力学”。根据他们的实验,AIRL 对环境动态的变化更有抵抗力。
要了解更多信息,我推荐以下链接:
- 从不同来源模仿学习人形
- 生成性对抗性模仿学习
- 生成性对抗性模仿学习的呈现
- TextGAIL:用于文本生成的生成性对抗模仿学习
- 生成性对抗性模仿学习的最新进展
- 关于生成性对抗性模仿学习的计算和推广
- 通过生成性对抗性模仿学习来模仿复杂环境中的智能体
- 通过原始深度输入和生成性对抗性模仿学习进行社交兼容导航
- xGAIL:可解释的生成对抗模仿学习,用于可解释的人类决策分析
- 模仿学习:学习方法综述
- 损耗退火盖尔对样本高效稳定的模仿学习
- 生成性对抗性模仿学习(盖尔)
生成性对抗网络 101
如何构建一个简单的 GAN
自 2014 年首次提出以来,生成性对抗网络(简称 GANs)就成为了机器学习社区的头条新闻。基于一个巧妙简单的想法,GANs 很快成为产生人造图像的最先进的方法,这些图像现在与真实图像无法区分。他们不仅在生成人工智能艺术或人脸老化等有趣的任务中找到了应用,还在更实际的应用中找到了应用,如数据匿名化、提高照片分辨率等。在这篇文章中,我将解释 GAN 是如何工作的,我们将构建一个非常简单的 GAN 来生成新的口袋妖怪物种。我们开始吧!
关于甘斯
GANs 首先由 Goodfellow 等人提出,并被迅速开发以发现大量令人着迷的用例,例如生成人脸的逼真图片、图像到图像的翻译(想想在图片中的一匹马身上画条纹以使它成为斑马),或者衣服翻译(如果你想知道你穿同样的毛衣,但却是红色的高领毛衣会是什么样子)。他们甚至允许我们在图片上做算术:取一个戴眼镜的男人减去一个不戴眼镜的男人加上一个不戴眼镜的女人的图像,你会得到一个戴眼镜的女人的图像,从这个图像中你可以生成多个不同的戴眼镜的女人的图像。请查看这篇伟大的博文,获取更多 GAN 应用示例图片。看看这只猫。
一只不存在的猫,由 https://thiscatdoesnotexist.com/的生成。
这只猫既不喵喵叫也不咕噜咕噜叫。它不吃也不喝。因为它不存在。就像无数其他不存在的被甘斯创造出来的猫一样。你可以自己生成一些,只需导航到thiscatdoesnotexist.com。每次刷新页面,都会生成一个新的 cat。对于人或住宿也有类似的页面(虽然有些房间看起来还是有些毛骨悚然!).
甘斯直觉
GANs 基于一个有趣的简单想法:让两个神经网络相互竞争,希望竞争能推动它们走向精通。
GANs 背后的想法:让我们让两个神经网络相互竞争,希望竞争能推动它们走向精通。
总体目标是生成与训练数据中的内容无法区分的内容,例如图像。人们可以将这一思想应用于任何类型的数据,但是在本文中我们将重点关注图像。为了实现这一目标,我们需要两个独立的模型:
- 一个发生器**,以随机噪声为输入,并以此为基础生成图像;**
- A d 是鉴别器,它将图像作为输入(真实的或由生成器生成的),其工作是将它们分类为真实或虚假。
生成器的目标是生成逼真的图像来欺骗鉴别器,而鉴别器的目标是从真实图像中分辨出假货。将这两个模型拟人化是很有帮助的,把生成器想象成一个艺术品伪造者,把鉴别器想象成一个警察调查员,去抓捕伪造者。这两个网络的这些相互冲突的目标应该确保每一个在训练期间逐渐变得更好。最终,生成器将有望生成逼真的图像。
GAN 的示意图。图片由作者提供。
发电机👨🎨
发生器最简单的形式可以是一个微小的神经网络,它接受输入的噪声向量,将它传递几层,并以图像的形式输出一个张量。当处理图像时,我们通常会使用卷积层,但训练卷积 gan 本身也会带来挑战,因此为了这个介绍性示例的目的,让我们使用一个简单的前馈网络,基本上是一个多层感知器。
我们将使用口袋妖怪精灵数据集来生成我们自己的口袋妖怪物种。以下是一些示例图像。使用这个笔记本,你可以自己生成更多的样本。
口袋妖怪精灵数据集的样本。
让我们的生成器接受 64 个随机数的输入向量,输出一个形状为 49696 的向量(口袋妖怪 pics 是 96*96 像素,4 个颜色通道)。生成器的输出层将是一个 sigmoid 激活,以便它生成 0 到 1 之间的数字来匹配原始图像中的像素值。PyTorch 实现可能看起来像这样。随着单元数量的增加,您可以随意尝试添加更多的 linear-batchnorm-relu 块。
鉴别器👮♀️
鉴别器将是另一个小型神经网络,其任务是获取大小为 49696 的输入向量,该输入向量包含真实图像或虚假的发生器输出,并分类为两者之一。我们可以这样实现它。
同样,随意堆叠更多的层,例如从nn.Linear(4*96*96, 2048)
开始,每次继续将层大小分成两层。
培养
棘手的部分来了:如何训练这两个网络,使它们都能很好地学习自己的任务?关键是一前一后地训练它们,只用一个损失函数。损失函数的选择取决于鉴别器,因此我们可以使用二进制交叉熵损失,这是二进制图像分类的典型选择(在未来的帖子中,我将讨论使用更好的损失函数的更高级的 GANs)。让我们首先初始化两个模型,损失和优化器。
这个PokemonDataset
物体是我创作的,你可以在 GitHub 上找到它。现在,训练循环。我们对时期和批次进行迭代,对于每批训练数据,我们将梯度归零,计算鉴别器的损失,并更新模型的权重。接下来,我们对发电机做同样的事情。
剩下的问题是如何计算每个模型的损失。在上面的代码片段中,这是由定制的get_disc_loss()
和get_gen_loss()
函数处理的。让我们看看他们怎么做。
鉴频器损耗
第一,鉴频器的损耗。我们可以按照以下步骤计算它:
- 产生一些随机噪声,并将其馈送到发生器。这会产生一批假图像。
- 使用鉴别器将这些假图像分类为假的或真的。然后,用它对一批真实图像进行分类。这就产生了两组分类:赝品和真品。
- 使用零(“假”)作为基本事实标签,将“假损失”计算为假图像鉴别器输出的二进制交叉熵损失。接下来,计算“真实损失”,作为鉴别器输出真实图像的二进制交叉熵损失,使用 1(“真实”)作为基本事实标签。
- 将总损失计算为假损失和真损失的平均值。
这由下面的函数来处理。
发电机损耗
现在,让我们对发电机的损耗进行编码。这个会简单得多。我们只需要生成噪声,将其馈送到生成器以获得假图像,使用鉴别器对它们进行分类,并使用 1(“真实”)作为地面真相标签来计算这些分类的二进制交叉熵。我听到你问为什么是一个。回想一下,生成器的目标是欺骗鉴别器。当它产生假图像时,它希望它们被归类为真实的——每当不是这样时,生成器就会遭受损失。换句话说,如果鉴别器将每个发电机的输出分类为实数,那么发电机的损耗将为零。这个想法在下面的函数中实现。
现在我们有了所有的构建模块,我们可以运行训练循环。你可以在这个笔记本里自己运行(代码是根据 Coursera 的生成对抗网络(GANs)专门化由 Sharon Zhou 等人编写的)。在训练过程中,我们可能会时不时地给生成器输入一些噪声,看看它输出了什么。下面的图片显示了 GAN 生成的口袋妖怪在训练开始时,在几百个纪元后,以及在训练的很晚时候。
GAN 在训练开始时(左)、训练后期(中)和后期(右)生成的口袋妖怪。
跟你预想的不太一样?我们来看看为什么!
为什么这么模糊
生成器很快了解到,它应该专注于图像的中心区域,并保持背景白色。在训练的早期,它一直在图像中间产生噪点。随着训练的进行,一些熟悉的形状变得清晰可见。甚至后来,一些假的口袋妖怪出现了,它们类似于训练数据中的那些,尽管是以一种模糊的方式(你可以认出每个人最喜欢的皮卡丘,在中间一行和最右边一列!).如果你已经期待一个更现实的输出,不要放弃希望。让我们看看模型的哪些部分需要改进。
有几个,但其中两个最引人注目。首先,我们使用了一个简单的前馈网络来处理图像,这是相当次优的。切换到卷积神经网络应该会有很大帮助。第二,我们用于 gan 的二元交叉熵损失证明不是最佳选择;我会在另一篇文章中解释为什么会这样,以及什么样的损失函数会更好。
先说前者。查看下一篇文章,在这篇文章中,我们将 GAN 向前推进了一步,在生成器和鉴别器中添加了卷积,以构建所谓的深度卷积 GAN 或 DCGAN!
感谢
这个简单 GAN 的训练循环代码以及损失计算函数的灵感来自于 Coursera 的由 Sharon Zhou 等人提出的生成对抗网络(GANs)专门化。
感谢阅读!
如果你喜欢这篇文章,为什么不在我的新文章上 订阅电子邮件更新 ?通过 成为媒介会员 ,你可以支持我的写作,并无限制地访问其他作者和我自己的所有故事。
需要咨询?你可以问我任何事情,也可以在这里 预定我 1:1 。
你也可以试试我的其他文章。不能选择?从这些中选择一个:
**
生成性对抗网络服务于安全和网络安全
提高自动驾驶汽车安全性和网络安全性的新人工智能方法
照片由来自 Pexels 的 Tara Winstead 拍摄
未知的未知对于自动驾驶汽车来说是一个重大的安全困境。问题是如何确定哪些驾驶场景在整个开发过程中还没有考虑到。**自动驾驶汽车的验证需要尽可能多地识别和测试未知场景。**在为自动驾驶汽车开发网络安全时,我们必须回答同样的问题。在项目的早期阶段,总有一些可能的未知攻击需要考虑和解决。然而,安全开发活动倾向于离线分析、设计、实现和验证。预测未来可能的攻击还不是安全和安保发展的最新水平。应用人工智能方法来预测潜在的未来攻击或失败是最好的解决方案。
机器学习领域中的生成对抗网络(GAN)是一种保护系统免受攻击和构建更安全系统的新方法。 GAN 可以从输入的数据集学习生成新的样本,与标注的真实世界数据进行比较,决定它们是真实的还是虚假的。 GAN 由两个神经网络、一个生成器和一个鉴别器组成。GAN 是一种在许多应用中使用的生成方法,例如人脸或卡通人物的生成以及许多其他摄影应用。
这种方法还可以生成虚假信息、图像等。,这是社会不能接受但又不可避免的。网络安全措施应比网络攻击至少领先一步,以区分真实或虚假的信息、图像或视频。
发生器对鉴别器
生成器负责生成新样本,鉴别器在将生成的样本与标记的真实数据进行比较时起分类作用。生成器和鉴别器模型都必须在训练时优化分类率。鉴别器模型最小化分类错误率,生成器模型最大化分类错误率。
生成器和鉴别器都知道训练数据集,它们是真实世界的数据,但是生成器的输出包含真实和虚假的数据。鉴别器必须使用半监督方法对其进行分类。**数据科学家同时训练两个模型。如果鉴别器中的分类失败,则应该使用反向传播来更新生成器模型的参数。**发生器和鉴别器模型优化相同的参数,但基于零和概念相反。
GAN 确保自动驾驶汽车技术安全性的方法
黑客攻击无人驾驶车辆比司机在车内的车辆更关键。**根据攻击类型,攻击者可以修改车辆导航、反应、收集特定传感器数据等。从现有攻击中学习是 GAN 方法中非常相似的概念。**生成器根据已经观察到的攻击创建新的可能攻击。
GAN 可以生成真实的流量场景,以改善系统验证或稳健的系统行为。利用传感器建模,我们可以将 GAN 应用于生产更可靠的产品。
在本文中,我没有区分安全性和安全性,因为两者都可能导致开发人员必须评估的危险。安全性和安全性的区别在于攻击者的意图。安保和安全的共同点多于差异。
GAN 建议在以下使用案例中作为网络安全或安全措施:
图像处理:
GAN 生成的合成数据有助于验证用于对象分类或用户认证的图像处理模块。这同样适用于由照相机捕获的图像数据。**生成器可以生成许多在真实世界环境中难以找到或模拟的真实图像。**例如,使用深度学习分类算法可以将限速标志错误分类为不同的限速,如欧盟委员会的自动驾驶汽车测试和认证报告中所述。本报告提出了一种 GAN 方法来消除对抗性扰动。
基于场景的验证:
出于多种原因,自动驾驶汽车需要一种新的验证方法,例如,出于安全和安保原因,驾驶员无法承担责任作为汽车中的后备解决方案。另一个目的是在设计和验证时缺乏关于未知场景的知识。识别这种最糟糕的情况对自动驾驶汽车验证团队来说是一个重大挑战,以确保所有关键情况都已经得到分析,并对危险做出充分的响应。正如这篇论文中所描述的,GAN 可以生成新的、现实的轨迹。GAN 方法从图像域调整到时域以创建有效的轨迹。
稳健性的提高:
我们需要全自动驾驶汽车中的更多传感器,而不是汽车中的辅助功能,例如部分自动驾驶汽车中的车道辅助。因此,自动驾驶汽车更容易受到网络攻击的影响。**我们应该在安全方面保证系统在受到攻击时的健壮性。**这篇论文描述了一种提高系统鲁棒性的 GAN 方法。这种方法使用了不正确的数据,违反了与其他道路使用者保持安全距离的安全目标。自动驾驶汽车使用 GAN 方法验证距离变化,强化学习算法决定与其他道路使用者保持适当的距离。
传感器建模:
使用真实世界的数据来验证和确认自动驾驶汽车的传感器是一项复杂的任务。为了验证自动驾驶汽车,必须模拟可能的场景。这篇论文讨论了 GAN 方法在传感器生产中的应用。这种传感器建模方法有意制造生产传感器误差,以发现长期相关性。
如何保持数据的可靠性
任何数据都是攻击场景的来源。使用 GAN 方法可以更容易地区分真实数据和虚假数据。一个已经学会生成分类错误率很低的数据的高级生成模型,可以生成虚假的数据来欺骗任何系统,检查目标系统是否对合成攻击足够健壮。
GAN 可以成为评估人员论证系统抵御网络攻击能力的工具。**不仅针对已识别的攻击场景,而且针对犯罪分子尚未使用的未来可能的攻击场景的流程。这种方法是一种新趋势,将很快对安全和安保标准以及开发活动产生重大影响。**随着 GAN 方法的发展,我们也为攻击者提供支持,并为他们配备新武器。我们必须找到一种解决方案,至少领先网络攻击者一步。
GAN 的许多衍生产品,如 CGAN(条件性 GAN)、WGAN (Wasserstein GAN)和 LSTM-GAN(长期短期记忆 GAN),以及其他几种基于生成和判别模型的产品,都可以处理和解决安全问题。像 GAN 这样的生成过程对于开发应用程序的工程师来说是一个有价值的工具,在这些应用程序中,数据增强有助于提高功能的质量、可用性和效率。
https://medium.com/subscribe/@bhbenam
生成性对抗网络(GANs)——从直觉到实现
图片由纸
生成对抗网络
形式上,GANs 被定义为**两个神经网络在一场游戏中相互竞争(在博弈论的意义上,经常但不总是以零和游戏的形式)。给定一个训练集,这种技术学习生成具有与训练集相同的统计数据的新数据。**这个定义似乎非常数学化,如果你对实现算法更感兴趣的话,这可能不是很有用。在这篇博客中,我将为你提供算法如何工作以及你如何实现算法的直觉。
与普通的神经网络相比,GANs 可以生成质量更好的新数据。我们可以把它描述为两个网络相互竞争,这种竞争导致更好的结果,因为双方都在试图击败对方。
它的应用非常有趣,它使我们能够解决许多现实世界的问题。让我们先看看它的一些应用
- 生成与真实人脸惊人相似的人脸。
- 图像到图像的转换——给定边缘的图像,网络可以生成物体的彩色图片,或者给定夜间条件下的图片,它可以将其转换为白天条件,这在自动驾驶中有巨大的用途。
图片由纸制成
- 修复——给定一个失真的图像,它可以生成完整的图像,这在视频后处理、受损视频恢复和视频编辑中有很大的应用。
物体去除,图像由纸
GIF by LGTSM
现在让我们更深入地了解 GANs。根据形式定义,我们知道在这个算法中有两个网络。其中一个称为发生器,另一个称为鉴别器。
生成器网络生成具有某种统计属性的数据。我们希望统计特性与我们想要得到的输出类型相同。例如,在从夜晚到白天的图像到图像的翻译中,它应该能够正确地生成白天的图像。而在生成新的人脸时,它应该能够给出类似于真实世界人脸等的输出。
下面的代码是生成器的架构。它接受一个固定大小的随机输入(random_size ),然后生成一个扁平的图像(大小为 heightwidth 的 1D 数组),为了从输出中可视化图像,我们必须将输出向量整形为适当的(height,width)。在这里,我为生成器架构使用了完全连接的层。*
发电机架构
鉴别器充当发生器的评论(稍后解释)。它的主要工作是,给定一个特征点/图像,它试图将该特征点/图像分类到所需的类别中。例如,给定一幅图像,鉴别器将试图把给定的图像分类为真实的或伪造的(这里生成器的输出可能是伪造的)。在领域自适应的情况下,它试图将给定的特征分类为源或目标领域特征。
下面,代码是鉴别器的架构。它是将一幅展平的图像(shape - > heightwidth)作为输入,然后将输入分类为真假。这里我使用了完全连接的层。*
鉴别器架构
既然我们已经看到了单个模型的角色,那么让我们看看它们是如何互相帮助的。
仅培训生成器
让我们假设我们有一个经过训练的鉴别器,即它可以正确地将图像分类为真的和假的(通常情况下不是这样),并且我们只训练我们的生成器。然后我们用这个评论作为反馈,用生成器生成接近真实的图像。考虑发电机的培训过程如下:
- 最初,由于神经网络权重的随机初始化,会产生一些随机输出(用 G(z) 表示)。当这个通过鉴别器时,它肯定会被鉴别器分类为假的。
当我们开始训练时(图片由作者提供)
- 最后,当我们已经训练了生成器模型时,我们希望输出非常类似于训练数据集,即我们的鉴别器应该将生成器的输出(G(z))分类为实数。
训练结束时(图片由作者提供)
为了训练发生器,我们通过将 G(z) 的标签作为真实数据,使用来自鉴别器的输出来计算损耗,即我们强制发生器产生鉴别器可以分类为真实的输出。这样鉴别器就帮助了发生器。为了更好地说明,请看下面的损失公式:
发电机损失(图片由作者提供)
**理想情况下,**对于真实图像,鉴别器的输出为 0,而对于伪图像,其输出为 1。为了最小化上述损失,输出 D(G(z)) 应该接近 0,即我们正在训练发生器,以便其输出被鉴别器分类为实数。
下面的代码显示了生成器的训练方案。发生器 G(z)的输出被馈送到鉴别器,然后通过将输入到鉴别器的标记作为真实图像来计算损耗。然后,该损耗用于更新发电机的参数。
训练生成器
仅训练鉴别器
现在让我们假设我们有一个生成假图像的生成器,即输出质量很差,我们只训练我们的鉴别器。训练鉴别器与训练普通分类器是一样的。当我们的输入是假图像时,它分类为假,当输入是真实的(即来自训练数据)时,它分类为真实。
训练鉴别器(图片由作者提供)
鉴别器丢失(由纸成像)
上面的损耗公式强制鉴别器将真实输出分类为 1,将伪造/生成的输出分类为 0。
下面是鉴别器的训练方案,我们首先将真实图像(来自训练数据)馈送给鉴别器,并通过将这些图像的标签视为真实来计算损失。然后,我们将假图像(生成器的输出 G(z))馈送到鉴别器,并通过将 G(z)的标签视为假来计算损失。
训练鉴别器
现在我们已经讨论了如何分别训练生成器和鉴别器。然而,在现实世界中,我们必须同时训练他们两个。
完整的训练
考虑一下,两个网络最初都有随机权重。首先,我们通过将生成器的输出分类为假来训练鉴别器,将训练数据分类为真,并且只更新鉴别器的参数。然后,我们训练生成器,其中使用鉴别器,我们尝试将生成器的输出( G(z) )分类为实数,并仅更新生成器的参数。现在,如果我们的训练是稳定的,并且一切按预期进行,那么当鉴别器的输出对于训练数据和来自生成器的输出相同时,即鉴别器不能区分两者时,我们可以停止训练。
训练甘
这样,我们就完成了对 GANs 的介绍。我希望这个博客能让你对 GANs 的工作有一个好的直觉。完整的实现可以在下面的 GitHub 仓库中找到。
https://github.com/harsh-99/PyTorch-Tutorials/blob/master/GANS.ipynb
成为 介质会员 解锁并阅读介质上的许多其他故事。关注我们的 媒体 阅读更多此类博文。
生成人工智能:作为虚构与现实之间桥梁的视觉搜索
在三个用例中。
Same.energy 界面,作者截图
什么是真理?
F 首先,请告诉我,什么是虚构,什么是现实——在生成对抗网络的背景下?
我们已经看到了很多东西,在它的人工智能驱动的创造之前是不存在的。可以肯定的是, 中 GAN 生成的图像这个人不存在 或者 这个艺术品不存在 在物质世界中没有直接的参照物——它们是知识和 AI 模型训练的产物。但是当它们被传送到我们的世界,它们可能会有自己的故事,特定的意义,特定的用途,离开潜在的空间,变得比小说更真实。
的确,你可以用它们制作电影。你也可以制造欺诈和假货。错用不怪 AI,怪我们人类。你不能通过破坏技术来修复社会。
然而,在数字时代,重要的是要区分生成性和非生成性项目,防止假货,并利用艺术力量,直到现在不存在的可能性。
这里有三个用例可以启发你或者提高你的意识。
案例 1: StyleGAN2 投影
StyleGAN2 的研究人员有一个内置的“后门”,或者可以将 GAN 生成的图像追溯到潜在空间: StyleGAN2 投影。
如果您尝试将图像识别为生成图像,这可能非常有用。我不得不说,用 style gan 2Colab Notebooks和art breader(其中使用了 StyleGAN2-model,在 FFHQ-faces 上训练过)玩久了,你可以学习直觉来检测可能是生殖性的肖像。
但是使用投影你也可以做到。
以下是检测生成性图像并利用潜在空间发现它的最佳示例:
当然,原始图像在这里已经够怪异了。将它与另一幅肖像进行比较:
如你所见,找到的肖像是不一样的。为什么?因为我用其他工具修改了它,比如 ArtBreeder(混合各种图像,包括我的照片)。这是这张图片的“系谱树”:
Artbreeder,作者截图
这是 StyleGAN2-Projection 的第一个也可能是一个重大缺陷。要检测 1:1 的图像,应满足以下条件:
- StyleGAN2 应该生成没有任何修改的图像
- 您必须知道哪个数据集用于您正在应用投影的 StyleGAN2。
StyleGAN2 投影是一个很大的可能性,但可以用几种方式欺骗;所以才不靠谱。然而,它可以作为第一个工具使用——在特定情况下,它可能是有益的。
你可能会想起“亨特·拜登阴谋”的故事,主角是马丁·阿斯彭,他声称有证据证明这是一场捏造的破坏政治形象的亲特朗普运动。然而,马丁·阿斯彭并不存在;他的脸是由 StyleGAN2 生成的,这是 StyleGAN2 的投影:
正如你所看到的,这些面孔并不完全相同——这个故事背后的政治幕后操纵者可能使用了 StyleGAN2,但做了一些修改。
但即使这种方法不是 100%有效,也应该强调的是,人工智能研究人员将许多努力投入到防止人工智能解决方案被滥用的可能性中(即使是事后的,如假检测)。
**旁注:**毕竟,你可以出于艺术需要使用 StyleGAN2 投影,在不这样的地方寻找人脸。它与 Pareidolia 方法一起工作,可能会产生一些迷人/或可怕的结果:
案例 2:使用反向图像搜索的假货检测
另一种检测假图像的方法是反向图像搜索。这里有一个使用俄罗斯搜索引擎 Yandex 回溯假货的绝佳用例:
在这种情况下,从“此人不存在”页面获取的人脸用于搜索相同的图像。于是一个伪造的公司网页被发现了,上面有几张 GAN 生成的脸:
老实说,有两点:
- 这可能不一定是欺诈或伪造的,只是另一个即将开业的公司分支机构的模型,或者仍然没有同事的照片。例如,前面提到的在别尔哥罗德办公室的公司职员看起来很普通,不像甘。可能这只是另一个——我们,人类,西方——对俄国制造的*假货的偏见。即使不存在这样的情况,我们也会发现它们的另一种情况</pareidolia-of-ai-dba7cf44bfde?sk=f22677820ca169764e2c076fea98ee6e>或选择性知觉。不是所有的俄罗斯都是假的;不是所有的假货都是俄罗斯的。顺便说一句。将 GAN 的图像用于实体模型是一个非常明显的想法:你不需要购买股票图像,并且你的实体模型员工的脸不会在完全不同的产品上重复出现,如股票女孩“Ariane”。比较这个出租不存在,一个使用 StyleGAN2 faces 作为用户账号的生成页面(更像是一个实验)。*
- 如果这可能是一个骗局,这不仅仅是 Yandex 的特色,也不仅仅是俄罗斯的问题。唯一的问题是:Yandex 确实比谷歌(Google)更擅长寻找 GAN 的面孔。
谷歌搜索可能是查找全球虚假公司的一个好办法,但它也有缺陷:
作者截图
谷歌图片搜索 寻找的是相似的图片,而不是相同的图片。我想用TinEye来代替。这个工具通常非常适合检测用户在社交网络上联系你是否是假的。将它与其他相同的网页图像进行匹配可能会证明这个用户图片是一个股票图像,而使用这个用户图片的人可能是一个骗子。甚至还有 TinEye 插件。****
使用 TinEye 插件 = >查找使用图片的页面,截图由作者提供
TinEye 的问题是:没有一个完整的关于这个不存在的人的开放知识库来进行双重检查(这意味着整个潜在空间都是开放访问的,这可能是不可行的)。
相反,Yandex 可以找到另一个 GAN 生成的人脸,如果你只上传其中一个。而且 Yandex 的这个相似度比谷歌图片搜索的相似度要好用得多。******
并非所有类似的图像都是 GAN 生成的,但其中许多是。作者截图。
大概,Yandex 寻找的是 GAN 人脸上典型的特定图案?Yandex 的缺点是,它仍然主要在俄罗斯网络空间进行搜索,这可能会导致对“假面网络景观”的偏见。
我希望 TinEye 或 Yandex 类似的服务也可以使用 GAN2 或其他 GAN 生成的图像,甚至可以作为 Chrome 插件,在全球范围内寻找这种假照片。可能使用 StyleGAN2 投影,这可能需要一些时间:使用 StyleGAN2 Colab 笔记本,生成投影大约需要 10-15 分钟。
案例三:一样。能量——反向图像搜索的艺术运用
但这不仅仅是关于政治、欺诈和假货。人工智能作为一种创造性的机器,为艺术家、作家和电影制作人打开了新的视野。在真实数据的训练下,人工智能提供了关于我们世界的“幻觉”或“梦想”。而 AI 梦的视觉表现形式变成了我们的世界。
最近,一个引人入胜的视觉搜索引擎亮相: 相同。能源 由多媒体艺术家和游戏设计师雅各布·雅各布森创作。顾名思义,这个引擎寻找具有“相同能量”的图像,在风格和视觉上与你输入搜索的图像相似。该引擎使用机器学习工作,并由类似于 OpenAI 的 CLIP 的视觉分类模型提供燃料(该模型在承认 DALL-E 的情况下发布)。
如果你在这里输入一个任意的图像,系统会以特定的特征、模式和物体来识别它,并寻找语义上的相似性。
例如,如果我们输入达芬奇的自画像,我们会得到一组其他图像,描述类似“一个留着胡子的老人作为一幅画或一幅素描”。
********
达芬奇自拍(公共领域)//作者截图
我摆弄着比根的图像(由 Colab Notebook 和art breader生成)想知道是怎么回事
a)机器学习可以从混合种子中检测生成图像吗
b)这个视觉搜索引擎能从现实世界中找到相似的图像吗?当然,其中许多将是想象力的产物,但仍然是人类的产物。
上传了一些图片,我发现了灵感和头脑风暴的奇妙可能性。
就拿这个来说吧。在这里你可以看到种子和它们的强度用于生成这个黑白艺术图像:
图片网址:【artbreeder.com/i?k=8b4dfc7e99d0cb87d1c7 ,作者截图
这是同样的图片。能源可以找到:
作者截图
或者另一个:
图片页面:https://www.artbreeder.com/i?k=6ca1f4031e1fc1565e1e,作者截图
同样的能量,有着令人难忘的画面。
作者截图
另一种半抽象的观点:
图片页面:https://www.artbreeder.com/i?k=35f9d8d2bba080ecf586,作者截图
结果令人震惊:
作者截图
因此,人工智能生成的图像和视觉搜索的结果的结合可以带来新的见解、发现和视觉探索我们世界的方式。当然,它也可以使用通常的图像作为输入。但在我使用甘的新抽象概念后,我看到了未知队列的力量,引发了意想不到的视觉联想。
生成性图像带有错觉的危险,并带来新的艺术视角。这取决于我们人类,以仁慈、明智和创造性的方式使用它。
基于 NetworkX 的生成图模型
标准生成图方法的综合指南及其在 NetworkX 中的实现
奥马尔·弗洛雷斯在 Unsplash 上拍摄的照片
相关文章
你听说过诸如 GANs 或 VAEs 这样的生成方法吗?这些聪明的架构允许我们对复杂的分布进行建模,并生成令人信服的数据样本,这些样本几乎无法与真实数据区分开来。
生成方法在图形数据中也有应用。在本文中,我们将研究 3 种流行的方法,这些方法用于生成具有不同属性(如节点度或节点社区)的图。我们还将看看它在 NetworkX 包中各自的实现。我们开始吧!
注意:你可以在这里 运行这篇文章的 Colab 笔记本 。
erdős–rényi 模型
ER 模型是最流行和最简单的图形生成方法之一。该模型的主要思想是为两个节点之间的边设置统一的概率阈值。总的来说,该型号有两种变型和,但主要的一种可以定义如下:
ER 模型定义[1]。 A 是邻接矩阵,u,V 是图中的节点 V 。可以解释为两个任意且不同的节点之间的边的概率 r 。
上面的等式意味着:为出现在两个任意且不同的节点之间的边设置一个概率。 r 越高,连通图越密。
从 NetworkX 包中用nx.erdos_renyi_graph
函数生成 ER 图相当容易:
下面,我绘制了 3 个随机生成的图,概率分别为 0.1、0.3 和 0.5。
使用 NetworkX 软件包用 ER 模型生成的图形。 r 分别设置为 0.1、0.3、0.5。作者创建的图像。
虽然 ER 生成的图简单且计算快速,但是我们不能用这种方法来建模更复杂的图结构。使用 ER,不可能用图来建模主题、程度分布或社区。现在,我们将朝着能够在一定程度上模拟这些属性的更复杂的模型前进。
随机块模型
SBM 模型进一步发展了 ER 生成的概念。它为在某个社区(即节点集群)内的节点和来自不同社区的节点之间的节点定义了唯一的概率。
如果这还不太清楚,让我们看一个简单的例子,看看它是如何产生的。
对于 SBM,我们对每个集群内的节点和属于不同集群的节点有单独的概率。在此图中,绿色数字是出现在两个不同分类之间的边缘概率。每个集群内的数字是同一社区内节点的边概率。作者创建的图像。
我们看到概率是为每个社区和一对不同的社区定义的。值得注意的是,如果所有的概率都相等,SBM 就会退化为一个简单的 ER 模型。
我们可以将模型定义如下[1]:
- 图 V 中的每个节点 u 属于某个社区 Ci,其中 i∈(0,…,γ),γ为社区总数
- 对于每个节点 u ∈ Ci 和 v ∈ Cj,存在一个边的概率,使得:
属于社区 i 和j的两个节点之间的边的概率这里, A 是邻接矩阵,C(γxγ**)**是具有所有社区对的概率的概率矩阵。
其中 A 是邻接矩阵, C (大小为γ x γ) 是所有社区对的概率矩阵。
我们也可以使用 NetworkX 来创建 SBM 生成的图形。我们需要的只是一个nx.stochastic_block_model
函数和一些其他实用程序来很好地绘制它。
在上述脚本的最后,您可以看到我为 3 个不同的集群设置了社区大小,以及一个 community_probs 矩阵,该矩阵设置了这些集群的概率(对角线值是每个集群内的边缘概率)。用提供的 Colab 笔记本随意试验这些值。对于代码中可以找到的默认值,我得到了下图:
使用 NetworkX 生成的图形。作者创建的图像。
这种模型有许多变体。一些例子可能包括用于二部图或具有节点特征的图的 SBM 方法[1]。
巴拉巴希-艾伯特模型
真正的网络可以随着时间的推移而增长。这些网络的一些例子可以包括 Twitter 追随者的增加或论文引用的增长。这些网络的一个重要属性是,一些高度连接的节点将吸引更多的连接,甚至增长得更快。例如,某些 Twitter 账户拥有 10 万以上的关注者,增长速度比普通账户快得多,或者某些研究论文被引用 1000 次以上,但它们仍然比不太受欢迎的文献被广泛引用。
网络成长和优先依附这两个属性是巴拉巴希-艾伯特模型(BA)的基础。该模型试图在遵循优先连接增长的同时,迭代地向现有网络添加节点。这种迭代方法将这种技术与 erdős–rényi 和随机块模型区分开来,后者一次生成图形。
这种 BA 算法工作如下。最初,我们有 m_0 个节点,这些节点至少有一个到其他节点的链接[3]。然后,我们迭代地添加一定数量的新节点,这些新节点与其他节点有 m 个链接。这里, m 需要小于 *m_0。*新节点与图中节点 i 连接的概率定义为 pi:
新节点和节点 i 之间的连接概率。 ki 定义了节点 i 的度。
其中 ki 定义了节点 i 的度。
节点度的分布遵循一个幂律分布:
这正是我们想要的,因为这意味着吸引许多连接的节点有非零(但仍然相当小)的概率。因此,我们应该期待在我们的网络中有少量高度连接的节点。
我们可以使用 Networkx 生成 BA 模型的图形。负责 BA 模型的函数称为nx.generators.random_graphs.barabasi_albert_graph
。请注意,我隐藏了一些绘图函数的实现,以避免文章混乱。完整的代码可以在这里找到。
使用上面的脚本,我们可以生成 BA 图。如果我们将它与之前的随机块模型进行比较,我们可以看到现在我们的节点具有不同数量的连接。我们还可以观察到,一个节点比任何其他节点有更多的连接。
使用 NetworkX 生成的 BA 图。作者创建的图像。
总结
在本文中,我们已经看到了 3 种标准的生成图方法:erdős–rényi、随机块和 Barabási-Albert 模型。ER 模型使用最简单的方法来生成节点之间具有统一连接概率的图。SBM 方法进一步发展了这一思想,允许对每个社区内的节点连接以及不同社区对之间的连接分别建模。最后,BA 模型能够使用幂律分布和添加新节点的迭代方法在节点之间生成不同数量的连接。
图形生成模型还有一个有趣的领域,它使用深度学习来生成图形。这个会出现在下一篇文章里!
关于我
我是阿姆斯特丹大学的人工智能硕士学生。在我的业余时间,你可以发现我摆弄数据或者调试我的深度学习模型(我发誓这很有效!).我也喜欢徒步旅行:)
如果你想了解我的最新文章和其他有用的内容,以下是我的其他社交媒体资料:
参考
[2] 社区检测和随机块模型:最近的发展
[3] 网络科学书,第五章
生成网络:从 AE 到 VAE 到 GAN 到 CycleGAN
入门
生成网络进化指南
介绍
简而言之,生成网络背后的核心思想是捕捉数据的底层分布。这种分布不能直接观察到,但必须从训练数据中近似推断出来。多年来,出现了许多旨在生成类似于输入样本的数据的技术。
这篇文章打算给你一个进化的概述,从自动编码器开始,描述它的后代,变化的自动编码器,然后看一下 GAN,最后以作为 GAN 设置的扩展的 CycleGAN 结束。
自动编码器
早期的深度生成方法使用自动编码器[1]。这些网络旨在压缩低维潜在空间 z 中的底层分布,例如,通过连续减小层尺寸。这些低维表示充当瓶颈,并迫使网络学习紧凑的表示。
自动编码器的示意图;作者在[2]之后创作的。左边是原始的领域空间,真实的样本是从那里抽取的;右边是重建的输入。中间视觉上较小的块代表瓶颈层,用于强制数据压缩。
网络的第一部分是编码器部分,它将特征映射(编码)到上述低维潜在空间。这种编码自动发生,因此称为自动编码器。从这个编码表示中,解码器部分试图重建原始数据。这是一种无监督的技术,因为真实样本 x 和生成样本*x’*可以直接比较,不需要标签信息。
潜在空间 z 的大小影响输出质量;更大的空间产生更精确的重构样本x’。然而,解码器没有真正的生成能力(例如,它只能 re 构造样本,而不是发明它们)。
技术现状
用重构损失训练网络[2]
自动编码器的构造损失,根据其相似性将原始样本和重构样本配对。
其在输入样本 x 和重构样本*x’*之间的距离为零时最小。在这种情况下,网络实现了完美的重构。
想象一只猫的图片:你把它喂给模型,得到的猫越像你的输入,这个模型就越好。毕竟,你想认出你的宠物,不是吗?
一只猫。马蒂纽·拉马丹在 Unsplash 上拍摄的照片
可变自动编码器
这些生成能力可以通过调整潜在空间 z ,变化自动编码器(VAE)背后的思想【2,3,4,5;更多资源:链接 1 ,链接 2 。
变型自动编码器的示意图,由作者在[2]之后创建。与标准自动编码器设置的关键区别在于对潜在空间的修改,潜在空间被分成均值向量μ和标准差向量σ,这是大多数概率分布的参数。
与自动编码器类似,它由编码器部分和解码器部分组成。编码器学习输入数据的平均值μ和标准偏差σ,它为瓶颈层中的每个维度建模概率分布。在编码过程中,从潜在空间中抽取样本。采样层之后的输出是均值向量μ和偏差向量σ [2]之和。随机性(换句话说,创造力)是通过用随机常数η移动μ和缩放σ引入的,随机常数η来自正态分布。这种(重新)参数化技巧将网络和概率部分分开,使反向传播照常进行[2]。
请这样想:
你想(再次)处理猫的图像。不是简单地让网络压缩图片,而是让它学习输入样本的特征。这可能是毛发的厚度、尾巴的长度、毛发的颜色、耳朵的大小等等。这就是为什么我们将μ和σ作为向量:对于每个特征(毛发、耳朵、尾巴等)。),我们对概率分布建模,了解属性的值(例如尾部长度)有多可能。生成一个样本,然后混合这些属性,生成一个新的猫图像——也许是一个未知的种族?
另一只猫。由 Milada Vigerova 在 Unsplash 上拍摄的照片
为了防止网络记住其输入样本,正则化项被添加到损失函数 L 中,即 Kullback-Leibler 散度。这种差异允许在两个概率分布之间进行比较;在 VAE 的设定中,它被用来“在潜在空间的中心周围平均分配编码(这将是我们的猫的属性)”[2],从而防止记忆。这里,潜在空间被理解为概率分布,并与先验分布相比较,假设分布产生真实样本 x 。这通常是一个单位高斯分布,均值为 0,方差为 1。
先验分布捕获了我们对数据可能如何分布的假设。通常,您希望这尽可能不包含信息,因此使用标准高斯。对于猫的设置,我们的分布可能会说尾巴不长于 20 厘米,或者猫的耳朵通常在 5 到 10 厘米高之间。
技术现状
基本的 VAE 架构利用了两个损耗。第一个是重建损失,如自动编码器设置中的损失,第二个是正则化项,即前面提到的 Kullback-Leibler 散度。这种差异来自概率理论,用于导出概率分布的参数(如平均值或方差)。这符合必须学习这些参数的 VAE 设置。当且仅当两个概率分布相等时(换句话说,当两个随机变量 Y₁和 Y₂相等时),这里使用的散度函数为 0,否则更大。
将 KL 散度加到损失上,使得潜在空间更接近所选择的先验。对于基本的 VAE,这个先验实际上局限于高斯分布。给定网络的潜在分布和这个先验,我们有[2,3]:
其中φ,θ是编码器和解码器的参数(权重), R 是已知的重建损失, KL 是 Kullback-Leibler 散度。当重构样本与输入样本没有区别时,以及当学习的潜在概率分布等于固定的先验时,这种损失最小。
生成对抗网络
在给定数据集之后对人工样本进行建模可以直接通过将真实数据与生成的数据进行比较来完成,或者间接通过利用下游任务来完成,下游任务反过来使网络能够生成真实样本。对于直接方法,可以使用最大平均差异,这超出了本文的范围;例如,参见[7]了解更多信息。
生成对抗网络(GANs) [8]背后的技术依赖于间接比较。在这个框架中,两个网络被联合训练:生成器被训练从噪声中生成人工样本,看起来尽可能真实;鉴别器试图将它们与真实样本区分开来。
噪声输入是真实数据分布的先验,类似于 VAE 设置中的高斯先验。生成器学习一个函数,该函数将这个简单分布(白噪声)转换为代表所需数据的复杂分布。这个转换函数是一个复杂的函数(意思是“不简单”),神经网络已经证明它学习得非常好;网络权重是函数的参数。鉴别器是生成器的对手,深度神经网络将其输入映射到单个标量,输出输入是真实样本的概率。
GAN 框架的示意图,由作者在[2]之后创建。左边是学习从噪声到目标域的变换的生成器部分,右边是鉴别器部分,将这样生成的假样本与真实数据样本区分开。
这个过程可以看作是两个玩家的 min-max 博弈。这个博弈中的均衡状态是生成器生成不可区分的假样本,鉴别器始终返回 0.5,即,猜测。在[8]中的算法 1 中描述了训练过程:首先,为 k 步更新鉴别器,然后更新发生器的权重。最后一次更新是通过提升梯度进行的;因为目的是欺骗鉴别器(,即,增加误差),所以必须采用梯度的上升。反向传播更新变换函数的权重,该权重随着时间的推移接近期望的分布。
为了使鉴别器不仅了解真实和虚假样本之间的区别,而且了解真实数据的分布,它在训练期间看到虚假样本和真实样本对。这反过来使生成器能够创建更逼真的样本。
对于猫的设定,我们可以收集我们的宠物的各种图像,这些是真实的样本。从噪声开始,生成器在鉴频器结果的指导下,连续生成更好的样本。这些猫的照片一开始可能看起来很模糊,但随着时间的推移,它们变得越来越真实。鉴别者通过看到真实的猫和生成的猫来判断我们生成图像的质量(即真实性)。
一只真正的猫,不是人工生成的!照片由桑吉亚在 Unsplash 上拍摄
技术现状
其思想是生成一个概率分布,该概率分布模拟来自目标域的底层分布。为了实现这一点,定义了网络输入上的先验p _ z[8],其中 z 是来自该空间的样本。生成网络 G 作为转化函数,将简单的先验分布转化为复杂的分布。与鉴别器一起,两者都遵循
在这个两人游戏中,生成器试图最小化它产生的错误(因此 min ),鉴别器被训练以最大化它的分类精度(因此 max )。
CycleGAN
使用 CycleGAN 对 GAN 框架进行了扩展[9]。这种方法最初出现是为了解决图像到图像的转换问题,其中输入图像来自一个域(例如,白天),而期望的输出来自另一个域(例如,夜晚)。以前的方法需要成对图像{mountain_day,mountain_night}的详尽且昂贵的数据集,这对于更复杂的域改变是禁止的。其次,生成过程容易出现模式崩溃,所有输入样本都被映射到一个单一的输出样本[10];这拖延了训练。
CycleGAN 方法在 set 级别上解决了这个任务;它从域 X 和域 Y 获取不成对的数据集,不需要白噪声输入。CycleGAN 网络旨在双向学习这两个领域之间的潜在关系。域转移X∑X→Y∑Y由生成器 G 完成,而转移 y → x 由 F 完成:
CycleGAN 框架的示意图;作者在[2]之后创作的。左边的鉴别器 D_x 学习区分域 X 的真实样本和 f 产生的虚假样本,右边的鉴别器 D_y 学习区分域 Y 的真实数据和 g 产生的虚假样本。
现在,对于我们奔跑的猫的例子,我们可以将我们的宠物“转化”成一只老虎。因此,我们收集猫和老虎的图像。一个生成器将我们的猫转换成老虎,另一个生成器负责向后的方向,从老虎创建一只猫。
为什么我们甚至需要这种倒退的方向?
为了防止模式崩溃:如果我们不能保证生成的输出是基于我们的输入图像,理论上我们可以总是返回相同的猫到老虎映射的图像。显然,这不会是完全错误的,但这并不是我们真正想要的。
这种转移的成功由周期一致性损失来保证(我认为这是非常聪明的事情):给定一个输入 x ,生成器 G 生成y’。第二发电机 F 变换y’→x’。理想情况下,在映射到 Y 域并返回——完成一个循环——*x’*与 x 相同。
循环一致性的实用性也可以在其他领域看到:将一个英语句子翻译成法语,然后再翻译回英语,应该会产生相同的原始句子[9]。
生成的数据(我们的 cat 图像)的“质量”由鉴别器 D_y 观察,该鉴别器区分真 y 样本和假 y 样本。第二次映射的质量由 D_x 观察,它区分真实样本 x 和生成的样本。总损耗包括两个发生器-鉴别器[8]对的损耗和循环一致性损耗。最后一个损耗通过将每个输入强制为一个互斥输出来防止上述模式崩溃。
对于我们的猫-老虎设置,我们有一个专家来区分猫和假猫,还有一个专家来区分老虎和假老虎。鉴别器与生成器(如果这是一个词的话)一起工作:猫与假猫鉴别器越好,老虎→猫生成器越好;另一个方向也类似。这就是为什么甘的设定可以被看作是一个双人游戏。
技术现状
扩展 GAN 设置,一个 CycleGAN 可以被视为学习两个复杂的变换函数:从分布 A 到 B ,以及从 B 到 A 。
摘要
深度神经网络的生成能力已经发展了几年,早期的方法使用自动编码器框架。在此基础上,变分自动编码器通过从潜在空间中随机采样来增加更强的生成能力。当[8]提出生成对抗网时,实现了一个里程碑,使得模型能够学习从噪声到目标域的转换。CycleGAN 框架通过使用两个生成器和两个鉴别器来保留样本中包含的原始信息,从而扩展了这种方法。
回顾一下,要点是
- 自动编码器压缩并重建它们的输入
- 可变自动编码器增加了更多的生成技术
- GANs(最初)使用白噪声作为输入来生成数据
- CycleGANs 扩展了 GAN 概念,使训练更加稳定
这个帖子到此为止。如有任何更正、评论或意见,请留言。感谢阅读!
文献学
如果您想了解更多信息,请参考以下资源:
[1] G. Hinton 和 R. Salakhutdinov,用神经网络减少数据的维数 (2006),科学
[2] A. Amini 和 A. Soleimany,深度学习介绍:深度生成模型 (2020),麻省理工学院演讲
[3] D. Kingma 和 M. Welling,随机梯度 VB 和变分自动编码器 (2014),第二届学习表征国际会议,ICLR
[4] D. Rezende 等,深度生成模型中的随机反向传播和近似推理 (2014),第 31 届机器学习国际会议论文集(ICML)
[5] X .陈等。,变分有损自动编码器 (2017),arXiv
[6] A. Valenti 等人,通过对抗性自动编码器学习风格感知的符号音乐表示 (2020),第 24 届欧洲人工智能会议(ECAI2020)
[7] A. Gretton 等,双样本问题的核方法 (2007),神经信息处理系统进展
[8] I. Goodfellow 等,生成对抗网络 (2014),神经信息处理系统进展
[9]朱等,利用循环一致对抗网络的不成对图像到图像翻译 (2017),IEEE 计算机视觉国际会议论文集
[10] Ian Goodfellow,NIPS 2016 教程:生成对抗网络 (2016),arXiv
R:超参数整定中的遗传算法
在 R 中使用遗传算法调整模型的超参数
动机
监督学习成为机器学习(ML)领域的主要任务之一,其中监督学习本身的目标是在给定数据中的特征/自变量的情况下预测目标/因变量。近年来研究的最大似然法的研究课题之一是超参数调整。
我们可以用于超参数调整的一种流行技术是使用网格搜索(GS)算法。尽管 GS 是 ML 中超参数调整的一种流行算法,但当涉及大型数据集和/或多个超参数时,它非常耗时且计算量大。为此,开发了几种替代技术,其中之一是使用遗传算法。在这篇文章中,我将告诉你如何在 r 中使用遗传算法来调整你的超参数。
那么,什么是超参数调谐呢?
ML 模型中超参数的调整会极大地影响其预测性能,因此为模型设置合适的超参数非常重要。传统上,ML 模型中的超参数调整通常通过试错过程来执行。根据 ML 模型中存在的超参数的数量,这个过程可能会非常耗时,尤其是当我们处理大量数据时。
超参数调整问题通常被视为优化问题,其中我们想要优化的目标函数是模型本身的预测性能。超参数调优[3]中经常遇到的挑战如下。
- 一个数据集中的超参数设置可能会导致高预测性能,但在另一个数据集中可能不会。
- 超参数有时是相互依赖的,例如随机森林中的
ntree
(树的数量)和mtry
(随机选择的变量的数量)。 - 耗时的超参数调整过程。
超参数整定的遗传算法
遗传算法的思想是通过选择最佳或最合适的解以及罕见和随机的突变发生来获得目标函数的最优解。对于那些想了解算法如何工作的人,我在这里写了一篇解释算法概念的文章。
在这种情况下,由于我们想要调整 ML 模型上的超参数,因此该算法中使用的“群体”是具有不同超参数值的模型列表。用于超参数调整的遗传算法的伪代码如下所示。
遗传算法超参数整定伪代码(图片由作者提供)
案例分析
在本文中,我使用 UCI 机器学习库中的混凝土抗压强度数据集实现了超参数调整的遗传算法。该数据集的目标是预测混凝土抗压强度值,因此存在回归问题。
混凝土抗压强度数据集(图片取自 UCI 机器学习库)
变量信息如下。
- 水泥(成分 1) —定量—m3 混合物中的千克数—输入变量
- 高炉矿渣(成分 2) —定量—m3 混合物中的千克数—输入变量
- 飞灰(成分 3) —定量—m3 混合物中的千克数—输入变量
- 水(成分 4) —定量—m3 混合物中的千克数—输入变量
- 超塑化剂(成分 5) —定量—m3 混合物中的千克数—输入变量
- 粗骨料(成分 6) —定量—m3 混合物中的千克数—输入变量
- 细骨料(成分 7) —定量—m3 混合物中的千克数—输入变量
- 年龄—定量—天数(1~365) —输入变量
- 混凝土抗压强度—定量— MPa —输出变量
对于这种情况,我使用随机森林(对于离散值超参数情况)和梯度推进(对于实值超参数情况)模型。
数据预处理
首先,我们导入我们需要的数据和库。
library(car)
library(MASS)
library(tseries)
library(lmtest)
library(tidyverse)
library(GA)
library(mice)
library(caret)
library(caTools)
library(rsample)
library(gbm)
library(glmnet)
library(tictoc)
library(randomForest)#Data Importing
data=read.csv("data_input/Concrete_Data.csv",sep=';')
summary(data)
str(data)
我们按如下方式检查数据汇总。
> str(data)
'data.frame': 1030 obs. of 9 variables:
$ Cement : num 540 540 332 332 199 ...
$ Blast.Furnace.Slag : num 0 0 142 142 132 ...
$ Fly.Ash : num 0 0 0 0 0 0 0 0 0 0 ...
$ Water : num 162 162 228 228 192 228 228 228 228 228 ...
$ Superplasticizer : num 2.5 2.5 0 0 0 0 0 0 0 0 ...
$ Coarse.Aggregate : num 1040 1055 932 932 978 ...
$ Fine.Aggregate : num 676 676 594 594 826 ...
$ Age : int 28 28 270 365 360 90 365 28 28 28 ...
$ Concrete.compressive.strength: num 80 61.9 40.3 41 44.3 ...
然后,我们使用来自mice
库的md.pattern
检查数据集中是否存在缺失值,如下所示。
> md.pattern(data)
/\ /\
{ `---' }
{ O O }
==> V <== No need for mice. This data set is completely observed.
\ \|/ /
`-----'Cement Blast.Furnace.Slag Fly.Ash Water Superplasticizer Coarse.Aggregate Fine.Aggregate Age
1030 1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0
Concrete.compressive.strength
1030 1 0
0 0
缺失的价值分析(图片由作者提供)
我们可以看到没有丢失的值,所以我们可以进入下一步了。然后,我们将数据分成 70:30 比例的训练和测试数据,如下所示。
#Data Splitting
split=initial_split(data,prop=0.7)
data.train=training(split)
data.test=testing(split)
实施(离散值超参数)
对于离散值超参数的情况,我们使用随机森林模型,我们想要调整的超参数是ntree
和mtry
。由于ntree
和mtry
是离散值超参数,我们在优化过程中使用二进制编码。在这里,我将ntree
的范围设置为 1 到 512,将mtry
的范围设置为 1 到 8(您可以设置一个更大的范围,但请记住随机森林非常耗时,所以只要您有耐心等待,就继续吧)。为了检查我们需要多少位,我们可以通过将每个超参数的最大值相乘并将其与超参数的数量相加来计算,如下所示。
> log2(512*8)+2
[1] 14
根据上面的计算,我们需要 14 位。如果ntree
和mtry
的转换值为 0,我们将其改为 1(因为最小值范围为 1)。然后,如果ntree
的转换值大于 512,我们就把它改成 512(因为最大值范围是 512)。同样,如果mtry
的转换值大于 8,我们将其更改为 8(因为最大值范围是 8)。接下来,我们创建想要实现的目标函数。记住,遗传算法的目的是最大化目标值,我们希望 RMSE 值尽可能小,因此我们将 RMSE 值设置为负值。
fit_rf=function(x)
{
ntree=binary2decimal(x[1:10]) #ntree from 1 to 2^9
mtry=binary2decimal(x[11:14]) # mtry from 1 to 2^3
if(ntree==0)
{
ntree=1
}
if(mtry==0)
{
mtry=1
}
if(ntree>512)
{
ntree=512
}
if(mtry>8)
{
mtry=8
}
model=randomForest(Concrete.compressive.strength~.,data=data.train,mtry=mtry,
ntree=ntree)
predictions=predict(model,data.test)
rmse=sqrt(mean((data.test$Concrete.compressive.strength-predictions)^2))
return(-rmse) #since GA maximize the objective function and we want to minimize RMSE
}
现在,让我们通过编写这几行代码来看看如何将其实现为ga
函数。
tic()
GA3=ga(type='binary',fitness=fit_rf,nBits=14,
maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
summary(GA3)
plot(GA3)
toc()
随机森林超参数调谐结果的遗传算法(图片由作者提供)
> tic()
> GA3=ga(type='binary',fitness=fit_rf,nBits=14,
+ maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
GA | iter = 1 | Mean = -5.277882 | Best = -4.946697
GA | iter = 2 | Mean = -5.152451 | Best = -4.946697
GA | iter = 3 | Mean = -5.182143 | Best = -4.946697
GA | iter = 4 | Mean = -5.115866 | Best = -4.921109
GA | iter = 5 | Mean = -5.075498 | Best = -4.921109
GA | iter = 6 | Mean = -5.132925 | Best = -4.921109
GA | iter = 7 | Mean = -5.089994 | Best = -4.921109
GA | iter = 8 | Mean = -5.126774 | Best = -4.921109
GA | iter = 9 | Mean = -5.078846 | Best = -4.921109
GA | iter = 10 | Mean = -5.163979 | Best = -4.919853
GA | iter = 11 | Mean = -5.205034 | Best = -4.919853
GA | iter = 12 | Mean = -5.207537 | Best = -4.919853
GA | iter = 13 | Mean = -5.098879 | Best = -4.919853
GA | iter = 14 | Mean = -5.118728 | Best = -4.919853
GA | iter = 15 | Mean = -5.202860 | Best = -4.919853
GA | iter = 16 | Mean = -5.145285 | Best = -4.919853
GA | iter = 17 | Mean = -5.107588 | Best = -4.919853
GA | iter = 18 | Mean = -5.032939 | Best = -4.919853
GA | iter = 19 | Mean = -5.041192 | Best = -4.885373
GA | iter = 20 | Mean = -5.039374 | Best = -4.885373
GA | iter = 21 | Mean = -5.034047 | Best = -4.885373
GA | iter = 22 | Mean = -5.030971 | Best = -4.885373
GA | iter = 23 | Mean = -5.023164 | Best = -4.885373
GA | iter = 24 | Mean = -5.026200 | Best = -4.829599
GA | iter = 25 | Mean = -5.077859 | Best = -4.829599
GA | iter = 26 | Mean = -5.080206 | Best = -4.829599
GA | iter = 27 | Mean = -5.033013 | Best = -4.829599
GA | iter = 28 | Mean = -5.071353 | Best = -4.809166
GA | iter = 29 | Mean = -5.057733 | Best = -4.809166
GA | iter = 30 | Mean = -5.048505 | Best = -4.809166
> summary(GA3)
-- Genetic Algorithm -------------------GA settings:
Type = binary
Population size = 50
Number of generations = 30
Elitism = 2
Crossover probability = 0.8
Mutation probability = 0.1GA results:
Iterations = 30
Fitness function value = -4.809166
Solution =
x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 ... x13 x14
[1,] 0 0 0 1 0 1 0 1 0 0 0 1
> plot(GA3)
> toc()
1101.77 sec elapsed
我们可以看到最合适的ntree
和mtry
值如下。
> ga_rf_fit=as.data.frame(GA3@bestSol)
> ga_ntree=apply(ga_rf_fit[, 1:10],1,binary2decimal)
> ga_mtry=apply(ga_rf_fit[, 11:14],1,binary2decimal)
> ga_ntree
[1] 76
> ga_mtry
[1] 4
从上面的结果来看,每一代中最好的个体产生的 RMSE 在每一代中是递减的,其中最终一代中的最适结果为 76 个ntree
和 4 个mtry
,RMSE 值为 4.809166。
实现(实值超参数)
对于实值超参数的情况,我们使用梯度增强模型,我们想要调整的超参数是n.trees
、shrinkage
和interaction.depth
。请注意,n.trees
和interaction.depth
是离散值超参数,因此技巧是将底值函数应用于模型函数中的n.trees
和interaction.depth
值,如下所示。
fit_gbm=function(ntree,shrinkage,interaction)
{
model=gbm(Concrete.compressive.strength~.,data=data.train,distribution="gaussian",
n.trees=floor(ntree),shrinkage=shrinkage,interaction.depth=floor(interaction))
predictions=predict(model,data.test)
rmse=sqrt(mean((data.test$Concrete.compressive.strength-predictions)^2))
return(rmse)
}
然后,我们将目标函数实现到ga
函数中,如下所示。
tic()
GA2=ga(type='real-valued',fitness=function(x) -fit_gbm(x[1],x[2],x[3]),
lower=c(1,1e-4,1),upper=c(512,1e-1,3),maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
summary(GA2)
plot(GA2)
toc()
遗传算法梯度增强超参数调谐结果(图片由作者提供)
> summary(GA2)
-- Genetic Algorithm -------------------GA settings:
Type = real-valued
Population size = 50
Number of generations = 30
Elitism = 2
Crossover probability = 0.8
Mutation probability = 0.1
Search domain =
x1 x2 x3
lower 1 1e-04 1
upper 512 1e-01 3GA results:
Iterations = 30
Fitness function value = -4.939432
Solution =
x1 x2 x3
[1,] 470.8652 0.08298563 2.346486
> plot(GA2)
> toc()
72.26 sec elapsed
从上面的结果来看,每一代中最好的个体产生的 RMSE 在每一代中是递减的,其中最终一代中的最适结果为 470 n.trees
,0.08298563 shrinkage
,2 interaction.depth
,RMSE 值为 4.939432。
结论
这就是了,你可以在 r 中实现超参数调整的遗传算法,你可以尝试不同的数据集,或者尝试在分类问题上实现它。此外,您可以尝试不同的预测性能指标来查看不同的结果。永远记住,ML 是一个广阔的领域,所以永远要尝试实验!
像往常一样,如果您有任何问题,请随时在我的联系人下面提问或讨论!在我的下一篇文章中再见!
说到超参数调谐…(从 Imgflip 生成的图像)
作者联系方式
LinkedIn: 拉登·奥勒留和希卡·维亚迪努格罗霍
中:https://medium.com/@radenaurelius
参考文献
[1]叶一成,利用人工神经网络对高性能混凝土强度进行建模 (1998),水泥与混凝土研究。
https://rpubs.com/Argaadya/550805
[3] Rafael G. Mantovani,Tomáhorváth,Ricardo Cerri,Joaquin Vanschoren,andéc . p . l . f . de Carvalho,决策树归纳算法的超参数调整 (2016),2016 年第五届巴西智能系统会议。
[4]https://archive . ics . UCI . edu/ml/datasets/Concrete+抗压+强度
[5] Nikolaos Gorgolis,Ioannis Hatzilygeroudis,Zoltan·伊斯特尼斯,Lazlo — Grad Gyenne,通过遗传算法优化 LSTM 网络模型的超参数 (2019),2019 年第十届信息、智能、系统与应用国际会议(IISA)。
[6] Luca Scrucca,GA:R(2013)中的遗传算法包,统计软件杂志。
[7]https://www . rdocumentation . org/packages/GA/versions/3.2/topics/GA
R 中的遗传算法:背包问题
塞巴斯蒂安·戈德堡在 Unsplash 上的照片
用遗传算法求解 R 中的背包问题
动机
背包问题是最优化,特别是组合最优化中的著名问题之一。这个问题的动机来自于一个人需要最大化他的背包容量——因此得名——尽可能多的物品。有许多方法可以解决这个问题,但是在本文中,我将给出一个例子,使用 r。
背包问题
在本文中,我们将尝试解决的背包问题是0–1 背包问题。给定一组从 1 到 n 编号的 n 个项目,每个项目的权重为 w_i,值为 v_i。假设每个项目的副本限制为 1,即该项目要么包含在背包中,要么不包含在背包中。这里我们希望最大化目标函数(即背包中物品的价值)
其中目标函数服从约束函数
遗传算法概念
遗传算法是一种基于自然选择进化思想的优化算法。查尔斯·达尔文提出,自然选择进化是通过两个原则:自然选择和突变,来决定有多少种生物会适应环境而生存。基于这一概念,遗传算法的目标是通过选择最佳或最合适的解决方案以及罕见的随机突变事件来获得目标函数的最优解。算法本身可以解释如下。
遗传算法流程图(图片由作者提供)
- 初始化我们将优化的数据和/或函数。
- 初始化种群大小、最大迭代次数(代数)、交叉概率、变异概率和精英数(不会发生变异的最佳或最适个体)。
- 从群体中选择两个个体,然后以概率 p 在两个个体之间进行交叉。
- 然后,在两个概率为 p 的个体之间进行变异(通常变异的概率很低)。
- 重复步骤 3 和 4,直到一代中的所有个体都被训练。这些所有的个体将被用于训练下一代,直到代数达到极限。
为了让您更好地理解遗传算法,让我们跳到案例研究,在这里我们将使用遗传算法来解决 r 中的背包问题。
案例分析:用遗传算法解决背包问题
假设你想和你的朋友去徒步旅行,你有徒步旅行可以使用的物品,每件物品的重量(以公斤为单位)和生存点分别如下。
可用的图片,分别显示每件物品的重量和生存点数(图片由作者提供)
再假设你有一个背包,可以装下最大容量 25 公斤的物品,其中每个物品只能带一份。目标是:你想最大化背包的容量,同时最大化你的生存点数。从问题陈述中,我们可以定义物品的重量为约束函数,而背包中物品累积的生存点数为目标函数。
对于本文中的实现,这里我们使用 Luca Scrucca [2]创建的 R 中的GA
库。首先,我们需要输入我们通过编写这些代码行所使用的数据和参数。
#0-1 Knapsack's Problemlibrary(GA)item=c('raincoat','pocket knife','mineral water','gloves','sleeping bag','tent','portable stove','canned food','snacks')
weight=c(2,1,6,1,4,9,5,8,3)
survival=c(5,3,15,5,6,18,8,20,8)
data=data.frame(item,weight,survival)
max_weight=25
为了让你更好地理解这个问题中的遗传算法,假设我们最初在你的背包中只带了一把小刀、矿泉水和零食。我们可以把它写成“染色体”,既然我们要解决的问题是一个 0–1 背包问题,那么从下面这几行代码来看,1 表示我们带来了物品,而 0 表示我们留下了物品。
#1 means that we bring the item, while 0 means that we left the item
chromosomes=c(0,1,1,0,0,0,0,0,1)
data[chromosomes==1,]
我们可以看到如下结果。
> data[chromosomes==1,]
item weight survival
2 pocket knife 1 3
3 mineral water 6 15
9 snacks 3 8
然后,我们通过编写下面的代码行来创建我们想要用约束函数优化的目标函数。我们将在GA
库中的ga
函数中使用的fitness
函数。
#create the function that we want to optimize
fitness=function(x)
{
current_survpoint=x%*%data$survival
current_weight=x%*%data$weight
if(current_weight>max_weight)
{
return(0)
}
else
{
return(current_survpoint)
}
}
现在有趣的部分来了:使用遗传算法的优化过程。假设我们想要为优化过程创建最多 30 代和 50 个个体。为了再现性,我们写下seed
参数并保留最佳解。
GA=ga(type='binary',fitness=fitness,nBits=nrow(data),maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
summary(GA)
plot(GA)
通过运行上面的代码行,我们可以获得如下结果。
> GA=ga(type='binary',fitness=fitness,nBits=nrow(data),maxiter=30,popSize=50,seed=1234,keepBest=TRUE)
GA | iter = 1 | Mean = 31.92 | Best = 61.00
GA | iter = 2 | Mean = 31.32 | Best = 61.00
GA | iter = 3 | Mean = 33.08 | Best = 61.00
GA | iter = 4 | Mean = 36.14 | Best = 61.00
GA | iter = 5 | Mean = 42.42 | Best = 61.00
GA | iter = 6 | Mean = 36.56 | Best = 61.00
GA | iter = 7 | Mean = 37.32 | Best = 61.00
GA | iter = 8 | Mean = 38.18 | Best = 61.00
GA | iter = 9 | Mean = 39.02 | Best = 61.00
GA | iter = 10 | Mean = 38.92 | Best = 61.00
GA | iter = 11 | Mean = 37.54 | Best = 61.00
GA | iter = 12 | Mean = 35.14 | Best = 61.00
GA | iter = 13 | Mean = 36.28 | Best = 61.00
GA | iter = 14 | Mean = 40.82 | Best = 61.00
GA | iter = 15 | Mean = 44.26 | Best = 61.00
GA | iter = 16 | Mean = 41.62 | Best = 61.00
GA | iter = 17 | Mean = 38.66 | Best = 61.00
GA | iter = 18 | Mean = 36.24 | Best = 61.00
GA | iter = 19 | Mean = 43 | Best = 61
GA | iter = 20 | Mean = 43.48 | Best = 61.00
GA | iter = 21 | Mean = 43.08 | Best = 61.00
GA | iter = 22 | Mean = 44.88 | Best = 61.00
GA | iter = 23 | Mean = 46.84 | Best = 61.00
GA | iter = 24 | Mean = 46.8 | Best = 61.0
GA | iter = 25 | Mean = 42.62 | Best = 61.00
GA | iter = 26 | Mean = 46.52 | Best = 61.00
GA | iter = 27 | Mean = 46.14 | Best = 61.00
GA | iter = 28 | Mean = 43.8 | Best = 61.0
GA | iter = 29 | Mean = 46.16 | Best = 61.00
GA | iter = 30 | Mean = 42.6 | Best = 61.0> summary(GA)
-- Genetic Algorithm -------------------
GA settings:
Type = binary
Population size = 50
Number of generations = 30
Elitism = 2
Crossover probability = 0.8
Mutation probability = 0.1GA results:
Iterations = 30
Fitness function value = 61
Solution =
x1 x2 x3 x4 x5 x6 x7 x8 x9
[1,] 1 0 1 1 0 0 1 1 1> GA@summary
max mean q3 median q1 min
[1,] 61 31.92 48 36.0 16 0
[2,] 61 31.32 47 31.0 24 0
[3,] 61 33.08 51 36.5 13 0
[4,] 61 36.14 52 39.0 31 0
[5,] 61 42.42 56 47.5 38 0
[6,] 61 36.56 52 41.5 26 0
[7,] 61 37.32 54 43.0 29 0
[8,] 61 38.18 54 43.0 29 0
[9,] 61 39.02 55 47.0 33 0
[10,] 61 38.92 52 43.5 33 0
[11,] 61 37.54 48 39.0 33 0
[12,] 61 35.14 47 39.0 29 0
[13,] 61 36.28 47 41.0 23 0
[14,] 61 40.82 51 43.0 34 0
[15,] 61 44.26 51 48.0 38 20
[16,] 61 41.62 52 45.0 34 0
[17,] 61 38.66 53 41.5 28 0
[18,] 61 36.24 51 39.5 28 0
[19,] 61 43.00 56 48.0 37 0
[20,] 61 43.48 56 48.0 39 0
[21,] 61 43.08 56 48.0 40 0
[22,] 61 44.88 56 51.0 41 0
[23,] 61 46.84 56 52.0 41 0
[24,] 61 46.80 56 48.0 41 0
[25,] 61 42.62 56 48.0 33 0
[26,] 61 46.52 56 48.0 42 0
[27,] 61 46.14 54 47.0 43 0
[28,] 61 43.80 56 49.5 40 0
[29,] 61 46.16 54 50.0 43 0
[30,] 61 42.60 56 48.0 36 0
遗传算法优化结果— GA(图片由作者提供)
从上面的结果中,我们可以看到,每一代人的表现都在提高。我们可以从适应值(即本例中的生存点)均值和中值看出,它在每一代中都有增加的趋势。让我们试着再训练它一次,但是要用更多代。
GA2=ga(type='binary',fitness=fitness,nBits=nrow(data),maxiter=50,popSize=50,seed=1234,keepBest=TRUE)
GA3=ga(type='binary',fitness=fitness,nBits=nrow(data),maxiter=100,popSize=50,seed=1234,keepBest=TRUE)
plot(GA2)
plot(GA3)
遗传算法优化结果— GA2(图片由作者提供)
遗传算法优化结果— GA3(图片由作者提供)
从GA2
和GA3
中,我们可以看到,根据该代适应值的平均值和中值,每个个体的优化结果在 40 岁左右和 60 岁左右的代处于最佳状态。我们还可以看到,从第 72 代开始,最佳适应值增加到 62。
由于我们保留了每个优化过程的最佳结果,因此我们希望根据遗传算法优化的最佳结果来找出我们可以为徒步旅行带来的物品。我们可以看到来自GA3
的总结如下。
> summary(GA3)
-- Genetic Algorithm -------------------
GA settings:
Type = binary
Population size = 50
Number of generations = 100
Elitism = 2
Crossover probability = 0.8
Mutation probability = 0.1GA results:
Iterations = 100
Fitness function value = 62
Solution =
x1 x2 x3 x4 x5 x6 x7 x8 x9
[1,] 1 1 1 1 1 0 0 1 1
从上面的结果,我们可以得出结论,我们可以包括在背包的物品是雨衣,小刀,矿泉水,手套,睡袋,罐头食品和零食。我们可以计算背包的重量,以确保背包没有超载。
> chromosomes_final=c(1,1,1,1,1,0,0,1,1)
> cat(chromosomes_final%*%data$weight)
25
太好了!我们可以看到物品的重量和背包容量是一样的!
结论
这就对了。您可以通过在 r 中实现遗传算法,以最大的生存点和容量与朋友一起徒步旅行(当然最好在疫情结束后进行)。事实上,您可以在许多现实世界的应用中使用遗传算法来解决背包问题,例如选择最佳表现的投资组合、生产调度等等。
像往常一样,如果您有任何问题或讨论,请随时通过我的 LinkedIn 联系我。保持安全,保持健康!
参考文献
[1] G. B. Matthews,关于数的划分 (1897),伦敦数学学会会刊。
[2] Luca Scrucca,GA:R(2013)中的遗传算法包,统计软件杂志。
[3]https://www . rdocumentation . org/packages/GA/versions/3.2/topics/GA
[4]哈维·m·萨尔金和科内利斯·A·德·克鲁弗,背包问题:调查 (1975),《海军研究后勤季刊》。
[5] Krzysztof Dudziński 和 stanisaw Walukiewicz,背包问题的精确方法及其推广 (1987 年),《欧洲运筹学杂志》。
[6] Sami Khuri,Thomas bck 和 rg Heitkö tter,《零/一多重背包问题和遗传算法》 (1994),SAC ’ 94:1994 年 ACM 应用计算研讨会会议录。
[7]https://rpubs.com/Argaadya/550805
遗传算法的发展
为 B2B 市场的 ICP 评分创建人工智能算法
M 任何人都听说过最终消费者对人工智能领域的巨大怀疑:“我们已经在市场上待了 50 年,所以我们更知道该做什么”。
你在谈论你的人工智能,但它是如何工作的?你能给我们销售部写个算法吗?我们如何解释这些结果?
从这些欲望中,一个流行的任务出现了:ICP-segmentation for B2B。ICP —理想的客户档案,销售中的目标细分市场。在输入端有一个公司的参数:国家、金额、收入;在输出端,我们预测一些其他参数:****
- 潜在客户的转化
- 客户能给你什么收入
- 这个人是他公司里做决定的人吗,等等。
接下来,我们计算分数,从而计算进入一个或另一个组的概率。
模型
任务看起来很清楚:我们获取输入参数,将它们转换成所需的形式,代入模型,并训练模型。然而,如前所述,我们的解决方案的最终用户不仅希望看到结果,还希望了解为什么某个最终方案比一组具有良好直觉的专业员工更好地解决了他们的问题。因此,除了有效之外,我们的决定必须是可解释的。
为了在问题的效率和可解释性之间找到一个折中的办法,我们得出了下面的数学模型:
作者图片
或者更简单地,对参数的影响有约束的截断二次模型。最后分数从-100 到 100,一切都诠释的相当好。你可以尝试建立一个基于直觉的模型(我们与美国合作,这意味着我们将最重视它),或者你可以找到一个基于实际转换数据或利润的模型。
这就是蛮力问题的来源,它应该使用遗传算法来解决,因为普通线性规划(经过简化)的方法会在数据量上遇到困难。每个集合(x,y)将被简称为基因。
在每个阶段,我们使用数据集中每一行的公式计算得分,并使用几个损失函数中的一个计算该基因预测结果的好坏。
已经研究了几种损失函数:
1-矩阵:有一个惩罚矩阵,其中我们计算每行的惩罚或奖励,例如,如果我们试图将样本分成两组,那么在第一类或第二类错误的情况下,我们给出惩罚-1,而在落入正确组的情况下,我们给出奖励 1
作者图片
2-按平均值:计算每组的平均目标参数,并尝试找出各组之间的最大距离。
尽管使用第一个损失函数的结果更容易解释,但得到的组太不均匀。结果,当组的数量多于两个时,有效性被分组。结果,由于分组数据的随机性,这些组太不均匀了,所以让我们选择第二个选项。PCA 后的样本分布(混沌参考):
作者图片
算法优化方法
遗传算法是对原始样本的一系列转换,在每一个阶段,它都会丢弃最差的结果。最初算法对于大问题自然是多线程的,增长不是线性的。例如,与没有多线程的算法相比,在 16 个内核上运行可以提高近 10 倍。优化采样的损失函数也是值得考虑的。但也有不太明显的方式。
减少多线程计算中 Map-reduce 的数量
我想讨论的第一件事是减少并行化过程中的 map-reduce 数量。遗传算法分为几个阶段,即:繁殖、变异、计算下一代。所有这些都可以合并到一个任务中,并在参数中包含一个触发器。也就是说,不是:
**CURRENT_POPULATION = mutation.Mutation(CURRENT_POPULATION,triggers)
CURRENT_POPULATION = reproduction.Reproduction_multythread(CURRENT_POPULATION)**
可以合并成一个功能:
**CURRENT_POPULATION = mut_rep_iteration.Itr(CURRENT_POPULATION,triggers)**
比较一次迭代速度的结果:
作者图片
组合功能(新的 fn)比以前的(旧的 fn)几乎好 10%。该算法本身可以计算几乎一整天,这意味着计算可以少花 2-3 个小时。
初始近似值的选择
首先,让我们回忆一下我们正在研究的数学模型:
作者图片
显然,如果我们在遗传算法中取的不是随机值,而是,例如,一些有效的基因,那么该算法将需要较少的迭代。
让我们应用几个有争议的近似值。
1 —仅近似选项 yⱼ :
- 做一个随机集 x ,代入公式,得到每行通常的线性方程
- 将每个 yⱼ 作为方程组计算
- 为了符合条件,将 y 的极端值再次代入公式,再次用较少的变量求解通常的 SLAE 系统,并重复几次
- 每轮 yⱼ
- 我们获得了每个参数 yⱼ 的一些初始近似值
这个假设是有意义的,因为许多参数 y 经常在不同的方案中重复。如果某个参数是好的(强烈影响结果),那么它在任何方案中都将有一个最大值或最小值。
2 —一般近似变量(梯度下降):
- 做选项 1
- 我们解决逆问题:代入参数 y 计算 x
- 重复 N 次
这里,除了局部参数之外,我们还想看看哪个组对最终结果的影响最大。该算法的速度较低。因此,对于每个变体,进行了五次试验。
当前参数集:
一代幸存者:50,000
儿童人数:25,000 人
变种人数量:12500 人
现在让我们看看结果:
作者图片
变体 1 与干净启动相同,这意味着近似没有导致积极的结果,但是第二个(变体 2)看起来很有希望,但是让我们看看执行时间图。
作者图片
由于花费在初始近似上的时间,执行所花费的时间显著增加。这有点不公平。所以,让我们尝试将通常的算法与变体 2 进行比较,给常规算法更多的资源,并通过在每次迭代时扩展样本来近似时间。
作者图片
作者图片
尽管资源远远优于选项 2 (fp2),但实现持续更好的结果是不可能的。理论上,这可以通过搜索超参数和过滤下一代来防止优势来纠正。这个方向的研究还在继续,所以选择第二种形式的初始近似。
这个问题的初始近似稳定了答案,优化了资源。初始近似选择为梯度下降的几次迭代:
**gen = ret_random_gen(0) #Full random gen
for i in range(0,iters):
gen = CalculateByGenMG(gen) # calculate only X
gen = CalculateByGenML(gen) # calculate only Y**
确认
最后,我想提供生产中模型验证的图形数据。
这是训练(左图)和验证(右图)时的分布。(图片作者)
训练是基于支票大小的数据。每条线索从低到高分为一组,如您所见,级别越高,高检查的概率越高。传入的数据结构略有变化,但组的区分保持稳定。
结论
遗传算法是一个资源密集型过程,优化这一过程可能成为其创建的主要任务。该算法易于使用,有助于在蛮力问题中找到最优解,并证明了其有效性。
遗传算法机器人:进化高度,使用 Python,C++和 Arduino。
用遗传算法代替预定的数学模型设计飞行控制系统。
用于测试进化高度机器人的三个机器人中的两个。作者图片
摘要:
这项研究的目的是设计一个飞行控制系统,没有预先确定的数学模型,而是使用遗传算法来保持最佳高度。本研究是通过定量的实证研究方法完成的。在进行研究的过程中,我们发现对新手用户来说,编写遗传算法程序是很麻烦的。因此,我们创建并发布了一个名为 EasyGA 的开源 Python 包。
在一次试验中使用 15 条染色体的初始群体,每条染色体 10 个基因,共 100 代。装置的节流值具有 1 秒的相关基因值。每个机器人至少进行 30 次试验,以显示研究中的统计显著性。当试验完成后,机器学习就实现了。结果表明,在不使用预先确定的数学模型的情况下,实时优化单自由度(DOF)设备是可能的。
工作原理:
为了运行该实验成功所需的遗传算法,需要 Arduino Uno、Python、电子鸭式风扇(EDF)、电子速度控制器(ESC)、超声波测距模块(USRM)和笔记本电脑。
Ardunio Uno: 是一款开源的微控制器板。这种微控制器板带有数字和模拟引脚。这些针有不同的用途。一些引脚用于向其他设备发送 3.3V 和 5V 电源,其他引脚用作输入和输出引脚,向其他设备发送脉宽调制(PWM)信号。
进化高度机器人布线图。作者图片
在本实验中,数字引脚 9、10 和 11 将用于发送 PWM 信号和接收来自超声波测距模块的传感信息。数字引脚 9 (TRIG)用于信号输出,引脚 10 (ECHO)用于信号输入,引脚 11 用于向 ESC 发送 PWM 信号。
Arduino C++: 写在 Arduino 上的代码以节流值的形式接收来自 python 脚本的指示。Arduino 然后执行这些指令,同时从 USRM 读取高度,并使用串行通信将它们传输回 python。
Python: Python 被用作处理遗传算法的主要语言,同时也向 Arduino 发送指示。
**SQL 数据库:**Sqlite3 数据库用于存储来自机器人和遗传算法的所有运行和配置数据。它还用于查找趋势和查询数据。
**一个 DOF 装置:**该装置由一个 EDF 风扇、USRM、一个碳纤维管、各种配线和三个 3D 打印部件组成:中间连接器和平台。该设备的平台被设计为在功能上与 EDF 运行所需的所有部件和零件一起工作。法国电力要求将 120 毫米 x 20mm 毫米的碳纤维管直接连接到风扇。
进化中的高空机器人所有主要部件的标签图像。作者图片
中间连接器被设计得比平台更宽。连接器比平台宽,因此超声波测距模块有足够大的空间来精确测量模块到设备的距离。
显示从超声波测距模块(USRM)到中间连接器的距离为 6 厘米。作者图片
高频超声波信号从模块发送到中间连接器,并作为声纳返回到模块,使其能够计算距离。
机器人健身功能:
适应度函数决定了染色体在特定任务中的表现。为了测试这项研究中的适应度函数,染色体被编码为 throttle 值,解析为一个字符串,并串行发送到 Arduino Uno。Arduino Uno 运行编码的染色体,并将适应性数据发送回 Python 脚本。Python 脚本随后对数据进行评估。这项研究的适应度函数是看机器人的 EDF 能在 USRM 上方 6 厘米的位置保持多好。在体能评估期间,总分是根据它与 6 厘米的总距离计算的。目标是使整体适应度为 0。
机器人适应度函数的图形表示。线代表期望的适合度。作者图片
在这里,您可以找到适应度函数的图形表示和用于评估染色体的代码。
代码视图:
用于评估机器人运行适应性的代码。
遗传算法设置:
该研究具有 6 个⁰可能的染色体组合或配置的搜索空间。使用遗传算法允许在搜索空间中快速搜索相对较好的解决方案。该解决方案可能是众多最佳解决方案中的一个,也可能是一个在对研究加以限制的情况下被认为适用的解决方案。
在研究过程中,人们发现,对遗传算法应该如何构造的任何清晰的解释或任何好的工具也有助于存储、跟踪和理解完成这样一项研究所需的信息。这个团队由 5 个人组成,花了一年时间为 Arduino 和 EasyGA python 包本身创建串行通信结构。
对于机器人,团队决定使用 EasyGA 的默认配置设置,因为它处理所有的超级参数。这是一个目标,以尽量减少机器人的错误,最终成为一行代码。python 代码可以在下面找到,更详细的列表可以在进化高度机器人 Github 上找到。
测试进化机器人时的 EasyGA 配置设置。
完整的代码通常是不共享的,但是我们认为在使用 EasyGA python 包时有必要展示简单性。
完整 Python 代码:
结果:
对于这项研究,目标是证明只需要一个遗传算法来优化一个单自由度机器人。不仅证明了这是可能的,该团队还希望确保可以通过使用多个机器人来完成这项工作。研究中使用了三个机器人,数据显示它们都能够学习。
每台机器人都经过了至少 30 次试验,每次试验都证明它们之间的机械差异仍然来自遗传算法的机器学习的相同结果。
用于寻找机器学习结果的三个机器人。从左到右——凯尔、杰夫和琳达。作者图片
这些机器人都被造得一模一样,但通过潜在的机械差异,它们都有一点点不同。在值的变化中看到的差异将成为每个机器人的接近最优的解决方案。
试验:种群规模 = 15,染色体长度 = 10,世代 = 100
**左:**所有试验最低染色体的平均值。**右:**所有试验中最低的染色体。作者提供的图片
讨论:
回想起来,测试所有可能的染色体组合是非常耗时的。一种更好的方法可能是结合模拟试验,然后进行实际测试和优化。这种双向方法既有在模拟中运行初始代的好处,在模拟中使用计算能力处理试验,随后是现实生活中的试验和培训,以进一步优化系统。
贡献:
我想感谢所有帮助过这个项目的人。以下个人都对研究产生了影响。
- Dylan Ballback 凭借他惊人的机械工程设计技能。
- 雷切尔·塞科德审阅并帮助撰写了所有内容。
- Jack Nguyen 与我和其他 4 名学生共同创建了 EasyGA。
- Mohammad Alali 编写 C++代码和 starter GA 代码。
- 雅各布·罗密欧(Jacob Romeo)帮着查阅文献和操作机器人。
- Matthew Verleger 博士是该研究项目的导师。
- Embry Riddle 本科生研究 Ignite 计划赞助该研究。
更多的人间接地帮助了这个项目,但是我仍然想对他们说谢谢。
感谢您的阅读,
丹尼尔·威尔扎克
自然语言处理的遗传算法
为什么遗传算法对预处理自然语言处理数据有效
图 1:遗传算法训练一个红色正方形来避开蓝色矩形。图片作者。
"数据准备约占数据科学家工作的 80% . "——福布斯
NLP 建模项目也不例外——通常最耗时的步骤是整理数据,然后从清理后的数据中开发特征。有许多工具可以促进这一过程,但仍然很费力。
为了帮助特征工程步骤,中佛罗里达大学的研究人员发表了一篇 2021 年的论文,该论文利用遗传算法来删除不重要的标记化文本。遗传算法(GA)是受进化启发的优化,在复杂数据上表现良好,因此它们自然也适用于 NLP 数据。它们也很容易并行化并且易于实现。
让我们从技术概述开始,然后深入了解到底发生了什么…
技术 TLDR
- **将你的数据符号化,建立一个词汇表。**引用的论文使用 python 包 mosestokenizer 将句子拆分成克,克是单独的符号或单词。
- 给每克分配随机权重(0 到 1 之间)。每一克代表我们人口中的一个个体。
- 调整模型的超参数并运行。调整 GA 更像是一门艺术,而不是科学,所以只需摆弄那些有意义的数字。
- **使用 ROUGE-N 模型确定精确度。**引用的论文使用了 ROUGE-N 的 F1 评分,这是精度和召回率的平均值,但您可以使用其他目标函数。
- **标记新数据并开始开发您的 NLP 模型。**既然您的 GA 已经训练好了,您可以标记一个看不见的训练集并开发您的 NLP 模型。
酷,但是这实际上是如何工作的呢?
让我们慢一点,围绕遗传算法发展一些直觉。
什么是遗传算法?
首先,我们来讨论 GA 是如何工作的。
图 2:遗传算法生成的流程图。图片作者。
在图 2 中,我们可以看到遗传算法的流程——它并不像看起来那么复杂。我们将我们的人口(黄框)初始化为克的加权向量,其中每个克的值是一个单词或符号。权重被随机初始化为 0 到 1 之间的值。
接下来,我们将初始人口输入算法。深蓝色的值对应于我们算法中的单个世代。浅蓝色的交叉和突变是变异的类型。让我们依次看一看每一个:
- **适应度函数:**首先,我们定义了我们的适应度函数,它计算了一个个体繁衍后代的概率。在我们的例子中,我们将使用 ROUGE-N 的 F1 值。更高的分数意味着一个个体更有可能繁衍后代。
- **父母选择:**接下来,我们定义谁能和谁不能繁殖。论文中的例子使用了一种叫做锦标赛选择的东西,我们随机抽取个人样本并选出一个获胜者。胜利者可以繁殖后代。
- 交配池:在这一步,我们将获胜的父母聚集成随机的一对。
- **变化:接下来,**我们以预定义的方式随机改变我们的数据,希望创建一个更适合的群体。第一种方法叫做交叉,涉及到两个父母交换他们的权重的某个百分比,并返回这两个新的权重向量作为孩子。通常,这个百分比是由随机选择的交叉指数决定的;交换超过该索引的所有值。第二种叫做突变,涉及随机改变每个父代的低概率权重。
- **后代:**从这里,我们可以聚合父母和后代。如果有一个人数上限,我们会去掉最不合适的人,直到我们在这个上限之下。
一代完成后,我们评估我们人口的适应性。如果满足我们的停止标准,我们将返回重量总体,并对它们进行平均,以获得每克重量的单个值。如果我们的停止标准没有得到满足,我们的人口被认为是不适合的,我们喂养的个体到另一代。
抛开伦理不谈,遗传算法很酷,对吧?
如果你仍然不相信,这里有一个 GA,它试图通过反复试验来猜测一个句子的内容…
图 3:试图猜测句子价值的遗传算法。图片作者。
如果我们使用暴力方法,我们将需要尝试 n^k 组合,其中 n 是我们字符串中的字符总数,而 k 是我们字母表中的字母总数。该示例将采用 27⁵以上的可能组合(小写/大写字符和一个空格)。
遗传算法在 51 代人口规模为 30 的情况下猜测了我们的字符串,这意味着它测试了不到 1530 个组合,以得出正确的结果。并且,它还尝试了符号。
但是,它们为什么有效呢?
遗传算法在复杂数据上表现良好。传统的基于梯度的优化,使用模型的导数来确定搜索的方向,要求我们的模型首先有导数。因此,如果模型是不可微的,我们很遗憾不能使用基于梯度的优化。此外,如果梯度非常“颠簸”,基本的梯度优化,如随机梯度下降,可能不会找到全局最优。
另一方面,遗传算法不需要可微分的模型。它们的随机性也有助于它们避免陷入局部最优,这非常适合“颠簸”和复杂的梯度,如克重。它们也很容易并行化,只要稍加调整,开箱即用就能很好地工作。
遗传算法的主要缺点是它们不能保证最优解,无论是局部的还是全局的。对于需要优化的情况,这可能是一个交易破坏者。
直观的例子
在我们的最后一节中,让我们来看看一种训练“船只”避开障碍物并找到红色方块的遗传算法。
图 4:训练船只避开障碍物并找到红色方块的遗传算法的可视化。图片作者。
如果我们看一下上面的图 4,我们会很快注意到,从第 3 代到第 5 代,船只在避开绿色矩形方面有所改进。这是因为如果他们的“基因”使他们更有可能死亡,他们不会繁殖。
然而,在这种配置中,船只没有视线概念;他们只是随机向一个方向移动,并记住过去的工作方式。因为特征空间太差,这种配置又用了 8 代船才意外降落红场。如果我们给他们一个全新的地图,这将需要另一个完整的训练周期。
为了提高船只快速优化和归纳新问题的能力,我们需要更好的特征空间和更多的学习环境。
同样,对于 NLP,无论遗传算法执行得多好,简单的符号化通常都不能创建足够健壮的模型。更复杂的特征,如克数、前/后克数等。是开发有效模型所必需的。
遗传算法提供了一种有效且高效的方法来开发标记化文法的词汇表。不会了。不多不少。
实施说明
- 遗传算法没有最佳超参数的规则。通常的做法是,在使用机器允许的最大群体规模和世代数时,尝试几种参数组合。
- 如果令牌的大小写没有被用作特性,请将令牌转换为小写。这可以大大减少词汇量。
- 个人感兴趣的一个领域是使用 GA(和其他优化算法)来处理我们建模的特征工程部分。有什么想法吗?
感谢阅读!我将再写 45 篇文章,将“学术”研究引入 DS 行业。查看我关于将遗传算法应用于 NLP 数据的链接/想法的评论。
图像分类的遗传程序设计
人工选择作为学习计算机视觉任务的驱动力
查尔斯·达尔文的雕塑。图片来自 Unsplash 的胡尔基·奥莰·塔巴克
这里有一大群松鼠住在我的后院。进化给了它们完美的体型和灵活性来征服树木和土地。直到几年前,这个松鼠社会生活得很愉快,没有与他们的人类邻居互动。
在某个时候,我妻子安装了一个喂鸟器,这样我们就可以近距离观察鸟儿了。这些诱人的种子给松鼠带来了意想不到的机会。虽然他们进化的环境不包括任何种子分配器,但他们发明了新的行为来达到他们的目标。如果你碰巧在你的后院安装了喂鸟器,你肯定知道:无论观鸟者如何让松鼠远离种子,聪明的啮齿动物得到它们想要的东西只是时间问题。
一只聪明的松鼠。图片由 Nathalie Famery 提供。
它们不仅完美地适应了自然环境,而且当机会出现时,它们还能发明新的行为。我们无法制造出接近这种智能水平的机器。然而,进化创造了它。智力是可行的(因为它存在)但我们无法复制的东西之一。
我们无法复制松鼠所展示的智慧,但我们可以模仿物种进化中的机制。这是一个叫做进化算法的机器学习技术家族背后的想法。这些技术受自然选择的启发,模拟了给定问题的候选解决方案群体的进化。对给定任务表现最佳的候选解决方案(即个体)被选为下一代的父代。
在进化算法中,每个个体都是一个基因型(决定完成任务的指令的一组信息)的容器。当从双亲中创造一个新个体时,部分基因型从双亲中被复制。虽然我们不知道个体基因型的哪一部分有助于它的成功,但它的每个孩子都会随机地继承大约一半的遗传信息。与同代的其他个体相比,孩子的成功将决定遗传的基因是否保留在基因库中。
遗传表演程序
进化算法类别之间的主要区别在于它们代表个体的方式。在 遗传编程 中,进化算法的一个实例,个体被表示为一个叫做计算图的树形结构。计算图实现了函数的组合,其中节点表示原始函数,边表示值。这些值从原始函数中输出,并进一步传递给其他原始函数。终端可以是常量,也可以是输入变量。
表示函数 f(x,y) = sin(3x) + y 的计算图形。图片由作者提供。
用于从双亲创建孩子的两个主要操作符是交叉和变异。交叉是一种操作,通过这种操作,我们在一个亲本的图中随机选择一个切割点,并拼接从另一个亲本取得的分支。
交叉示例:用父级 2 的框架分支替换父级 1 的框架分支,以生成子级。箭头颜色代表数据类型。替换分支的输出数据类型必须与原始分支输出数据类型相匹配(本例中为绿色箭头)。图片由作者提供。
突变是用随机生长的分支替换个体(通常是新产生的孩子)中随机选择的切割点的过程。随机生长的分支可以是简单的终端节点,也可以是任意复杂的树。唯一的要求是生长分支的输出数据类型与剪切分支的数据类型相匹配。
突变实例:左手侧个体中的框架分支被右手侧个体中随机生长的分支替换。图片由作者提供。
在开创性的著作《 遗传编程:通过自然选择的方式进行计算机编程》(1992)中,John Koza 建议所有的节点都应该是可互换的,即不需要数据类型匹配。根据我的经验,在对个体的评估会导致大量计算成本的领域,比如计算机视觉,实现强类型遗传编程会更有效。通过强制节点之间的类型匹配,我们确保一个个体将代表一个可以被评估的函数。否则,我们可能会遇到这样的风险,例如,一个节点向另一个节点提供一个整数,而另一个节点需要一个图像作为输入。这种情况不是有效的函数,因此到目前为止所做的所有计算都将被浪费。
人口的进化
一旦我们知道如何在我们选择的任务域中生成有效的计算图,并且我们知道如何从父代生成后代,我们就可以应用下面的遗传编程高级算法:
遗传规划的高级算法。图片由作者提供。
图像分类
在这个库中,你会找到一个简单的图像分类任务的代码,这个任务是用遗传编程实现的。任务是将图像分类为“圆盘”和“正方形”。
我们将图像分为“圆盘”和“正方形”两类。图片由作者提供。
除了实现遗传编程算法(基于给定标准的选择和新一代的创建)的核心的代码之外,我们还需要实现特定领域的代码,它将告诉解释器原函数做什么。在我们的例子中,任务的领域是图像处理;原语函数将是 OpenCV 函数的子集。
必须规定定义个人在任务中表现如何的标准。在我们的例子中,成本(我们希望最小化的正数)将是训练集中错误分类的观察值的比例。增加了一个惩罚项,与个体拥有的节点数成比例。这是为了在同等精度的情况下,小计算图优于大计算图。
群体中每个个体的成本评估。作者代码。
一旦所有的超参数都设置好了,我们就开始种群进化。每一代,冠军个体都会被保存。停止标准可以是当一代的冠军在验证数据集上达到期望的准确度时。
图像分类器群体的成本和验证准确性(通过每一代冠军进行评估)的典型演变。图片由作者提供。
与基于梯度下降的机器学习方法相反,在梯度下降的情况下,成本函数稳定地降低(尤其是在第一个时期),遗传编程群体的成本函数往往随着连续的平稳期而降低。值得注意的是,遗传编程并不假设目标函数是可微的。由于这个原因,没有指示用于局部改善的梯度下降方向的信号。相反,遗传规划依赖于在成本函数中表现为离散步骤的定性变化(即函数架构的变化)。当一个个体从它的父母那里接受了一个新的分支组合或者产生了一个有利的突变时,这些质的变化就发生了。
结论
遗传编程是一个领域不可知的机器学习框架,它不假设一个可微分的目标函数。我用遗传编程实现了一个简单的图像分类器作为概念证明。正如你所猜测的,一个内置图像处理功能的深度学习库可以用更少的努力来执行同样的任务,但乐趣在哪里呢?
我希望像遗传编程这样的进化算法能在计算机视觉和其他领域找到越来越多的应用,特别是在原函数不易微分的地方。
随意试验代码。如果你心中有一个可以使用基因编程的应用(或者如果你有办法让松鼠远离喂鸟者),我会很高兴听到它。
[1]在文献中,我们经常遇到的不是成本,而是适合度值,这通常是一个我们希望最大化的正数。
[2]由于个体由计算图形表示,如果原函数是可微的,则可以应用反向传播。因此,梯度下降可以优化个体的常数,但对于遗传编程框架来说不是必需的。这就是为什么在我的抽象类解释器中,实现方法 FunctionDefinition() 是强制的,而实现 FunctionDerivative() 是可选的。
你如何把基因组变成一幅画
使用 Python 可视化基因组数据
“你的基因组看起来就像文森特·梵高画的二维码……”
…对我来说还不是一句搭讪的话,但直到结束才算结束。
乔治·修拉的《T4 岛上的一个星期天下午》是有史以来最著名的点彩画——成千上万个点构成了一件艺术品
乔治·修拉——芝加哥艺术学院,公共领域|有史以来最著名的点彩画。
当我开始可视化基因组数据时,我得出了这个结论:
基因组。加拿大是。艺术也是。
从左至右:家族性红斑狼疮、中华红斑狼疮、早熟红斑狼疮的 38 号染色体
看,这些不是点彩画的杰作。更像是你服用迷幻药然后盯着电视看时看到的效果。
但是我在做这件事的时候得到了很多乐趣,如果你正在学习遗传学、Python 或者 cs,你可能也会。
从左上像素开始,逐行继续,每个彩色像素代表生物体基因组序列中 4 个核苷酸中的 1 个。
为什么提到点彩?电视和显示器上的数字图像基本上是点彩“画”,用像素代替点,用 RGB 值代替油彩。
我将讲述我是如何使用初级 Python 和免费的基因数据来制作这些图像的。
弄清楚
这是我想要建造的:
**输入:**一个包含生物体基因组序列的. txt 文件。
**输出:**一个. png 图像(尽可能接近正方形),其中每个彩色像素代表一个核苷酸。
搜索 NCBI 的基因组数据库可以相当容易地找到基因组序列:例如 S. praecaptivus 、 H. cinaed i。
作者使用 ray.so
由于第一行不包含核苷酸,我们跳过它。然后将列表连接成一个字符串。
产量呢?堆栈溢出研究告诉我,我可以用numpy
创建一个空数组,用 RGB 值填充,然后将数组导出为图像使用PIL
的Image
。
作者使用 ray.so
这就是我的代码三明治的顶部和底部。现在我需要一些方法来:
- 为任何给定的序列获取适当的尺寸。(
def **dimensions**
) - 为阵列中的每个“像素”分配正确的 RGB 值。(
def **generate**
)
规模
我希望图像尽可能接近正方形,所以高度h
和宽度w
需要在数值上接近。
每个像素匹配一个核苷酸。因此,对于任何给定的长度序列seq_length
,期望尺寸h
和w
将是它们之间差异最小的因子对(即最接近的一对)。
我们称这个函数为dimensions
。
作者使用雷.索
首先,一个字符串的长度seq
= seq_length
。然后,我们取其平方根的整数形式,a
。
- 如果
seq_length
除以a
的余数为 0:则seq_length
为平方数,尺寸为a
和a
。 - 如果不是:我们给
a
加 1,然后再用seq_length
除以a
,直到余数为 0。
这将找到最接近平方根的因子对**。在所有可能的因子对中,这两个永远是最接近的。**
>>> dimensions("AAAAAAAAAAAA")
[3, 4]
>>> dimensions("AAAAAAAAAAAAAAAA")
[4, 4]
>>> dimensions("AAAAAAAAAAAAAAAAAA")
[6, 3]
当我们的序列长度是一个质数**😗*时,我们会遇到一个问题
>>> dimensions(“AAAAAAAAAAAAAAAAA”)
[17, 1]
一个 1×17 的图像很难看到,对我的祖先来说是可耻的。我必须做得更好:
作者使用 ray.so
如果我们到达a
等于seq_length
的点,我们再次递归调用seq
上的dimensions
,这一次是通过移除最后一个基数。这确保了一个非质数。
基因组通常有超过一百万个碱基长——去掉一个没问题:
>>> dimensions("AAAAAAAAAAAA")
[3, 4]
>>> dimensions("AAAAAAAAAAAAAAAAAA")
[6, 3]
>>> dimensions("AAAAAAAAAAAAAAAAA") # length = 17, remove final base
[4, 4]
就像一部独立恐怖电影高潮前迷人的二十多岁的年轻人,我以为我是安全的。但是上帝,我错了。
在一只拉布拉多寻回犬的第 38 条染色体上测试这段代码,给了我这个怪物:
就是比背景稍微亮一点的乐队。|我的电脑截图,因为我实际上无法上传这张图片。
你能看见它吗?当然不是。实际图像大约是 250,000×95 像素。
没有错,但是任何非质数的最接近的因子对仍然可能相距很远。这严重扭曲了高宽比,所以我对函数做了一些修改:
作者使用 ray.so
现在,如果a
大于或等于 5 ×另一个因子(即纵横比超过 1:5),我们在seq[:-1]
上再次递归调用dimensions
函数。这可能导致从末端去掉 1+个核苷酸——在寻回犬染色体中,我们丢失了 3 个。
虽然 vals[0]几乎总是大于 vals[1],但在极少数情况下并非如此。取列表的最小值和最大值确保宽度总是大于高度。|作者使用 ray.so
剩下要做的就是分配h
和w
值,并将它们插入到我们的数组命令中。
现在让我们用 RGB 值填充数组:
产生
我们首先创建一个字典,为每个碱基分配一个 RGB 值:
我通常使用coolors.co来查找调色板。|作者使用 ray.so
FASTA 文件(Y,R,K)中还有其他字母可能,但这是我目前遇到的唯一一个。(N 表示任何核酸)。
因为我想一行一行地进行,所以我将嵌套一个循环,该循环遍历数组中的每一行中的每一个像素(也就是每一列):
作者使用 ray.so
data[i,j]
索引数组中每个可能的元素,从左上角的data[0,0]
开始,一直到右下角的data[h-1,w-1]
,一行一行。
按作者
data
元素的坐标i
和j
与seq
字符串中的对应字符的关系如下:
data[i,j] == seq[j+i*w] #row index * width + column indexh = 10
w = 10## data[0,0] -> seq[0+0*10] = seq[0]
## data[0,9] -> seq[9+0*10] = seq[9]
## data[1,0] -> seq[0+1*10] = seq[10]
## data[9,9] -> seq[9+9*10] = seq[99]
因此,我们最终的generate
函数如下所示:
作者使用雷.索
请注意,我们没有将data[i,j]
设置为来自seq
的相应字符,而是设置为来自colours
的该字符的 RGB 值。
当我们把这些放在一起,我们得到这个:
代码本身可能会被清理,但那是以后的事了。|作者作者
将此应用于不同的基因组,我得到了一些有趣的结果:
从左上顺时针方向:家犬狼疮,染色体 38;大肠杆菌;s .邦戈里;白花蛇舌草;H. cinaedi。|作者
摆弄颜色也很有趣:
这将被用来做什么?
我有几个想法:
- 一个只接受邀请的社交网络,在这里你可以用你第七条染色体的图像代替短代码来添加好友。
- Tinder,除了你唯一能添加的图片是你的基因组可视化。这样,你知道你的对手喜欢你的内在。
- 一种加密货币,在这种货币中,你不需要从哈希函数中解密,而是必须手动将基因组 vis 翻译回字母,一个像素一个像素。
- 一个 NFT。(实际上我现在正在努力。)
- 一种视觉辅助工具,用于解释服用迷幻药后的电视画面。
我的外卖
- 我认为这是一种看待基因组数据的有趣方式。诚然,不是超级有用。但是它们看起来很酷吗?100%.(可能更像是 75%)。
- 这只是当我们把生物学和代码结合起来时,我们能做什么的一瞥。
你觉得我下一步应该做什么?我可能会对同源基因或整个进化史这样做。让我知道!
如何在基因组干草堆中找到 DNA 针
使用 Python 寻找基因组中的调控基序
穆尔托·希拉利
如果我请你帮我大海捞针,你只会出于礼节而答应。
如果我告诉你实际上干草堆里有 10 根针,而且它们看起来都略有不同,愤怒会像打掉我的牙齿一样吞噬你。
这是生物学家在寻找调控基序时面临的任务。这些是基因组中的短 DNA 片段,结合转录因子。TF 是提高或降低其他基因转录水平(表达)的蛋白质。
像针一样,调控基序通常彼此相似,但不完全相同。生物信息学家面临的问题是在他们拥有的所有遗传数据中找到彼此最相似的一组基序。
一旦我们做到了,我们就能理解重要功能背后的机制,如光合作用或结核休眠。
我已经学会了如何使用 Python 来做这件事,你可以在 Codeacademy 上学习。你也可以这样做。
在本文中,我们将:
- 为 DNA 基序矩阵生成计数和图谱矩阵。
- 创建一个一致性基序,以对我们数据中所有基序之间的保守程度进行评分。
- 根据我们的轮廓矩阵确定任何可能的模体出现的概率。
- 将这些函数编译成一个贪婪搜索算法来扫描 MTB 基因上游区域的基序。
这篇文章假设你有遗传学和 Python 的基础知识。
倒过来看
假设我们已经有了一个 motfis 矩阵,我们想要测量每个 motfis 之间的相似性——保守水平。(每列中最保守的核苷酸大写。)
(这些是来自黑腹果蝇的 NF-kB 结合位点基序,来自生物信息学算法)。|作者图片
我们的工作:
- 计算每列中最高度保守的核苷酸。(
Count()
) - 生成“共有”基序,其中每个碱基是来自
Motifs
中每列的最保守的核苷酸。(Consensus())
- 对
Motifs
中每个模体与共有模体之间的相似度进行评分。(Score()
)
计数(图案)
创建一个字典count
,其中关键字是核苷酸('A', 'C', 'T', ‘G’
),值是列表。每个列表元素是关键字的核苷酸在Motifs
的索引(列)中出现的次数:
’ a ‘在列中出现两次,’ C ‘出现一次,’ T '出现七次。|作者
所有代码片段均由作者使用 ray.so
我们初始化一个空字典count
并用核苷酸键填充它。每一个值都是一个0
的列表,只要是Motifs
中的第一个母题。
然后我们迭代Motifs
中的每一个元素;当我们在Motifs[i][j]
遇到一个核苷酸symbol
时,我们在第j
个索引处增加那个symbol
键的值。
一个惊喜的工具,将帮助我们以后
将计数字典转换为具有Profile(Motifs)
功能的频率字典;
将count
中的每个列表元素除以Motifs
中的主题数。我们得到这样的结果:
按作者
这个以后会派上用场的。
共识(主题)
现在,我们可以调用Count()
作为子程序。在count
字典的每个索引处取最高计数的核苷酸并附加到空字符串consensus
:
按作者
在外部循环中,我们遍历来自count
的列表值中的每个元素。在内部循环中,我们遍历每个核苷酸键。这让我们可以比较第j
个索引处的每个键值。我们更新m
总是最高值,让frequentSymbol
=对应的核苷酸symbol
。
Consensus(Motifs)
>>'**TCGGGGATTTCC'**
分数(主题)
为了对基序中基序之间的保守程度进行评分,我们可以使用索引motif[j]
遍历每个元素。
外部循环的范围是行,内部循环的范围是列。
如果motif[j]
处的核苷酸符号与consensus[j]
不匹配,我们增加score
。分数越高=保守性越低。
让我们变得贪婪
我们有一种方法来衡量图案之间的保守性。现在,我们需要生成许多潜在矩阵Motifs
,并找到最小化score
的那个。
我们可以用贪婪搜索算法来做到这一点;这意味着我们的算法将在迭代的每一步选择最佳选项。更多此处。
贪婪算法有三个组成部分:
- 数据:它必须迭代一组数据。
- 规则:它遵循规则在迭代的每一步做什么。
- 结果:每一步都将该规则的结果加到答案中。
让我们定义 GreedyMotifSearch(Dna,k,t)其中:
Dna
是一个 DNA 字符串矩阵,我们正在扫描其中的图案。k
是图案的长度。t
是Dna
中 DNA 串的数量。
我们算法的组成部分:
- **数据:**遍历
**Dna**
第一个字符串中所有可能的 k-mers。(外环)。 - 规则:从
Dna
中的每隔一个字符串中为那些 k-mers 找到最佳匹配。(内循环)。 - 结果:将结果追加到列表
Motifs
中。
我们可以从创建一个暂定列表BestMotifs
开始,其中每个基序都是Dna
中每个 DNA 串的第一个 k-mer。如果我们以后创建一个有更好分数的矩阵,我们将更新这个列表。
让我们从Dna[0]
中取出第一个 k-mer(再次)将其附加到一个新列表Motifs
。我们将对第一个 DNA 链中每一个可能的 k-mer 都这样做——这是我们的外环。
我们将基于从Dna[0]
中提取的第一个 k-mer 来构建Motifs
的其余部分。(这是第二步,规则)。
使用我们之前制作的Profile
函数的轮廓,我们想要在下一个 DNA 串、Dna[1]
中找到最相似的 k-mer。
怎么会?好吧,我们还没有这样做的函数,所以让我们写一个。
公关(文本,个人资料)
让我们看看我们的简介矩阵。每个元素是该核苷酸出现在基序中该位置的概率。
如果分布矩阵随机产生基序,共有序列将出现得最频繁。
**我们还可以确定任何其他字符串基序出现的概率。**简单地乘以每个碱基出现在各自位置的几率:
每个红色碱基都是对共有字符串(顶部)的偏离。注意当我们远离共识字符串时,每个字符串的概率是如何下降的。
更高的概率=根据Profile
更好的匹配。
参数是一个 DNA 字符串Text
和一个档案矩阵Profile
。Text[i]
是Text
中索引i
处的核苷酸,也是Profile
中列表的关键字。Profile[Text[i]][i]
是同一索引i
的概率值。
profilemostparblepattern(Text,k,Profile)
我们现在可以找到任何 k-mer 成为基序的概率——给定一个概率矩阵Profile
。
让我们遍历一长串 DNA Text
中的所有 k-mers,并根据Profile
找到最可能的一个(最佳匹配):
我们生成一个包含 k-mer 及其概率的字典,然后返回第一个具有最高值的 k-mer。(具体内联)。
现在,给定一个Profile
,一个长度k
的基元,以及一个更长的字符串Text
来扫描 k-mers,我们可以返回到GreedyMotifSearch
。
我们在下一串 DNA ( Dna[1]
)中找到最可能的模式,并将其附加到Motifs
。(这是第三步,结果)。我们更新这个新矩阵的轮廓P
,并对每个 DNA 串重复这个过程。
当我们完成内部循环时,我们可以比较Motifs
和BestMotifs
的分数。如果Motifs
得分降低,我们更新BestMotifs
;在Dna[0]
中对每个可能的 k-mer 重复该过程。
熵(主题)
我们还没有完全完成。我们的得分函数是不完善的。请注意,一些列比其他列有更多的变化,但它们仍然得分相同(第二列和最后一列)。
在该图中,每列的分数被取下来并相加。这是为了视觉辅助;在代码中,我们不需要一定遵守这种模式,也不会遵守。
跟踪每一列的守恒水平的更好的方法是测量熵。
配置文件矩阵中的每一列都是一个概率分布,即总和为 1 的正数。
熵是该分布的不确定性,通过对每个概率乘以其二进制对数求和并乘以-1 得出:
塞巴斯蒂安·科维亚特科夫斯基
更低的熵=更少的不确定性和更大的守恒。
因为我们要对所有的值求和,所以我们不必逐列进行。我还选择了减法,而不是加法,因为我们在公式中采用了最终答案的负数。结果是一样的。
遍历profile
中的每一个元素,如果概率值大于 0 就更新entropy
(否则我们无法取其二进制对数)。这种公式在实践中更常用,但为了简单起见,这里只是一个脚注。
让我们带着这个宝贝转一圈:
用结核病进行测试
你可能得了肺结核而不自知。结核分枝杆菌结核分枝杆菌(MTB)可以在你的体内潜伏多年,然后才会产生任何影响。
生物学家将缺氧(缺氧)与 MTB 潜伏期联系起来,并发现了帮助细菌在低氧条件下生存的转录因子(DosR)。
我们将观察 DosR 影响的一些基因的上游区域,试图找到一些它可能结合的基序。(我修改了GreedyMotifSearch
,用Entropy()
代替了Score()
。)
我们正在查看的 DNA 字符串可以在这里找到,我已经将它们收集到一个名为DosR
的列表中。
您的结果:
['ATGACCAGCGAGCTG',
'CCGATCGGCATCACT',
'ACCGTCGATGTGCCC',
'GGGTCAGGTATATTT',
'GTGACCGACGTCCCC',
'CCGCTGGCGACGCTG',
'GTGTCCGGCATGATC',
'CGGCCAGACAAGCTT',
'GCGATAGGTGAGATT',
'CTCATCGCTGTCATC'] 18.492751844642765 CCGACCGGCATGCTC
恭喜你,成功了!亲吻你的配偶,和一只狗击掌,开着警车兜风。
对吗?
如果你看一下文献,这些不是你要找的主题。
他们使用的算法和数据更好——贪婪算法的速度快,但准确性差。
实际上,我们今天开发的算法永远不会被使用——就像我在精神崩溃时买的滚轴溜冰鞋一样。
关键要点
- 这可能不是最重要的算法,但它为将来学习更复杂的算法奠定了基础。
- 复杂的问题可以有复杂的解决方案——但是你仍然可以使用简单的工具来构建它们(比如你可以在 Codeacademy 上免费学习的所有 Python)。
感谢阅读!
我写的其他生物信息学文章:
[## 你如何把基因组变成一幅画
towardsdatascience.com](/genome-painting-c7e2398b4579)