面向生命科学的深度学习(一)
近年来,生命科学和数据科学已经融合。机器人技术和自动化的进步使化学家和生物学家能够产生大量数据。如今,科学家们一天内能够生成的数据量比 20 年前的前辈整个职业生涯中能够生成的数据量还要多。这种快速生成数据的能力也带来了许多新的科学挑战。我们不再处于将数据加载到电子表格中并制作几张图表的时代。为了从这些数据集中提炼科学知识,我们必须能够识别和提取非显而易见的关系。在过去几年中出现的一种强大的工具是
原文:Deep Learning for the Life Sciences
译者:飞龙
前言
近年来,生命科学和数据科学已经融合。机器人技术和自动化的进步使化学家和生物学家能够产生大量数据。如今,科学家们一天内能够生成的数据量比 20 年前的前辈整个职业生涯中能够生成的数据量还要多。这种快速生成数据的能力也带来了许多新的科学挑战。我们不再处于将数据加载到电子表格中并制作几张图表的时代。为了从这些数据集中提炼科学知识,我们必须能够识别和提取非显而易见的关系。
在过去几年中出现的一种强大的工具是深度学习,这是一类算法,已经彻底改变了解决问题的方法,如图像分析、语言翻译和语音识别。深度学习算法擅长识别和利用大型数据集中的模式。出于这些原因,深度学习在生命科学领域有广泛的应用。本书概述了深度学习在遗传学、药物发现和医学诊断等领域的应用。我们描述的许多示例都附带有代码示例,为读者提供了对方法的实际介绍,并为未来的研究和探索提供了起点。
本书中使用的约定
本书中使用以下排版约定:
斜体
指示新术语、URL、电子邮件地址、文件名和文件扩展名。
固定宽度
用于程序清单,以及在段落中引用程序元素,如变量或函数名称、数据库、数据类型、环境变量、语句和关键字。
粗体固定宽度
显示用户应该按照字面意思输入的命令或其他文本。
斜体固定宽度
显示应该由用户提供值或由上下文确定值替换的文本。
提示
此元素表示提示或建议。
注意
此元素表示一般说明。
警告
此元素表示警告或注意事项。
使用代码示例
附加材料(代码示例、练习等)可在https://github.com/deepchem/DeepLearningLifeSciences下载。
这本书旨在帮助您完成工作。一般来说,如果本书提供了示例代码,您可以在您的程序和文档中使用它。除非您复制了代码的大部分内容,否则无需征得我们的许可。例如,编写一个使用本书中几个代码块的程序不需要许可。出售或分发包含 O’Reilly 图书示例的 CD-ROM 需要许可。引用本书并引用示例代码回答问题不需要许可。将本书中大量示例代码合并到产品文档中需要许可。
我们感谢,但不要求署名。署名通常包括标题、作者、出版商和 ISBN。例如:“生命科学的深度学习,作者 Bharath Ramsundar、Peter Eastman、Patrick Walters 和 Vijay Pande(O’Reilly)。版权 2019 年 Bharath Ramsundar、Karl Leswing、Peter Eastman 和 Vijay Pande,978-1-492-03983-9。”
如果您认为您使用的代码示例超出了合理使用范围或上述许可,请随时通过permissions@oreilly.com与我们联系。
致谢
我们要感谢 Nicole Tache,我们在 O’Reilly 的编辑,以及技术审阅员和测试审阅员对本书的宝贵贡献。此外,我们还要感谢 Karl Leswing 和 Zhenqin(Michael)Wu 对代码的贡献,以及 Johnny Israeli 对基因组学章节的宝贵建议。
Bharath 感谢他的家人在许多漫长的周末和夜晚为这本书工作时给予的支持和鼓励。
Peter 感谢他的妻子一直以来的支持,以及许多同事们对机器学习的教导。
Pat 感谢他的妻子 Andrea,以及他的女儿 Alee 和 Maddy,感谢她们的爱和支持。他还要感谢 Vertex Pharmaceuticals 和 Relay Therapeutics 的过去和现在的同事们,从他们那里学到了很多。
最后,我们要感谢 DeepChem 开源社区在整个项目期间给予的鼓励和支持。
第一章:为什么选择生命科学?
虽然有许多技术倾向和对数据的热情可以追求的方向,但很少有领域能与生物医学研究的基本影响相匹配。现代医学的出现从根本上改变了人类存在的本质。在过去 20 年里,我们已经看到了许多创新,这些创新已经改变了无数个体的生活。当 HIV/AIDS 首次出现在 1981 年时,这是一种基本上致命的疾病。抗逆转录病毒疗法的持续发展已经显著延长了发达国家患者的预期寿命。其他疾病,如肝炎 C,在十年前被认为基本上无法治愈,现在可以治愈。遗传学的进步使得能够识别并希望很快治疗各种疾病。诊断和仪器的创新使得医生能够具体识别和针对人体内的疾病。许多这些突破受益于并将继续受到计算方法的推动。
为什么选择深度学习?
机器学习算法现在已经成为从在线购物到社交媒体的关键组成部分。计算机科学家团队正在开发能够让亚马逊 Echo 或 Google Home 等数字助手理解语音的算法。机器学习的进步使得网页在不同语言之间进行常规即时翻译成为可能。除了机器学习对日常生活的影响,它还影响了许多物理和生命科学领域。算法被应用于从望远镜图像中检测新星系到大型强子对撞机上的亚原子相互作用分类等各个方面。
这些技术进步的推动因素之一是一类被称为深度神经网络的机器学习方法的发展。虽然人工神经网络的技术基础在上世纪 50 年代就已经发展出来,并在上世纪 80 年代得到完善,但这种技术的真正威力直到过去 10 年计算机硬件的进步才得以充分实现。我们将在下一章中提供深度神经网络的更全面概述,但重要的是要承认一些通过深度学习应用而发生的进步:
-
许多在手机、电脑、电视和其他互联网设备中变得无处不在的语音识别技术都是由深度学习推动的。
-
图像识别是自动驾驶汽车、互联网搜索和其他应用的关键组成部分。许多在深度学习中的相同发展推动了消费者应用的发展,现在也被用于生物医学研究,例如将肿瘤细胞分类为不同类型。
-
推荐系统已经成为在线体验的关键组成部分。像亚马逊这样的公司使用深度学习来推动他们的“购买此商品的顾客还购买了”方法,以鼓励额外的购买。Netflix 使用类似的方法来推荐个人可能想看的电影。这些推荐系统背后的许多想法正在被用来识别可能为药物发现工作提供起点的新分子。
-
语言翻译曾经是非常复杂的基于规则系统的领域。在过去几年里,由深度学习驱动的系统已经超越了经过多年手工策划的系统。许多相同的想法现在也被用来从科学文献中提取概念,并提醒科学家可能错过的期刊文章。
这些只是通过深度学习方法应用而产生的一些创新。我们正处于一个有趣的时刻,科学数据广泛可用,以及处理这些数据的方法。那些能够将数据与学习数据中模式的新方法相结合的人可以取得重大的科学进步。
当代生命科学关乎数据
正如前面提到的,生命科学的基本性质已经发生了变化。机器人技术和微型化实验的可用性带来了实验数据量的显著增加。在 20 世纪 80 年代,生物学家会进行一次实验并生成一个结果。这种数据通常可以通过手工操作,可能辅以口袋计算器的帮助来处理。如果我们快进到今天的生物学,我们有仪器能够在一两天内生成数百万个实验数据点。像基因测序这样可以生成大量数据集的实验已经变得廉价和常规化。
基因测序的进步导致了建立数据库,将个体的基因密码与多种与健康相关的结果联系起来,包括糖尿病、癌症和囊性纤维化等遗传疾病。通过使用计算技术来分析和挖掘这些数据,科学家们正在理解这些疾病的原因,并利用这种理解来开发新的治疗方法。
曾经主要依赖人类观察的学科现在正在利用那些无法手动分析的数据集。机器学习现在常规用于分类细胞图像。这些机器学习模型的输出用于识别和分类癌症肿瘤,并评估潜在疾病治疗的效果。
实验技术的进步导致了几个数据库的发展,这些数据库记录了化学物质的结构以及这些化学物质对各种生物过程或活动的影响。这些结构-活性关系(SARs)构成了一个被称为化学信息学或化学信息学的领域的基础。科学家们挖掘这些大型数据集,并利用这些数据构建预测模型,推动下一代药物开发。
随着这些大量数据的出现,需要一种新型的科学家,他们在科学和计算领域都感到自在。具备这种混合能力的人有可能解锁大数据集中的结构和趋势,并发现明天的科学发现。
你将学到什么?
在本书的前几章中,我们提供了深度学习的概述以及它如何应用于生命科学。我们从机器学习开始,它被定义为“编程计算机以便它们可以从数据中学习的科学(和艺术)。”
第二章简要介绍了深度学习。我们从一个示例开始,说明这种类型的机器学习如何用于执行像线性回归这样的简单任务,并逐渐发展到更复杂的模型,这些模型通常用于解决生命科学领域的实际问题。机器学习通常通过最初将数据集分为用于生成模型的训练集和用于评估模型性能的测试集来进行。在第二章中,我们讨论了围绕预测模型的训练和验证的一些细节。一旦生成了模型,通过改变一些称为超参数的特征,通常可以优化其性能。本章概述了这个过程。深度学习不是一种单一的技术,而是一组相关方法。第二章以介绍一些最重要的深度学习变体而结束。
在第三章中,我们介绍了 DeepChem,这是一个开源编程库,专门设计用于简化各种生命科学应用的深度学习模型的创建。在概述 DeepChem 之后,我们介绍了我们的第一个编程示例,演示了如何使用 DeepChem 库生成一个用于预测分子毒性的模型。在第二个编程示例中,我们展示了 DeepChem 如何用于分类图像,这是现代生物学中的常见任务。正如前面简要提到的,深度学习在各种成像应用中被使用,从癌症诊断到青光眼检测。这些特定应用的讨论随后激发了对深度学习方法内部运作的一些解释。
第四章概述了机器学习如何应用于分子。我们首先介绍了分子,构成我们周围一切的基本单位。尽管分子可以被视为类似于积木,但它们并不是刚性的。分子是灵活的,并表现出动态行为。为了使用深度学习等计算方法对分子进行表征,我们需要找到一种在计算机中表示分子的方法。这些编码可以被视为类似于图像可以被表示为一组像素的方式。在第四章的后半部分,我们描述了多种表示分子的方法以及如何利用这些表示构建深度学习模型。
第五章介绍了生物物理学领域,将物理定律应用于生物现象。我们从讨论蛋白质开始,这些分子机器使生命成为可能。预测药物对人体的影响的关键组成部分是理解它们与蛋白质的相互作用。为了理解这些影响,我们首先概述蛋白质的构造和蛋白质结构的差异。蛋白质是其三维结构决定其生物功能的实体。为了让机器学习模型预测药物分子对蛋白质功能的影响,我们需要以机器学习程序可以处理的形式表示这种三维结构。在第五章的后半部分,我们探讨了多种表示蛋白质结构的方法。有了这些知识,我们然后回顾另一个代码示例,其中我们使用深度学习来预测药物分子与蛋白质相互作用的程度。
遗传学已成为当代医学的关键组成部分。肿瘤的基因测序使癌症的个性化治疗成为可能,并有潜力彻底改变医学。基因测序曾经是一个需要巨额投资的复杂过程,现在已经变得司空见惯,可以常规进行。我们甚至已经达到了狗主人可以获得廉价基因测试来确定他们宠物血统的程度。在第六章中,我们提供了遗传学和基因组学的概述,从 DNA 和 RNA 的介绍开始,这些是用来产生蛋白质的模板。最近的发现揭示了 DNA 和 RNA 的相互作用比最初认为的要复杂得多。在第六章的后半部分,我们提供了几个代码示例,演示了深度学习如何用于预测影响 DNA 和 RNA 相互作用的多个因素。
在本章的前面,我们提到了通过将深度学习应用于生物和医学图像分析而取得的许多进展。这些实验研究的许多现象对人眼来说太小而无法观察到。为了获得用于深度学习方法的图像,我们需要利用显微镜。第七章概述了显微镜学的多种形式,从我们在学校使用的简单光学显微镜到能够以原子分辨率获得图像的复杂仪器。本章还涵盖了当前方法的一些局限性,并提供了用于获得驱动深度学习模型的图像的实验流程信息。
一个提供巨大希望的领域是将深度学习应用于医学诊断。医学非常复杂,没有一个医生可以亲自掌握所有可用的医学知识。在理想情况下,机器学习模型可以消化医学文献,并帮助医疗专业人员进行诊断。虽然我们尚未达到这一点,但已经取得了一些积极的步骤。第八章从医学诊断的机器学习方法的历史开始,描述了从手工编码规则到医学结果的统计分析的过渡。与我们讨论过的许多主题一样,关键组成部分是以机器学习程序可处理的格式表示医学信息。在本章中,我们介绍了电子健康记录以及围绕这些记录的一些问题。在许多情况下,医学图像可能非常复杂,对这些图像的分析和解释甚至对熟练的人类专家来说都可能很困难。在这些情况下,深度学习可以通过对图像进行分类和识别关键特征来增强人类分析师的技能。第八章最后列举了深度学习如何用于分析来自各种领域的医学图像的一些示例。
正如我们之前提到的,机器学习正在成为药物发现工作的关键组成部分。科学家使用深度学习模型来评估药物分子和蛋白质之间的相互作用。这些相互作用可能引发对患者有治疗影响的生物反应。到目前为止,我们讨论的模型是判别模型。给定一个分子的一组特征,模型生成某种属性的预测。这些预测需要一个输入分子,这个输入分子可能来自一个大型可用分子数据库,也可能来自科学家的想象。如果我们不依赖于当前存在的东西,或者我们可以想象的东西,而是有一个可以“发明”新分子的计算机程序呢?第九章介绍了一种称为生成模型的深度学习程序。生成模型最初是在一组现有分子上进行训练,然后用于生成新分子。生成这些分子的深度学习程序也可能受到预测新分子活性的其他模型的影响。
到目前为止,我们已经将深度学习模型描述为“黑匣子”。我们向模型提供一组输入数据,模型生成一个预测,但没有解释预测是如何或为什么生成的。在许多情况下,这种类型的预测可能不够理想。如果我们有一个用于医学诊断的深度学习模型,我们通常需要了解诊断背后的推理。对诊断原因的解释将使医生对预测更有信心,也可能影响治疗决策。深度学习的一个历史性缺点是,尽管模型通常可靠,但很难解释。目前正在开发许多技术,以使用户更好地理解导致预测的因素。第十章概述了一些用于使人类理解模型预测的技术。预测模型的另一个重要方面是模型预测的准确性。了解模型准确性可以帮助我们确定要依赖该模型的程度。鉴于机器学习可以用于潜在地做出挽救生命的诊断,了解模型准确性至关重要。第十章的最后一节概述了一些可用于评估模型预测准确性的技术。
在第十一章中,我们使用 DeepChem 展示了一个真实的案例研究。在这个例子中,我们使用一种称为虚拟筛选的技术来识别新药物发现的潜在起点。药物发现是一个复杂的过程,通常以一种称为筛选的技术开始。筛选用于识别可以优化以最终生成药物的分子。筛选可以通过实验进行,其中数百万分子在被称为测定的微型生物学测试中进行测试,也可以在计算机中使用虚拟筛选。在虚拟筛选中,一组已知药物或其他生物活性分子用于训练一个机器学习模型。然后,这个机器学习模型被用来预测大量分子的活性。由于机器学习方法的速度,数亿分子通常可以在几天的计算机时间内处理完毕。
本书的最后一章探讨了深度学习在生命科学中的当前影响和未来潜力。讨论了当前努力面临的一些挑战,包括数据集的可用性和质量。我们还强调了在诊断、个性化医学、制药开发和生物学研究等许多其他领域中的机遇和潜在风险。
¹ Furbush, James. “Machine Learning: A Quick and Simple Definition.” https://www.oreilly.com/ideas/machine-learning-a-quick-and-simple-definition. 2018.
第二章:深度学习简介
本章的目标是介绍深度学习的基本原理。如果您已经有很多深度学习经验,可以随意略读本章,然后继续下一章。如果您经验较少,应该仔细学习本章,因为它涵盖的内容对于理解本书的其余部分至关重要。
在我们讨论的大多数问题中,我们的任务是创建一个数学函数:
y = f ( x )
请注意x和y是用粗体书写的。这表示它们是向量。该函数可能接受许多数字作为输入,也许是成千上万,它可能产生许多数字作为输出。以下是您可能想要创建的一些函数示例:
-
x包含图像中所有像素的颜色。如果图像中包含猫,则f(x)应该等于 1,如果不包含则等于 0。
-
与上述相同,只是f(x)应该是一个数字向量。第一个元素表示图像是否包含猫,第二个元素表示是否包含狗,第三个元素表示是否包含飞机,以此类推,针对成千上万种对象。
-
x包含染色体的 DNA 序列。y应该是一个向量,其长度等于染色体中碱基的数量。如果该碱基是编码蛋白质的区域的一部分,则每个元素应该等于 1,否则为 0。
-
x描述了分子的结构。(我们将在后面的章节中讨论表示分子的各种方法。)y应该是一个向量,其中每个元素描述分子的某些物理性质:它在水中溶解的容易程度,它与其他分子结合的强度等等。
正如您所看到的,f(x)可能是一个非常复杂的函数!它通常接受一个长向量作为输入,并尝试从中提取信息,这些信息仅仅从查看输入数字是不明显的。
解决这个问题的传统方法是手动设计一个函数。您将从分析问题开始。哪些像素模式倾向于表明猫的存在?哪些 DNA 模式倾向于区分编码区域和非编码区域?您将编写计算机代码来识别特定类型的特征,然后尝试识别可靠产生所需结果的特征组合。这个过程缓慢而费力,且严重依赖于执行者的专业知识。
机器学习采用完全不同的方法。与手动设计函数不同,您允许计算机根据数据学习自己的函数。您收集成千上万甚至数百万张图像,每张都标记了是否包含猫。您将所有这些训练数据呈现给计算机,并让它搜索一个函数,对于包含猫的图像始终接近 1,对于没有猫的图像接近 0。
“让计算机搜索函数”是什么意思?一般来说,你创建一个模型,定义了一大类函数。模型包括参数,可以取任何值的变量。通过选择参数的值,你从模型定义的所有函数中选择一个特定的函数。计算机的任务是选择参数的值。它试图找到这样的值,使得当你的训练数据作为输入时,输出尽可能接近相应的目标。
线性模型
你可能考虑尝试的最简单的模型之一是线性模型:
y = Mx + b
在这个方程中,M是一个矩阵(有时被称为“权重”),b是一个向量(称为“偏差”)。它们的大小由输入和输出值的数量确定。如果x的长度为 T,你希望y的长度为 S,那么M将是一个 S×T 矩阵,b将是长度为 S 的向量。它们一起构成模型的参数。这个方程简单地表示每个输出组件是输入组件的线性组合。通过设置参数(M和b),你可以选择任何你想要的每个组件的线性组合。
这是最早的机器学习模型之一。它是在 1957 年引入的,被称为感知器。这个名字是一个了不起的营销手段:听起来像是科幻,似乎承诺了美好的事物,但实际上它只是一个线性变换。无论如何,这个名字已经坚持了半个多世纪。
线性模型非常容易以完全通用的方式来构建。无论你应用它到什么问题,它的形式都完全相同。线性模型之间唯一的区别是输入和输出向量的长度。从那里开始,只需要选择参数值,可以通过通用算法简单地完成。这正是我们在机器学习中想要的:一个与你要解决的问题无关的模型和算法。只需提供训练数据,参数会自动确定,将通用模型转换为解决你的问题的函数。
不幸的是,线性模型也非常有限。正如在图 2-1 中所示,线性模型(在一维中,即一条直线)简单地无法拟合大多数真实数据集。当你转向非常高维的数据时,问题变得更糟。在图像中像素值的线性组合将无法可靠地识别图像中是否包含猫。这个任务需要一个更加复杂的非线性模型。事实上,任何解决这个问题的模型都必然会非常复杂和非常非线性。但是我们如何以通用的方式来构建它呢?所有可能的非线性函数空间都是无限复杂的。我们如何定义一个模型,以便通过选择参数值,我们几乎可以创建任何我们想要的非线性函数?
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0201.png
图 2-1. 线性模型无法拟合遵循曲线的数据点。这需要一个非线性模型。
多层感知器
一个简单的方法是堆叠多个线性变换,一个接一个。例如,我们可以写成:
y = M 2 𝜙 ( M 1 x + b 1 ) + b 2
仔细看看我们在这里做了什么。我们从一个普通的线性变换开始,M 1 x+b 1。然后我们通过一个非线性函数𝜙(x)将结果传递,然后对结果应用第二个线性变换。函数𝜙(x),也就是激活函数,是使这个工作正常运行的重要部分。没有它,模型仍然是线性的,比之前的模型没有更强大。线性组合的线性组合本身只不过是原始输入的线性组合!通过插入一个非线性,我们使模型能够学习更广泛的函数。
我们不需要停在两个线性变换上。我们可以堆叠任意多个线性变换在一起:
h 1 = 𝜙 1 ( M 1 x + b 1 )h 2 = 𝜙 2 ( M 2 h 1 + b 2 )
...
h n-1 = 𝜙 n-1 ( M n-1 h n-2 + b n-1 )y = 𝜙 n ( M n h n-1 + b n )
这个模型被称为多层感知器,简称 MLP。中间步骤h i被称为隐藏层。这个名字指的是它们既不是输入也不是输出,只是在计算结果的过程中使用的中间值。还要注意,我们为每个𝜙(x)添加了一个下标。这表示不同的层可能使用不同的非线性。
您可以将这个计算视为一堆层,如图 2-2 所示。每一层对应于一个线性变换,后面跟着一个非线性。信息从一层流向另一层,一层的输出成为下一层的输入。每一层都有自己的一组参数,这些参数确定了如何从输入计算输出。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0202.png
图 2-2。一个多层感知器,被视为一堆层,信息从一层流向下一层。
多层感知器及其变体有时也被称为神经网络。这个名称反映了机器学习和神经生物学之间的相似之处。生物神经元连接到许多其他神经元。它从它们那里接收信号,将信号相加,然后根据结果发送自己的信号。作为一个非常粗略的近似,你可以将 MLP 想象成与你的大脑中的神经元工作方式相同!
激活函数𝜙(x)应该是什么?令人惊讶的答案是,这大部分并不重要。当然,这并不完全正确。显然它很重要,但并不像你可能期望的那样重要。几乎任何合理的函数(单调,相当平滑)都可以工作。多年来已经尝试了许多不同的函数,尽管有些比其他的效果更好,但几乎所有的函数都可以产生不错的结果。
今天最流行的激活函数可能是修正线性单元(ReLU),𝜙(x)= max (0,x)。如果你不确定使用什么函数,这可能是一个很好的默认选择。其他常见选择包括双曲正切,tanh (x),和逻辑 Sigmoid,𝜙(x)=1/(1 +e -x )。所有这些函数都显示在图 2-3 中。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0203.png
图 2-3。三种常见的激活函数:修正线性单元,双曲正切和逻辑 Sigmoid。
我们还必须为 MLP 选择另外两个属性:它的宽度和深度。对于简单的线性模型,我们没有选择。鉴于x和y的长度,M和b的大小完全确定。但隐藏层不是这样。宽度指的是隐藏层的大小。我们可以选择每个hi的长度。根据问题的不同,你可能希望它们比输入和输出向量大得多或小得多。
深度指的是模型中的层数。只有一个隐藏层的模型被描述为浅层。有许多隐藏层的模型被描述为深层。事实上,这就是“深度学习”这个术语的起源;它只是意味着“使用具有许多层的模型的机器学习”。
在模型中选择层数和宽度涉及到与科学一样多的艺术。或者,更正式地说,“这仍然是一个活跃的研究领域。”通常只是尝试很多组合,看看哪种有效。然而,有一些原则可能提供指导,或者至少帮助你事后理解你的结果:
-
具有一个隐藏层的 MLP 是一个通用逼近器。
这意味着它可以近似任何函数(在某些相当合理的限制范围内)。在某种意义上,你永远不需要超过一个隐藏层。这已经足够复制你可能想要的任何函数。不幸的是,这个结果带来了一个重要的警告:近似的准确性取决于隐藏层的宽度,你可能需要一个非常宽的层来获得对于特定问题的足够准确性。这将引出我们到第二个原则。
-
深度模型通常需要比浅层模型更少的参数。
这个陈述故意有些模糊。对于特定特殊情况可以证明更严格的陈述,但它仍然适用作为一个一般指导原则。也许以下是更好的陈述方式:每个问题都需要一个具有一定深度的模型才能有效地实现可接受的准确性。在较浅的深度下,层的宽度(因此参数的总数)会迅速增加。这使得听起来你应该总是更喜欢深度模型而不是浅层模型。不幸的是,这在一定程度上与第三个原则相矛盾。
-
深度模型往往比浅层模型更难训练。
直到 2007 年左右,大多数机器学习模型都是浅层的。深度模型的理论优势是已知的,但研究人员通常无法成功地训练它们。从那时起,一系列进步逐渐提高了深度模型的实用性。这些进步包括更好的训练算法,更容易训练的新型模型,当然还有更快的计算机以及更大的数据集,用于训练模型。这些进步催生了“深度学习”作为一个领域。然而,尽管有所改进,总体原则仍然成立:深度模型往往比浅层模型更难训练。
训练模型
这将我们带到下一个主题:我们到底如何训练一个模型?MLPs 为我们提供了一个(大多数)通用的模型,可以用于任何问题。(我们稍后将讨论其他更专门的模型类型。)现在我们需要一个类似的通用算法来找到给定问题的模型参数的最佳值。我们该怎么做?
首先,你需要的当然是一组数据来进行训练。这个数据集被称为训练集。它应该包含大量的(x,y)对,也被称为样本。每个样本指定了模型的输入,以及当给定该输入时希望模型的输出是什么。例如,训练集可以是一组图像,以及标签指示每个图像是否包含猫。
接下来,你需要定义一个损失函数 L(y,y ^),其中 y 是模型的实际输出,y ^ 是训练集中指定的目标值。这是你衡量模型是否很好地复制训练数据的方式。然后对训练集中的每个样本进行平均:
平均损失 = 1 N Σ i=1 N L ( y i , y ^ i )
L(y,y ^) 当其参数接近时应该很小,而当它们相距较远时应该很大。换句话说,我们拿训练集中的每个样本,尝试将每个样本作为模型的输入,并查看输出与目标值的接近程度。然后我们对整个训练集进行平均。
对于每个问题需要选择一个合适的损失函数。一个常见的选择是欧几里德距离(也称为L2距离),L ( y , y ^ ) = Σ i (y i -y ^ i ) 2。(在这个表达式中,yi表示向量y的第i个分量。)当y表示概率分布时,一个常见的选择是交叉熵,L ( y , y ^ ) = -Σ i y i log y ^ i。还有其他选择,没有普遍的“最佳”选择。这取决于您问题的细节。
现在我们有一种衡量模型效果的方法,我们需要一种改进它的方法。我们希望搜索最小化训练集上平均损失的参数值。有许多方法可以做到这一点,但大多数深度学习工作都使用某种变体的梯度下降算法。让θ表示模型中的所有参数集。梯度下降涉及采取一系列小步骤:
θ ← θ - ϵ ∂ ∂θ 〈 L 〉
其中〈 L 〉是训练集上的平均损失。每一步都会在“下坡”方向上移动一个微小的距离。它会稍微改变模型的每个参数,目的是使平均损失减少。如果所有条件都符合,月相正好,这最终将产生一组参数,这些参数能够很好地解决您的问题。ϵ被称为学习率,它决定了每一步参数的变化量。它需要非常谨慎地选择:太小的值会导致学习速度非常慢,而太大的值会阻止算法学习。
这个算法确实有效,但存在一个严重问题。对于梯度下降的每一步,我们需要循环遍历训练集中的每个样本。这意味着训练模型所需的时间与训练集的大小成正比!假设您的训练集中有一百万个样本,计算一个样本的损失梯度需要一百万次操作,并且需要一百万步才能找到一个好的模型。(所有这些数字都是真实深度学习应用程序的典型数字。)训练将需要一百万的五次方次操作。即使在一台快速计算机上,这也需要相当长的时间。
幸运的是,有一个更好的解决方案:通过对少量样本进行平均来估计〈 L 〉。这是随机梯度下降(SGD)算法的基础。对于每一步,我们从训练集中取一小组样本(称为批次),计算损失函数的梯度,仅在批次中的样本上进行平均。我们可以将其视为对整个训练集进行平均的估计,尽管这可能是一个非常嘈杂的估计。我们执行一步梯度下降,然后为下一步选择一个新的样本批次。
这种算法往往更快。每个步骤所需的时间仅取决于每个批次的大小,这可以相当小(通常在 100 个样本左右的数量级),并且与训练集的大小无关。缺点是每个步骤在减少损失方面的效果较差,因为它是基于梯度的嘈杂估计而不是真实梯度。尽管如此,它确实会导致整体训练时间大大缩短。
深度学习中使用的大多数优化算法都基于 SGD,但有许多改进它的变体。幸运的是,您通常可以将这些算法视为黑匣子,并相信它们会在不了解其工作细节的情况下做正确的事情。今天使用最广泛的两种算法称为 Adam 和 RMSProp。如果您对要使用的算法有疑问,那么这两种算法中的任何一种可能都是一个合理的选择。
验证
假设您已经按照迄今所述的一切做了。您收集了大量的训练数据。您选择了一个模型,然后运行了一个训练算法,直到损失变得非常小。恭喜,您现在有一个解决问题的函数!
对吗?
抱歉,事情并不那么简单!您唯一确切知道的是该函数在训练数据上表现良好。您可能希望它在其他数据上也表现良好,但肯定不能指望。现在您需要验证模型,看看它是否适用于未经专门训练的数据。
为此,您需要第二个数据集,称为测试集。它与训练集具有完全相同的形式,即一组( x , y )对,但两者不应有共同的样本。您在训练集上训练模型,然后在测试集上测试它。这将引出机器学习中最重要的原则之一:
- 在设计或训练模型时,绝对不能使用测试集。
事实上,最好永远不要查看测试集中的数据。测试集数据仅用于测试完全训练的模型,以了解其工作效果如何。如果允许测试集以任何方式影响模型,您就有可能得到一个在测试集上比在未参与创建模型的其他数据上表现更好的模型。它不再是一个真正的测试集,而只是另一种类型的训练集。
这与数学概念过拟合有关。训练数据应该代表一个更大的数据分布,即您可能希望在模型上使用的所有输入集。但您无法对所有可能的输入进行训练。您只能创建一个有限的训练样本集,对其进行训练,并希望它学习到适用于其他样本的通用策略。过拟合是指当训练捕捉到训练样本的特定特征时,模型在这些样本上的表现比其他样本更好。
正则化
过拟合是任何使用机器学习的人都会遇到的主要问题。鉴于此,您不会感到惊讶地了解到已经开发了许多技术来避免过拟合。这些技术统称为正则化。任何正则化技术的目标都是避免过拟合,并产生一个在任何输入上都表现良好的训练模型,而不仅仅是用于训练的特定输入。
在讨论特定的正则化技术之前,有两个非常重要的要点需要了解。
首先,避免过拟合的最佳方法 几乎总是 获得更多的训练数据。您的训练集越大,它越能更好地代表“真实”数据分布,学习算法过拟合的可能性就越小。当然,有时这是不可能的:也许您根本无法获得更多数据,或者收集数据可能非常昂贵。在这种情况下,您只能尽力利用手头的数据,如果过拟合是一个问题,您将不得不使用正则化来避免它。但更多的数据可能会比正则化产生更好的结果。
其次,没有普遍“最佳”的正则化方法。这一切都取决于问题。毕竟,训练算法并不知道自己正在过拟合。它只知道训练数据。它不知道真实数据分布与训练数据的差异,因此它能做的最好就是生成一个在训练集上表现良好的模型。如果这不是您想要的,那就由您告诉它。
这就是任何正则化方法的本质:偏向训练过程,更喜欢某些类型的模型而不是其他类型。您对“好”模型应该具有哪些特性以及它与过拟合模型有何不同做出假设,然后告诉训练算法更喜欢具有这些特性的模型。当然,这些假设通常是隐含的而不是明确的。通过选择特定的正则化方法,您可能不清楚自己做出了什么假设。但它们总是存在的。
最简单的正则化方法之一就是减少模型的训练步骤。在训练初期,模型倾向于捕捉到训练数据的粗略特性,这些特性可能适用于真实分布。它运行得越久,就越有可能开始捕捉特定训练样本的细节。通过限制训练步骤的数量,您减少了过拟合的机会。更正式地说,您实际上是假设“好”的参数值不应该与您开始训练时的值有太大的不同。
另一种方法是限制模型中参数的大小。例如,您可以向损失函数添加一个与 |θ| 2 成比例的项,其中 θ 是包含模型所有参数的向量。通过这样做,您假设“好”的参数值不应该比必要的大。这反映了过拟合通常(虽然不总是)涉及一些参数变得非常大的事实。
一种非常流行的正则化方法称为辍学。它涉及做一些乍看起来荒谬的事情,但实际上效果出奇的好。对于模型中的每个隐藏层,您随机选择输出向量hi中的一部分元素,并将它们设置为 0。在梯度下降的每一步中,您选择不同的随机元素子集。这可能看起来会破坏模型:当内部计算不断随机设置为 0 时,您如何指望它能够工作?辍学为什么有效的数学理论有点复杂。非常粗略地说,通过使用辍学,您假设模型中没有任何个别计算应该太重要。您应该能够随机删除任何个别计算,而模型的其余部分应该继续在没有它的情况下工作。这迫使它学习冗余的、高度分布的数据表示,使过度拟合不太可能发生。如果您不确定要使用哪种正则化方法,辍学是一个不错的尝试。
超参数优化
到目前为止,您可能已经注意到,即使使用一个被认为是通用的模型和“通用”学习算法,也有很多选择要做。例如:
-
模型中的层数
-
每一层的宽度
-
要执行的训练步数
-
训练过程中使用的学习率
-
使用辍学时要设置为 0 的元素的比例
这些选项称为超参数。超参数是模型或训练算法的任何方面,必须事先设置而不是由训练算法学习。但是您应该如何选择它们呢?难道机器学习的整个目的不是根据数据自动选择设置吗?
这将我们带到超参数优化的主题。最简单的方法就是尝试每个超参数的许多值,看看哪个效果最好。当您想尝试许多超参数的许多值时,这变得非常昂贵,因此有更复杂的方法,但基本思想仍然相同:尝试不同的组合,看看哪个效果最好。
但是如何确定哪个效果最好呢?最简单的答案可能是看看哪个产生了训练集上损失函数(或其他准确度度量)的最低值。但请记住,这不是我们真正关心的。我们想要最小化测试集上的错误,而不是训练集。这对于影响正则化的超参数尤为重要,例如辍学率。低训练集错误可能只意味着模型过度拟合,优化于训练数据的精确细节。因此,我们希望尝试许多超参数值,然后使用在测试集上最小化损失的那些值。
但我们不能这样做!记住:在设计或训练模型时,绝不能以任何方式使用测试集。它的作用是告诉您模型在从未见过的新数据上可能的工作效果。仅因为某个特定的超参数集恰好在测试集上效果最好,并不意味着这些值将始终效果最好。我们不能让测试集影响模型,否则它就不再是一个无偏的测试集。
解决方案是创建另一个数据集,称为验证集。它不能与训练集或测试集共享任何样本。完整的流程如下:
-
对于每组超参数值,在训练集上训练模型,然后计算验证集上的损失。
-
接受在验证集上给出最低损失的超参数集作为最终模型。
-
在测试集上评估最终模型,以获得其工作效果的无偏度量。
其他类型的模型
这还留下了一个你需要做出的决定,这本身就是一个庞大的主题:使用什么样的模型。在本章的前面,我们介绍了多层感知器。它们的优点是作为一类通用模型,可以应用于许多不同的问题。不幸的是,它们也有严重的缺点。它们需要大量的参数,这使它们非常容易过拟合。当它们有超过一两个隐藏层时,训练变得困难。在许多情况下,通过使用一个更少通用的模型,利用问题的特定特征,你可以获得更好的结果。
这本书的大部分内容都是讨论在生命科学中特别有用的特定类型的模型。这些可以等到后面的章节再讨论。但是在这个介绍中,有两类非常重要的模型我们应该讨论,它们在许多不同领域中被广泛使用。它们被称为卷积神经网络和循环神经网络。
卷积神经网络
卷积神经网络(简称 CNN)是最早被广泛使用的深度模型之一。它们被开发用于图像处理和计算机视觉。它们仍然是许多涉及在矩形网格上采样的连续数据的问题的绝佳选择:音频信号(1D)、图像(2D)、体积 MRI 数据(3D)等等。
它们也是一类真正体现“神经网络”这个术语的模型。CNN 的设计最初受到猫的视觉皮层工作的启发。(猫在深度学习领域的黎明时期起到了核心作用。)从 20 世纪 50 年代到 80 年代进行的研究揭示了视觉是通过一系列层次来处理的。第一层中的每个神经元从视野的一个小区域(其感受野)接收输入。不同的神经元专门用于检测特定的局部模式或特征,如垂直或水平线。第二层中的细胞从第一层中的局部细胞群接收输入,结合它们的信号来检测更复杂的模式,覆盖更大的感受野。每一层可以被看作是原始图像的一个新表示,用更大更抽象的模式来描述比前一层中的模式。
CNN 反映了这种设计,将输入图像通过一系列层。在这个意义上,它们就像 MLP,但是每一层的结构是非常不同的。MLP 使用全连接层。输出向量的每个元素都取决于输入向量的每个元素。CNN 使用卷积层,利用了空间局部性。每个输出元素对应于图像的一个小区域,并且仅取决于该区域内的输入值。这极大地减少了定义每一层的参数数量。实际上,它假设权重矩阵Mi的大多数元素都是 0,因为每个输出元素仅取决于少量的输入元素。
卷积层进一步假设参数对于图像的每个局部区域都是相同的。如果一个层使用一组参数在图像的一个位置检测水平线,那么它也会使用完全相同的参数在图像的其他任何地方检测水平线。这使得该层的参数数量与图像的大小无关。它只需要学习一个单一的卷积核,定义了如何从图像的任何局部区域计算输出特征。这个局部区域通常非常小,可能是 5 乘 5 像素。在这种情况下,要学习的参数数量仅为每个区域的输出特征数量的 25 倍。与全连接层中的参数数量相比,这是微不足道的,使得 CNN 比 MLP 更容易训练,更不容易过拟合。
循环神经网络
循环神经网络(简称 RNNs)有些不同。它们通常用于处理以元素序列形式呈现的数据:文本文档中的单词,DNA 分子中的碱基等。序列中的元素逐个输入到网络的输入中。但然后网络做了一些非常不同的事情:每个层的输出被反馈到下一步的自身输入中!这使得 RNNs 具有一种记忆。当序列中的元素(单词、DNA 碱基等)被输入到网络中时,每个层的输入取决于该元素,但也取决于所有先前的元素(图 2-4)。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0204.png
图 2-4. 一个循环神经网络。当序列的每个元素(x 1,x 2,…)被馈送到输入时,输出(y 1,y 2,…)既取决于输入元素,也取决于上一步中 RNN 自身的输出。
因此,循环层的输入有两部分:常规输入(即网络中前一层的输出)和循环输入(等于前一步的自身输出)。然后需要根据这些输入计算一个新的输出。原则上你可以使用全连接层,但实际上通常效果不是很好。研究人员已经开发出其他类型的层,在 RNN 中效果要好得多。最流行的两种类型分别称为门控循环单元(GRU)和长短期记忆(LSTM)。现在不用担心细节;只需记住,如果你正在创建一个 RNN,通常应该使用这些类型的层来构建它。
拥有记忆使得循环神经网络(RNNs)在根本上与我们讨论过的其他模型有所不同。使用卷积神经网络(CNN)或多层感知器(MLP),你只需将一个值输入到网络的输入中,然后得到一个不同的值。输出完全由输入决定。但对于 RNN 来说并非如此。该模型有自己的内部状态,由最近一步的所有层的输出组成。每次将一个新值输入到模型中时,输出不仅取决于输入值,还取决于内部状态。同样,内部状态也会受到每个新输入值的影响。这使得 RNN 非常强大,并允许它们用于许多不同的应用。
进一步阅读
深度学习是一个庞大的主题,本章仅对其进行了最简要的介绍。这应该足以帮助你阅读和理解本书的其余部分,但如果你计划在该领域进行严肃的工作,你将需要获得更全面的背景知识。幸运的是,网络上有许多优秀的深度学习资源可供参考。以下是一些你可能要查阅的材料建议:
-
神经网络与深度学习 由迈克尔·尼尔森(Determination Press)涵盖了与本章大致相同的材料,但对每个主题进行了更详细的讨论。如果你想要对深度学习的基础知识有扎实的工作了解,足以在自己的工作中使用它,那么这是一个很好的起点。
-
深度学习 由伊恩·古德费洛、约书亚·本吉奥和亚伦·库维尔(麻省理工学院出版社)撰写,是由该领域顶尖研究人员撰写的更高级的介绍。它期望读者具有类似计算机科学研究生的背景,并对主题背后的数学理论进行更详细的讨论。你可以轻松地使用深度模型而不必理解所有理论,但如果你想在深度学习领域进行原创研究(而不仅仅是将深度模型作为解决其他领域问题的工具),这本书是一个绝佳的资源。
-
《深度学习的 TensorFlow》(O’Reilly 出版)由 Bharath Ramsundar 和 Reza Zadeh 撰写,为从业者介绍了深度学习的核心概念,旨在建立直观理解,而不深入探讨这些模型的数学基础。对于那些对深度学习的实际方面感兴趣的人来说,这可能是一个有用的参考资料。
第三章:使用 DeepChem 进行机器学习
本章简要介绍了使用 DeepChem 进行机器学习的内容,DeepChem 是建立在 TensorFlow 平台之上的库,旨在促进在生命科学领域中使用深度学习。DeepChem 提供了大量适用于生命科学应用的模型、算法和数据集。在本书的其余部分,我们将使用 DeepChem 来进行案例研究。
为什么不直接使用 Keras、TensorFlow 或 PyTorch?
这是一个常见问题。简短的答案是,这些软件包的开发人员专注于支持对他们的核心用户有用的某些类型的用例。例如,对于图像处理、文本处理和语音分析有广泛的支持。但是在这些库中通常没有类似的支持来处理分子、基因数据集或显微镜数据集。DeepChem 的目标是为这些应用程序提供一流的支持。这意味着添加自定义的深度学习原语、支持所需的文件类型,以及为这些用例提供广泛的教程和文档。
DeepChem 还设计为与 TensorFlow 生态系统很好地集成,因此您应该能够将 DeepChem 代码与其他 TensorFlow 应用程序代码混合使用。
在本章的其余部分,我们将假设您已经在您的计算机上安装了 DeepChem,并且准备运行示例。如果您尚未安装 DeepChem,不要担心。只需访问DeepChem 网站,并按照您系统的安装说明进行操作。
DeepChem 对 Windows 的支持
目前,DeepChem 不支持在 Windows 上安装。如果可能的话,我们建议您使用 Mac 或 Linux 工作站来完成本书中的示例。我们从用户那里得知,DeepChem 可以在更现代的 Windows 发行版中的 Windows 子系统 Linux(WSL)上运行。
如果您无法获得 Mac 或 Linux 机器的访问权限,或者无法使用 WSL,我们很乐意帮助您获得 DeepChem 在 Windows 上的支持。请联系作者,告诉我们您遇到的具体问题,我们将尽力解决。我们希望在未来版本的书中取消这一限制,并为未来的读者提供对 Windows 的支持。
DeepChem 数据集
DeepChem 使用Dataset对象的基本抽象来封装用于机器学习的数据。Dataset包含有关一组样本的信息:输入向量x、目标输出向量y,以及可能包括每个样本表示的描述等其他信息。有不同方式存储数据的Dataset的子类。特别是,NumpyDataset对象作为 NumPy 数组的便捷包装器,并将被广泛使用。在本节中,我们将演示如何使用NumpyDataset进行一个简单的代码案例研究。所有这些代码都可以在交互式 Python 解释器中输入;在适当的情况下,输出将显示出来。
我们从一些简单的导入开始:
import deepchem as dc
import numpy as np
让我们现在构建一些简单的 NumPy 数组:
x = np.random.random((4, 5))
y = np.random.random((4, 1))
这个数据集将有四个样本。数组x对于每个样本有五个元素(“特征”),而y对于每个样本有一个元素。让我们快速查看我们抽样的实际数组(请注意,当您在本地运行此代码时,您应该期望看到不同的数字,因为您的随机种子将是不同的):
In : x
Out:
array([[0.960767 , 0.31300931, 0.23342295, 0.59850938, 0.30457302],
[0.48891533, 0.69610528, 0.02846666, 0.20008034, 0.94781389],
[0.17353084, 0.95867152, 0.73392433, 0.47493093, 0.4970179 ],
[0.15392434, 0.95759308, 0.72501478, 0.38191593, 0.16335888]])
In : y
Out:
array([[0.00631553],
[0.69677301],
[0.16545319],
[0.04906014]])
让我们现在将这些数组封装在一个NumpyDataset对象中:
dataset = dc.data.NumpyDataset(x, y)
我们可以解开dataset对象,以获取我们存储在其中的原始数组:
In : print(dataset.X)
[[0.960767 0.31300931 0.23342295 0.59850938 0.30457302]
[0.48891533 0.69610528 0.02846666 0.20008034 0.94781389]
[0.17353084 0.95867152 0.73392433 0.47493093 0.4970179 ]
[0.15392434 0.95759308 0.72501478 0.38191593 0.16335888]]
In : print(dataset.y)
[[0.00631553]
[0.69677301]
[0.16545319]
[0.04906014]]
请注意,这些数组与原始数组x和y相同:
In : np.array_equal(x, dataset.X)
Out : True
In : np.array_equal(y, dataset.y)
Out : True
其他类型的数据集
DeepChem 支持其他类型的Dataset对象,如前所述。当处理无法完全存储在计算机内存中的大型数据集时,这些类型主要变得有用。DeepChem 还集成了使用 TensorFlow 的tf.data数据集加载工具的功能。我们将在需要时涉及这些更高级的库功能。
训练一个模型来预测分子的毒性
在这一部分,我们将演示如何使用 DeepChem 来训练一个模型来预测分子的毒性。在后面的章节中,我们将更深入地解释分子毒性预测的工作原理,但在这一部分,我们将把它作为一个黑盒示例,展示 DeepChem 模型如何用于解决机器学习挑战。让我们从一对必要的导入开始:
import numpy as np
import deepchem as dc
接下来是加载用于训练机器学习模型的相关毒性数据集。DeepChem 维护一个名为dc.molnet(MoleculeNet 的缩写)的模块,其中包含一些用于机器学习实验的预处理数据集。特别是,我们将使用dc.molnet.load_tox21()函数,它将为我们加载和处理 Tox21 毒性数据集。当您第一次运行这些命令时,DeepChem 将在您的计算机上本地处理数据集。您应该期望看到如下的处理说明:
In : tox21_tasks, tox21_datasets, transformers = dc.molnet.load_tox21()
Out: Loading raw samples now.
shard_size: 8192
About to start loading CSV from /tmp/tox21.CSV.gz
Loading shard 1 of size 8192.
Featurizing sample 0
Featurizing sample 1000
Featurizing sample 2000
Featurizing sample 3000
Featurizing sample 4000
Featurizing sample 5000
Featurizing sample 6000
Featurizing sample 7000
TIMING: featurizing shard 0 took 15.671 s
TIMING: dataset construction took 16.277 s
Loading dataset from disk.
TIMING: dataset construction took 1.344 s
Loading dataset from disk.
TIMING: dataset construction took 1.165 s
Loading dataset from disk.
TIMING: dataset construction took 0.779 s
Loading dataset from disk.
TIMING: dataset construction took 0.726 s
Loading dataset from disk.
特征化的过程是将包含有关分子信息的数据集转换为矩阵和向量,以便在机器学习分析中使用。我们将在后续章节中更深入地探讨这个过程。不过,让我们从这里开始,快速查看我们处理过的数据。
dc.molnet.load_tox21()函数返回多个输出:tox21_tasks、tox21_datasets和transformers。让我们简要地看一下每一个:
In : tox21_tasks
Out:
['NR-AR',
'NR-AR-LBD',
'NR-AhR',
'NR-Aromatase',
'NR-ER',
'NR-ER-LBD',
'NR-PPAR-gamma',
'SR-ARE',
'SR-ATAD5',
'SR-HSE',
'SR-MMP',
'SR-p53']
In : len(tox21_tasks)
Out: 12
这里的 12 个任务中的每一个对应于一个特定的生物实验。在这种情况下,这些任务中的每一个都是针对酶活性测定的,该测定衡量了 Tox21 数据集中的分子是否与所讨论的生物靶标结合。诸如NR-AR等术语对应于这些靶标。在这种情况下,这些靶标中的每一个都是一种被认为与潜在治疗分子的毒性反应相关联的特定酶。
我需要了解多少生物学知识?
对于进入生命科学领域的计算机科学家和工程师来说,生物学术语的范围可能令人眼花缭乱。然而,并不需要深入了解生物学就能开始在生命科学领域产生影响。如果您的主要背景是计算机科学,尝试以计算机科学的类比方式理解生物系统可能会有所帮助。想象细胞或动物是您无法控制的复杂遗留代码库。作为工程师,您有一些关于这些系统(测定)的实验性测量数据,可以用来对底层机制有一些了解。机器学习是理解生物系统的一种非常强大的工具,因为学习算法能够以大多数自动的方式提取有用的相关性。这使得即使是生物学初学者有时也能发现深刻的生物洞察。
在本书的其余部分,我们会简要讨论基础生物学。这些说明可以作为进入广阔生物学文献的入口点。公共参考资料,如维基百科,通常包含大量有用的信息,可以帮助启动您的生物学教育。
接下来,让我们考虑tox21_datasets。使用复数形式的提示表明,这个字段实际上是一个包含多个dc.data.Dataset对象的元组:
In : tox21_datasets
Out:
(<deepchem.data.datasets.DiskDataset at 0x7f9804d6c390>,
<deepchem.data.datasets.DiskDataset at 0x7f9804d6c780>,
<deepchem.data.datasets.DiskDataset at 0x7f9804c5a518>)
在这种情况下,这些数据集对应于您在上一章中了解的训练、验证和测试集。您可能注意到这些是DiskDataset对象;dc.molnet模块会将这些数据集缓存在您的磁盘上,这样您就不需要反复对 Tox21 数据集进行特征化。让我们正确地拆分这些数据集:
train_dataset, valid_dataset, test_dataset = tox21_datasets
处理新数据集时,首先查看它们的形状非常有用。要这样做,请检查shape属性:
In : train_dataset.X.shape
Out: (6264, 1024)
In : valid_dataset.X.shape
Out: (783, 1024)
In : test_dataset.X.shape
Out: (784, 1024)
train_dataset包含总共 6,264 个样本,每个样本都有一个长度为 1,024 的相关特征向量。同样,valid_dataset和test_dataset分别包含 783 和 784 个样本。现在让我们快速查看这些数据集的y向量:
In : np.shape(train_dataset.y)
Out: (6264, 12)
In : np.shape(valid_dataset.y)
Out: (783, 12)
In : np.shape(test_dataset.y)
Out: (784, 12)
每个样本有 12 个数据点,也称为标签。这些对应于我们之前讨论的 12 个任务。在这个特定的数据集中,样本对应于分子,任务对应于生化测定,每个标签是特定分子上特定测定的结果。这些是我们想要训练模型来预测的内容。
然而,有一个复杂之处:Tox21 的实际实验数据集并没有测试每个生物实验中的每种分子。这意味着一些标签是没有意义的占位符。对于一些分子的一些属性,我们根本没有数据,因此在训练和测试模型时需要忽略这些数组的元素。
我们如何找出哪些标签实际上被测量了?我们可以检查数据集的w字段,记录其权重。每当我们为模型计算损失函数时,我们在对任务和样本求和之前乘以w。这可以用于几个目的,其中一个是标记缺失数据。如果一个标签的权重为 0,则该标签不会影响损失,并且在训练过程中会被忽略。让我们深入挖掘一下,找出我们的数据集中实际测量了多少个标签:
In : train_dataset.w.shape
Out: (6264, 12)
In : np.count_nonzero(train_dataset.w)
Out: 62166
In : np.count_nonzero(train_dataset.w == 0)
Out: 13002
在标签数组中的 6,264×12 = 75,168 个元素中,只有 62,166 个实际测量过。其他 13,002 个对应于缺失的测量值,应该被忽略。您可能会问,为什么我们仍然保留这样的条目。答案主要是为了方便;不规则形状的数组比带有一组权重的常规矩阵更难在代码中进行推理和处理。
处理数据集具有挑战性
在这里需要注意的是,为了在生命科学中使用,清理和处理数据集可能非常具有挑战性。许多原始数据集将包含系统性的错误类别。如果所讨论的数据集是由外部组织(合同研究机构或 CRO)进行的实验构建的,那么该数据集很可能是系统性错误的。因此,许多生命科学组织都会保留内部的科学家,他们的工作是验证和清理这些数据集。
一般来说,如果您的机器学习算法在生命科学任务中无法正常工作,很可能根本原因不是算法本身,而是您使用的数据源中存在的系统性错误。
现在让我们检查transformers,这是load_tox21()返回的最终输出。转换器是一种以某种方式修改数据集的对象。DeepChem 提供许多可以以有用方式操作数据的转换器。在 MoleculeNet 中找到的数据加载例程总是返回已应用于数据的转换器列表,因为您可能以后需要它们来“取消转换”数据。让我们看看这种情况下有什么:
In : transformers
Out: [<deepchem.trans.transformers.BalancingTransformer at 0x7f99dd73c6d8>]
这里的数据已经通过 BalancingTransformer 进行了转换。这个类用于纠正不平衡的数据。在 Tox21 的情况下,大多数分子不与大多数目标结合。事实上,超过 90% 的标签是 0。这意味着一个模型可以轻松地通过始终预测 0 来获得超过 90% 的准确率,无论输入是什么。不幸的是,那个模型将是完全无用的!在分类任务中,不平衡的数据,即某些类别的训练样本比其他类别多得多,是一个常见问题。
幸运的是,有一个简单的解决方案:调整数据集的权重矩阵以进行补偿。BalancingTransformer 调整单个数据点的权重,使得分配给每个类别的总权重相同。这样,损失函数对任何一个类别都没有系统偏好。损失只能通过学会正确区分类别来减少。
现在我们已经探索了 Tox21 数据集,让我们开始探索如何在这些数据集上训练模型。DeepChem 的 dc.models 子模块包含各种不同的生命科学特定模型。所有这些不同的模型都继承自父类 dc.models.Model。这个父类旨在提供一个遵循常见 Python 约定的通用 API。如果您使用过其他 Python 机器学习包,您应该会发现许多 dc.models.Model 方法看起来非常熟悉。
在本章中,我们不会深入探讨这些模型是如何构建的细节。相反,我们将提供一个实例,展示如何实例化一个标准的 DeepChem 模型,dc.models.MultitaskClassifier。这个模型构建了一个全连接网络(MLP),将输入特征映射到多个输出预测。这对于 多任务 问题非常有用,其中每个样本有多个标签。它非常适合我们的 Tox21 数据集,因为我们有 12 个不同的检测任务需要同时预测。让我们看看如何在 DeepChem 中构建一个 MultitaskClassifier:
model = dc.models.MultitaskClassifier(n_tasks=12,
n_features=1024,
layer_sizes=[1000])
这里有各种不同的选项。让我们简要回顾一下。n_tasks 是任务的数量,n_features 是每个样本的输入特征数量。正如我们之前看到的,Tox21 数据集有 12 个任务和每个样本 1,024 个特征。layer_sizes 是一个设置网络中完全连接隐藏层数量和每个隐藏层宽度的列表。在这种情况下,我们指定有一个宽度为 1,000 的单隐藏层。
现在我们已经构建了模型,我们如何在 Tox21 数据集上训练它呢?每个 Model 对象都有一个 fit() 方法,用于将模型拟合到包含在 Dataset 对象中的数据中。然后,对我们的 MultitaskClassifier 对象进行拟合是一个简单的调用:
model.fit(train_dataset, nb_epoch=10)
请注意,我们在这里添加了一个标志。nb_epoch=10 表示将进行 10 个梯度下降训练周期。一个 epoch 指的是对数据集中所有样本进行一次完整遍历。为了训练模型,您将训练集分成批次,并对每个批次进行一步梯度下降。在理想情况下,您会在数据用尽之前达到一个良好优化的模型。实际上,通常没有足够的训练数据,所以在模型完全训练之前就用尽了数据。然后您需要开始重复使用数据,对数据集进行额外的遍历。这样可以使用更少的数据训练模型,但使用的 epoch 越多,最终得到过拟合模型的可能性就越大。
现在让我们评估训练模型的性能。为了评估模型的工作效果,有必要指定一个度量标准。DeepChem 类dc.metrics.Metric提供了一种为模型指定度量标准的通用方法。对于 Tox21 数据集,ROC AUC 分数是一个有用的度量标准,所以让我们使用它进行分析。然而,请注意这里的一个细微之处:有多个 Tox21 任务。我们应该在哪一个上计算 ROC AUC?一个好的策略是计算所有任务的平均 ROC AUC 分数。幸运的是,这很容易做到:
metric = dc.metrics.Metric(dc.metrics.roc_auc_score, np.mean)
由于我们指定了np.mean,所有任务的 ROC AUC 分数的平均值将被报告。DeepChem 模型支持评估函数model.evaluate(),该函数评估模型在给定数据集和度量标准上的性能。
ROC AUC
我们想将分子分类为有毒或无毒,但模型输出连续数字,而不是离散预测。在实践中,您选择一个阈值值,并预测当输出大于阈值时分子是有毒的。较低的阈值将产生许多假阳性(预测安全分子实际上是有毒的)。较高的阈值将产生较少的假阳性,但会产生更多的假阴性(错误地预测有毒分子是安全的)。
接收器操作特性(ROC)曲线是一种方便的可视化权衡方式。您可以尝试许多不同的阈值值,然后绘制真正阳性率与假阳性率随着阈值变化而变化的曲线。一个示例显示在图 3-1 中。
ROC AUC 是 ROC 曲线下的总面积。曲线下的面积(AUC)提供了模型区分不同类别的能力的指示。如果存在任何阈值值,每个样本都被正确分类,ROC AUC 分数为 1。在另一个极端,如果模型输出与真实类别无关的完全随机值,ROC AUC 分数为 0.5。这使得它成为一个用于总结分类器工作效果的有用数字。这只是一个启发式方法,但是它是一个流行的方法。
train_scores = model.evaluate(train_dataset, [metric], transformers)
test_scores = model.evaluate(test_dataset, [metric], transformers)
现在我们已经计算了分数,让我们来看看!
In : `print``(``train_scores``)`
...: `print``(``test_scores``)`
Out
{'mean-roc_auc_score': 0.9659541853946179}
{'mean-roc_auc_score': 0.7915464001982299}
请注意,我们在训练集上的得分(0.96)比测试集上的得分(0.79)要好得多。这表明模型已经过拟合。我们真正关心的是测试集得分。这些数字在这个数据集上并不是最好的可能值 - 在撰写本文时,Tox21 数据集的最先进 ROC AUC 分数略低于 0.9 - 但对于一个开箱即用的系统来说,它们并不算差。其中一个 12 个任务的完整 ROC 曲线显示在图 3-1 中。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0301.png
图 3-1。12 个任务中的一个的 ROC 曲线。虚线对角线显示了一个只是随机猜测的模型的曲线。实际曲线始终远高于对角线,表明我们比随机猜测要好得多。
案例研究:训练一个 MNIST 模型
在前一节中,我们介绍了使用 DeepChem 训练机器学习模型的基础知识。然而,我们使用了一个预先制作的模型类dc.models.MultitaskClassifier。有时候,您可能希望创建一个新的深度学习架构,而不是使用一个预配置的架构。在本节中,我们将讨论如何在 MNIST 数字识别数据集上训练卷积神经网络。与之前的示例不同,这次我们将自己指定完整的深度学习架构。为此,我们将介绍dc.models.TensorGraph类,它提供了在 DeepChem 中构建深度架构的框架。
何时使用预制模型有意义?
在本节中,我们将在 MNIST 上使用自定义架构。在之前的示例中,我们使用了“罐头”(即预定义)架构。每种选择何时合理?如果对于某个问题有一个经过充分调试的罐头架构,那么使用它可能是合理的。但如果你正在处理一个没有组合好这样的架构的新数据集,通常需要创建一个自定义架构。熟悉使用罐头和自定义架构是很重要的,因此我们在本章中包含了每种类型的示例。
MNIST 手写数字识别数据集
MNIST 手写数字识别数据集(参见图 3-2)需要构建一个机器学习模型,可以正确分类手写数字。挑战在于对 0 到 9 的数字进行分类,给定 28×28 像素的黑白图像。数据集包含 60,000 个训练示例和 10,000 个测试示例。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0302.png
图 3-2。从 MNIST 手写数字识别数据集中抽取的样本。 (来源:GitHub)
就机器学习问题而言,MNIST 数据集并不特别具有挑战性。数十年的研究已经产生了最先进的算法,在这个数据集上实现了接近 100%的测试集准确率。因此,MNIST 数据集不再适用于研究工作,但对于教学目的来说是一个很好的工具。
DeepChem 只适用于生命科学吗?
正如我们在本章前面提到的,完全可以使用其他深度学习包来进行生命科学应用。同样,也可以使用 DeepChem 构建通用的机器学习系统。虽然在 DeepChem 中构建电影推荐系统可能比使用更专门的工具更困难,但这是完全可行的。而且有充分的理由:已经有多项研究探讨了将推荐系统算法用于分子结合预测的应用。在一个领域使用的机器学习架构通常会延伸到其他领域,因此保持创新工作所需的灵活性是很重要的。
MNIST 的卷积架构
DeepChem 使用TensorGraph类来构建非标准的深度学习架构。在本节中,我们将逐步介绍构建卷积架构所需的代码,如图 3-3 所示。它从两个卷积层开始,用于识别图像中的局部特征。然后是两个全连接层,用于从这些局部特征预测数字。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0303.png
图 3-3。本节中将构建的用于处理 MNIST 数据集的架构示意图。
首先,执行以下命令下载原始的 MNIST 数据文件并将其存储在本地:
mkdir MNIST_data
cd MNIST_data
wget http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
wget http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
wget http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
wget http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
cd ..
现在让我们加载这些数据集:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
我们将处理这些原始数据,使其适合 DeepChem 进行分析。让我们从必要的导入开始:
import deepchem as dc
import tensorflow as tf
import deepchem.models.tensorgraph.layers as layers
子模块deepchem.models.tensorgraph.layers包含一系列“层”。这些层作为深度架构的构建模块,可以组合起来构建新的深度学习架构。我们将很快展示层对象是如何使用的。接下来,我们构建NumpyDataset对象,用来包装 MNIST 的训练和测试数据集:
train_dataset = dc.data.NumpyDataset(mnist.train.images, mnist.train.labels)
test_dataset = dc.data.NumpyDataset(mnist.test.images, mnist.test.labels)
请注意,尽管最初没有定义测试数据集,但 TensorFlow 的input_data()函数会负责分离出一个适当的测试数据集供我们使用。有了训练和测试数据集,我们现在可以转向定义 MNIST 卷积网络的架构。
这是基于的关键概念是可以组合层对象来构建新模型。正如我们在上一章中讨论的,每个层从前面的层接收输入并计算一个输出,该输出可以传递给后续层。在最开始,有接收特征和标签的输入层。在另一端是返回执行计算结果的输出层。在这个例子中,我们将组合一系列层以构建一个图像处理卷积网络。我们首先定义一个新的TensorGraph对象:
model = dc.models.TensorGraph(model_dir='mnist')
model_dir选项指定应保存模型参数的目录。您可以省略这一点,就像我们在之前的例子中所做的那样,但是那样模型就不会被保存。一旦 Python 解释器退出,您辛苦训练模型的所有工作都将被抛弃!指定一个目录允许您稍后重新加载模型并进行新的预测。
注意,由于TensorGraph继承自Model,因此该对象是dc.models.Model的一个实例,并支持我们之前看到的相同的fit()和evaluate()函数:
In : isinstance(model, dc.models.Model)
Out: True
我们还没有向model中添加任何内容,因此我们的模型可能不太有趣。让我们通过使用Feature和Label类为特征和标签添加一些输入:
feature = layers.Feature(shape=(None, 784))
label = layers.Label(shape=(None, 10))
MNIST 包含大小为 28×28 的图像。当展平时,这些形成长度为 784 的特征向量。标签具有第二维度为 10,因为有 10 个可能的数字值,并且该向量是独热编码的。请注意,None被用作输入维度。在构建在 TensorFlow 上的系统中,值None通常表示给定层能够接受该维度上任何大小的输入。换句话说,我们的对象feature能够接受形状为(20, 784)和(97, 784)的输入。在这种情况下,第一个维度对应于批量大小,因此我们的模型将能够接受任意数量样本的批次。
独热编码
MNIST 数据集是分类的。也就是说,对象属于有限列表中的一个潜在类别。在这种情况下,这些类别是数字 0 到 9。我们如何将这些类别馈送到机器学习系统中?一个明显的答案是简单地输入一个从 0 到 9 取值的单个数字。然而,出于各种技术原因,这种编码通常似乎效果不佳。人们通常使用的替代方法是独热编码。MNIST 的每个标签是一个长度为 10 的向量,其中一个元素设置为 1,其他所有元素设置为 0。如果非零值在第 0 个索引处,则标签对应于数字 0。如果非零值在第 9 个索引处,则标签对应于数字 9。
为了将卷积层应用于我们的输入,我们需要将我们的平面特征向量转换为形状为(28, 28)的矩阵。为此,我们将使用一个Reshape层:
make_image = layers.Reshape(shape=(None, 28, 28), in_layers=feature)
这里再次值None表示可以处理任意批量大小。请注意我们有一个关键字参数in_layers=feature。这表示Reshape层以我们先前的Feature层feature作为输入。现在我们已成功地重塑了输入,我们可以将其传递给卷积层:
conv2d_1 = layers.Conv2D(num_outputs=32, activation_fn=tf.nn.relu,
in_layers=make_image)
conv2d_2 = layers.Conv2D(num_outputs=64, activation_fn=tf.nn.relu,
in_layers=conv2d_1)
在这里,Conv2D类对其输入的每个样本应用 2D 卷积,然后通过修正线性单元(ReLU)激活函数传递。请注意如何使用in_layers将先前的层传递给后续层作为输入。我们希望最后应用Dense(全连接)层到卷积层的输出。但是,Conv2D层的输出是 2D 的,因此我们首先需要应用一个Flatten层将我们的输入展平为一维(更准确地说,Conv2D层为每个样本产生一个 2D 输出,因此其输出具有三个维度;Flatten层将其折叠为每个样本的单个维度,或者总共两个维度):
flatten = layers.Flatten(in_layers=conv2d_2)
dense1 = layers.Dense(out_channels=1024, activation_fn=tf.nn.relu,
in_layers=flatten)
dense2 = layers.Dense(out_channels=10, activation_fn=None, in_layers=dense1)
Dense层中的out_channels参数指定了层的宽度。第一层每个样本输出 1,024 个值,但第二层输出 10 个值,对应于我们的 10 个可能的数字值。现在我们希望将此输出连接到损失函数,以便我们可以训练输出以准确预测类别。我们将使用SoftMaxCrossEntropy损失来执行这种形式的训练:
smce = layers.SoftMaxCrossEntropy(in_layers=[label, dense2])
loss = layers.ReduceMean(in_layers=smce)
model.set_loss(loss)
请注意,SoftMaxCrossEntropy层接受最后一个Dense层的标签和输出作为输入。它计算每个样本的损失函数的值,因此我们需要对所有样本进行平均以获得最终损失。这是通过调用model.set_loss()将ReduceMean层设置为我们模型的损失函数来完成的。
SoftMax 和 SoftMaxCrossEntropy
通常希望模型输出概率分布。对于 MNIST,我们希望输出给定样本代表每个数字的概率。每个输出必须为正,并且它们必须总和为 1。实现这一点的一种简单方法是让模型计算任意数字,然后通过令人困惑地命名为softmax函数传递它们:
指数在分子中确保所有值为正,并且分母中的总和确保它们加起来为 1。如果x的一个元素远远大于其他元素,则相应的输出元素非常接近 1,而所有其他输出则非常接近 0。
SoftMaxCrossEntropy首先使用 softmax 函数将输出转换为概率,然后计算这些概率与标签的交叉熵。请记住,标签是独热编码的:正确类别为 1,其他所有类别为 0。您可以将其视为概率分布!当正确类别的预测概率尽可能接近 1 时,损失最小。这两个操作(softmax 后跟交叉熵)经常一起出现,将它们作为单个步骤进行计算比分开执行更稳定。
为了数值稳定性,像SoftMaxCrossEntropy这样的层会计算对数概率。我们需要使用SoftMax层来转换输出以获得每个类别的输出概率。我们将使用model.add_output()将此输出添加到model中:
output = layers.SoftMax(in_layers=dense2)
model.add_output(output)
现在我们可以使用与上一节中调用的相同的fit()函数来训练模型:
model.fit(train_dataset, nb_epoch=10)
请注意,这个方法调用可能需要一些时间在标准笔记本电脑上执行!如果函数执行速度不够快,请尝试使用nb_epoch=1。结果会更糟,但您将能够更快地完成本章的其余部分。
这次我们将定义我们的度量为准确率,即正确预测的标签比例:
metric = dc.metrics.Metric(dc.metrics.accuracy_score)
然后我们可以使用与之前相同的计算来计算准确率:
train_scores = model.evaluate(train_dataset, [metric])
test_scores = model.evaluate(test_dataset, [metric])
这会产生出色的性能:训练集的准确率为 0.999,测试集的准确率为 0.991。我们的模型正确识别了超过 99%的测试集样本。
尝试获取 GPU 访问权限
正如您在本章中看到的,深度学习代码可能运行得相当慢!在一台好的笔记本电脑上训练卷积神经网络可能需要超过一个小时才能完成。这是因为这段代码依赖于对图像数据的大量线性代数运算。大多数 CPU 并不适合执行这些类型的计算。
如果可能的话,尽量获取现代图形处理单元的访问权限。这些卡最初是为游戏开发的,但现在用于许多类型的数值计算。大多数现代深度学习工作负载在 GPU 上运行速度要快得多。您将在本书中看到的示例也将更容易使用 GPU 完成。
如果无法获得 GPU 的访问权限,也不用担心。您仍然可以完成本书中的练习,只是可能会花费更长的时间(您可能需要在等待代码运行完成时喝杯咖啡或读本书)。
结论
在这一章中,您已经学会了如何使用 DeepChem 库来实现一些简单的机器学习系统。在本书的其余部分中,我们将继续使用 DeepChem 作为我们的首选库,所以如果您还没有对该库的基本知识有很好的掌握,不要担心。将会有更多的例子出现。
在接下来的章节中,我们将开始介绍在生命科学数据集上进行有效机器学习所需的基本概念。在下一章中,我们将向您介绍分子上的机器学习。
第四章:分子的机器学习
本章涵盖了在分子数据上执行机器学习的基础知识。在深入研究本章之前,我们简要讨论一下为什么分子机器学习可能是一个有益的研究课题。现代材料科学和化学的许多工作都是出于设计具有期望性质的新分子的需要。虽然已经进行了大量的科学工作来开发新的设计策略,但有时仍然需要进行大量的随机搜索来构建有趣的分子。分子机器学习的梦想是用引导搜索取代这种随机实验,机器学习预测器可以提出哪些新分子可能具有期望的性质。这样准确的预测器可以促进创造具有有用性质的全新材料和化学品。
一旦特征化,分子仍然需要进行学习。我们将回顾一些用于学习分子功能的算法,包括简单的全连接网络以及更复杂的技术,如图卷积。我们还将描述图卷积技术的一些局限性,以及我们应该期望和不应该期望的内容。我们将以一个有趣数据集上的分子机器学习案例研究结束本章。
这个梦想很吸引人,但我们如何开始这条道路呢?第一步是构建技术方法,将分子转化为数字向量,然后将其传递给学习算法。这些方法被称为分子特征化。我们将在本章中涵盖其中一些,并在下一章中涵盖更多。
什么是分子?
分子是复杂的实体,研究人员已经开发了许多不同的技术来对其进行特征化。这些表示包括化学描述符向量,2D 图表示,3D 静电网格表示,轨道基函数表示等等。
确定给定样本中存在的分子可能是非常具有挑战性的。目前最流行的技术依赖于质谱。质谱的基本思想是用电子轰击样本。这种轰击会将分子破碎成碎片。这些碎片通常会电离,即吸收或失去电子而带电。这些带电碎片被电场推动,根据它们的质荷比分离它们。检测到的带电碎片的分布被称为光谱。图 4-1 说明了这个过程。从检测到的碎片集合中,通常可以确定原始样本中存在的精确分子。然而,这个过程仍然是有损失和困难的。许多研究人员正在积极研究利用深度学习算法改进质谱技术,以便从检测到的带电光谱中更容易地识别原始分子。
质谱
在深入研究分子机器学习之前,回顾一下分子到底是什么将是有用的。这个问题听起来有点愚蠢,因为像 H[2]O 和 CO[2]这样的分子甚至被介绍给年幼的孩子。答案不是显而易见的。然而,事实是,对于绝大多数人类的存在,我们根本不知道分子的存在。考虑一个思想实验:你如何说服一个怀疑的外星人分子实体存在?答案是相当复杂的。例如,你可能需要使用质谱仪!
注意执行此检测的复杂性!分子是复杂的实体,很难准确地确定。
为了开始,让我们假设一个分子的定义是一组由物理力连接在一起的原子。分子是化合物中最小的基本单位,可以参与化学反应。分子中的原子通过化学键连接在一起,这些键将它们粘在一起并限制它们相对于彼此的运动。分子的大小范围很广,从只有几个原子到成千上万个原子不等。图 4-2 提供了这种模型中分子的简单描述。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0401.png
图 4-1. 一个质谱仪的简单示意图。(来源:Wikimedia.)
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0402.png
图 4-2. 一个咖啡因分子的“球棒”图示。原子用彩色球体表示(黑色是碳,红色是氧,蓝色是氮,白色是氢),由代表化学键的棍子连接。
有了这个基本描述,我们将在接下来的几节中深入探讨分子化学的各个方面的更多细节。在第一次阅读本章时,您不必完全掌握所有这些概念,但掌握一些化学领域的基本知识可能会有用。
分子是动态的、量子实体
我们刚刚提供了一个关于原子和键的分子的简单描述。非常重要的是要记住,在任何分子内部都有更多的事情发生。首先,分子是动态实体,因此给定分子内的所有原子都在相互之间快速运动。键本身在伸缩和快速振动长度方面。原子很常见地会迅速从分子中脱离并重新加入。当我们讨论分子构象时,我们很快会看到更多关于分子动态性质的内容。
更奇怪的是,分子是量子的。说一个实体是量子有很多层面,但简单来说,重要的是要注意,“原子”和“键”远没有简单的球棒图表所暗示的那么明确定义。在这里的定义中有很多模糊性。在这个阶段理解这些复杂性并不重要,但要记住我们对分子的描述是非常近似的。这可能具有实际意义,因为有些学习任务可能需要用不同的描述来描述分子。
分子键是什么?
您可能已经有一段时间没有学习基础化学了,所以我们将花时间在这里和那里复习基本化学概念。最基本的问题是,化学键是什么?
构成日常生活的分子由原子组成,通常是非常大量的原子。这些原子通过化学键连接在一起。这些键基本上通过它们共享的电子将原子“粘”在一起。有许多不同类型的分子键,包括共价键和几种非共价键。
共价键
共价键涉及两个原子之间的电子共享,使得相同的电子在两个原子周围花费时间(图 4-3)。一般来说,共价键是最强的化学键类型。它们在化学反应中形成和断裂。共价键往往非常稳定:一旦形成,就需要大量能量来断裂,因此原子可以长时间保持结合。这就是为什么分子表现为独立的对象而不是无关的原子松散集合。事实上,共价键是定义分子的东西:分子是由共价键连接的一组原子。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0403.png
图 4-3。左:两个被电子云包围的原子核。右:当原子靠近时,电子开始在原子核之间的空间中花费更多时间。这会吸引原子核靠近,形成原子之间的共价键。
非共价键
非共价键不涉及原子之间的电子直接共享,但涉及较弱的电磁相互作用。由于它们不像共价键那样强,它们更加短暂,不断地断裂和重组。非共价键不像共价键那样“定义”分子,但它们对决定分子形状和不同分子之间相互关联的方式有巨大影响。
“非共价键”是一个泛指,涵盖了几种不同类型的相互作用。一些非共价键的例子包括氢键(图 4-4)、盐桥、π-堆叠等。这些类型的相互作用在药物设计中通常起着至关重要的作用,因为大多数药物通过非共价相互作用与人体内的生物分子相互作用。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0404.png
图 4-4。水分子之间的氢键相互作用很强,氢与相邻分子上的氧之间存在氢键。强大的氢键网络在一定程度上有助于水作为溶剂的作用。(来源:维基共享资源。)
在本书的不同部分我们会遇到这些类型的键。在本章中,我们将主要讨论共价键,但当我们开始研究一些生物物理深度模型时,非共价相互作用将变得更加关键。
分子图
图是由节点通过边连接在一起的数学数据结构(图 4-5)。图在计算机科学中是非常有用的抽象。事实上,有一个称为图论的数学分支专门用于理解图的属性并找到操纵和分析它们的方法。图被用来描述从构成网络的计算机到构成图像的像素,再到曾与凯文·贝肯一起出演电影的演员等各种事物。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0405.png
图 4-5。一个由六个节点通过边连接的数学图的示例。(来源:维基共享资源。)
重要的是,分子也可以被视为图(图 4-6)。在这种描述中,原子是图中的节点,化学键是边。任何分子都可以转换为相应的分子图。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0406.png
图 4-6。将苯分子转化为分子图的示例。请注意,原子被转换为节点,化学键被转换为边。
在本章的其余部分,我们将反复将分子转化为图形,以便分析它们并学会对它们进行预测。
分子构象
分子图描述了分子中的原子集合以及它们如何相互结合。但还有另一件非常重要的事情我们需要知道:原子在 3D 空间中相对于彼此的位置。这被称为分子的构象。
原子、键和构象彼此相关。如果两个原子共价结合,那么它们之间的距离往往会固定,严格限制可能的构象。由三个或四个共价结合原子组成的角度也经常受到限制。有时会有整个原子团是完全刚性的,作为一个单一单位一起移动。但分子的其他部分是灵活的,允许原子相对于彼此移动。例如,许多(但不是所有)共价键允许它们连接的原子团绕键的轴自由旋转。这使得分子可以呈现许多不同的构象。
图 4-7 展示了一个非常流行的分子:蔗糖,也称为食糖。它既以 2D 化学结构形式展示,也以 3D 构象形式展示。蔗糖由两个环连接在一起。每个环都相当刚性,因此其形状随时间变化很少。但连接它们的连接物更加灵活,允许环相对于彼此移动。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0407.png
图 4-7。蔗糖,以 3D 构象和 2D 化学结构表示。 (改编自维基媒体图像(维基媒体和维基百科)。)
随着分子变得更大,它们可以采取的构象数量急剧增加。对于大型大分子,如蛋白质(图 4-8),目前需要非常昂贵的模拟来探索可能构象的集合。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0408.png
图 4-8。以 3D 形式呈现的细菌紫质的构象(用于捕获光能)。蛋白质的构象特别复杂,具有多个 3D 几何图案,并提醒我们分子除了化学式外还具有几何形状。(来源:维基媒体。)
分子的手性
一些分子(包括许多药物)有两种镜像形式。这被称为手性。手性分子既有“右手”形式(也称为“R”形式),也有“左手”形式(也称为“S”形式),如图 4-9 所示。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0409.png
图 4-9。螺环化合物的轴向手性(由两个或更多环连接在一起的化合物)。请注意,这两种手性变体分别标记为“R”和“S”。这种约定在化学文献中很普遍。
手性非常重要,也是实验室化学家和计算化学家的许多挫折的根源。首先,产生手性分子的化学反应通常不区分形式,会产生相等数量的两种手性。如果你想最终只得到一种形式,你的制造过程立即变得更加复杂。此外,许多物理性质对两种手性是相同的,因此许多实验无法区分给定分子的手性版本。计算模型也是如此。例如,两种手性具有相同的分子图,因此任何仅依赖于分子图的机器学习模型将无法区分它们。
如果两种形式在实践中表现相同,这就不会那么重要,但情况通常并非如此。一种药物的两种手性形式可能结合到完全不同的蛋白质上,并在体内产生非常不同的效果。在许多情况下,只有一种形式的药物具有期望的治疗效果。另一种形式只会产生额外的副作用而没有任何好处。
手性化合物不同效应的一个具体例子是扑热息痛,这种药物在 20 世纪 50 年代和 60 年代被开出作为镇静剂。这种药物后来作为治疗与怀孕相关的恶心和晨吐的非处方药出售。扑热息痛的 R 型是有效的镇静剂,而 S 型是致畸的,已被证明会导致严重的先天缺陷。这些困难进一步加剧了扑热息痛在体内两种不同形式之间的相互转化或消旋。
对分子进行特征化
有了这些基本化学描述,我们如何开始对分子进行特征化呢?为了对分子进行机器学习,我们需要将它们转换为可以用作模型输入的特征向量。在本节中,我们将讨论 DeepChem 特征化子模块dc.feat,并解释如何使用它以各种方式对分子进行特征化。
SMILES 字符串和 RDKit
SMILES 是一种用文本字符串指定分子的流行方法。该首字母缩略词代表“简化分子输入线条系统”,这个名字听起来相当别扭,肯定有人费了很大劲才想出来。SMILES 字符串以一种既简洁又相对直观的方式描述了分子的原子和键,对化学家来说很直观。对非化学家来说,这些字符串往往看起来像是毫无意义的随机字符模式。例如,“OCCc1c©n+Cc2cnc©nc2N”描述了重要的营养素硫胺素,也被称为维生素 B1。
DeepChem 使用 SMILES 字符串作为其数据集中表示分子的格式。有一些深度学习模型直接接受 SMILES 字符串作为输入,试图学习识别文本表示中的有意义特征。但更常见的情况是,我们首先将字符串转换为适合手头问题的不同表示形式(或特征化)。
DeepChem 依赖于另一个开源化学信息学软件包 RDKit,以便处理分子。RDKit 提供了许多功能,用于处理 SMILES 字符串。它在将数据集中的字符串转换为分子图和下面描述的其他表示形式中起着核心作用。
扩展连接指纹
化学指纹是由 1 和 0 组成的向量,表示分子中特定特征的存在或缺失。扩展连接性指纹(ECFPs)是一类结合了几个有用特征的特征化。它们将任意大小的分子转换为固定长度的向量。这很重要,因为许多模型要求它们的输入具有完全相同的大小。ECFPs 让您可以使用具有许多不同大小的分子的相同模型。ECFPs 也非常容易比较。您只需取两个分子的指纹并比较相应元素。匹配的元素越多,分子越相似。最后,ECFPs 计算速度很快。
指纹向量的每个元素表示特定分子特征的存在或缺失,由原子的某种局部排列定义。算法首先独立考虑每个原子,并查看原子的一些属性:其元素,形成的共价键数等。这些属性的每种独特组合都是一个特征,相应的向量元素设置为 1 以表示其存在。然后算法向外工作,将每个原子与其所有键合的原子结合。这定义了一组更大的特征,并设置了相应的向量元素。这种技术的最常见变体是 ECFP4 算法,允许子片段在中心原子周围有两个键的半径。
RDKit 库提供了计算 ECFP4 指纹的工具函数。DeepChem 提供了这些函数的便捷封装。dc.feat.CircularFingerprint类继承自Featurizer,并提供了对分子进行特征化的标准接口:
smiles = ['C1CCCCC1', 'O1CCOCC1'] # cyclohexane and dioxane
mols = [Chem.MolFromSmiles(smile) for smile in smiles]
feat = dc.feat.CircularFingerprint(size=1024)
arr = feat.featurize(mols)
# arr is a 2-by-1024 array containing the fingerprints for
# the two molecules
ECFPs 确实有一个重要的缺点:指纹编码了大量关于分子的信息,但也会丢失一些信息。两种不同的分子可能具有相同的指纹,而且给定一个指纹,不可能唯一确定它来自哪个分子。
分子描述符
另一种思路认为,用一组物理化学描述符描述分子是有用的。这些通常对应于描述分子结构的各种计算量。这些量,如对数分配系数或极性表面积,通常是从经典物理学或化学中导出的。RDKit 软件包在分子上计算了许多这样的物理描述符。DeepChem 的特征化器dc.feat.RDKitDescriptors()提供了执行相同计算的简单方法:
feat = dc.feat.RDKitDescriptors()
arr = feat.featurize(mols)
# arr is a 2-by-111 array containing properties of the
# two molecules
这种特征化对于某些问题显然更有用。它通常最适合用于预测依赖于分子相对通用性质的事物。它不太可能用于预测依赖于原子详细排列的性质。
图卷积
前一节中描述的特征化是由人类设计的。专家仔细考虑了如何以可用作机器学习模型输入的方式表示分子,然后手动编码了表示。我们是否可以让模型自己找出最佳的分子表示方式呢?这正是机器学习的全部意义:我们可以尝试从数据中自动学习特征化,而不是自己设计特征化。
作为类比,考虑图像识别的卷积神经网络。网络的输入是原始图像。它由每个像素的数字向量组成,例如三个颜色分量。这是图像的一个非常简单、完全通用的表示。第一个卷积层学习识别简单的模式,比如垂直或水平线。它的输出再次是每个像素的数字向量,但现在以更抽象的方式表示。每个数字代表某些局部几何特征的存在。
网络通过一系列层继续。每一层输出图像的新表示,比前一层的表示更抽象,与原始颜色分量的联系更少。这些表示是从数据中自动学习的,而不是由人类设计的。没有人告诉模型要寻找什么模式来识别图像中是否包含猫。模型通过训练自己找出这一点。
图卷积网络采用相同的思想,并将其应用于图形。正如常规 CNN 从每个像素的数字向量开始,图卷积网络从每个节点和/或边的数字向量开始。当图表示一个分子时,这些数字可以是每个原子的高级化学性质,比如其元素、电荷和杂化状态。正如常规卷积层根据其输入的局部区域计算每个像素的新向量一样,图卷积层根据每个节点和/或边计算一个新向量。输出是通过将学习的卷积核应用于图的每个局部区域来计算的,其中“局部”现在是根据节点之间的边来定义的。例如,它可能根据同一原子的输入向量和直接键合到的任何其他原子的输入向量为每个原子计算一个输出向量。
这就是一般的想法。当涉及到细节时,许多不同的变体已经被提出。幸运的是,DeepChem 包括了许多这些架构的实现,所以即使不理解所有细节,你也可以尝试它们。示例包括图卷积(GraphConvModel)、编织模型(WeaveModel)、消息传递神经网络(MPNNModel)、深度张量神经网络(DTNNModel)等。
图卷积网络是分析分子的强大工具,但它们有一个重要的限制:计算仅基于分子图。它们不接收有关分子构象的信息,因此它们无法希望预测任何依赖构象的东西。这使它们最适合于小型、大部分刚性的分子。在下一章中,我们将讨论更适用于可以呈现许多构象的大型、灵活分子的方法。
训练模型以预测溶解度
让我们把所有的部分放在一起,在真实的化学数据集上训练一个模型,以预测一个重要的分子性质。首先我们将加载数据:
tasks, datasets, transformers = dc.molnet.load_delaney(featurizer='GraphConv')
train_dataset, valid_dataset, test_dataset = datasets
这个数据集包含有关溶解度的信息,这是衡量分子在水中溶解程度的指标。这个性质对于任何希望用作药物的化学物质都非常重要。如果它不容易溶解,将足够量的化合物注入患者的血液以产生治疗效果可能是不可能的。药物化学家花费大量时间修改分子,试图增加它们的溶解度。
请注意,我们指定了选项featurizer='GraphConv'。我们将使用图卷积模型,这告诉 MoleculeNet 将每个分子的 SMILES 字符串转换为模型所需的格式。
现在让我们构建并训练模型:
model = GraphConvModel(n_tasks=1, mode='regression', dropout=0.2)
model.fit(train_dataset, nb_epoch=100)
我们指定只有一个任务,也就是说,每个样本只有一个输出值(溶解度)。我们还指定这是一个回归模型,意味着标签是连续的数字,模型应尽可能准确地复制它们。这与分类模型相反,分类模型试图预测每个样本属于固定类别中的哪一个。为了减少过拟合,我们指定了一个 0.2 的丢弃率,意味着每个卷积层的输出的 20%将随机设置为 0。
就是这样!现在我们可以评估模型,看看它的表现如何。我们将使用皮尔逊相关系数作为我们的评估指标:
metric = dc.metrics.Metric(dc.metrics.pearson_r2_score)
print(model.evaluate(train_dataset, [metric], transformers))
print(model.evaluate(test_dataset, [metric], transformers))
这报告了训练集的相关系数为 0.95,测试集为 0.83。显然有点过拟合,但不是太严重。相关系数为 0.83 是相当可观的。我们的模型成功地根据分子结构预测了分子的溶解度!
现在我们有了模型,我们可以用它来预测新分子的溶解度。假设我们对以下五种分子感兴趣,以 SMILES 字符串指定:
smiles = ['COC(C)(C)CCCC(C)CC=CC(C)=CC(=O)OC(C)C',
'CCOC(=O)CC',
'CSc1nc(NC(C)C)nc(NC(C)C)n1',
'CC(C#C)N(C)C(=O)Nc1ccc(Cl)cc1',
'Cc1cc2ccccc2cc1C']
要将这些作为模型的输入,我们必须首先使用 RDKit 解析 SMILES 字符串,然后使用 DeepChem 特征化器将其转换为图卷积所期望的格式:
from rdkit import Chem
mols = [Chem.MolFromSmiles(s) for s in smiles]
featurizer = dc.feat.ConvMolFeaturizer()
x = featurizer.featurize(mols)
现在我们可以将它们传递给模型,并要求它预测它们的溶解度:
predicted_solubility = model.predict_on_batch(x)
MoleculeNet
我们现在已经看到从molnet模块加载的两个数据集:上一章的 Tox21 毒性数据集,以及本章的 Delaney 溶解度数据集。MoleculeNet 是一个大型的数据集合,对于分子机器学习非常有用。如图 4-10 所示,它包含许多种分子属性的数据。这些属性从可以用量子力学计算的低级物理属性到与人体相互作用的非常高级信息,如毒性和副作用。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0410.png
图 4-10。MoleculeNet 托管许多不同的数据集,来自不同的分子科学。科学家们发现预测分子的量子、物理化学、生物物理和生理特性非常有用。
在开发新的机器学习方法时,您可以使用 MoleculeNet 作为一组标准基准来测试您的方法。在*moleculenet.ai*上,您可以查看一组标准模型在每个数据集上的表现数据,从而了解您的方法与已建立技术相比如何。
SMARTS 字符串
在许多常用的应用程序中,例如文字处理,我们需要搜索特定的文本字符串。在化学信息学中,我们遇到类似的情况,我们想确定分子中的原子是否与特定模式匹配。有许多可能出现这种情况的用例:
-
搜索包含特定亚结构的分子的数据库
-
将一组分子对齐在一个共同的亚结构上以改善可视化
-
在图中突出显示一个亚结构
-
在计算过程中约束一个亚结构
SMARTS 是先前描述的 SMILES 语言的扩展,可用于创建查询。人们可以将 SMARTS 模式视为用于搜索文本的正则表达式。例如,在搜索文件系统时,可以指定类似于“foo*.bar”的查询,这将匹配 foo.bar、foo3.bar 和 foolish.bar。在最简单的级别上,任何 SMILES 字符串也可以是 SMARTS 字符串。SMILES 字符串“CCC”也是一个有效的 SMARTS 字符串,将匹配三个相邻脂肪碳原子的序列。让我们看一个代码示例,展示如何从 SMILES 字符串定义分子,显示这些分子,并突出显示与 SMARTS 模式匹配的原子。
首先,我们将导入必要的库并从一组 SMILES 字符串中创建一个分子列表。图 4-11 显示了结果:
from rdkit import Chem
from rdkit.Chem.Draw import MolsToGridImage
smiles_list = ["CCCCC","CCOCC","CCNCC","CCSCC"]
mol_list = [Chem.MolFromSmiles(x) for x in smiles_list]
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0411.png
图 4-11。从 SMILES 生成的化学结构
现在我们可以看到哪些 SMILES 字符串与 SMARTS 模式“CCC”匹配(参见图 4-12):
query = Chem.MolFromSmarts("CCC")
match_list = [mol.GetSubstructMatch(query) for mol in
mol_list]
MolsToGridImage(mols=mol_list, molsPerRow=4,
highlightAtomLists=match_list)
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0412.png
图 4-12。与 SMARTS 表达式“CCC”匹配的分子。
在这张图中有几点需要注意。首先是 SMARTS 表达式只匹配第一个结构。其他结构不包含三个相邻的碳。还要注意,SMARTS 模式可以以多种方式匹配此图中的第一个分子——它可以从第一个、第二或第三个碳原子开始匹配三个相邻的碳原子。RDKit 中还有其他函数可以返回所有可能的 SMARTS 匹配,但我们现在不会涵盖这些内容。
可以使用额外的通配符字符来匹配特定的原子集。与文本一样,“”字符可用于匹配任何原子。SMARTS 模式“CC”将匹配一个连接到另一个脂肪碳的脂肪碳(参见图 4-13)。
query = Chem.MolFromSmarts("C*C")
match_list = [mol.GetSubstructMatch(query) for mol in
mol_list]
MolsToGridImage(mols=mol_list, molsPerRow=4,
highlightAtomLists=match_list)
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0413.png
图 4-13。与 SMARTS 表达式“C*C”匹配的分子。
SMARTS 语法可以扩展为仅允许特定的原子集。例如,字符串“C[C,O,N]C”将匹配连接到另一个碳原子的碳、氧或氮原子(参见图 4-14):
query = Chem.MolFromSmarts("C[C,N,O]C")
match_list = [mol.GetSubstructMatch(query) for mol in
mol_list]
MolsToGridImage(mols=mol_list, molsPerRow=4,
highlightAtomLists=match_list)
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0414.png
图 4-14。与 SMARTS 表达式“C[C,N,O]C”匹配的分子。
SMARTS 还有很多内容超出了这个简短介绍的范围。建议感兴趣的读者阅读“Daylight Theory Manual”以深入了解 SMILES 和 SMARTS。¹ 正如我们将在第十一章中看到的,SMARTS 可以用于构建复杂的查询,以识别在生物测定中可能存在问题的分子。
结论
在这一章中,您已经学习了分子机器学习的基础知识。在简要回顾基础化学知识之后,我们探讨了分子在计算系统中传统的表示方法。您还学习了图卷积,这是一种在深度学习中对分子建模的较新方法,并看到了如何使用机器学习来预测重要物理性质的完整工作示例。这些技术将成为后续章节构建的基础。
¹ Daylight Chemical Information Systems, Inc. “Daylight Theory Manual.” http://www.daylight.com/dayhtml/doc/theory/. 2011.
第五章:生物物理机器学习
在本章中,我们将探讨如何使用深度学习来理解生物物理系统。特别是,我们将深入探讨如何预测类似药物的小分子如何与人体中感兴趣的蛋白质结合。
这个问题在药物发现中具有基本的兴趣。以有针对性的方式调节单个蛋白质往往可以产生显著的治疗效果。例如,突破性的癌症药物伊马替尼紧密结合 BCR-ABL,这也是其有效性的原因之一。对于其他疾病,要找到具有相同疗效的单个蛋白质靶标可能是具有挑战性的,但抽象概念仍然是有用的。在人体中有很多机制在起作用,找到一个有效的心理模型可能是至关重要的。
药物不仅仅靶向单个蛋白质
正如我们讨论过的,将为疾病设计药物的问题简化为设计与给定蛋白质紧密相互作用的药物的问题可能非常有用。但非常重要的是要意识到,实际上,任何给定的药物都将与人体中许多不同的子系统相互作用。研究这种多方面的相互作用被广泛称为多药效学。
目前,处理多药效学的计算方法仍然相对不发达,因此测试多药效的黄金标准仍然是动物和人体实验。随着计算技术的成熟,这种情况可能会在未来几年发生变化。
因此,我们的目标是设计能够有效预测给定分子何时与给定蛋白质相互作用的学习算法。我们如何做到这一点呢?首先,我们可以借鉴上一章关于分子机器学习的一些技术,尝试创建一个特定于蛋白质的模型。这样一个模型将会在给定一组分子(无论是否与给定蛋白质结合)的数据集的情况下,学习预测新分子是否会结合。这个想法实际上并不糟糕,但需要大量的数据来适应当前系统。理想情况下,我们希望有一种算法,可以在没有大量数据的情况下为新蛋白质工作。
事实证明,关键在于利用蛋白质的物理特性。正如我们将在下一节中讨论的那样,关于蛋白质分子的物理结构已经有了相当多的了解。特别是,可以使用现代实验技术创建蛋白质的 3D 状态的快照。这些 3D 快照可以输入学习算法中,并用于预测结合。还可以拍摄蛋白质与较小分子(通常称为配体)相互作用的快照。如果您现在觉得这个讨论很抽象,不用担心。在本章中,您将看到大量实用的代码。
我们将从更深入地概述蛋白质及其在生物学中的功能开始这一章。然后我们将转向计算机科学,并介绍一些用于将蛋白质系统特征化的算法,这些算法可以将生物物理系统转化为向量或张量以供学习使用。在本章的最后部分,我们将通过一个深入的案例研究来构建蛋白质-配体结合相互作用模型。为了进行实验,我们将介绍包含一系列实验确定的蛋白质-配体结构的 PDBBind 数据集。我们将演示如何使用 DeepChem 对这个数据集进行特征化。然后我们将在这些特征化的数据集上构建一些模型,包括深度模型和简单模型,并研究它们的性能。
为什么叫生物物理学?
人们常说,所有生物学都基于化学,所有化学都基于物理。乍一看,生物学和物理学可能看起来相距甚远。但正如我们将在本章后面更详细地讨论的那样,物理定律是所有生物机制的核心。此外,蛋白质结构的研究很大程度上取决于在物理学中精细改进的实验技术的使用。操纵纳米尺度的机器(因为蛋白质实际上就是这样)需要在理论和实践方面具有相当的物理复杂性。
有趣的是,我们将在本章讨论的深度学习算法与用于研究粒子物理系统或物理模拟的深度学习架构存在显著相似之处。这些主题超出了本书的范围,但我们鼓励感兴趣的读者进一步探索。
蛋白质结构
蛋白质是细胞中完成大部分工作的微型机器。尽管它们体积很小,但它们可能非常复杂。典型的蛋白质由数千个以精确方式排列的原子组成。
要理解任何机器,您必须知道它由哪些部分组成以及它们是如何组装在一起的。在了解汽车有底部的车轮、中间的空间用于搭载乘客以及乘客可以进出的门之前,您无法希望理解汽车。蛋白质也是如此。要理解它的工作原理,您必须确切地知道它是如何组装的。
此外,您需要知道它如何与其他分子相互作用。很少有机器是孤立运行的。汽车与搭载的乘客、行驶的道路以及使其移动的能源相互作用。这也适用于大多数蛋白质。它们作用于分子(例如,催化化学反应),被其他分子作用(例如,调节其活性),并从其他分子中吸取能量。所有这些相互作用取决于两个分子中原子的具体位置。要理解它们,您必须知道原子在三维空间中的排列方式。
不幸的是,您不能只是用显微镜观察蛋白质;它们太小了。相反,科学家们不得不发明复杂而巧妙的方法来确定蛋白质的结构。目前有三种这样的方法:X 射线晶体学、核磁共振(简称 NMR)和冷冻电子显微镜(简称 cryo-EM)。
X 射线晶体学是最古老的方法,仍然是最广泛使用的方法。大约 90%已知的蛋白质结构是通过这种方法确定的。晶体学涉及生长感兴趣蛋白质的晶体(许多蛋白质分子紧密堆积在一起形成规律重复的图案)。然后在晶体上照射 X 射线,测量散射光,然后分析结果以确定单个分子的结构。尽管这种方法取得了成功,但它有许多限制。即使在最好的情况下,它也是缓慢且昂贵的。许多蛋白质无法形成晶体,使晶体学成为不可能。将蛋白质包装成晶体可能会改变其结构,因此结果可能与其在活细胞中的结构不同。许多蛋白质是灵活的,可以采取一系列结构,但晶体学只产生一个静止的快照。但即使有这些限制,它仍然是一个非常强大和重要的工具。
核磁共振是第二常见的方法。它作用于溶液中的蛋白质,因此无需生长晶体。这使得它成为无法结晶的蛋白质的重要替代方法。与产生单个固定快照的晶体学不同,核磁共振产生代表蛋白质在溶液中可能呈现的形状范围的结构集合。这是一个非常重要的好处,因为它提供了有关蛋白质如何移动的信息。不幸的是,核磁共振也有其局限性。它需要高浓度的溶液,因此主要限于小型、高溶解性的蛋白质。
近年来,冷冻电镜已经成为确定蛋白质结构的第三种选择。它涉及迅速冷冻蛋白质分子,然后用电子显微镜对其进行成像。每个图像的分辨率远远不足以看清精确的细节;但通过结合许多不同的图像,可以产生一个最终结构,其分辨率比任何单个电子显微镜图像都要高得多。经过几十年对方法和技术的稳步改进,冷冻电镜终于开始接近原子分辨率。与晶体学和核磁共振不同,它适用于无法结晶的大型蛋白质。这可能使其成为未来几年中非常重要的技术。
蛋白质数据银行(PDB)是已知蛋白质结构的主要存储库。目前,它包含超过 142,000 个结构,如图 5-1 中的结构。这可能看起来很多,但远远不及我们真正想要的。已知蛋白质的数量是数量级更大的,而且每时每刻都在发现更多。对于您想研究的任何蛋白质,很有可能其结构仍然未知。而且您确实希望每种蛋白质有多个结构,而不仅仅是一个。许多蛋白质可以存在于多种功能上不同的状态(例如,“活跃”和“非活跃”状态),因此您希望了解每种状态的结构。如果蛋白质与其他分子结合,您希望有一个单独的结构,其中蛋白质与每个分子结合,以便您可以准确地看到它们如何结合。PDB 是一个很棒的资源,但整个领域仍处于“低数据”阶段。我们拥有的数据远远不及我们想要的,一个主要挑战是弄清如何充分利用我们所拥有的数据。这可能会持续几十年。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0501.png
图 5-1。来自炭疽芽孢杆菌的 CapD 蛋白的晶体结构,炭疽病原体。确定细菌蛋白质的结构可以成为抗生素设计的有力工具。更一般地说,确定与治疗相关的蛋白质的结构是现代药物发现的关键步骤之一。
蛋白质序列
到目前为止,在本章中,我们主要讨论了蛋白质的结构,但我们还没有详细说明蛋白质在原子层面上由什么构成。蛋白质是由称为氨基酸的基本构建块构建而成。这些氨基酸是一组共享共同核心的分子,但具有不同的“侧链”附着(图 5-2)。这些不同的侧链改变了蛋白质的行为。
蛋白质是一条氨基酸链,一个接一个地连接在一起(图 5-3)。氨基酸链的起始部分通常被称为 N-末端,而链的末端被称为 C-末端。小的氨基酸链通常被称为肽,而较长的链被称为蛋白质。肽太小,无法具有复杂的三维结构,但蛋白质的结构可以非常复杂。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0502.png
图 5-2。氨基酸是蛋白质结构的构建块。这张图表示了一些常见氨基酸的化学结构。(改编自维基媒体。)
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0503.png
图 5-3。一个由四个氨基酸组成的链,N-末端在左侧,C-末端在右侧。(来源:维基百科。)
值得注意的是,虽然大多数蛋白质具有刚性形状,但也有固有无序蛋白质,其区域不愿采取刚性形状(图 5-4)。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0504.png
图 5-4。SUMO-1 蛋白的快照。蛋白质的中心核心具有结构,而 N-末端和 C-末端区域是无序的。像 SUMO-1 这样的固有无序蛋白质在计算上是具有挑战性的。
在本章的其余部分,我们将主要讨论具有刚性、三维形状的蛋白质。处理没有固定形状的松散结构对现代计算技术仍然是具有挑战性的。
我们不能通过计算来预测三维蛋白质结构吗?
阅读本节后,您可能会想知道为什么我们不直接使用算法来预测有趣的蛋白质分子的结构,而是依赖复杂的物理实验。这是一个很好的问题,实际上已经有几十年的关于计算预测蛋白质结构的工作。
预测蛋白质结构有两种主要方法。第一种被称为同源建模。蛋白质序列和结构是亿万年演化的产物。如果两个蛋白质是近亲(技术术语是“同源物”),它们可能具有相似的结构。通过同源建模预测蛋白质的结构,您首先寻找一个结构已知的同源物,然后根据两种蛋白质序列之间的差异进行调整。同源建模对于确定蛋白质的整体形状效果还不错,但通常会出现细节错误。当然,这要求您已经知道一个同源蛋白质的结构。
另一种主要方法是物理建模。利用物理定律的知识,您尝试探索蛋白质可能采取的许多不同构象,并预测哪种构象最稳定。这种方法需要大量的计算时间。直到大约十年前,这是不可能的。即使在今天,它也只适用于小型、快速折叠的蛋白质。此外,它需要物理近似来加快计算速度,这些近似会降低结果的准确性。物理建模通常会预测正确的结构,但并非总是如此。
蛋白质结合简介
到目前为止,本章我们已经讨论了大量关于蛋白质结构的内容,但我们并没有多说蛋白质如何与其他分子相互作用。在实践中,蛋白质通常与小分子结合。有时,这种结合行为对蛋白质的功能至关重要:给定蛋白质的主要作用可能涉及与特定分子的结合。例如,细胞中的信号传导通常通过蛋白质与另一种分子结合的机制传递信息。有时,结合到蛋白质的分子是外来的:可能是我们创造的用于操纵蛋白质的药物,可能是干扰其功能的毒素。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0505.png
图 5-5. 通过嵌入在细胞膜中的蛋白质传导的信号。(来源:维基百科。)
了解分子如何、何时、何地与蛋白质结合对于理解它们的功能并开发药物至关重要。如果我们能够利用人体细胞的信号传导机制,我们就可以在人体中引发期望的医学反应。
蛋白质结合涉及许多非常特定的相互作用,这使得计算预测变得困难。仅仅几个原子位置的微小变化就可以决定分子是否与蛋白质结合。此外,许多蛋白质是灵活的,不断移动。蛋白质可能在特定构象时能够结合分子,但在其他构象时则不能。结合反过来可能导致蛋白质构象的进一步变化,从而影响其功能。
在本章的其余部分,我们将以理解蛋白质结合的挑战作为激励计算的示例。我们将深入探讨当前深度学习和机器学习方法,以预测结合事件。
生物物理特征化
正如我们在上一章中讨论的那样,将机器学习应用于新领域的关键步骤之一是找出如何将训练数据转换(或特征化)为适合学习算法的格式。我们已经讨论了许多特征化单个小分子的技术。也许我们可以将这些技术调整为在生物物理系统中使用?
不幸的是,生物物理系统的行为受到它们的 3D 结构的严格限制,因此前几章的 2D 技术缺少关键信息。因此,我们将在本章讨论一对新的特征化技术。第一种特征化技术,网格特征化,明确搜索 3D 结构中关键物理相互作用的存在,例如氢键和盐桥(稍后会详细介绍),这些相互作用已知在决定蛋白质结构中起重要作用。这种技术的优势在于我们可以依赖大量关于蛋白质物理的已知事实。当然,弱点在于我们受到已知物理的约束,减少了我们的算法能够检测新物理的机会。
另一种特征化技术是原子特征化,它简单地提供了系统中所有原子的 3D 位置和身份的处理表示。这使得学习算法的挑战变得更加困难,因为它必须学会识别关键的物理相互作用,但也使得学习算法能够检测到有趣行为的新模式。
PDB 文件及其缺陷
蛋白质结构通常存储在 PDB 文件中。这些文件只是包含结构中原子描述及其相对于彼此的坐标空间位置的文本文件。特征化算法通常依赖于读取 PDB 文件并将其存储到内存数据结构中的库。到目前为止一切顺利,对吧?
不幸的是,PDB 文件经常存在格式错误。原因在于底层物理学。通常,实验无法提供足够的分辨率来完全指定蛋白质结构的某个部分。这些区域在 PDB 文件中未指定,因此很常见地发现许多原子甚至整个蛋白质的亚结构缺失在核心结构中。
DeepChem 等库通常会尝试做“正确”的事情,并通过算法填补这些缺失区域。重要的是要注意,这种清理只是近似的,仍然没有完全令人满意的替代方案,即让专业人员在蛋白质结构(在适当的查看程序中)上查找问题。希望在未来几年内,处理这些错误的软件工具将得到改进,对专家指导的需求将减少。
网格特征化
通过将生物物理结构转换为向量,我们可以使用机器学习算法对其进行预测。可以想象,为处理蛋白质-配体系统而设计特征化算法将是有用的。然而,设计这样的算法是相当困难的。理想情况下,特征化技术需要在设计中将这些系统的化学知识融入其中,以便提取有用的特征。
这些特征可能包括蛋白质和配体之间的非共价键的计数,例如氢键或其他相互作用。(大多数蛋白质-配体系统之间没有蛋白质和配体之间的共价键。)
幸运的是,DeepChem 有这样一个可用的特征化器。其RdkitGridFeaturizer将一组相关的化学信息总结为一个简短的向量,用于学习算法。虽然不必深入了解底层科学就能使用特征化器,但了解底层物理学仍然是有用的。因此,在我们深入描述网格特征化器计算之前,我们将首先回顾一些有关大分子复合物的相关生物物理学。
在阅读本节时,可能有必要回顾前一章中关于基本化学相互作用的讨论。共价键和非共价键等概念将经常出现。
网格特征化器在给定结构中搜索这种化学相互作用的存在,并构建一个包含这些相互作用计数的特征向量。我们将在本章后面更详细地介绍这是如何通过算法完成的。
氢键
当氢原子与氧或氮等更电负原子共价键合时,共享电子大部分时间都靠近更电负的原子。这使得氢带有净正电荷。如果这个带正电的氢接近另一个带有净负电荷的原子,它们会相互吸引。这就是氢键(图 5-6)。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0506.png
图 5-6。氢键的渲染示例。氧上的过剩负电荷与氢上的过剩正电荷相互作用,形成键合作用。(来源:Wikimedia。)
由于氢原子非常小,它们可以非常靠近其他原子,导致强烈的静电吸引力。这使得氢键成为最强的非共价相互作用之一。它们是一种通常稳定分子系统的关键相互作用形式。例如,水独特的性质很大程度上归因于水分子之间形成的氢键网络。
RdkitGridFeaturizer尝试通过检查适当接近的蛋白质/配体原子对来计算结构中存在的氢键。这需要对距离应用一个截断,这在某种程度上是任意的。实际上,原子之间不存在明确的成键和非成键之间的分界线。这可能导致一些被错误识别的相互作用,但经验上,简单的截断通常效果还不错。
盐桥
盐桥是两个氨基酸之间的一种非共价吸引力,其中一个带有正电荷,另一个带有负电荷(见图 5-7)。它结合了离子键和氢键。尽管这些键相对较弱,但它们可以通过在蛋白质序列中远距离的氨基酸之间提供相互作用来帮助稳定蛋白质的结构。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0507.png
图 5-7。谷氨酸和赖氨酸之间盐桥的插图。盐桥是一种离子式静电相互作用和氢键的组合,用于稳定结构。(来源:Wikimedia。)
网格特征化器尝试通过明确检查已知形成这种相互作用的氨基酸对(如谷氨酸和赖氨酸),并且在蛋白质的三维结构中处于密切物理接近的位置来检测盐桥。
Pi-堆叠相互作用
Pi-堆叠相互作用是芳香环之间的一种非共价相互作用(图 5-8)。这些是平坦的、环形的结构,出现在许多生物分子中,包括 DNA 和 RNA。它们还出现在一些氨基酸的侧链中,包括苯丙氨酸、酪氨酸和色氨酸。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0508.png
图 5-8。苯分子中的芳香环。这种环结构以其异常稳定性而闻名。此外,芳香环中的所有原子都位于同一平面上。相比之下,非同质环的原子并不在同一平面上。
粗略地说,pi-堆叠相互作用发生在两个芳香环“堆叠”在一起时。图 5-9 显示了两个苯环可以相互作用的一些方式。这种堆叠相互作用,就像盐桥一样,可以帮助稳定各种大分子结构。重要的是,pi-堆叠相互作用可以在配体-蛋白相互作用中找到,因为芳香环通常出现在小分子中。网格特征化器通过检测芳香环的存在并检查它们的质心之间的距离和两个平面之间的角度来计算这些相互作用。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0509.png
图 5-9。各种非共价芳香环相互作用。在位移相互作用中,两个芳香环的中心略微偏离彼此。在边对面相互作用中,一个芳香环的边叠在另一个的面上。夹心结构有两个环直接叠放,但比位移或边对面相互作用的能量更不利,因为相同电荷的区域会紧密相互作用。
此时,您可能想知道为什么这种类型的相互作用被称为π-堆叠。这个名字指的是π键,一种共价化学键的形式,其中两个共价键合原子的电子轨道重叠。在芳香环中,环中的所有原子都参与了一个共同的π键。这种共同键解释了芳香环的稳定性,并且还解释了它的许多独特化学性质。
对于那些不是化学家的读者,如果这些材料目前还不太明白,不要担心太多。DeepChem 抽象了许多这些实现细节,因此在开发时不需要经常担心π-堆叠。然而,了解这些相互作用的存在并在基础化学中发挥重要作用是有用的。
复杂的几何结构和快照
在这一部分,我们介绍了许多关于静态几何配置的相互作用。非常重要的是要意识到键是动态实体,在真实的物理系统中,键会以令人眼花缭乱的速度伸展、断裂、破裂和重组。请记住,当有人说盐桥存在时,他们真正的意思是在某种统计平均意义上,盐桥在特定位置很可能经常存在。
指纹
从前一章,您可能还记得使用圆形指纹。这些指纹计算分子中给定类型的片段数量,然后使用哈希函数将这些片段计数适应到固定长度的向量中。这种片段计数也可以用于 3D 分子复合物。尽管仅仅计算片段通常不足以计算系统的几何结构,但已知存在的片段的知识对机器学习系统仍然有用。这可能是因为某些片段的存在可以强烈表明某些分子事件。
一些实现细节
要搜索化学特征,如氢键,dc.feat.RdkitGridFeaturizer需要能够有效地处理分子的几何结构。DeepChem 使用 RDKit 库将每个分子、蛋白质和配体加载到一个共同的内存对象中。然后,这些分子被转换为包含空间中所有原子位置的 NumPy 数组。例如,一个具有N个原子的分子可以表示为形状为(*N*, 3)的 NumPy 数组,其中每行表示 3D 空间中一个原子的位置。
然后,进行(粗略的)氢键检测只需要查看所有可能形成氢键(如氧和氢)的原子对,这些原子彼此之间足够接近。检测其他类型的键也使用相同的计算策略。对于处理芳香结构,有一些特殊代码来检测结构中芳香环的存在并计算它们的质心。
原子特征化
在上一节的结尾,我们简要概述了RdkitGridFeaturizer如何计算氢键等特征。大多数操作将具有N个原子的分子转换为形状为(*N*, 3)的 NumPy 数组,然后从这些数组开始执行各种额外的计算。
您可以轻松想象,为给定分子进行特征化可能只涉及计算这个(*N*, 3)数组并将其传递给适当的机器学习算法。然后,模型可以自行学习哪些特征是重要的,而不是依赖人类选择并手动编码它们。
事实上,这是可以实现的,只需多做几个步骤。(*N*, 3)位置数组不区分原子类型,因此您还需要提供另一个数组,列出每个原子的原子序数。作为第二个实现驱动的注意事项,计算形状为(*N*, 3)的两个位置数组之间的成对距离可能非常耗费计算资源。在预处理步骤中创建“邻居列表”是有用的,其中邻居列表维护了靠近任何给定原子的邻近原子的列表。
DeepChem 提供了一个dc.feat.ComplexNeighborListFragmentAtomicCoordinates特征化器,可以为您处理其中的大部分内容。我们不会在本章进一步讨论它,但知道它作为另一个选择是很好的。
PDBBind 案例研究
有了这个介绍,让我们开始尝试处理生物物理数据集的一些代码示例。我们将首先介绍 PDBBind 数据集和结合自由能预测问题。然后,我们将提供如何对 PDBBind 数据集进行特征化的代码示例,并演示如何为其构建机器学习模型。我们将以讨论如何评估结果结束案例研究。
PDBBind 数据集
PDBBind 数据集包含大量生物分子晶体结构及其结合亲和力。有一些术语,让我们停下来解释一下。生物分子是任何生物感兴趣的分子。这不仅包括蛋白质,还包括核酸(如 DNA 和 RNA)、脂质和较小的药物样分子。生物分子系统的丰富性很大程度上来自各种生物分子之间的相互作用(我们已经详细讨论过)。结合亲和力是两种分子形成复合物的实验测定亲和力,这两种分子相互作用。如果形成这样的复合物是能量有利的,那么分子将更多时间保持在这种构型中,而不是其他构型中。
PDBBind 数据集已经收集了许多生物分子复合物的结构。其中绝大多数是蛋白质-配体复合物,但数据集还包含蛋白质-蛋白质、蛋白质-核酸和核酸-配体复合物。对于我们的目的,我们将专注于蛋白质-配体子集。完整数据集包含近 15000 个这样的复合物,其中“精炼”和“核心”集合包含更小但更干净的复合物子集。每个复合物都附带了对该复合物的结合亲和力的实验测量。PDBBind 数据集的学习挑战是根据蛋白质-配体结构预测复合物的结合亲和力。
PDBBind 的数据是从蛋白质数据银行中收集的。请注意,PDB(因此 PDBBind)中的数据非常异质!不同的研究小组有不同的实验设置,不同小组进行的不同测量之间可能存在高实验方差。因此,我们将主要使用 PDBBind 数据集的经过筛选的精炼子集来进行我们的实验工作。
动态很重要!
在这个案例研究中,我们将蛋白质和配体视为一个冻结的快照。请注意,这是非常不符合物理规律的!蛋白质和配体实际上在快速运动,配体会在蛋白质的结合口中进出。此外,蛋白质甚至可能没有一个固定的结合口。对于一些蛋白质,可能有多个不同的位点与潜在的配体相互作用。
所有这些因素的组合意味着我们的模型的准确性将相对有限。如果我们有更多的数据,可能强大的学习模型可以学会考虑这些因素,但在数据集更有限的情况下,这是具有挑战性的。
您可能应该注意这些信息。设计更好的生物物理深度学习模型以准确考虑这些系统的热力学行为仍然是一个重要的未解问题。
如果您没有结构会怎么样?
药物发现的老手可能会在这里停顿一分钟。事实是,在实验上确定一个复杂结构要比测量结合亲和力更困难。这在直觉上是有道理的。结合亲和力是给定生物分子复合物的一个单一数字,而结构是一个丰富的三维快照。从结构预测结合亲和力可能感觉有点本末倒置!
对于这个(公平的)指责有几个答案。第一个是确定生物分子系统的结合亲和力是一个物理上有趣的问题。检查我们能否准确预测这种结合亲和力是一个值得的测试问题,可以用来评估我们的机器学习方法,并可以作为设计能够理解复杂生物物理系统的深度架构的基石。
第二个答案是,我们可以使用现有的计算工具,比如“对接”软件,来预测蛋白质-配体复合物的近似结构,只要我们有蛋白质的结构。虽然直接预测蛋白质结构是一个艰巨的挑战,但在已有蛋白质结构的情况下,预测蛋白质-配体复合物的结构就相对容易一些。因此,在这个案例研究中,通过将其与对接引擎配对,您可能能够使用我们将创建的系统进行有用的预测。事实上,DeepChem 支持这种用例,但在本章中我们不会深入探讨这一更高级的功能。
总的来说,在进行机器学习时,查看数据集中的单个数据点或文件可能特别有用。在与本书相关的代码存储库中,我们包含了一个名为 2D3U 的蛋白质-配体复合物的 PDB 文件。它包含有关蛋白质的氨基酸(也称为残基)的信息。此外,PDB 文件包含每个原子在三维空间中的坐标。这些坐标的单位是埃(1 埃等于 10 的负 10 次方米)。这个坐标系的原点是任意设置的,以帮助可视化蛋白质,并且通常设置在蛋白质的质心处。我们建议花一分钟时间在文本编辑器中打开这个文件并查看一下。
为什么氨基酸被称为残基?
当您花更多时间处理生物物理数据时,您将经常遇到将氨基酸称为“残基”的术语。这涉及到蛋白质形成的化学过程。当两个氨基酸在一个不断增长的链中连接在一起时,一个氧和两个氢被移除。在这个反应发生后,所谓的“残基”就是氨基酸剩余的部分。
理解 PDB 文件的内容可能非常困难,因此让我们可视化一个蛋白质。我们将使用NGLview可视化包,它与 Jupyter 笔记本很好地集成。在与本章相关的代码存储库中的笔记本中,您将能够操纵和与可视化的蛋白质进行交互。目前,图 5-10 显示了在 Jupyter 笔记本中生成的蛋白质-配体复合物(2D3U)的可视化。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0510.png
图 5-10。来自 PDBBind 数据集的 2D3U 蛋白质-配体复合物的可视化。请注意,为了方便可视化,蛋白质以卡通格式表示,而配体(靠近右上角)以球棒格式表示以获得完整细节。
请注意配体如何位于蛋白质的一种“口袋”中。通过旋转可视化以从不同角度观察,您可以更清楚地看到这一点。
蛋白质可视化工具
考虑到可视化蛋白质对于处理它们的重要性,有许多蛋白质可视化工具可供选择。虽然 NGLview 具有令人惊叹的 Jupyter 集成功能,但更常见的是看到其他工具,如VMD,PyMOL,或Chimera,被专业的药物发现者使用。然而,请注意,这些工具通常并非完全开源,并且可能没有开发人员友好的 API。尽管如此,如果您计划花费大量时间处理蛋白质结构,使用其中一个更成熟的工具可能仍然值得权衡。
对 PDBBind 数据集进行特征化
让我们从构建一个我们可以检查的RdkitGridFeaturizer对象开始:
import deepchem as dc
grid_featurizer = dc.feat.RdkitGridFeaturizer(
voxel_width=2.0,
feature_types=['hbond', 'salt_bridge', 'pi_stack',
'cation_pi', 'ecfp', 'splif'],
sanitize=True, flatten=True)
这里有许多选项,让我们暂停一下并考虑它们的含义。sanitize=True标志要求特征化器尝试清理给定的任何结构。回想一下我们之前讨论过的,结构经常存在错误。清理步骤将尝试修复它检测到的任何明显错误。设置flatten=True要求特征化器为每个输入结构输出一个一维特征向量。
feature_types标志设置了RdkitGridFeaturizer将尝试在输入结构中检测的生物物理和化学特征的类型。请注意,许多我们在本章前面讨论过的化学键的存在:氢键,盐桥等。最后,选项voxel_width=2.0将组成网格的体素的大小设置为 2 埃。RdkitGridFeaturizer将蛋白质转换为体素化表示,以用于提取有用的特征。对于每个空间体素,它计算生物物理特征,并计算一个局部指纹向量。RdkitGridFeaturizer计算两种不同类型的指纹,即 ECFP 和 SPLIF 指纹。
体素化
什么是体素化?广义上说,体素是像素的三维模拟(参见图 5-11)。正如图像的像素化表示对处理图像数据非常有用一样,体素化表示在处理 3D 数据时也非常关键。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0511.png
图 5-11。一个球的体素化表示。请注意每个体素代表一个输入的空间立方体。
我们现在准备加载 PDBBind 数据集。实际上,我们不需要使用刚刚定义的特征化器:MoleculeNet 会为我们处理。如果在加载数据集时包含标志featurizer="grid",它将自动执行网格特征化:
tasks, datasets, transformers = dc.molnet.load_pdbbind(
featurizer="grid", split="random", subset="core")
train_dataset, valid_dataset, test_dataset = datasets
通过这段代码片段,我们已经加载并对 PDBBind 的核心子集进行了特征化。在一台快速计算机上,这应该在 10 分钟内运行。在现代服务器上,对精炼子集进行特征化将需要几个小时。
现在我们已经掌握了数据,让我们开始构建一些机器学习模型。我们将首先训练一个称为随机森林的经典模型:
from sklearn.ensemble import RandomForestRegressor
sklearn_model = RandomForestRegressor(n_estimators=100)
model = dc.models.SklearnModel(sklearn_model)
model.fit(train_dataset)
作为替代方案,我们还将尝试构建一个用于预测蛋白质-配体结合的神经网络。我们可以使用dc.models.MultitaskRegressor类构建一个具有两个隐藏层的 MLP。我们将隐藏层的宽度分别设置为 2,000 和 1,000,并使用 50%的丢失率来减少过度拟合。
n_features = train_dataset.X.shape[1]
model = dc.models.MultitaskRegressor(
n_tasks=len(pdbbind_tasks),
n_features=n_features,
layer_sizes=[2000, 1000],
dropouts=0.5,
learning_rate=0.0003)
model.fit(train_dataset, nb_epoch=250)
基线模型
深度学习模型有时很难正确优化。即使是经验丰富的从业者在调整深度模型时也很容易出错。因此,构建一个更加稳健的基线模型至关重要,即使它可能表现较低。
随机森林是基线的非常有用选择。它们通常在学习任务中表现出色,而且调整量相对较小。随机森林分类器构建许多“决策树”分类器,每个分类器仅使用可用特征的随机子集,然后通过多数投票结合这些分类器的个别决策。
Scikit-learn 是一个无价的包,用于构建简单的机器学习基线。我们将在本章中使用 scikit-learn 构建一个基线模型,使用RdkitGridFeaturizer将复合物特征化为随机森林的输入。
现在我们有了一个经过训练的模型,我们可以继续检查其准确性。为了评估模型的准确性,我们必须首先定义一个合适的指标。让我们使用 Pearson R²分数。这是一个介于-1 和 1 之间的数字,其中 0 表示真实标签和预测标签之间没有相关性,1 表示完美相关性。
metric = dc.metrics.Metric(dc.metrics.pearson_r2_score)
现在让我们根据这个指标评估模型在训练和测试数据集上的准确性。执行此操作的代码在两个模型之间再次共享:
print("Evaluating model")
train_scores = model.evaluate(train_dataset, [metric], transformers)
test_scores = model.evaluate(test_dataset, [metric], transformers)
print("Train scores")
print(train_scores)
print("Test scores")
print(test_scores)
许多架构可能具有类似的效果
在本节中,我们提供了如何使用带有网格特征化的 MLP 来模拟 DeepChem 中的蛋白质-配体结构的代码示例。重要的是要注意,还有许多其他深度架构具有类似的效果。已经有一系列关于使用 3D 卷积网络来预测基于体素特征化的蛋白质-配体结合相互作用的工作。其他工作使用了我们在上一章中看到的图卷积的变体来处理大分子复合物。
这些架构之间有什么区别?到目前为止,大多数看起来具有类似的预测能力。我们使用网格特征化是因为 DeepChem 中有一个经过调整的实现,但其他模型也可能满足您的需求。未来版本的 DeepChem 可能会包括额外的架构来实现这一目的。
对于随机森林,这报告了训练集得分为 0.979,但测试集得分仅为 0.133。它在复制训练数据方面表现出色,但在预测测试数据方面表现非常糟糕。显然,它过度拟合得相当严重。
相比之下,神经网络的训练集得分为 0.990,测试集得分为 0.359。它在训练集上稍微表现更好,在测试集上表现更好。显然仍然存在过度拟合,但过度拟合的程度有所减少,模型预测新数据的整体能力更高。
了解相关系数是理解我们构建的模型的一个强大的第一步,但直接可视化我们的预测与实际实验数据的相关性总是有用的。图 5-12 显示了在测试集上运行时每个模型的真实与预测标签。我们立即看到神经网络的预测与真实数据的相关性要比随机森林的要更接近。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0512.png
图 5-12。在测试集上运行时两个模型的真实与预测标签。
结论
在本章中,您已经了解了将深度学习应用于生物物理系统,特别是解决预测蛋白质-配体系统结合亲和力的问题。您可能会好奇您学到的技能有多通用。您能否应用这些相同的模型和技术来理解其他生物物理数据集?让我们进行一个快速调查和浏览。
蛋白质-蛋白质和蛋白质-DNA 系统在高层次上遵循与蛋白质-配体系统相同的基本物理规律。相同的氢键,盐桥,π-堆积相互作用等起着关键作用。我们能否只是重复使用本章的代码来分析这些系统?答案是有点复杂的。驱动蛋白质-配体相互作用的许多物理相互作用是由带电动力驱动的。另一方面,蛋白质-蛋白质动力学可能更多地受到体积疏水相互作用的影响。我们不会深入探讨这些相互作用的含义,但它们在某种程度上在质性上与蛋白质-配体相互作用有所不同。这可能意味着RdkitGridFeaturizer可能无法很好地表征这些相互作用。另一方面,原子卷积模型可能更适合处理这些系统,因为这些深度模型中的物理相互作用的信息要少得多。
尽管如此,规模仍然存在一个重大问题。原子卷积模型训练速度相当慢,需要大量内存。将这些模型扩展到处理更大的蛋白质-蛋白质系统需要在工程端进行额外的工作。DeepChem 开发团队正在努力解决这些和其他挑战,但可能需要更多时间才能取得成果。
抗体-抗原相互作用是另一种关键的生物物理相互作用形式。抗体是 Y 形蛋白质(参见图 5-13),具有可变的“抗原结合位点”,用于结合抗原。在这里,抗原是与特定病原体相关的分子。在培养中生长的细胞可以被利用来产生针对特定抗原的抗体。如果培养中的所有细胞都是给定细胞的克隆体,那么产生的抗体将是相同的。这种“单克隆抗体”最近在广泛的治疗中得到了应用。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0513.png
图 5-13。抗体-抗原相互作用示意图。 (来源:Wikimedia.)
抗体的设计直到现在主要还是一门实验科学。部分原因是由于获取 3D 抗体结构所涉及的挑战。然而,建模复杂的抗原-抗体结合位点也被证明是一个挑战。我们在本章中介绍的一些技术可能在未来几年内在抗体-抗原结合建模中找到有益的用途。
我们还提到了动态在理解蛋白质物理学中的重要性。我们不能直接在蛋白质模拟中进行深度学习,以了解哪些配体可以结合到蛋白质吗?原则上是可以的,但仍然存在巨大的挑战。一些公司正在积极应对这一挑战,但良好的开源工具尚未推出。
在第十一章中,我们将回顾一些生物物理技术,并展示这些模型如何对药物发现工作非常有用。
第六章:基因组学的深度学习
每个生物体的核心是其基因组:包含制造生物体工作部分的所有指令的 DNA 分子。如果一个细胞是一台计算机,那么它的基因组序列就是它执行的软件。如果 DNA 可以被视为软件,信息是计算机处理的,那么我们肯定可以使用我们自己的计算机来分析这些信息并理解它是如何运作的?
当然,DNA 不仅仅是一个抽象的存储介质。它是一种行为复杂的物理分子。它还与成千上万的其他分子相互作用,所有这些分子都在维持、复制、指导和执行 DNA 中包含的指令方面发挥重要作用。基因组是一个由成千上万部分组成的巨大而复杂的机器。我们对大多数这些部分如何工作仍知之甚少,更不用说它们如何作为一个整体运作了。
这将引出遗传学和基因组学这两个领域。遗传学将 DNA 视为抽象信息。它研究遗传模式,或者在人群中寻找相关性,以发现 DNA 序列和生理特征之间的联系。另一方面,基因组学将基因组视为一个物理机器。它试图理解构成该机器的部分以及它们如何协同工作。这两种方法是互补的,深度学习可以成为它们两者的强大工具。
DNA、RNA 和蛋白质
即使你不是生物学家,在你的教育过程中,你可能也学习过基因组是如何运作的基础知识。我们将首先回顾通常在入门课程中教授的基因组的简化图景。然后我们将描述现实世界更为复杂的一些方面。
DNA 是一种聚合物:一长串重复单元串在一起。在 DNA 的情况下,有四种可能出现的单元(称为碱基):腺嘌呤、胞嘧啶、鸟嘌呤和胸腺嘧啶,简称为 A、C、G 和 T(参见图 6-1)。关于如何制造生物体的几乎所有信息最终都编码在构成其基因组的这四种重复单元的特定模式中。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0601.png
图 6-1. DNA 分子的结构。它由许多 A、C、G 和 T 碱基组成的两条链组成。这两条链是互补的:一条链中的每个 C 与另一条链中的 G 配对,一条链中的每个 A 与另一条链中的 T 配对。 (来源:Wikimedia.)
如果 DNA 是软件,那么蛋白质就是最重要的硬件。蛋白质是微小的机器,在细胞中几乎完成所有工作。蛋白质也是聚合物,由称为氨基酸的重复单元组成。有 20 种主要氨基酸,它们的物理性质差异很大。有些大,而有些小。有些带有电荷,而有些没有。有些倾向于吸引水,而有些倾向于排斥水。当恰到好处的氨基酸集合以恰到好处的顺序串在一起时,它将自发地折叠成一个三维形状,所有部分都被正确地定位,以使其作为一个机器发挥作用。
DNA 的主要功能之一是记录生物体蛋白质的氨基酸序列。它以一种简单直接的方式做到这一点。特定的 DNA 片段直接对应于特定的蛋白质。每个三个 DNA 碱基序列(称为密码子)对应一个氨基酸。例如,模式 AAA 表示氨基酸赖氨酸,而模式 GCC 表示氨基酸丙氨酸。
从 DNA 到蛋白质涉及另一种分子,RNA,它作为中间表示来携带信息从细胞的一部分到另一部分。RNA 是另一种聚合物,化学上与 DNA 非常相似。它也有四种碱基,可以以任意顺序链接在一起。要创建蛋白质,信息必须被复制两次。首先,DNA 序列被转录成等效的 RNA 序列,然后 RNA 分子被翻译成蛋白质分子。携带信息的 RNA 分子称为信使 RNA,简称 mRNA。
这告诉我们蛋白质是如何制造的,但没有告诉我们何时。人类细胞可以制造许多不同的蛋白质。它肯定不会一直生产所有这些蛋白质的副本,对吧?显然必须有某种调节机制来控制何时制造哪些蛋白质。在传统观念中,这是由称为*转录因子(TFs)*的特殊蛋白质完成的。每个 TF 识别并结合到特定的 DNA 序列。根据特定的 TF 和其结合位置,它可以增加或减少附近基因的转录速率。
这提供了一个简单、易于理解的基因组工作方式的图像。DNA 的工作是编码蛋白质。DNA 的一段(称为基因)使用简单、明确定义的密码编码蛋白质。DNA 被转录为 RNA,它只作为信息载体。然后 RNA 被转化为蛋白质,蛋白质才是真正的工作。整个过程非常优雅,就像一个有才华的工程师设计的东西。多年来,人们一直相信这种图像基本上是正确的。所以,在我们揭示现实实际上更加混乱和复杂之前,花点时间享受一下吧。
现在进入真实世界
现在是时候谈论基因组真正的工作方式了。在前一节中描述的图像简单而优雅,但不幸的是它与现实几乎没有联系。本节将快速介绍大量信息,但不用担心记住或理解所有内容。重要的是要对生物体的令人难以置信的复杂性有所感知。我们将在本章的后面回到其中一些主题,并进行更详细的讨论。
让我们从考虑 DNA 分子(称为染色体)开始。在细菌中,DNA 存在为简单的自由漂浮分子。但真核生物(包括变形虫、人类和中间所有生物)拥有更大的基因组。为了适应细胞内,每个染色体必须被打包到非常小的空间中。这是通过将其缠绕在称为组蛋白的蛋白质周围来实现的。但如果所有 DNA 都被紧密打包起来,它如何被转录呢?答案当然是不能。在基因可以被转录之前,首先必须解开包含它的 DNA 片段。细胞如何知道哪些 DNA 需要解开呢?答案仍然不明确。据信涉及各种类型的组蛋白分子的化学修饰,以及识别特定修饰的蛋白质。显然涉及到一种调节机制,但许多细节仍然未知。我们将很快回到这个主题。
DNA 本身可以通过一种称为甲基化的过程进行化学修饰。DNA 的一段被高度甲基化,就越不可能被转录,因此这是细胞可以用来控制蛋白质产生的另一种调节机制。但它如何控制哪些 DNA 区域被甲基化呢?这也仍然不明确。
在前一节中,我们说特定的 DNA 片段对应于特定的蛋白质。这对细菌来说是正确的,但在真核生物中情况更加复杂。在 DNA 被转录成信使 RNA 后,该 RNA 经常被编辑以去除部分并连接(或剪接)剩余部分(称为外显子)。最终被翻译成蛋白质的 RNA 序列可能与原始 DNA 序列不同。此外,许多基因具有多个剪接变体 - 去除部分以形成最终序列的不同方式。这意味着单个 DNA 片段实际上可以编码多种不同的蛋白质!
所有这些听起来开始变得非常复杂了吗?好吧,继续阅读,因为我们才刚刚开始!进化选择能够起作用的机制,而不关心它们是否简单或易于理解。这导致了非常复杂的系统,理解它们需要我们面对这种复杂性。
在传统观念中,RNA 被视为仅仅是一个信息载体,但即使在基因组学的早期,生物学家们就知道这并不完全正确。将 mRNA 翻译成蛋白质的工作是由核糖体完成的,这是由部分蛋白质和部分 RNA 组成的复杂分子机器。翻译中的另一个关键角色是由称为转运 RNA(或简称 tRNA)的分子执行的。这些分子定义了“遗传密码”,识别 mRNA 中的三个碱基的模式,并将正确的氨基酸添加到不断增长的蛋白质中。因此,半个多世纪以来,我们已经知道至少有三种 RNA:mRNA,核糖体 RNA 和 tRNA。
但 RNA 仍然有许多窍门。它是一种令人惊讶地多才多艺的分子。在过去的几十年中,发现了许多其他类型的 RNA。以下是一些例子:
-
微小 RNA(miRNAs)是一种短的 RNA 片段,它们结合到信使 RNA 上,阻止其被翻译成蛋白质。这是一种在某些动物,尤其是哺乳动物中非常重要的调节机制。
-
短干扰 RNA(siRNA)是另一种类型的 RNA,它结合到 mRNA 上并阻止其被翻译。它类似于 miRNA,但 siRNA 是双链的(不像 miRNA 是单链的),它们的一些功能细节是不同的。我们将在本章后面更详细地讨论 siRNA。
-
核酶是可以作为酶来催化化学反应的 RNA 分子。化学是生命细胞中发生的一切的基础,因此催化剂对生命至关重要。通常这项工作由蛋白质完成,但我们现在知道有时也由 RNA 完成。
-
核糖开关是由两部分组成的 RNA 分子。一部分充当信使 RNA,而另一部分能够结合到小分子上。当它结合时,可以启用或阻止 mRNA 的翻译。这是另一种调节机制,可以根据细胞中特定小分子的浓度来调整蛋白质的产生。
当然,所有这些不同类型的 RNA 都必须被制造出来,DNA 必须包含如何制造它们的说明。因此,DNA 不仅仅是一串编码蛋白质序列的字符串。它还包含 RNA 序列,以及转录因子和其他调节分子的结合位点,以及有关如何剪接信使 RNA 的说明,以及影响其如何缠绕在组蛋白周围以及哪些基因被转录的各种化学修饰。
现在考虑核糖体将 mRNA 翻译成蛋白质后会发生什么。一些蛋白质可以自发地折叠成正确的三维形状,但许多其他蛋白质需要其他蛋白质(称为分子伴侣)的帮助。在翻译后,蛋白质通常需要额外的化学修饰。然后,成品蛋白质必须被运送到细胞的正确位置以完成其工作,并在不再需要时最终被降解。每个这些过程都受到额外的调节机制的控制,并涉及与许多其他分子的相互作用。
如果这一切听起来令人不知所措,那是因为它确实如此!一个活体生物比人类创造的任何机器都要复杂得多。试图理解它应该让你感到害怕!
但这也是为什么机器学习是如此强大的工具。我们有大量数据,这些数据是由一个复杂且不被充分理解的过程生成的。我们希望发现数据中隐藏的微妙模式。这正是深度学习擅长的问题类型!
事实上,深度学习非常适合这个问题。传统的统计技术很难表示基因组的复杂性。它们通常基于简化的假设。例如,它们寻找变量之间的线性关系,或者试图将一个变量建模为仅取决于少数其他变量。但基因组涉及数百个变量之间的复杂非线性关系:这正是深度神经网络可以有效描述的关系类型。
转录因子结合
以将深度学习应用于基因组学为例,让我们考虑预测转录因子结合的问题。回想一下,TF 是结合到 DNA 的蛋白质。当它们结合时,它们会影响附近基因被转录成 RNA 的概率。但是 TF 如何知道在哪里结合?像基因组学的许多问题一样,这个问题有一个简单的答案,然后是许多复杂性。
在第一次近似中,每个转录因子都有一个特定的 DNA 序列,称为其结合位点基序,它会与之结合。结合位点基序往往很短,通常为 10 个碱基或更少。无论 TF 的基序出现在基因组的哪个位置,TF 都会与之结合。
实际上,基序并不完全特异。一个 TF 可能能够结合许多相似但不完全相同的序列。基序内的一些碱基可能比其他碱基更重要。这通常被建模为位置权重矩阵,指定 TF 对基序内每个位置的每个可能碱基的偏好程度。当然,这假设基序内的每个位置都是独立的,这并不总是正确的。有时,甚至基序的长度也会有所变化。虽然结合主要由基序内的碱基决定,但基序两侧的 DNA 也可能会产生一些影响。
这只考虑了序列!DNA 的其他方面也可能很重要。许多 TF 受到 DNA 的物理形状的影响,例如双螺旋的紧密程度。如果 DNA 被甲基化,那可能会影响 TF 的结合。请记住,真核生物中的大多数 DNA 都被紧密包裹在组蛋白周围。TF 只能结合到已经展开的部分。
其他分子也发挥着重要作用。TF 经常与其他分子相互作用,这些相互作用可能会影响 DNA 结合。例如,TF 可能会与第二个分子结合形成一个复合物,然后该复合物会与 TF 单独结合到不同的 DNA 基序。
生物学家花费了数十年来解开这些细节并设计 TF 结合的模型。让我们看看是否可以使用深度学习直接从数据中学习模型,而不是做这些工作。
TF 结合的卷积模型
对于这个例子,我们将使用一个名为 JUND 的特定转录因子的实验数据。进行了一个实验来识别人类基因组中它结合的每个位置。为了使事情更容易处理,我们只包括染色体 22 的数据,这是最小的人类染色体之一。它仍然有超过 5000 万个碱基,因此我们有足够的数据来处理。整个染色体已经被分成短片段,每个片段长 101 个碱基,并且每个片段已被标记以指示是否包含 JUND 结合的位置。我们将尝试训练一个模型,根据每个片段的序列来预测这些标签。
这些序列是用一位热编码表示的。对于每个碱基,我们有四个数字,其中一个设置为 1,其他设置为 0。哪个数字设置为 1 表示碱基是 A、C、G 还是 T。
为了处理数据,我们将使用一个卷积神经网络,就像我们在第三章中识别手写数字时所做的那样。实际上,您会发现这两个模型在很大程度上相似。这次我们将使用 1D 卷积,因为我们处理的是 1D 数据(DNA 序列)而不是 2D 数据(图像),但模型的基本组件将是相同的:输入,一系列卷积层,一个或多个密集层来计算输出,以及一个交叉熵损失函数。
让我们从创建一个TensorGraph并定义输入开始:
model = dc.models.TensorGraph(batch_size=1000)
features = layers.Feature(shape=(None, 101, 4))
labels = layers.Label(shape=(None, 1))
weights = layers.Weights(shape=(None, 1))
注意输入的大小。对于每个样本,我们有一个大小为 101(碱基数)乘以 4(每个碱基的一位热编码)的特征向量。我们还有一个标签的单个数字(0 或 1,表示是否包含结合位点)和一个权重的单个数字。在这个例子中使用损失函数中的权重是至关重要的,因为数据非常不平衡。不到 1%的所有样本包含结合位点。这意味着模型可以通过只为每个样本输出 0 来轻松获得超过 99%的准确率。我们通过给正样本比负样本更高的权重来防止这种情况。
接下来,我们创建一个具有相同参数的三个卷积层的堆叠:
prev = features
for i in range(3):
prev = layers.Conv1D(filters=15, kernel_size=10,
activation=tf.nn.relu, padding='same',
in_layers=prev)
prev = layers.Dropout(dropout_prob=0.5, in_layers=prev)
我们指定卷积核的宽度为 10,并且每个层应包括 15 个滤波器(即输出)。第一层以原始特征(每个碱基四个数字)作为输入。它查看连续 10 个碱基的跨度,因此总共有 40 个输入值。对于每个跨度,它将这 40 个值乘以一个卷积核以产生 15 个输出值。第二层再次查看 10 个碱基的跨度,但这次的输入是第一层计算的 15 个值。它为每个碱基计算一组新的 15 个值,依此类推。
为了防止过拟合,我们在每个卷积层后添加一个 dropout 层。dropout 概率设置为 0.5,意味着 50%的所有输出值会被随机设置为 0。
接下来我们使用一个密集层来计算输出:
logits = layers.Dense(out_channels=1, in_layers=layers.Flatten(prev))
output = layers.Sigmoid(logits)
model.add_output(output)
我们希望输出在 0 到 1 之间,这样我们可以将其解释为特定样本包含结合位点的概率。密集层可以产生任意值,不限于任何特定范围。因此,我们通过一个逻辑 sigmoid 函数将其压缩到所需的范围。这个函数的输入通常被称为对数几率。这个名称指的是数学对数几率函数,它是逻辑 sigmoid 的反函数。
最后,我们计算每个样本的交叉熵并乘以权重以获得损失:
loss = layers.SigmoidCrossEntropy(in_layers=[labels, logits])
weighted_loss = layers.WeightedError(in_layers=[loss, weights])
model.set_loss(weighted_loss)
请注意,出于数值稳定性的原因,交叉熵层以对数几率作为输入,而不是逻辑 sigmoid 函数的输出。
现在我们准备训练和评估模型。我们使用 ROC AUC 作为我们的评估指标。在每 10 个训练周期之后,我们在训练集和验证集上评估模型:
train = dc.data.DiskDataset('train_dataset')
valid = dc.data.DiskDataset('valid_dataset')
metric = dc.metrics.Metric(dc.metrics.roc_auc_score)
for i in range(20):
model.fit(train, nb_epoch=10)
print(model.evaluate(train, [metric]))
print(model.evaluate(valid, [metric]))
结果显示在图 6-2 中。验证集性能在 50 个 epochs 后达到约 0.75 的峰值,然后略有下降。训练集性能继续增加,最终在约 0.87 左右趋于稳定。这告诉我们,超过 50 个 epochs 的训练只会导致过拟合,我们应该在那一点停止训练:
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0602.png
图 6-2。训练集(虚线)和验证集(实线)训练期间 ROC AUC 分数的演变。
ROC AUC 分数为 0.75 并不算糟糕,但也不是很好。可能我们可以通过改进模型来提高它。我们可以尝试改变许多超参数:卷积层的数量,每层的核宽度,每层的滤波器数量,dropout 率等。我们可以尝试许多组合,也许会找到一个性能更好的组合。
但我们也知道,这个模型能够工作的好坏存在根本限制。它只看到 DNA 序列作为输入,而 TF 结合还取决于许多其他因素:可访问性、甲基化、形状、其他分子的存在等。任何忽略这些因素的模型在预测准确性方面都会受到限制。所以现在让我们尝试添加第二个输入,看看是否有帮助。
染色质可访问性
名称染色质指的是构成染色体的一切:DNA、组蛋白和各种其他蛋白质和 RNA 分子。染色质可访问性指的是染色体的每个部分对外部分子的可访问程度。当 DNA 紧密缠绕在组蛋白周围时,对转录因子和其他分子是不可访问的。它们无法接触到它,DNA 实际上是不活跃的。当它从组蛋白中解开时,它再次变得可访问,并恢复其作为细胞机器中心部分的角色。
染色质可访问性既不是均匀的也不是静态的。它在细胞类型和细胞生命周期阶段之间变化。它可以受到环境条件的影响。这是细胞用来调节其基因组活动的工具之一。任何基因都可以通过将其所在染色体区域包装起来而关闭。
可访问性也在 DNA 对细胞内事件的反应中不断变化。与将可访问性视为二元选择(可访问或不可访问)不同,将其视为连续变量(每个区域可访问的时间比例)更好。
我们在上一节分析的数据来自对一种名为 HepG2 的细胞的实验。实验确定了基因组中转录因子 JUND 结合的位置。结果受染色质可访问性的影响。如果 HepG2 细胞中的某个特定区域几乎总是不可访问,即使 DNA 序列本来是一个完美的结合位点,实验也很难在那里找到 JUND 结合。因此,让我们尝试将可访问性纳入我们的模型。
首先让我们加载一些关于可访问性的数据。我们将其保存在一个文本文件中,其中每一行对应于我们数据集中的一个样本(染色体 22 的 101 个碱基片段)。一行包含样本 ID,后面跟着一个数字,表示该区域在 HepG2 细胞中通常有多可访问。我们将其加载到一个 Python 字典中:
span_accessibility = {}
for line in open('accessibility.txt'):
fields = line.split()
span_accessibility[fields[0]] = float(fields[1])
现在开始构建模型。我们将几乎完全使用与上一节相同的模型,只有两个小改变。首先,我们需要一个第二个特征输入来表示可访问性数值。每个样本都有一个数字:
accessibility = layers.Feature(shape=(None, 1))
现在我们需要将可访问性值纳入计算中。我们可以以许多方式做到这一点。在本例中,我们将使用一种特别简单的方法。在前一节中,我们将最后一个卷积层的输出展平,然后将其用作计算输出的密集层的输入。
logits = layers.Dense(out_channels=1, in_layers=layers.Flatten(prev))
这次我们将做同样的事情,但也将可访问性附加到卷积的输出中:
prev = layers.Concat([layers.Flatten(prev), accessibility])
logits = layers.Dense(out_channels=1, in_layers=prev)
模型就是这样了!现在是训练的时候了。
在这一点上,我们遇到了一个困难:我们的模型有两个不同的“特征”层!到目前为止,我们的模型只有一个“特征”层,一个“标签”层,可能还有一个“权重”层。我们通过调用fit(dataset)来训练它们,这会自动将正确的数据连接到每个层:特征的数据集X字段,标签的y字段,权重的w字段。但是当模型具有多个特征集时,这显然行不通。
通过使用 DeepChem 的更高级功能来处理这种情况。我们可以编写一个 Python 生成器函数,该函数会迭代批次。每个批次由一个字典表示,其键是输入层,其值是用于这些层的 NumPy 数组:
def generate_batches(dataset, epochs):
for epoch in range(epochs):
for X, y, w, ids in dataset.iterbatches(batch_size=1000,
pad_batches=True):
yield {
features: X,
accessibility: np.array([span_accessibility[id] for id in ids]),
labels: y,
weights: w
}
注意数据集如何为我们迭代批次。它为每个批次提供数据,我们可以从中构建模型所需的任何输入。
现在训练和评估过程与以前完全相同。我们使用了接受生成器而不是数据集的方法的替代形式:
for i in range(20):
model.fit_generator(generate_batches(train, 10))
print(model.evaluate_generator(generate_batches(train, 1), [metric],
labels=[labels], weights=[weights]))
print(model.evaluate_generator(generate_batches(valid, 1), [metric],
labels=[labels], weights=[weights]))
结果显示在图 6-3 中。与忽略染色质可访问性的模型相比,训练集和验证集的分数都有所提高。ROC AUC 分数现在达到了训练集的 0.91 和验证集的 0.80。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0603.png
图 6-3。在包括染色质可访问性作为输入时,训练集(虚线)和验证集(实线)的 ROC AUC 分数在训练期间的演变。
RNA 干扰
对于我们的最后一个示例,让我们转向 RNA。与 DNA 类似,这是由称为碱基的四个重复单元组成的聚合物。实际上,四个碱基中的三个与它们的 DNA 版本几乎相同,只是多了一个氧原子。第四个碱基有些不同。RNA 中没有胸腺嘧啶(T),而是有一种称为尿嘧啶(U)的碱基。当 DNA 序列被转录成 RNA 时,每个 T 都会被 U 替换。
碱基 G 和 C 彼此互补,即它们有很强的结合倾向。同样,碱基 A 和 T(或 U)是互补的。如果你有两条 DNA 或 RNA 链,其中一条中的每个碱基与另一条中对应的碱基互补,那么这两条链就会倾向于粘在一起。这个事实在许多生物过程中起着关键作用,包括转录和翻译,以及细胞分裂时的 DNA 复制。
这也是所谓的RNA 干扰的核心。这种现象直到 1990 年代才被发现,这一发现导致了 2006 年的诺贝尔奖。一小段 RNA,其序列与信使 RNA 的一部分互补,可以结合到该 mRNA 上。当这种情况发生时,它会“沉默”mRNA,防止其被翻译成蛋白质。执行沉默的分子称为短干扰 RNA(siRNA)。
除此之外,这个过程还有更多内容。RNA 干扰是一个复杂的生物机制,不仅仅是两个孤立的 RNA 链碰巧粘在一起的副作用。它始于 siRNA 结合到一组被称为RNA 诱导沉默复合物(RISC)的蛋白质。RISC 使用 siRNA 作为模板来搜索细胞中匹配的 mRNA 并降解它们。这既是调节基因表达的机制,也是对抗病毒的防御。
这也是生物学和医学的强大工具。它让你暂时“关闭”任何你想要的基因。你可以用它来治疗疾病,或者研究当一个基因被禁用时会发生什么。只需识别你想要阻断的 mRNA,选择任何短片段,并创建一个具有互补序列的 siRNA 分子。
当然,事情并不像那么简单。你不能随意选择 mRNA 的任何片段,因为 RNA 分子并不只是四个字母的抽象模式。它们是具有独特属性的物理对象,这些属性取决于序列。一些 RNA 分子比其他的更稳定。一些与它们的互补序列结合得更紧密。一些折叠成形状,使得 RISC 更难与它们结合。这意味着一些 siRNA 序列比其他的更有效,如果你想将 RNA 干扰作为一种工具使用,你需要知道如何选择一个好的!
生物学家已经开发了许多用于选择 siRNA 序列的经验法则。例如,他们会说,第一个碱基应该是 A 或 G,G 和 C 碱基应该占序列的 30%到 50%,等等。这些经验法则是有帮助的,但让我们看看是否可以利用机器学习做得更好。
我们将使用一个包含 2,431 个 siRNA 分子的库来训练我们的模型,每个分子长 21 个碱基。每一个都经过实验测试,并标记为 0 到 1 之间的值,表示它在沉默目标基因方面的有效性。较小的值表示无效的分子,而较大的值表示更有效的分子。模型以序列作为输入,并尝试预测有效性。
这是构建模型的代码:
model = dc.models.TensorGraph()
features = layers.Feature(shape=(None, 21, 4))
labels = layers.Label(shape=(None, 1))
prev = features
for i in range(2):
prev = layers.Conv1D(filters=10, kernel_size=10,
activation=tf.nn.relu, padding='same',
in_layers=prev)
prev = layers.Dropout(dropout_prob=0.3, in_layers=prev)
output = layers.Dense(out_channels=1, activation_fn=tf.sigmoid,
in_layers=layers.Flatten(prev))
model.add_output(output)
loss = layers.ReduceMean(layers.L2Loss(in_layers=[labels, output]))
model.set_loss(loss)
这与我们用于 TF 结合的模型非常相似,只是有一些区别。因为我们使用较短的序列并在较少的数据上进行训练,所以我们减小了模型的大小。只有 2 个卷积层,每层有 10 个滤波器,而不是 15 个。也不需要权重,因为我们希望在优化过程中每个样本都能做出贡献。
我们还使用了不同的损失函数。TF 结合的模型是一个分类模型。每个标签要么是 0,要么是 1,我们试图预测这两个离散值中的哪一个。但这个模型是一个回归模型。标签是连续的数字,模型试图尽可能地匹配它们。因此,我们使用L 2距离作为我们的损失函数,它试图最小化真实标签和预测标签之间的均方差。
这是训练模型的代码:
train = dc.data.DiskDataset('train_siRNA')
valid = dc.data.DiskDataset('valid_siRNA')
metric = dc.metrics.Metric(dc.metrics.pearsonr, mode='regression')
for i in range(20):
model.fit(train, nb_epoch=10)
print(model.evaluate(train, [metric]))
print(model.evaluate(valid, [metric]))
对于 TF 结合,我们使用 ROC AUC 作为我们的评估指标,它衡量模型如何将数据分成两类。这对于分类问题是合适的,但对于回归问题来说没有意义,因此我们使用皮尔逊相关系数。这是一个介于-1 和 1 之间的数字,其中 0 表示模型根本没有提供信息,1 表示模型完美地重现了实验数据。
结果显示在图 6-4 中。验证集得分在 50 个 epochs 后达到 0.65 的峰值。训练集得分继续增加,但由于验证集得分没有进一步提高,这只是过拟合。考虑到模型的简单性和有限的训练数据量,相关系数 0.65 已经相当不错。在更大数据集上训练的更复杂模型稍微更好,但这已经是非常可观的表现了。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0604.png
图 6-4. 在训练过程中 Pearson 相关系数的演变,包括训练集(虚线)和验证集(实线)。
结论
基因组是一个极其复杂的机器,有大量的部分共同工作,指导和执行蛋白质和其他分子的制造。深度学习是研究它的强大工具。神经网络可以挑出基因组数据中微妙的模式,提供对基因组功能的洞察,同时也可以对其进行预测。
与生命科学的大多数其他领域相比,基因组学产生了大量的实验数据。例如,单个人类基因组序列包含超过 60 亿个碱基。传统的统计技术很难在所有这些数据中找到信号。它们经常需要简化假设,这些假设并不能反映基因组调控的复杂性。深度学习非常适合处理这些数据,并推动我们对生命细胞核心功能的理解。
¹ Huesken, D., J. Lange, C. Mickanin, J. Weiler, F. Asselbergs, J. Warner, B. Meloon, S. Engel, A. Rosenberg, D. Cohen, M. Labow, M. Reinhardt, F. Natt, and J. Hall, “Design of a Genome-Wide siRNA Library Using an Artificial Neural Network.” Nature Biotechnology 23:995–1001. 2005. doi.org/10.1038/nbt1118.
第七章:机器学习用于显微镜
在这一章中,我们向您介绍显微镜的深度学习技术。在这些应用中,我们试图理解显微图像的生物结构。例如,我们可能对在给定图像中某种特定类型的细胞数量感兴趣,或者我们可能试图识别特定的细胞器。显微镜是生命科学中最基本的工具之一,显微镜技术的进步极大地推动了人类科学的发展。即使对于怀疑论者来说,眼见为实,能够直观地检查细胞等生物实体,有助于对生命的基本机制有更直观的理解。对细胞核和细胞骨架的生动可视化(如图 7-1)比教科书中干燥的讨论更有助于更深入地理解。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0701.png
图 7-1 人源 SK8/18-2 细胞。这些细胞被染色以突出它们的细胞核和细胞骨架,并使用荧光显微镜成像。(来源:维基媒体。)
问题在于深度学习如何在显微镜中发挥作用。直到最近,分析显微镜图像的唯一方法是让人类(通常是研究生或研究助理)手动检查这些图像以寻找有用的模式。最近,诸如CellProfiler之类的工具使生物学家能够自动组装处理成像数据的流程。
自动化高通量显微镜图像分析
在过去几十年的自动化进步使得在某些系统上进行自动化高通量显微镜成为可能。这些系统利用简单的机器人技术(用于自动处理样本)和图像处理算法来自动处理图像。这些图像处理应用程序,如分离细胞的前景和背景以及获取简单的细胞计数和其他基本测量。此外,诸如 CellProfiler 之类的工具使得没有编程经验的生物学家能够构建新的自动化流程来处理细胞数据。
然而,自动化显微系统传统上面临着许多限制。首先,现有的计算机视觉流程无法执行复杂的视觉任务。此外,为了进行分析,样本的适当准备需要实验人员具有相当的专业知识。因此,尽管自动化显微术在促进复杂新实验方面取得了相当大的成功,但它仍然是一个相对小众的技术。
因此,深度学习有望扩展诸如 CellProfiler 之类工具的能力。如果深度分析方法能够执行更复杂的分析,自动化显微镜可能会成为一个更有效的工具。因此,深度显微镜引起了相当大的研究兴趣,我们将在本章的其余部分看到。
深度学习技术的希望在于它们将使自动化显微镜流程变得更加灵活。深度学习系统显示出有望能够执行几乎任何人类图像分析师能够执行的任务。此外,早期研究表明,深度学习技术可能会大大扩展廉价显微镜硬件的能力,潜在地使廉价显微镜能够执行目前仅能使用非常复杂和昂贵的设备进行的分析。
展望未来,甚至可以训练“模拟”实验测定的深度模型。这些系统能够在某些有限情况下预测实验结果,甚至无需运行相关实验。这是一种非常强大的能力,也是深度网络在基于图像的生物学领域激发了许多关于潜在潜力的兴奋。
在本章中,我们将教你深度显微镜学的基础知识。我们将演示深度学习系统如何学习执行简单任务,如细胞计数和细胞分割。此外,我们将讨论如何构建可扩展系统,以处理更复杂的图像处理流程。
显微镜学简介
在我们深入算法之前,让我们先谈谈基础知识。显微镜学是利用物理系统观察小物体的科学。传统上,显微镜是纯光学设备,使用精细磨制的透镜来扩大样本的分辨率。最近,显微镜学领域开始大量依赖电子束或甚至物理探针等技术来产生高分辨率样本。
几个世纪以来,显微镜学与生命科学紧密联系在一起。17 世纪,安东·范·李文霍克使用早期光学显微镜(他自己设计和制造)以前所未有的细节描述微生物(如图 7-2 所示)。这些观察在很大程度上取决于范·李文霍克在显微镜学方面的进步,特别是他发明了一种新透镜,使分辨率明显提高,超过了当时可用的显微镜。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0702.png
图 7-2. 范·李文霍克在现代时代制造的显微镜的复制品。范·李文霍克保留了他的透镜磨削过程的关键细节,直到 1950 年代,美国和苏联的科学家才成功复制了这款显微镜。 (来源:维基百科.)
高分辨率光学显微镜的发明引发了微生物学的革命。显微镜技术的传播和能够大规模查看细胞、细菌和其他微生物的能力使整个微生物学领域和病原模型的发展成为可能。很难过分强调显微镜对现代生命科学的影响。
光学显微镜可以是简单的或复合的。简单显微镜仅使用单个透镜进行放大。复合显微镜使用多个透镜实现更高的分辨率,但在构造上增加了额外的复杂性。第一个实用的复合显微镜直到 19 世纪中叶才实现!可以说,下一个主要的光学显微镜系统设计转变直到 1980 年代才发生,随着数字显微镜的出现,使显微镜捕捉的图像可以写入计算机存储。正如我们在前一节中提到的,自动显微镜使用数字显微镜捕捉大量图像。这些可以用于进行捕捉实验干扰效应的大规模生物学实验。
现代光学显微镜
尽管光学显微镜已经存在几个世纪,但在这一领域仍然存在相当多的创新。其中最基本的技术之一是光学切片。光学显微镜具有当前焦点的焦平面。已经开发了各种技术来将图像聚焦在所选的焦平面上。然后,这些聚焦图像可以通过算法拼接在一起,创建高分辨率图像甚至是原始图像的 3D 重建。图 7-3 直观地展示了如何将花粉颗粒的切片图像组合在一起以产生高保真度图像。
共焦显微镜是光学切片问题的常见解决方案。它们使用针孔阻挡来自焦外的光线,使共焦显微镜能够实现更好的深度感知。通过移动显微镜的焦点并进行水平扫描,您可以获得整个样本的全景图像,具有增强的光学分辨率和对比度。有趣的历史背景是,共焦成像的概念最初由 AI 先驱马文·明斯基(见图 7-4)申请专利。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0703.png
图 7-3. 花粉颗粒成像:(a)花粉颗粒的光学切片荧光图像;(b)合成图像;(c)一组花粉颗粒的合成图像。(来源:Wikimedia。)
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0704.png
图 7-4. 明斯基原始专利中介绍共焦扫描显微镜的图像。在历史的有趣转折中,明斯基更为人所知的是他在人工智能领域的开创性工作。(来源:Wikimedia。)
设计良好的光学切片显微镜在捕获生物系统的 3D 图像方面表现出色,因为扫描可以用于聚焦图像的多个部分。这些聚焦图像可以通过算法拼接在一起,产生美丽的 3D 重建。
在接下来的部分中,我们将探讨限制光学显微镜的基本限制,并调查一些已经设计用于解决这些限制的技术。这些材料目前与深度学习没有直接关系(原因我们将讨论),但我们认为这将让您更好地了解当今显微镜面临的挑战。如果您想帮助设计下一代机器学习驱动的显微镜系统,这种直觉将会很有用。然而,如果您急于查看一些代码,我们鼓励您跳转到后续部分,那里我们将深入探讨更直接的应用。
深度学习不能做什么?
深度学习似乎可以在显微镜领域产生影响,因为深度学习擅长处理图像,而显微镜则是关于图像捕获的。但值得问一下:目前深度学习在显微镜领域有哪些方面做得不多?正如我们在本章后面看到的,为显微成像准备样本可能需要相当复杂的技术。此外,样本制备需要相当的物理灵巧,因为实验者必须能够将样本固定为一个物理对象。我们如何可能利用深度学习自动化或加速这个过程?
现在不幸的事实是,机器人系统仍然非常有限。虽然像对样本进行共焦扫描这样的简单任务很容易处理,但清洁和准备样本需要相当的专业知识。在可预见的未来,任何可用的机器人系统都不太可能具有这种能力。
每当您听到关于学习技术未来影响的预测时,将示例准备工作等示例记在心中是很有用的。生命科学中的许多痛点涉及诸如样本准备之类的任务,这些任务对今天的机器学习来说根本不可行。这可能会改变,但至少在未来几年内可能不会发生。
衍射极限
当研究新的物理仪器,如显微镜时,从尝试了解其限制开始是有用的。显微镜做不到什么?事实证明,这个问题已经被以前的物理学家世代深入研究过(也有一些最近的惊喜!)。开始的地方是衍射极限,这是显微镜可能具有的分辨率的理论极限:
d = λ 2nsinθ
量nsinθ经常被重写为数值孔径 NA。λ是光的波长。请注意这里的隐含假设。我们假设样本是用某种形式的光照射的。让我们快速看一下那里的光波谱(参见图 7-5)。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0705.png
图 7-5。光的波长。请注意,低波长光源如 X 射线具有越来越高的能量。因此,它们经常会破坏精细的生物样本。
请注意,可见光仅占此光谱的一小部分。原则上,我们应该能够使用波长足够低的光使所需的分辨率任意好。在某种程度上,这已经发生了。许多显微镜使用能量更高的电磁波。例如,紫外显微镜利用紫外线波长较小的事实来实现更高的分辨率。我们不能进一步采用这种模式并使用波长更小的光吗?例如,为什么不使用 X 射线或γ射线显微镜?这里的主要问题是光毒性。波长较小的光具有高能量。将这种光照射到样本上可能会破坏样本的结构。此外,高波长光对实验者是危险的,并且需要特殊的实验设施。
幸运的是,还存在许多其他绕过衍射极限的技术。其中一种使用电子(它们也有波长!)来成像样本。另一种使用物理探针而不是光。避免分辨率限制的另一种方法是利用近场电磁波。使用多个照明荧光物质的技巧也可以降低限制。我们将在接下来的部分讨论这些技术。
电子和原子力显微镜
在 1930 年代,电子显微镜的出现引发了现代显微镜的巨大飞跃。电子显微镜使用电子束而不是可见光来获取物体的图像。由于电子的波长比可见光的波长小得多,使用电子束而不是光波可以获得更详细的图像。为什么这有意义呢?嗯,电子不是粒子吗?请记住,物质可以表现出波动性质。这就是所谓的德布罗意波长,由路易斯·德布罗意首次提出:
λ = h p = h mv
在这里,h是普朗克常数,m和v分别是所讨论粒子的质量和速度。(对于物理学家来说,请注意这个公式并没有考虑相对论效应。有修改版本的公式考虑了这些效应。)电子显微镜利用电子的波动性质来成像物体。电子的波长取决于其能量,但在标准电子枪可实现的波长下,波长很容易达到亚纳米级。将其代入之前讨论的衍射极限模型,很容易看出电子显微镜是一个强大的工具。早在 20 世纪 30 年代初就已经建造了第一台原型电子显微镜。虽然这些构造已经得到了相当的改进,但今天的电子显微镜仍然依赖于相同的核心原理(见图 7-6)。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0706.png
图 7-6。现代透射电子显微镜的组件。(来源:维基共享资源)。
请注意,我们在这里并没有完全避开光毒性问题。为了获得波长非常小的电子,我们需要增加它们的能量,而在非常高的能量下,我们将再次破坏样本。此外,为了通过电子显微镜成像,样本的准备过程可能会相当复杂。然而,电子显微镜的使用已经允许对微观系统进行惊人的成像(见图 7-7)。扫描电子显微镜通过扫描输入样品以获得更大的视野,可以实现分辨率达到一纳米的图像。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0707.png
图 7-7。扫描电子显微镜放大 500 倍的花粉。(来源:维基共享资源)。
原子力显微镜(AFM)提供了另一种突破光学衍射极限的方法。这种技术利用一个探针悬臂来物理探测给定表面。悬臂与样品之间的直接物理接触允许获得分辨率为亚纳米级的图像。事实上,有时候甚至可以成像单个原子!原子力显微镜还可以提供与表面的直接接触相关的三维图像。
力显微镜在广义上是一种最近的技术。第一台原子力显微镜是在 20 世纪 80 年代发明的,当时纳米尺度制造技术已经发展到可以准确制造所需探针的程度。因此,在生命科学领域的应用仍处于初期阶段。已经有一些关于使用 AFM 探针成像细胞和生物分子的研究,但这些技术仍处于早期阶段。
超分辨显微镜
到目前为止,在本章中我们已经讨论了许多扩展衍射极限的方法,包括使用更高波长的光或物理探针以实现更高分辨率。然而,在 20 世纪下半叶出现了一项科学突破,人们意识到存在整个系列的方法可以突破衍射极限。这些技术统称为超分辨显微镜技术:
功能性超分辨显微镜
利用嵌入在被成像样本中的发光物质的物理特性。例如,在生物显微镜中,荧光标记(稍后详细介绍)可以突出显示特定的生物分子。这些技术允许标准光学显微镜检测发光体。功能性超分辨率技术可以广泛分为确定性和随机技术。
确定性超分辨率显微镜
一些发光物质对激发具有非线性响应。这实际上是什么意思?这个想法是可以通过“关闭”附近的其他发光体来实现对特定发光体的任意聚焦。这背后的物理学有点复杂,但成熟的技术,如受激发射消融(STED)显微镜已经证明了这种技术。
随机超分辨率显微镜
生物系统中的发光分子受到随机运动的影响。这意味着如果跟踪发光粒子的运动,可以对其测量进行平均,从而得出其真实位置的低误差估计。有许多技术(如 STORM、PALM 和 BALM 显微镜)对这个基本想法进行了改进。这些超分辨率技术在现代生物学和化学中产生了巨大影响,因为它们使相对廉价的光学设备能够探测纳米尺度系统的行为。2014 年诺贝尔化学奖授予了功能性超分辨率技术的先驱者。
深度超分辨率技术
最近的研究开始利用深度学习技术重建超分辨率视图。这些技术声称通过从稀疏、快速获取的图像进行重建,可以使超分辨率显微镜的速度提高数个数量级。尽管仍处于起步阶段,但这显示了作为深度学习未来应用领域的潜力。
近场显微镜是另一种利用样本中局部电磁信息的超分辨率技术。这些“残余波”不遵守衍射极限,因此可以实现更高的分辨率。然而,这种权衡是显微镜必须从样本极近处收集光线(距离样本一波长内的光线)。这意味着尽管近场技术在物理上非常有趣,但实际应用仍具有挑战性。最近,还可以构建具有负折射率的“超材料”。实际上,这些材料的性质意味着近场残余波可以被放大,从而允许对样本进行更远距离的成像。这个领域的研究仍处于早期阶段,但非常令人兴奋。
深度学习和衍射极限?
令人心动的线索表明,深度学习可能有助于推广超分辨率显微镜。一些早期论文表明,深度学习算法可能加快超分辨率图像的构建,或者使用相对廉价的硬件实现有效的超分辨率。 (我们在前面的注释中指出了一篇这样的论文。)
这些线索特别引人注目,因为深度学习可以有效地执行诸如图像去模糊之类的任务。这些证据表明,可能可以基于深度学习构建一套强大的超分辨率工具,从而极大地促进这些技术的采用。目前,这项研究仍处于初期阶段,令人信服的工具尚不存在。然而,我们希望这种状况在未来几年内会发生改变。
为显微镜准备生物样本
在生命科学中应用显微镜的一个至关重要的步骤是为显微镜准备样本。这可能是一个非常复杂的过程,需要相当多的实验经验。我们在本节中讨论了几种准备样本的技术,并评论了这些技术可能出错并产生意外实验性伪迹的方式。
染色
最早的光学显微镜可以放大观察微观物体。这种功能使对小物体的理解有了惊人的提升,但它的主要局限是无法突出图像中的某些区域以增加对比度。这导致了化学染料的发展,使科学家们能够查看图像中的区域以增加对比度。
已经开发了各种各样的染料来处理不同类型的样本。染色程序本身可能非常复杂,包含多个步骤。染料在科学上可能具有极大的影响力。事实上,根据细菌对细菌革兰氏染色的反应,通常将细菌分类为“革兰阳性”或“革兰阴性”。深度学习系统的一个任务可能是在显微镜样本中分割和标记革兰阳性和革兰阴性细菌。如果您正在开发潜在的抗生素,这将使您能够分别研究其对革兰阳性和革兰阴性物种的影响。
作为开发者,我为什么要关心这个问题?
阅读本节的一些人可能是开发人员,对处理构建和部署深度显微镜流水线的挑战感兴趣。您可能会合理地问自己是否应该关心样本准备的生物学。
如果您确实专注于构建流水线的挑战,直接跳到本章的案例研究可能会对您最有帮助。然而,了解基本样本准备可能会在以后避免麻烦,并使您具备有效与生物学家同行沟通的词汇。如果生物学要求您为染料添加元数据字段,这一部分将让您对他们实际要求的内容有一个很好的了解。这值得您花几分钟的时间!
为革兰阴性细菌开发抗菌剂
目前药物发现中的一个主要挑战是为革兰阴性细菌开发有效的抗生素。革兰阴性细菌有一个额外的细胞壁,阻止了针对革兰阳性细菌的肽聚糖细胞壁的常见抗菌剂有效发挥作用。
这一挑战变得更加紧迫,因为许多细菌菌株通过水平基因转移等方法获得了革兰阴性抗性,细菌感染导致的死亡再次上升,这是在控制几十年后的情况。
可能很可能将您已经看到的分子设计深度学习方法与您将在本章学习的一些基于成像的技术相结合,以在这个问题上取得进展。我们鼓励那些对可能性感到好奇的人更仔细地探索这个领域。
样本固定
大型生物样本,如组织,如果任其自生自灭,往往会迅速降解。样本中的代谢过程会消耗并破坏样本中的器官、细胞和细胞器的结构。"固定"的过程旨在阻止这一过程,并稳定样本的内容,以便正确成像。已经设计了许多固定剂,这些剂有助于这一过程。固定剂的一个核心功能是变性蛋白质并关闭蛋白酶。如果允许,这些酶会消耗样本。
此外,固定的过程旨在杀死可能损坏样本的微生物。例如,在热固定中,样本通过巴塞尔燃烧器。这个过程可能会损坏样本的内部结构。另一种常见的技术是浸泡固定,样本被浸泡在固定液中并允许浸泡。例如,一个样本可以在冷甲醛中浸泡一段时间,比如 24 小时。
灌注 是一种固定大型动物(如小鼠)组织样本的技术。实验者将固定剂注入心脏,等待小鼠死亡后提取组织样本。这个过程允许固定剂自然地在组织中传播,通常会产生更好的结果。
分段样本
查看生物样本的一个重要部分是能够切出样本的薄片供显微镜观察。有许多巧妙的工具来促进这个过程,包括显微切片机(见图 7-8),它将生物样本切成薄片以便观察。显微切片机有其局限性:用这种方式很难切割非常小的物体。对于这样的小物体,最好使用共焦显微镜等技术。
值得停下来问一下为什么知道有显微切片机这样的设备是有用的。嗯,假设你是一名工程师,正在建造一个处理多个脑成像样本的管道。样本大脑很可能是使用显微切片机或类似的切割设备切成薄片的。了解这个过程的物理特性将有助于你,如果你(例如)正在构建一个用于一致组织这样的图像的模式。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0708.png
图 7-8. 一幅早期的图示了 1770 年的显微切片机。 (来源:维基共享资源.)
荧光显微镜
荧光显微镜是一种利用荧光现象的光学显微镜,其中材料样本吸收一种波长的光并以另一种波长发射。这是一种自然的物理现象;例如,一些矿物质在暴露在紫外光下时会发出荧光。然而,当应用于生物学时,情况就变得特别有趣。许多细菌在其蛋白质吸收高能光并发射低能光时会自然发出荧光。
荧光物质和荧光标记
荧光物质是一种可以在特定波长重新发射光的化合物。这些化合物在生物学中是至关重要的工具,因为它们允许实验者详细地成像给定细胞的特定组分。在实验中,荧光物质通常作为染料应用到特定细胞上。图 7-9 展示了一种常见荧光物质的分子结构。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0709.png
图 7-9. DAPI(4’,6-二胺基二苯基吲哚)是一种常见的荧光染料,结合到 DNA 的腺嘧啶-胸腺嘧啶富集区域。因为它可以穿过细胞膜,所以常用来染色细胞内部。 (来源:维基共享资源.)
荧光标记是一种将荧光物质附着到体内感兴趣的生物分子的技术。有多种有效的技术可以实现这一点。在显微镜成像中很有用,常常希望突出图像的特定部分。荧光标记可以非常有效地实现这一点。
荧光显微镜已经被证明对生物研究是一个巨大的福音,因为它允许研究人员放大给定生物样本中的特定子系统,而不是处理整个样本。在研究单个细胞或细胞内的单个分子时,使用标记可以证明对于聚焦注意力于有趣的子系统是非常宝贵的。图 7-10 显示了如何使用荧光染料选择性地可视化人类细胞核中的特定染色体。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0710.png
图 7-10。一个人类淋巴细胞核图像,染色体 13 和 21 染有 DAPI(一种流行的荧光染料)以发出光。 (来源:维基百科。)
荧光显微镜可以是一个非常精确的工具,用于跟踪分子的单一结合事件等事件。例如,蛋白质与配体的结合事件(如第五章中讨论的)可以通过荧光测定法检测到。
样本制备人为物
值得注意的是,样本制备可能是一个非常棘手的过程。原始样本的制备常常会导致被成像对象的变形,这可能会导致一些混淆。一个有趣的例子是中间体的情况,下面的警告说明中讨论了这一点。
中间体:一个虚构的细胞器
为了进行电子显微镜检查,固定细胞的过程引入了一个关键的人为物,即革兰氏阳性细菌中的中间体(见图 7-11)。由于为电子显微镜制备样本的过程导致的细胞壁降解,最初被认为是自然结构而不是人为物。
请注意,类似的人为物可能存在于您自己的样本中。此外,深度网络完全有可能训练自己检测这种人为物,而不是训练自己发现真实的生物学。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0711.png
图 7-11。中间体是由电子显微镜制备引入的人为物,曾被认为是细胞中真实结构。 (改编自维基百科。)
追踪显微镜样本的来源
当您设计处理显微镜数据的系统时,跟踪样本的来源将至关重要。每个图像应该带有关于收集图像的条件的信息。这可能包括用于捕获图像的物理设备、监督成像过程的技术人员、被成像的样本以及收集样本的物理位置。生物学是极其棘手的“调试”。像前面警告中描述的问题可能长期未被追踪。确保维护有关图像来源的充分元数据可能会在未来为您和您的团队避免重大问题。
深度学习应用
在本节中,我们简要回顾了深度学习在显微镜学中的各种应用,如细胞计数、细胞分割和计算测定法构建。正如我们之前在本章中所指出的,这只是深度显微镜可能的应用的有限子集。然而,了解这些基本应用将使您具备发明自己新的深度显微镜应用所需的理解。
细胞计数
一个简单的任务是计算出现在给定图像中的细胞数量。您可能会合理地问为什么这是一个有趣的任务。对于许多生物实验,跟踪经过给定干预后存活的细胞数量可能非常有用。例如,也许这些细胞来自一个癌细胞系,而干预是应用抗癌化合物。一个成功的干预会减少活着的癌细胞数量,因此有一个可以准确计算这些活着的细胞数量的深度学习系统而无需人工干预将是非常有用的。
什么是细胞系?
在生物学中,研究特定类型的细胞通常是有用的。对一组细胞进行实验的第一步是获得大量这样的细胞。细胞系就是这样的细胞。细胞系是从特定来源培养出来的细胞,在实验室条件下可以稳定生长。
细胞系已经在无数生物学论文中使用,但对其进行的科学研究往往存在严重的担忧。首先,将细胞从其自然环境中移除可能会从根本上改变其生物学特性。越来越多的证据表明,细胞的环境可以从根本上塑造其对刺激的反应。
更严重的是,细胞系经常受到污染。来自一个细胞系的细胞可能会污染来自另一个细胞系的细胞,因此在“乳腺癌”细胞系上的结果实际上对乳腺癌研究者来说毫无意义!
因此,对细胞系的研究经常受到谨慎对待,其结果仅作为尝试在动物或人类测试中复制的动力。尽管如此,细胞系研究为生物研究提供了一个宝贵的简单入口点,并且仍然普遍存在。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0712.png
图 7-12。果蝇细胞样本。请注意显微镜图像中的图像条件与照片中的图像条件可能会有很大不同。(来源:细胞图像库。)
正如图 7-12 所示,细胞显微镜图像中的图像条件可能与标准图像条件有很大不同,因此并不明显卷积神经网络等技术是否可以适应细胞计数等任务。幸运的是,大量的实验工作表明,卷积网络在学习显微镜数据集方面表现得相当不错。
在 DeepChem 中实现细胞计数
本节将介绍使用 DeepChem 进行细胞计数的深度学习模型的构建。我们将从加载和特征化细胞计数数据集开始。我们使用广泛生物图像基准集(BBBC)来获取一个有用的显微镜数据集。
BBBC 数据集
BBBC 数据集包含来自各种细胞分析的注释生物图像数据集的有用集合。这是一个有用的资源,可以帮助您训练自己的深度显微镜模型。DeepChem 拥有一系列图像处理资源,使您更容易处理这些数据集。特别是,DeepChem 的ImageLoader类有助于加载数据集。
处理图像数据集
图像通常以标准图像文件格式(PNG、JPEG 等)存储在磁盘上。图像数据集的处理流程通常会从磁盘中读取这些文件,并将它们转换为适当的内存表示,通常是一个多维数组。在 Python 处理流程中,这个数组通常只是一个 NumPy 数组。对于一个高为N像素,宽为M像素,具有 3 个 RGB 颜色通道的图像,你会得到一个形状为(N, M, 3)的数组。如果你有 10 张这样的图像,这些图像通常会被批处理成一个形状为(10, N, M, 3)的数组。
在将数据集加载到 DeepChem 之前,您首先需要将其下载到本地。我们将用于此任务的 BBBC005 数据集相当大(略小于 2 GB),因此请确保您的开发机器有足够的可用空间:
wget https://data.broadinstitute.org/bbbc/BBBC005/BBBC005_v1_images.zip
unzip BBBC005_v1_images.zip
将数据集下载到本地计算机后,您现在可以使用ImageLoader将此数据集加载到 DeepChem 中:
image_dir = 'BBBC005_v1_images'
files = []
labels = []
for f in os.listdir(image_dir):
if f.endswith('.TIF'):
files.append(os.path.join(image_dir, f))
labels.append(int(re.findall('_C(.*?)_', f)[0]))
loader = dc.data.ImageLoader()
dataset = loader.featurize(files, np.array(labels))
这段代码遍历了图像的下载目录并提取了图像文件。标签被编码在文件名中,因此我们使用简单的正则表达式来提取每个图像中的细胞数量。我们使用ImageLoader将其转换为 DeepChem 数据集。
现在让我们将这个数据集分成训练、验证和测试集:
splitter = dc.splits.RandomSplitter()
train_dataset, valid_dataset, test_dataset = splitter.train_valid_test_split(
dataset, seed=123)
现在,我们可以定义模型本身。在这种情况下,让我们制作一个简单的卷积架构,最后是一个全连接层:
learning_rate = dc.models.tensorgraph.optimizers.ExponentialDecay(0.001, 0.9,
250)
model = dc.models.TensorGraph(learning_rate=learning_rate, model_dir='model')
features = layers.Feature(shape=(None, 520, 696))
labels = layers.Label(shape=(None,))
prev_layer = features
for num_outputs in [16, 32, 64, 128, 256]:
prev_layer = layers.Conv2D(num_outputs, kernel_size=5, stride=2,
in_layers=prev_layer)
output = layers.Dense(1, in_layers=layers.Flatten(prev_layer))
model.add_output(output)
loss = layers.ReduceSum(layers.L2Loss(in_layers=(output, labels)))
model.set_loss(loss)
请注意,我们使用L2Loss来训练我们的模型作为回归任务。尽管细胞计数是整数,但我们对图像中细胞数量没有自然的上限。
训练这个模型将需要一些计算工作(稍后会详细介绍),因此,为了开始,我们建议使用我们的预训练模型进行基本实验。这个模型可以直接用于进行预测。有关下载预训练模型的说明,请参见与本书相关的代码存储库。下载完成后,您可以使用以下方法将预训练权重加载到模型中:
model.restore()
让我们拿出这个预训练模型试试。首先,我们将计算我们的细胞计数任务的测试集上的平均预测误差:
y_pred = model.predict(test_dataset).flatten()
print(np.sqrt(np.mean((y_pred-test_dataset.y)**2)))
当您尝试运行模型时,您会得到什么准确性?
那么,您如何为自己训练这个模型呢?您可以通过在数据集上训练 50 个时期来拟合模型:
model.fit(train_dataset, nb_epoch=50)
这个学习任务将需要一定的计算资源。在一台好的 GPU 上,它应该在一个小时左右内完成。在 CPU 系统上轻松训练模型可能不可行。
训练后,在验证和测试集上测试模型的准确性。它是否与预训练模型的匹配?
细胞分割
细胞分割的任务涉及注释给定细胞显微镜图像,以指示细胞出现的位置和背景出现的位置。为什么这很有用?如果您回想一下我们之前讨论的革兰氏阳性和革兰氏阴性细菌,您可能会猜到为什么一个自动系统用于分离这两种细菌类型可能会很有用。事实证明,类似的问题在所有细胞显微镜图像中都会出现(以及在我们将在第八章中看到的成像的其他领域)。
分割掩模提供了显着更精细的分辨率,并允许进行比细胞计数更精细的分析。例如,了解给定板上有多少细胞覆盖可能是有用的。一旦生成了分割掩模,这样的分析就很容易进行。图 7-13 提供了从合成数据集生成的分割掩模的示例。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0713.png
图 7-13. 细胞的合成数据集(左侧)以及前景/背景掩模,注明细胞出现在图像中的位置。 (来源: Broad Institute.)
也就是说,分割要求机器学习模型比计数要求更多。能够精确区分细胞和非细胞区域需要更高的学习精度。因此,不足为奇的是,机器学习分割方法仍然比简单的细胞计数方法更难使其正常工作。我们将在本章后面尝试一个分割模型。
分割掩模是从哪里来的?
值得注意的是,分割掩模是复杂的对象。除了深度学习技术外,一般不存在生成这种掩模的好算法。那么我们如何启动训练所需的数据以改进深度分割技术?一个可能的方法是使用合成数据,就像图 7-13 中那样。因为细胞图像是以合成方式生成的,掩模也可以合成生成。这是一个有用的技巧,但它显然有局限性,因为它将限制我们学到的分割方法适用于类似的图像。
一个更一般的程序是让人类注释者生成合适的分割掩模。类似的程序被广泛用于训练自动驾驶汽车。在那个任务中,找到注释行人和街道标志的分割是至关重要的,大量的人类分割者被用来生成所需的训练数据。随着机器学习显微镜技术的重要性不断增长,类似的人类流水线可能会变得至关重要。
在 DeepChem 中实现细胞分割
在这一部分,我们将在与之前用于细胞计数任务相同的 BBBC005 数据集上训练一个细胞分割模型。然而,这里有一个关键的微妙之处。在细胞计数挑战中,每个训练图像都有一个简单的计数作为标签。然而,在细胞分割任务中,每个标签本身就是一幅图像。这意味着细胞分割模型实际上是一种“图像转换器”,而不是简单的分类或回归模型。让我们从获取这个数据集开始。我们必须从 BBBC 网站检索分割掩模,使用以下命令:
wget https://data.broadinstitute.org/bbbc/BBBC005/BBBC005_v1_ground_truth.zip
unzip BBBC005_v1_ground_truth.zip
地面真实数据大约是 10MB,所以下载起来应该比完整的 BBBC005 数据集更容易。现在让我们将这个数据集加载到 DeepChem 中。幸运的是,ImageLoader已经设置好处理图像分割数据集,不需要太多额外的麻烦:
image_dir = 'BBBC005_v1_images'
label_dir = 'BBBC005_v1_ground_truth'
rows = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P')
blurs = (1, 4, 7, 10, 14, 17, 20, 23, 26, 29, 32, 35, 39, 42, 45, 48)
files = []
labels = []
for f in os.listdir(label_dir):
if f.endswith('.TIF'):
for row, blur in zip(rows, blurs):
fname = f.replace('_F1', '_F%d'%blur).replace('_A', '_%s'%row)
files.append(os.path.join(image_dir, fname))
labels.append(os.path.join(label_dir, f))
loader = dc.data.ImageLoader()
dataset = loader.featurize(files, labels)
现在我们已经加载和处理了我们的数据集,让我们开始构建一些深度学习模型。和以前一样,我们将把这个数据集分成训练、验证和测试集:
splitter = dc.splits.RandomSplitter()
train_dataset, valid_dataset, test_dataset = splitter.train_valid_test_split(
dataset, seed=123)
我们可以使用什么架构来进行图像分割任务?这不仅仅是使用一个简单的卷积架构,因为我们的输出本身需要是一幅图像(分割掩模)。幸运的是,过去已经有一些适合这个任务的架构。U-Net 架构使用一系列堆叠的卷积来逐渐“下采样”然后“上采样”源图像,如图 7-14 所示。这种架构在图像分割任务中表现良好。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0714.png
图 7-14。生物医学图像分割的 U-Net 架构表示。(改编自弗莱堡大学。)
现在让我们在 DeepChem 中实现 U-Net:
learning_rate = dc.models.tensorgraph.optimizers.ExponentialDecay(0.01, 0.9, 250)
model = dc.models.TensorGraph(learning_rate=learning_rate,
model_dir='segmentation')
features = layers.Feature(shape=(None, 520, 696, 1)) / 255.0
labels = layers.Label(shape=(None, 520, 696, 1)) / 255.0
# Downsample three times.
conv1 = layers.Conv2D(16, kernel_size=5, stride=2, in_layers=features)
conv2 = layers.Conv2D(32, kernel_size=5, stride=2, in_layers=conv1)
conv3 = layers.Conv2D(64, kernel_size=5, stride=2, in_layers=conv2)
# Do a 1x1 convolution.
conv4 = layers.Conv2D(64, kernel_size=1, stride=1, in_layers=conv3)
# Upsample three times.
concat1 = layers.Concat(in_layers=[conv3, conv4], axis=3)
deconv1 = layers.Conv2DTranspose(32, kernel_size=5, stride=2, in_layers=concat1)
concat2 = layers.Concat(in_layers=[conv2, deconv1], axis=3)
deconv2 = layers.Conv2DTranspose(16, kernel_size=5, stride=2, in_layers=concat2)
concat3 = layers.Concat(in_layers=[conv1, deconv2], axis=3)
deconv3 = layers.Conv2DTranspose(1, kernel_size=5, stride=2, in_layers=concat3)
# Compute the final output.
concat4 = layers.Concat(in_layers=[features, deconv3], axis=3)
logits = layers.Conv2D(1, kernel_size=5, stride=1, activation_fn=None,
in_layers=concat4)
output = layers.Sigmoid(logits)
model.add_output(output)
loss = layers.ReduceSum(layers.SigmoidCrossEntropy(in_layers=(labels, logits)))
model.set_loss(loss)
这种架构比用于细胞计数的架构稍微复杂一些,但我们使用相同的基本代码结构和堆叠卷积层来实现我们想要的架构。和以前一样,让我们使用一个预训练模型来尝试这个架构。下载预训练模型的指导可在书的代码库中找到。一旦你把预训练权重放好,你可以像以前一样加载权重:
model.restore()
让我们使用这个模型创建一些掩模。调用model.predict_on_batch()允许我们预测一批输入的输出掩模。我们可以通过将我们的掩模与地面真实掩模进行比较并检查重叠部分来检查我们预测的准确性:
scores = []
for x, y, w, id in test_dataset.itersamples():
y_pred = model.predict_on_batch([x]).squeeze()
scores.append(np.mean((y>0) == (y_pred>0.5)))
print(np.mean(scores))
这应该返回大约 0.9899。这意味着将近 99% 的像素被正确预测了!这是一个不错的结果,但我们应该强调这只是一个玩具学习任务。一个简单的图像处理算法加上亮度阈值可能也能做得差不多。不过,这里展示的原则应该能够适用于更复杂的图像数据集。
好的,现在我们已经使用预训练模型进行了探索,让我们从头开始训练一个 U-Net 模型,进行 50 个 epochs 的训练,看看我们能得到什么结果:
model.fit(train_dataset, nb_epoch=50, checkpoint_interval=100)
和之前一样,这种训练需要大量的计算资源,在一台性能良好的 GPU 上可能需要几个小时。在 CPU 系统上训练这个模型可能并不可行。一旦模型训练完成,尝试运行结果并看看你得到了什么。你能达到预训练模型的准确率吗?
计算实验
细胞计数和分割是相当直观的任务,因此并不奇怪机器学习模型能够在这类数据集上表现良好。人们可能会合理地问,机器学习模型是否只能做到这些。
幸运的是,答案是否定的!机器学习模型能够捕捉到数据集中微妙的信号。例如,一项研究表明,深度学习模型能够预测原始图像中荧光标记的输出。值得停下来考虑这个结果有多么令人惊讶。正如我们在“为显微镜准备生物样本”中看到的,荧光染色可能是一个相当复杂的过程。令人惊讶的是,深度学习可能能够减少一些必要的准备工作。
这是一个令人兴奋的结果,但值得注意的是,这仍然是一个早期的结果。还需要做大量工作来“加固”这些技术,以便它们能够更广泛地应用。
结论
在本章中,我们向您介绍了显微镜学的基础知识以及一些基本的显微系统机器学习方法。我们对现代显微镜学的一些基本问题(尤其是应用于生物问题)进行了广泛介绍,并讨论了深度学习已经产生影响的领域,以及它未来可能产生更大影响的领域。
我们还提供了显微镜学中一些物理和生物学的全面概述,并试图传达为什么这些信息对于那些主要关注构建有效处理显微镜图像和模型管道的开发人员可能是有用的。了解物理原理,比如衍射极限,将使您能够理解为什么使用不同的显微技术以及深度学习可能对该领域的未来至关重要。了解生物样本制备技术将帮助您理解在设计实用显微系统时需要跟踪的元数据和注释类型。
虽然我们对深度学习技术在显微镜学中的潜在应用感到非常兴奋,但我们需要强调这些方法存在一些注意事项。首先,一些最近的研究强调了视觉卷积模型的脆弱性。简单的伪影可能会让这些模型出错并导致重大问题。例如,一个停车标志的图像可能会被轻微扰动,以至于模型将其分类为绿色交通灯。这对于自动驾驶汽车来说将是灾难性的!
鉴于这些证据,值得问一下深度显微镜模型存在哪些潜在的陷阱。深度显微镜模型是否可能只是从记忆中的先前数据点中填充?即使这并非其性能的全部解释,但至少部分深度模型的能力可能来自这种记忆数据的反刍。这很可能会导致虚假相关性的插补。因此,在对微观数据集进行科学分析时,停下来质疑你的结果是否是由模型人为因素或真实生物现象造成的将至关重要。我们将在接下来的章节中为您提供一些工具,以便您批判性地审查模型,从而更好地确定您的模型实际学到了什么。
在下一章中,我们将探讨深度学习在医学中的应用。我们将重复本章中涵盖的许多视觉深度学习技能。
¹ 欧阳伟等人。“深度学习大大加速了超分辨率定位显微镜。”自然生物技术36(2018 年 4 月):460–468。https://doi.org/10.1038/nbt.4106。
² 陶鑫等人。“用于深度图像去模糊的尺度循环网络。”https://arxiv.org/pdf/1802.01770.pdf。2018 年。
³ 克里斯滕森,埃里克。“体外标记:预测未标记图像中的荧光标记。”https://github.com/google/in-silico-labeling。
⁴ 罗森菲尔德,阿米尔,理查德·泽梅尔和约翰·K·索索斯。“房间里的大象。”https://arxiv.org/abs/1808.03305。2018 年。
第八章:医学的深度学习
正如我们在上一章中看到的,从视觉数据集中提取有意义的信息对于分析显微镜图像是有用的。这种处理视觉数据的能力同样对医学应用非常有用。现代医学的许多领域需要医生对医学扫描进行批判性分析。深度学习工具有可能使这种分析变得更加简单和快速(但可能更少可解释)。
让我们学习更多。我们将从简要概述早期的医学计算技术开始。我们将讨论一些这些方法的局限性,然后我们将开始介绍当前一系列基于深度学习的医学技术。我们将解释这些新技术如何可能使我们绕过旧技术的一些基本限制。我们将以讨论将深度学习应用于医学的一些伦理考虑结束本章。
计算机辅助诊断
设计计算机辅助诊断系统自从该领域出现以来一直是人工智能研究的主要焦点。最早的尝试使用手工策划的知识库。在这些系统中,专家医生将被征求编写因果推理规则(例如,参见图 8-1)。
通过确定性因素对不确定性进行基本支持。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0801.png
图 8-1。MYCIN 是一个早期用于诊断细菌感染的专家系统。这是一个 MYCIN 推理规则的示例(改编自萨里大学)。
这些规则是使用逻辑引擎组合的。设计了许多有效的推理技术,可以有效地组合大量的规则数据库。这种系统传统上被称为“专家系统”。
专家系统发生了什么?
尽管专家系统取得了一些显著的成功,但构建这些系统需要大量的努力。规则必须从专家那里费力地征求,并由训练有素的“知识工程师”策划。虽然一些专家系统在有限的领域取得了惊人的成果,但总体上它们过于脆弱,无法广泛使用。尽管如此,专家系统对计算机科学的许多领域产生了重大影响,许多现代技术(SQL、XML、贝叶斯网络等)都从专家系统技术中汲取灵感。
如果你是开发者,最好停下来考虑一下。尽管专家系统曾经是一项炙手可热的技术,但它们目前主要存在于历史的好奇中。今天大多数炙手可热的技术很可能最终会成为计算机科学历史上的好奇。这是计算机科学的一个特点,而不是一个缺陷。这个领域在快速重新发明自己,因此我们可以相信,取代今天技术的工具将满足一些今天的工具无法满足的关键需求。同时,就像专家系统一样,我们可以放心,今天技术的算法基础将在明天的工具中延续。
医学专家系统取得了一定的成就。其中一些被广泛部署并被国际接受。然而,这些系统未能在日常医生和护士中取得重大进展。一个问题是它们非常挑剔且难以使用。它们还要求用户能够以高度结构化的格式传递患者信息。考虑到当时计算机几乎没有进入标准诊所,要求医生和护士接受高度专业化的培训被证明是一个过大的要求。
使用贝叶斯网络进行概率诊断
专家系统工具的另一个主要问题是它们只能提供确定性预测。这种确定性预测并没有留下太多的不确定性空间。如果医生遇到一个诊断不明确的棘手患者怎么办?有一段时间,似乎如果专家系统可以修改以考虑不确定性,这将使它们取得成功。
这一基本观点引发了大量关于贝叶斯网络用于临床诊断的工作。(本书的一位作者在本科时曾花了一年时间研究这样的系统。)然而,这些系统遭受了与专家系统相同的许多限制。仍然需要从医生那里获取结构知识,而贝叶斯临床网络的设计者面临着从医生那里获取有意义概率的额外挑战。这个过程给采用过程增加了显著的开销。
此外,训练贝叶斯网络可能会很复杂。不同类型的贝叶斯网络需要不同的算法。与几乎所有网络都适用的梯度下降技术相比,这与深度学习算法形成了对比。学习的鲁棒性通常是促使广泛采用的原因。这一基本观点引发了大量关于贝叶斯网络用于临床诊断的工作。(参见图 8-2 中的一个贝叶斯网络的简单示例。)
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0802.png
图 8-2. 一个简单的贝叶斯网络示例,用于推断特定位置的草是否潮湿。(来源:维基媒体。)
易用性推动采用
专家系统和贝叶斯网络都未能赢得广泛的采用。至少部分原因是这些系统在开发者体验方面非常糟糕。从开发者的角度来看,设计贝叶斯网络或专家系统都需要不断地让医生参与开发。此外,系统的有效性关键取决于开发团队从医生那里提取有价值的见解的能力。
与深度网络形成对比。对于给定的数据类型(图像、分子、文本等)和给定的学习任务,有一组标准的度量可供使用。开发者只需遵循最佳的统计实践(如本书或其他书所教授的)即可构建一个功能性系统。对专业知识的依赖大大减少。这种简化无疑部分原因解释了深度网络为何获得了更广泛的采用。
电子健康记录数据
传统上,医院为他们的患者维护纸质档案。这些档案记录了患者的检查、药物和其他治疗,使医生可以通过快速查看档案来跟踪患者的健康状况。不幸的是,纸质健康记录存在许多困难。在医院之间转移记录需要大量工作,而且很难对纸质健康记录数据进行索引或搜索。
因此,在过去几十年中,许多国家都在大力推动从纸质记录转向电子健康记录(EHRs)。在美国,《平价医疗法案》的采用显著加速了它们的采用,现在大多数美国主要医疗提供商都将患者记录存储在 EHR 系统中。
电子健康记录系统的广泛应用推动了与电子健康记录数据一起工作的机器学习系统研究的繁荣。这些系统旨在使用大量患者记录的数据集来训练模型,以便能够预测诸如患者结果或风险等内容。在许多方面,这些电子健康记录模型是我们刚刚学习的专家系统和贝叶斯网络的智力继承者。与这些早期系统类似,电子健康记录模型旨在帮助诊断过程。然而,尽管早期系统旨在帮助医生进行实时诊断,但这些更新的系统(大多数)仅在后端工作。
许多项目已经尝试从电子健康记录数据中学习稳健的模型。虽然已经取得了一些显著成功,但对从业者来说,在电子健康记录数据上进行学习仍然具有挑战性。由于隐私问题,目前没有太多大型公共电子健康记录数据集可用。因此,迄今为止,只有少数精英研究人员能够设计这些系统。此外,电子健康记录数据往往非常混乱。由于人类医生和护士手动输入信息,大多数电子健康记录数据存在缺失字段和各种不同的约定。创建能够处理缺失数据的稳健模型已被证明具有挑战性。
ICD-10 代码
ICD-10 是用于患者疾病和症状的一组“代码”。这些标准代码近年来得到广泛采用,因为它们使保险公司和政府机构能够为疾病设定标准实践、治疗和治疗价格。
ICD-10 代码将人类疾病的高维连续空间“量化”(离散化)。通过标准化,它们使医生能够比较和分组患者。值得注意的是,出于这个原因,这些代码可能对电子健康记录系统和模型的开发者具有重要意义。如果您正在为新的电子健康记录系统设计数据仓库,请确保考虑您将放置代码的位置!
快速医疗互操作性资源(FHIR)
快速医疗互操作性资源(FHIR)规范是为了以标准和灵活的格式表示临床数据而开发的。来自谷歌的最新工作展示了如何将原始电子健康记录数据自动转换为 FHIR 格式。使用这种格式可以开发标准的深度架构,可以应用于任意电子健康记录数据,这意味着可以以即插即用的方式使用这些数据的标准开源工具。这项工作仍处于早期阶段,但对该领域的进展具有激动人心的意义。尽管标准化乍看起来可能很无聊,但它是未来进步的基础,因为它意味着可以有效地处理更大的数据集。
然而,这种情况开始发生改变。改进的工具,无论是用于预处理还是学习,已经开始使得在电子健康记录系统上进行有效学习成为可能。DeepPatient 系统在患者的医疗记录上训练一个去噪自动编码器,以创建一个患者表示,然后用于预测患者结果。在这个系统中,患者的记录从一组无序的文本信息转换为一个向量。将不同数据类型转换为向量的这种策略在深度学习中取得了广泛成功,并似乎有望在电子健康记录系统中提供有意义的改进。文献中出现了许多基于电子健康记录系统的模型,其中许多开始融入深度学习的最新工具,如循环网络或强化学习。虽然具有这些最新功能的模型仍在不断发展,但它们非常令人兴奋,并为未来几年该领域可能发展的方向提供了指引。
无监督学习呢?
在本书的大部分内容中,我们主要展示了监督学习方法。还有一整类“无监督”学习方法,它们不像监督训练数据那样依赖于标签。我们还没有真正介绍无监督学习作为一个概念,但基本思想是我们不再有与数据点相关联的标签。例如,想象我们有一组电子病历记录,但没有患者结果数据。我们能做什么?
最简单的答案是我们可以聚类记录。举个玩具例子,想象我们有“双胞胎”患者,他们的电子病历记录是相同的。预测这两位患者的结果会相似似乎是合理的。无监督学习技术,如k-means 或自动编码器实现了这种基本直觉的更复杂形式。您将在第九章中看到一个无监督算法的复杂示例。
无监督技术可以提供一些引人注目的见解,但这些方法有时可能命中或失误。虽然有一些引人注目的用例,如 DeepPatient,但总体而言,无监督方法仍然足够棘手,尚未广泛使用。然而,如果您是研究人员,致力于稳定无监督学习的方法仍然是一个引人注目(且具有挑战性)的未解问题。
大型患者电子病历数据库的危险?
许多大型机构正在向所有患者使用电子病历系统迈进。当这些大型数据集被标准化(可能以 FHIR 格式)并实现互操作性时会发生什么?积极的一面是,可能会支持应用程序,例如搜索具有特定疾病表型的患者。这种专注的搜索功能可能有助于医生更有效地为患者找到治疗方法,特别是对于患有罕见疾病的患者。
然而,不难想象大型患者数据库可能被恶意利用。例如,保险公司可能使用患者结果系统预先拒绝对高风险患者的保险,或者寻求保持高患者存活率的顶级外科医生可能避免对系统标记为高风险的患者进行手术。我们如何防范这些危险?
许多机器学习系统提出的问题无法用机器学习工具解决。相反,这些问题的答案可能在于禁止医生、保险公司和其他人的掠夺行为的立法。
电子病历真的有助于医生吗?
虽然电子病历显然有助于设计学习算法,但没有令人信服的证据表明电子病历实际上改善了医生的生活。挑战的一部分是今天的电子病历要求医生进行大量手动数据输入。对于患者来说,这创造了一种新的熟悉动态,医生在大部分咨询时间都在看电脑,而不是看实际患者。
这种现状让患者和医生都感到不满。医生感到疲惫,因为他们大部分时间都在做文书工作,而不是照顾患者,患者感到被忽视。下一代深度学习系统的希望是未来产品可能会改善这种不平衡。
然而,有一个真正的机会,下一代深度学习工具可能同样对医生不友好且无益。电子病历系统的设计者也没有旨在制造不友好的系统。
深度放射学
放射学是利用医学扫描来诊断疾病的科学。医生使用各种不同的扫描,如 MRI 扫描、超声波、X 射线和 CT 扫描。对于每一种扫描,挑战是从给定的扫描图像中诊断患者的状态。这看起来是一个非常适合卷积学习方法的挑战。正如我们在前几章中看到的,深度学习方法能够从图像数据中学习复杂的函数。现代放射学的大部分(至少是机械部分)包括对复杂医学图像数据进行分类和处理。扫描在医学中有着悠久而传奇的历史(参见图 8-4 中早期 X 射线的例子)。
在本节中,我们将快速介绍一些不同类型的扫描,并简要介绍一些深度学习应用。许多这些应用在质量上是相似的。它们首先从医疗机构获取足够大的扫描数据集。这些扫描用于训练卷积架构(参见图 8-3)。通常,该架构是标准的 VGG 或 ResNet 架构,但有时会对核心结构进行一些调整。经过训练的模型通常(至少根据可能天真的统计数据)在所涉及的任务上表现出色。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0803.png
图 8-3。这张图展示了一些标准的卷积架构(VGG-19,Resnet-34,数字表示应用的卷积数量)。这些架构是图像任务的标准,通常用于医疗应用。
这些进展导致了一些可能夸大的期望。一些知名的人工智能科学家,尤其是 Geoff Hinton,评论说,深度学习在放射学方面的发展将会进展到不再值得在不久的将来培训新的放射科医生。这是真的吗?最近有一系列进展,深度学习系统似乎已经实现了接近人类表现的成果。然而,这些结果带有许多警告,并且这些系统通常以未知的方式脆弱。
我们认为直接 1 对 1 替代医生的风险仍然很低,但存在系统性替代的真正风险。这是什么意思?新创企业正在努力创造新的商业模式,其中深度学习系统完成大部分扫描分析工作,只剩下少数医生。
深度学习实际上在学习医学吗?
对深度模型在医学图像中实际学习了什么进行了重要的分析。不幸的是,在许多情况下,深度模型似乎成功地捕捉到了图像中的非医学因素。例如,模型可能会隐式学习识别拍摄特定医学扫描的扫描中心。由于特定中心通常用于更严重或不太严重的患者,乍一看,模型可能看起来已经成功地学会了有用的医学知识,但实际上通常是无用的。
在这种情况下可以做些什么?对于这个问题,还没有定论,但一些早期方法正在出现。第一种方法是利用关于模型可解释性的不断增长的文献来仔细审查模型学习了什么。在第十章中,我们将深入探讨一些模型可解释性的方法。
另一种方法是在临床中进行前瞻性试验部署模型。前瞻性试验仍然是测试提出的医学干预措施的黄金标准,很可能它们在深度学习技术方面也将保持如此。
X 射线扫描和 CT 扫描
非正式地说,X 射线扫描——如果我们要准确的话,是放射学——涉及使用 X 射线查看身体内部结构(图 8-4)。计算机断层扫描(CT)是 X 射线扫描的一种变体,其中 X 射线源和探测器围绕被成像的物体旋转,从而产生 3D 图像。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0804.png
图 8-4。威廉·伦琴拍摄的他妻子安娜·伯莎·路德维希手部的第一张医学 X 射线照片。自从这张第一张照片以来,X 射线技术已经取得了长足的进步,深度学习有可能进一步推动其发展!
一个常见的误解是 X 射线扫描只能成像“硬”物体,比如骨头。事实证明这是错误的。CT 扫描通常用于成像身体组织,比如大脑(图 8-5),而反散射 X 射线经常用于机场安检点成像旅客。乳腺 X 线摄影使用低能量 X 射线扫描乳腺组织。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0805.png
图 8-5。人脑的 CT 扫描从底部到顶部。注意 CT 扫描提供 3D 信息的能力。(来源:维基媒体。)
值得注意的是,所有 X 射线扫描都已知与癌症有关,因此一个常见的目标是通过限制所需扫描的数量来减少患者接受辐射的风险。这种风险在 CT 扫描中更为明显,因为为了收集足够的数据,必须让患者暴露在辐射下更长的时间。已经设计了各种信号处理算法来减少 CT 所需的扫描数量。一些令人兴奋的最新工作已经开始使用深度学习来进一步调整这个重建过程,从而减少所需的扫描数量。
然而,在这个领域中,深度学习的大多数用途是用于分类扫描。例如,卷积网络已被用于从 CT 脑图像中分类阿尔茨海默病的进展。其他工作声称能够从胸部 X 射线扫描中诊断肺炎,准确度接近医生水平。深度学习也被用于在乳房 X 线摄影中实现强大的分类准确度。
人类水平的准确性很棘手!
当一篇论文声称其系统实现了接近人类准确度时,值得停下来考虑这意味着什么。通常,论文的作者选择某个度量标准(比如 ROC AUC),一组外部医生对所选研究的测试集进行注释。然后将模型在这个测试集上的准确度与“平均”医生的准确度进行比较(通常是医生评分的平均值或中位数)。
这是一个相当复杂的过程,有很多方面可能导致比较出错。首先,度量标准的选择可能起到作用——往往改变度量标准的选择会导致不同的结果。良好的分析将考虑多种不同的度量标准,以确保结论对这种差异具有鲁棒性。
另一个需要注意的一点是医生之间存在相当大的差异。值得检查以确保你选择的“平均”是可靠的。一个更好的度量标准可能是询问你的算法是否能够击败小组中的“最佳”医生。
第三个问题是确保测试集没有“污染”可能非常棘手。(请参阅我们在第七章中的警告。)细微的污染形式可能发生,即同一患者的扫描意外地出现在训练集和测试集中。如果您的模型准确率非常高,值得多次检查以防止此类泄漏。我们过去都曾犯过这些管道上的错误。
最后,“人类水平的准确性”通常并不意味着太多。正如我们所指出的,一些专家系统和贝叶斯网络在有限的任务上达到了人类水平的准确性,但未能对医学产生广泛影响。原因是医生执行一系列紧密联系的任务。一个医生在扫描阅读方面可能表现不佳,但可能能够利用其他信息提供更好的诊断。值得记住,这些任务通常是合成的,可能不符合最佳的医师实践。需要进行前瞻性临床试验,使用深度学习系统与同意的患者一起,以更准确地评估这些技术的有效性。
组织学
组织学是研究组织的学科,通常通过显微镜扫描来观察。我们不会过多讨论这个问题,因为设计深度组织学系统的问题是深度显微镜面临的问题的一个子集。回顾一下那一章,了解更多信息。我们只会简单地指出,深度学习模型在组织学研究中取得了良好的表现。
MRI 扫描
磁共振成像(MRI)是医生常用的另一种扫描形式。它不使用 X 射线,而是利用强磁场进行成像。因此,MRI 扫描的一个优点是辐射暴露有限。然而,这些扫描通常需要患者躺在嘈杂狭窄的 MRI 机器内,这种经历对患者可能比 X 射线扫描更不愉快。
像 CT 一样,MRI 能够组装 3D 图像。与 CT 扫描一样,许多深度学习研究试图简化这个重建过程。一些早期研究声称,深度学习技术可以改进传统信号处理方法,以减少 MRI 图像的扫描时间。此外,与其他扫描技术一样,许多研究试图使用深度网络对 MRI 图像进行分类、分割和处理,并取得了一些显著的成功。
信号处理的深度学习?
对于 CT 扫描和 MRI 扫描,我们已经提到深度网络已被用于更有效地帮助重建图像。这两个应用都是在信号处理中使用深度学习的更广泛趋势的例子。我们已经在旁敲侧击中看到了一些;超分辨率显微镜的深度学习方法也属于这个一般框架。
这种改进信号处理技术的工作从基础的角度来看非常令人兴奋,因为信号处理是一个高度数学化、发达的领域。深度学习在这里提供新的方向本身就是开创性的!然而,值得注意的是,传统的信号处理算法通常提供非常强大的基准线。因此,与图像分类不同,深度方法在这个领域尚未提供突破性的准确性改进。然而,这是一个持续而积极的研究领域。如果深度信号处理的工作最终比简单的图像处理更具影响力,这一点一点也不令人惊讶,因为这些技术有非常广泛的应用范围。
值得注意的是,医生使用许多其他类型的扫描。鉴于由强大的开源工具支持的深度学习应用的爆炸式增长,可以肯定地说,对于每种这样的扫描类型,都有一两项研究试图使用深度学习来完成任务。例如,深度学习已经应用于超声波、心电图(ECG)扫描、皮肤癌检测等。
卷积网络是一种非常强大的工具,因为人类活动很大程度上围绕着处理复杂的视觉信息。此外,开源框架的增长意味着全球研究人员已经加入了应用深度学习技术于新类型图像的竞赛。在许多方面,这种研究相对直接(至少在计算端),因为标准工具可以应用而不需要太多麻烦。如果您在一家公司工作时阅读本文,那么深度学习的这些特性很可能使您作为从业者感兴趣。
学习模型作为治疗方法
到目前为止,在本章中,我们已经看到学习模型可以成为医生的有效助手,帮助诊断和扫描理解的过程。然而,有一些令人兴奋的证据表明,学习模型可以超越成为医生的助手,成为治疗工具。
这可能如何运作呢?深度学习最大的优势之一是,现在首次有可能构建在感知数据上运行的实用软件。因此,机器学习系统有可能作为残疾患者的“眼睛”和“耳朵”。视觉系统可以帮助视力受损的患者更有效地在世界中导航。音频处理系统可以帮助听力受损的患者更有效地在世界中导航。这些系统面临着其他深度模型所没有的一系列挑战,因为它们必须在实时环境中有效运行。到目前为止,我们在本书中考虑过的所有模型都是批处理系统,适用于部署在后端服务器上,而不适用于部署在实时嵌入式设备上的模型。在处理机器学习生产中存在一系列挑战,我们在这里不会深入讨论,但我们鼓励感兴趣的读者深入研究这个主题。
我们还注意到,有一类独立的软件驱动治疗方法利用了现代软件对人类大脑的强大影响。最近的研究浪潮表明,现代软件应用如 Facebook、Google、微信等可以非常容易上瘾。这些应用程序设计有明亮的颜色,旨在刺激我们大脑中的许多相同中枢,就像赌场老虎机一样。越来越多的人认识到数字成瘾是许多患者面临的真正问题。这是本书范围之外的一个广泛领域,但我们指出,有证据表明现代软件的这种力量也可以用于好的方面。一些软件应用程序已经开发出利用现代应用程序的心理效应作为治疗干预的方法,帮助患有抑郁症或其他疾病的患者。
糖尿病视网膜病变
到目前为止,在本章中,我们已经从理论角度讨论了深度学习在医学上的应用。在本节中,我们将卷起袖子,用一个实际的例子来动手实践。具体来说,我们将建立一个模型来帮助诊断糖尿病视网膜病变患者的进展情况。
糖尿病视网膜病变是糖尿病损害眼睛健康的一种情况。这是导致失明的主要原因,尤其是在发展中国家。眼底是眼睛的内部区域,与晶状体相对。诊断糖尿病视网膜病变的常见策略是医生查看患者眼底的图像并手动标记。已经进行了大量工作来开发“眼底摄影”技术,以捕捉患者眼底图像(请参阅图 8-6)。
https://github.com/OpenDocCN/ibooker-dl-zh/raw/master/docs/dl-lfsci/img/dlls_0806.png
图 8-6。一位接受了散射激光手术治疗糖尿病视网膜病变的患者眼底图像。(来源:维基共享资源。)
糖尿病视网膜病变的学习挑战是设计一种算法,可以根据患者眼底图像对患者疾病进展进行分类。目前,进行这样的预测需要熟练的医生或技术人员。希望机器学习系统能够准确预测患者眼底图像的疾病进展。这可以为患者提供一种廉价的方法来了解他们的风险,他们可以在咨询更昂贵的专家医生进行诊断之前使用。
此外,与电子健康记录数据不同,眼底图像不包含关于患者的敏感信息,这使得收集大型眼底图像数据集更容易。因此,许多机器学习研究和挑战已经在糖尿病视网膜病变数据集上进行。特别是,Kaggle 赞助了一个比赛,旨在创建良好的糖尿病视网膜病变模型,并组织了一个高分辨率眼底图像数据集。在本节的其余部分,您将学习如何使用 DeepChem 在 Kaggle 糖尿病视网膜病变(DR)数据集上构建糖尿病视网膜病变分类器。
获取 Kaggle 糖尿病视网膜病变数据集
Kaggle 挑战的条款禁止我们直接在 DeepChem 服务器上镜像数据。因此,您需要手动从 Kaggle 网站下载数据。您将需要在 Kaggle 注册一个帐户,并通过他们的 API 下载数据集。完整数据集相当大(80 GB),因此如果您的互联网连接无法处理完整下载,您可能选择下载数据的子集。
请查看与本书相关的GitHub 存储库以获取有关下载此数据集的更多信息。这里的图像加载函数要求训练数据以特定的目录结构组织。有关此目录格式的详细信息在 GitHub 存储库中。
处理这些数据的第一步是预处理和加载原始数据。特别是,我们将每个图像裁剪以聚焦其包含视网膜的中心正方形。然后,我们将调整此中心正方形的大小为 512x512。
处理高分辨率图像
许多医学和科学中的图像数据集将包含非常高分辨率的图像。虽然直接在这些高分辨率图像上训练深度学习模型可能很诱人,但这通常在计算上具有挑战性。一个问题是大多数现代 GPU 的内存有限。这意味着在标准硬件上可能无法训练非常高分辨率的模型。此外,大多数图像处理系统(目前)期望其输入图像具有固定形状。这意味着来自不同相机的高分辨率图像必须被裁剪以适应标准形状。
幸运的是,裁剪和调整图像大小通常不会对机器学习系统的性能造成严重损害。进行更彻底的数据增强也很常见,其中会从每个源图像自动生成一些扰动图像。在这个特定案例研究中,我们执行了一些标准的数据增强。我们鼓励您深入研究增强代码,因为它可能对您自己的项目是一个有用的工具。
核心数据存储在磁盘上的一组目录中。我们使用 DeepChem 的ImageLoader类从磁盘加载这些图像。如果您感兴趣,可以详细查看这些加载和预处理代码,但我们已将其封装成一个方便的辅助函数。与 MoleculeNet 加载器的风格相似,该函数还会进行随机训练、验证和测试分割:
train, valid, test = load_images_DR(split='random', seed=123)
现在我们已经有了这个学习任务的数据,让我们构建一个卷积架构来从这个数据集中学习。这个任务的架构相当标准,类似于您在本书中已经看到的其他架构,因此我们在这里不再重复。这是对底层卷积网络的对象包装器的调用:
# Define and build model
model = DRModel(
n_init_kernel=32,
batch_size=32,
learning_rate=1e-5,
augment=True,
model_dir='./test_model')
这段代码示例在 DeepChem 中定义了一个糖尿病视网膜病变卷积网络。正如我们将在后面看到的,训练这个模型将需要一些大量的计算。因此,我们建议您从 DeepChem 网站下载我们的预训练模型,并在早期探索中使用它。我们已经在完整的 Kaggle 糖尿病视网膜病变数据集上训练了这个模型,并为您的方便存储了其权重。您可以使用以下命令下载和存储模型(请注意,第一个命令应在一行上输入,+ / +后面没有空格):
wget https://s3-us-west-1.amazonaws.com/deepchem.io/featurized_datasets
/DR_model.tar.gz
mv DR_model.tar.gz test_model/
cd test_model
tar -zxvf DR_model.tar.gz
cd ..
然后,您可以按如下方式恢复训练模型的权重:
model.build()
model.restore(checkpoint="./test_model/model-84384")
我们正在从该模型中恢复特定的预训练“检查点”。我们将在与本书相关的代码存储库中提供有关恢复过程和用于实现它的完整脚本的更多详细信息。有了预训练模型,我们可以对其进行一些基本统计计算:
metrics = [
dc.metrics.Metric(DRAccuracy, mode='classification'),
dc.metrics.Metric(QuadWeightedKappa, mode='classification')
]
有许多有用的指标可用于评估糖尿病视网膜病变模型。在这里,我们使用DRAccuracy,这只是模型准确性(正确标签的百分比),以及 Cohen’s Kappa,这是用于衡量两个分类器之间一致性的统计量。这很有用,因为糖尿病视网膜病变学习任务是一个多类别学习问题。
让我们使用我们的指标在测试集上评估我们的预训练模型:
model.evaluate(test, metrics)
这将产生以下结果:
computed_metrics: [0.9339595787076572]
computed_metrics: [0.8494075470551462]
基本模型在我们的测试集上获得了 93.4%的准确率。不错!(重要的是要注意,这与 Kaggle 测试集不同——我们只是将 Kaggle 的训练集分成了训练/验证/测试集进行实验。您可以尝试将训练好的模型提交到 Kaggle 以在其测试集上进行评估。)现在,如果您有兴趣从头开始训练完整模型呢?这将在一个良好的 GPU 系统上进行一天或两天的训练,但是做起来相当简单:
for i in range(10):
model.fit(train, nb_epoch=10)
model.evaluate(train, metrics)
model.evaluate(valid, metrics)
model.evaluate(valid, cm)
model.evaluate(test, metrics)
model.evaluate(test, cm)
我们对模型进行了 100 个时期的训练,定期暂停以打印出模型的结果。如果您正在运行此作业,我们建议确保您的计算机在作业进行过程中不会关闭或进入睡眠状态。没有什么比在睡眠屏幕上丢失一个大作业更令人恼火!
结论
在许多方面,将机器学习应用于医学领域的潜力可能比我们迄今看到的其他应用更有影响力。这些其他应用可能已经改变了您在工作中的做法,但机器学习医疗系统很快将改变您个人的医疗体验,以及数百万甚至数十亿其他人的体验。因此,值得停下来思考一些伦理后果。
伦理考虑
这些系统的训练数据在可预见的未来可能会存在偏见。训练数据可能来自发达经济体的医疗系统,因此构建的模型可能对当前缺乏健全医疗系统的地区的准确性会大大降低。
此外,收集患者数据本身就充满潜在的伦理问题。医学在未经同意的情况下进行实验的历史悠久而饱受争议,尤其是针对边缘群体的人。以 1950 年代巴尔的摩的非裔美国癌症患者亨丽埃塔·拉克斯为例。从拉克斯女士肿瘤组织样本培养出的细胞系(“HeLa”)成为了标准的生物工具,并被用于成千上万篇研究论文中,然而这些研究的收益从未传达给她的家人。拉克斯女士的医生没有告知家人他取样的情况,也没有获得同意。直到 1970 年代,她的家人才得知 HeLa 细胞系的情况,当时医学研究人员联系他们寻求额外的样本。
在深度学习时代,这种情况如何会重演呢?一个患者的医疗记录可能会被用来训练一个学习系统,而患者或其家人并未同意。或者更现实的情况是,患者或家人可能会在病床边被诱使签署放弃他们数据权利的文件,希望最后时刻能得到治愈。
这些情景令人不安。我们中没有人会愿意得知我们所钟爱的家人的权利被机构医学或追求利润的初创企业侵犯。我们如何防止这些伦理违规事件发生呢?如果您参与数据收集工作,请暂停并询问数据来源。是否所有相关法律得到了适当的尊重?如果您是一家公司或研究机构的科学家或开发人员,您拥有有价值的技能,可以在组织内发挥影响力。如果您站出来,您将影响组织内的其他人站在您一边。如果您的组织拒绝倾听,您拥有有价值的技能,可以让您找到一个遵守高道德标准的组织工作。
失业问题
本书中其他章节涉及的大多数领域都是相对小众的科学学科。因此,这些领域的重大进展导致失业并不真实存在。相反,可以预期这些领域的就业增长将会发生,因为这些相对小众的领域将会突然变得更加容易接触到更广泛的开发人员和科学家。
医疗保健和医学是不同的。医疗保健是全球最大的行业之一,拥有数百万名医生、护士、技术人员等,为全球人口的需求提供服务。当这个工作人员中的重要部分面临深度学习工具时会发生什么?
医学的很多方面都是深具人情味的。拥有一个值得信赖的初级医疗保健提供者,确保他们始终为您的最佳利益着想,对于病人来说有着深远的影响。对于许多患者来说,随着许多繁琐工作的自动化,护理体验实际上可能会得到改善。
在美国,2010 年的医疗保健改革(《平价医疗法案》)加速了电子健康记录系统在美国医疗系统中的应用。许多医生报告称这些电子健康记录系统非常不友好,需要进行许多不必要的行政操作。部分原因是由于糟糕的软件设计,加剧了监管机构的控制,使得医疗机构难以转向更好的替代方案。但其中一部分是由于现今软件的局限性。利用深度学习系统来实现更智能的信息处理可以减轻医生的负担,使他们有更多时间与患者交流。
此外,世界上大多数国家的医疗保健系统与美国和欧洲的不匹配。开源工具和可访问数据集的增加将为世界其他地区的政府和企业家提供所需的工具,以服务其选民。
摘要
在本章中,您已经了解了将机器学习方法应用于医学问题的历史。我们首先为您概述了诸如专家系统和贝叶斯网络等经典方法,然后转向了更现代的电子健康记录和医学扫描工作。我们在本章结束时进行了一个深入的案例研究,训练了一个预测糖尿病视网膜病变患者进展的分类器。我们还在一些旁注中评论了医疗保健学习系统面临的挑战。我们将在第十章中回顾其中一些挑战,讨论深度学习系统的可解释性。
请参阅维基百科上的Dendral或Mycin以获取更多信息。
Asabere,Nana Yaw。“mMes:加纳卫生机构的移动医疗专家系统。” 国际科技杂志。2012 年 6 月。
Mandel,JC 等人。“SMART on FHIR:基于标准的、可互操作的应用平台,用于电子健康记录。” 2016 年。
Rajkomar,Alvin 等人。“使用电子健康记录进行可扩展和准确的深度学习。” NPJ 数字医学。2018 年。
Miotto,Riccardo,Li Li,Brian A. Kidd 和 Joel T. Dudley。“Deep Patient:从电子健康记录预测患者未来的无监督表示。” 2016 年。
Gawande,Atul。“为什么医生讨厌他们的电脑。” 纽约客。2018 年。
“AI,放射学和未来的工作。” 经济学家。2018 年。
Gao,Xiaohong W.,Rui Hui 和 Zengmin Tian。“基于深度学习网络的 CT 脑图像分类。” 2017 年。
Pranav Rajpurkar 等人。“CheXNet:基于深度学习的胸部 X 射线放射科医生级肺炎检测。” 2017 年。
Ribli,Dezso 等人。“使用深度学习在乳房 X 线照片中检测和分类病变。” 2018 年。
请参阅维基百科上的数字成瘾者以获取更多信息。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)