VAE简明教程
在过去的几年中,由于(并暗示)该领域取得了一些惊人的进步,基于深度学习的生成模型引起了越来越多的兴趣。 依靠大量的数据、精心设计的网络架构和智能训练技术,深度生成模型表现出了令人难以置信的能力,可以生成各种高度逼真的内容,例如图像、文本和声音。 在这些深度生成模型中,两个主要家族脱颖而出并值得特别关注:生成对抗网络(GAN)和变分自动编码器(VAE)。
在今年 1 月发表的上一篇文章中,我们深入讨论了生成对抗网络 (GAN),并特别展示了对抗训练如何对抗两个网络(生成器和判别器),以推动它们改进迭代 迭代后。 现在,我们在这篇文章中介绍另一种主要的深度生成模型:变分自动编码器(VAE)。 简而言之,VAE 是一种自动编码器,其编码分布在训练过程中进行正则化,以确保其潜在空间具有良好的属性,使我们能够生成一些新数据。 此外,“变分”一词源于正则化与统计学中的变分推理方法之间的密切关系。
如果最后两句话很好地概括了 VAE 的概念,那么它们也可能会提出很多问题。 什么是自动编码器? 潜在空间是什么以及为什么要对其进行正则化? 如何从 VAE 生成新数据? VAE 和变分推理之间有什么联系? 为了尽可能地描述 VAE,我们将尝试回答所有这些问题(以及许多其他问题!),并为读者提供尽可能多的见解(从基本直觉到更高级的数学细节)。 因此,这篇文章的目的不仅是讨论变分自动编码器所依赖的基本概念,而且是逐步构建并从一开始就产生这些概念的推理。
话不多说,让我们一起(重新)发现 VAE!
1、文章大纲
在第一部分中,我们将回顾一些关于降维和自动编码器的重要概念,这些概念对于理解 VAE 很有用。 然后,在第二部分中,我们将展示为什么自动编码器不能用于生成新数据,并将介绍变分自动编码器,它是自动编码器的正则化版本,使生成过程成为可能。 最后,在最后一节中,我们将基于变分推理对 VAE 进行更加数学化的表述。
注意: 在上一节中,我们试图使数学推导尽可能完整和清晰,以弥合直觉和方程之间的差距。 然而,不想深入研究 VAE 数学细节的读者可以跳过本节,而不会影响对主要概念的理解。 另请注意,在本文中,我们将滥用以下符号:对于随机变量 z,我们将表示 p(z) 该随机变量的分布(或密度,取决于上下文)
2、降维、PCA 和自动编码器
在第一节中,我们将首先讨论与降维相关的一些概念。 特别是,我们将简要回顾主成分分析(PCA)和自动编码器,展示这两种想法如何相互关联。
什么是降维?
在机器学习中,降维是减少描述某些数据的特征数量的过程。 这种减少可以通过选择(仅保留一些现有特征)或通过提取(基于旧特征创建数量减少的新特征)来完成,并且在需要低维数据(数据可视化、数据 存储、繁重计算……)。 尽管存在许多不同的降维方法,但我们可以设置一个与大多数(如果没有的话!)这些方法相匹配的全局框架。
首先,我们将编码器称为从“旧特征”表示(通过选择或提取)生成“新特征”表示的过程,并将解码器称为相反过程。 降维可以解释为数据压缩,其中编码器压缩数据(从初始空间到编码空间,也称为潜在空间),而解码器解压缩它们。 当然,根据初始数据分布、潜在空间维度和编码器定义,这种压缩可能是有损的,这意味着部分信息在编码过程中丢失并且在解码时无法恢复。
降维方法的主要目的是在给定系列中找到最佳的编码器/解码器对。 换句话说,对于给定的一组可能的编码器和解码器,我们正在寻找在编码时保留最大信息并且因此在解码时具有最小重构误差的对。 如果我们分别表示 E 和 D 我们正在考虑的编码器和解码器族,那么降维问题可以写成:
其中:
定义输入数据 x 和编码-解码数据 d(e(x)) 之间的重构误差度量。 最后请注意,在下文中,我们将表示数据的数量,n_d 表示初始(解码)空间的维度,n_e 表示缩减(编码)空间的维度。
3、主成分分析(PCA)
当谈到降维时,首先想到的方法之一是主成分分析(PCA)。 为了展示它如何适合我们刚刚描述的框架并建立与自动编码器的链接,让我们对 PCA 的工作原理进行高度概述,将大部分细节放在一边(请注意,我们计划就此主题写一篇完整的文章) 。
PCA的思想是构建n_e个新的独立特征,这些特征是n_d个旧特征的线性组合,使得数据在这些新特征定义的子空间上的投影尽可能接近初始数据(就欧几里德而言) 距离)。 换句话说,PCA正在寻找初始空间的最佳线性子空间(由新特征的正交基描述),使得通过它们在该子空间上的投影来逼近数据的误差尽可能小。
在我们的全局框架中进行翻译,我们正在寻找 n_e × n_d 矩阵(线性变换)的 E 系列中的编码器,其行是正交的(特征独立性),并在 n_d × n_e 矩阵的 D 系列中寻找相关的解码器。 可以证明,对应于协方差特征矩阵的 n_e 个最大特征值(范数)的酉特征向量是正交的(或者可以选择正交),并定义维度 n_e 的最佳子空间,以最小误差为 近似。 因此,可以选择这些n_e个特征向量作为我们的新特征,因此,降维问题可以表示为特征值/特征向量问题。 此外,还可以证明,在这种情况下,解码器矩阵是编码器矩阵的转置。
4、自动编码器
现在让我们讨论自动编码器,看看如何使用神经网络进行降维。 自动编码器的总体思想非常简单,包括将编码器和解码器设置为神经网络,并使用迭代优化过程学习最佳的编码解码方案。 因此,在每次迭代中,我们向自动编码器架构(编码器后跟解码器)提供一些数据,将编码解码输出与初始数据进行比较,并通过架构反向传播误差以更新网络的权重。
因此,直观地说,整个自动编码器架构(编码器+解码器)为数据创建了一个瓶颈,确保只有信息的主要结构化部分可以通过并被重建。 看看我们的总体框架,所考虑的编码器系列 E 由编码器网络架构定义,所考虑的解码器系列 D 由解码器网络架构定义,并且通过梯度下降完成最小化重建误差的编码器和解码器的搜索 通过这些网络的参数。
首先假设我们的编码器和解码器架构都只有一层,没有非线性(线性自动编码器)。 这样的编码器和解码器是可以表示为矩阵的简单线性变换。 在这种情况下,我们可以看到与 PCA 的明显联系,就像 PCA 一样,我们正在寻找最佳的线性子空间来投影数据,同时尽可能减少信息丢失。 用 PCA 获得的编码和解码矩阵自然地定义了我们通过梯度下降所满意达到的解决方案之一,但我们应该概述这不是唯一的解决方案。 事实上,可以选择多个基础来描述相同的最佳子空间,因此,多个编码器/解码器对可以给出最佳重建误差。 此外,对于线性自动编码器,与 PCA 相反,我们最终得到的新特征不必是独立的(神经网络中没有正交性约束)。
现在,我们假设编码器和解码器都是深度且非线性的。 在这种情况下,架构越复杂,自动编码器就越能进行高维数降低,同时保持较低的重建损失。 直观地说,如果我们的编码器和解码器有足够的自由度,我们可以将任何初始维度减少到 1。事实上,具有“无限能力”的编码器理论上可以采用我们的 N 个初始数据点并将它们编码为 1、2、3、 ... 最多 N(或者更一般地,作为实轴上的 N 整数),并且关联的解码器可以进行反向变换,并且在此过程中没有损失。
然而,在这里,我们应该记住两件事。 首先,在没有重建损失的情况下进行重要的降维通常会带来代价:潜在空间中缺乏可解释和可利用的结构(缺乏规律性)。 其次,大多数时候,降维的最终目的不仅仅是减少数据的维数,而是减少维数,同时将数据结构信息的主要部分保留在简化的表示中。 由于这两个原因,必须根据降维的最终目的仔细控制和调整潜在空间的维度和自动编码器的“深度”(定义压缩的程度和质量)。
5、变分自动编码器
到目前为止,我们已经讨论了降维问题并介绍了自动编码器,它是可以通过梯度下降进行训练的编码器-解码器架构。 现在让我们与内容生成问题联系起来,看看当前形式的自动编码器在该问题上的局限性,并介绍变分自动编码器。
自动编码器在内容生成方面的局限性
此时,想到的一个自然问题是“自动编码器和内容生成之间的联系是什么?”。 事实上,一旦自动编码器经过训练,我们就有了编码器和解码器,但仍然没有真正的方法来生成任何新内容。 乍一看,我们可能会想,如果潜在空间足够规则(编码器在训练过程中“组织”得很好),我们可以从该潜在空间中随机取出一个点并将其解码以获得新的 内容。 然后,解码器的行为或多或少就像生成对抗网络的生成器一样。
然而,正如我们在上一节中讨论的那样,自动编码器的潜在空间的规律性是一个难点,它取决于数据在初始空间中的分布、潜在空间的维度和编码器的架构。 因此,先验地确保编码器将以与我们刚刚描述的生成过程兼容的智能方式组织潜在空间是相当困难的(如果不是不可能的话)。
为了说明这一点,让我们考虑一下我们之前给出的示例,其中我们描述了一个编码器和一个解码器,其功能强大到足以将任何 N 个初始训练数据放到实轴上(每个数据点都被编码为实值)并在没有任何 重建损失。 在这种情况下,自动编码器的高自由度使得编码和解码成为可能,而不会丢失信息(尽管潜在空间的维数较低),这会导致严重的过度拟合,这意味着潜在空间的某些点将给出无意义的内容 一旦解码。 如果这个一维例子是自愿选择的相当极端,我们可以注意到自动编码器潜在空间规律性的问题比这更普遍,值得特别注意。
想一想,潜在空间中编码数据缺乏结构是很正常的。 事实上,在任务中,自动编码器没有经过任何训练来强制获得这样的组织:自动编码器只是被训练为以尽可能少的损失进行编码和解码,无论潜在空间是如何组织的。 因此,如果我们不小心架构的定义,很自然地,在训练过程中,网络会利用任何过度拟合的可能性来完成其任务以及它可以......除非我们明确地对其进行正则化!
6、变分自动编码器的定义
因此,为了能够将自动编码器的解码器用于生成目的,我们必须确保潜在空间足够规则。 获得这种规律性的一种可能的解决方案是在训练过程中引入显式正则化。 因此,正如我们在这篇文章的介绍中简要提到的,变分自动编码器可以定义为一种自动编码器,其训练经过正则化以避免过度拟合并确保潜在空间具有支持生成过程的良好属性。
就像标准自动编码器一样,变分自动编码器是一种由编码器和解码器组成的架构,经过训练以最小化编码解码数据与初始数据之间的重建误差。 然而,为了引入潜在空间的一些正则化,我们对编码解码过程进行了轻微的修改:我们不是将输入编码为单个点,而是将其编码为潜在空间上的分布。 然后模型的训练如下:
- 首先,输入被编码为潜在空间上的分布
- 其次,从该分布中采样潜在空间中的一个点
- 第三,对采样点进行解码并计算重构误差
- 最后,重构误差通过网络反向传播
在实践中,编码的分布被选择为正态分布,以便编码器可以被训练以返回描述这些高斯分布的均值和协方差矩阵。 输入被编码为具有一定方差而不是单点的分布的原因是,它可以非常自然地表达潜在空间正则化:编码器返回的分布被强制接近标准正态分布。 我们将在下一小节中看到,我们以这种方式确保潜在空间的局部和全局正则化(局部是因为方差控制,全局是因为均值控制)。
因此,训练 VAE 时最小化的损失函数由“重构项”(在最后一层)和“正则化项”(在最后一层)组成,这往往使编码-解码方案尽可能高效。 潜在层),它倾向于通过使编码器返回的分布接近标准正态分布来规范潜在空间的组织。 该正则化项表示为返回的分布与标准高斯分布之间的 Kulback-Leibler 散度,并将在下一节中进一步证明其合理性。 我们可以注意到,两个高斯分布之间的 Kullback-Leibler 散度具有封闭形式,可以直接用两个分布的均值和协方差矩阵来表示。
7、关于正则化的直觉
为了使生成过程成为可能,潜在空间所期望的规律性可以通过两个主要属性来表达:连续性(潜在空间中的两个接近点在解码后不应给出两个完全不同的内容)和完整性(对于选定的分布) ,从潜在空间采样的点一旦解码应该给出“有意义的”内容)。
VAE 将输入编码为分布而不是简单点的唯一事实不足以确保连续性和完整性。 如果没有明确定义的正则化项,为了最小化其重建误差,模型可以学习“忽略”返回分布的事实,并且其行为几乎像经典的自动编码器一样(导致过度拟合)。 为此,编码器可以返回具有微小方差的分布(这往往是准时分布),或者返回具有非常不同的均值的分布(这将在潜在空间中彼此相距甚远)。 在这两种情况下,分布的使用方式都是错误的(取消了预期收益)并且连续性和/或完整性得不到满足。
因此,为了避免这些影响,我们必须对协方差矩阵和编码器返回的分布均值进行正则化。 实际上,这种正则化是通过强制分布接近标准正态分布(中心分布和缩减分布)来完成的。 这样,我们要求协方差矩阵接近恒等,防止正点分布,并且均值接近 0,防止编码分布彼此相差太远。
通过这个正则化项,我们可以防止模型在潜在空间中对相距较远的数据进行编码,并鼓励尽可能多的返回分布“重叠”,从而满足预期的连续性和完整性条件。 当然,对于任何正则化项,这都是以训练数据上更高的重建误差为代价的。 然而,重建误差和 KL 散度之间的权衡是可以调整的,我们将在下一节中看到平衡的表达式如何从我们的形式推导中自然地出现。
总结本节,我们可以观察到通过正则化获得的连续性和完整性往往会在潜在空间中编码的信息上创建“梯度”。 例如,位于来自不同训练数据的两个编码分布的均值中间的潜在空间点应该在给出第一个分布的数据和给出第二个分布的数据之间的某个位置进行解码: 在这两种情况下,它都可以由自动编码器采样。
注意。 作为旁注,我们可以提到,我们提到的第二个潜在问题(网络将分布彼此远离)实际上几乎等同于第一个问题(网络倾向于返回准时分布),直到规模发生变化 :在这两种情况下,分布的方差相对于其均值之间的距离而言都变小。
8、VAE 的数学细节
在上一节中,我们给出了以下直观的概述:VAE 是自动编码器,它将输入编码为分布而不是点,并且其潜在空间“组织”通过将编码器返回的分布约束为接近标准高斯来正则化。 在本节中,我们将给出 VAE 的更数学化的观点,这将使我们能够更严格地证明正则化项的合理性。 为此,我们将建立一个清晰的概率框架,并将特别使用变分推理技术。
8.1 概率框架和假设
让我们首先定义一个概率图形模型来描述我们的数据。 我们用 x 表示代表我们数据的变量,并假设 x 是从不直接观察到的潜在变量 z(编码表示)生成的。 因此,对于每个数据点,假设有以下两个步骤的生成过程:
- 首先,从先验分布 p(z) 中采样潜在表示 z
- 其次,数据 x 从条件似然分布 p(x|z) 中采样
考虑到这样的概率模型,我们可以重新定义编码器和解码器的概念。 事实上,与考虑确定性编码器和解码器的简单自动编码器相反,我们现在将考虑这两个对象的概率版本。 “概率解码器”自然由 p(x|z) 定义,它描述了给定编码变量的解码变量的分布,而“概率编码器”由 p(z|x) 定义,它描述了 给定解码变量的编码变量。
此时,我们已经可以注意到,简单自动编码器中缺乏的潜在空间的正则化自然出现在数据生成过程的定义中:潜在空间中的编码表示 z 确实被假设遵循先验分布 p( z)。 否则,我们还可以想起著名的贝叶斯定理,该定理将先验 p(z)、似然性 p(x|z) 和后验 p(z|x) 联系起来
现在我们假设 p(z) 是标准高斯分布,并且 p(x|z) 是高斯分布,其均值由 z 变量的确定性函数 f 定义,其协方差矩阵的形式为 正常数 c 与单位矩阵 I 相乘。假设函数 f 属于表示为 F 的函数族,暂时未指定该函数族,稍后将选择该函数族。 因此,我们有
现在让我们考虑一下 f 是明确定义和固定的。 理论上,我们知道p(z)和p(x|z),我们可以使用贝叶斯定理来计算p(z|x):这是一个经典的贝叶斯推理问题。 然而,正如我们在上一篇文章中讨论的那样,这种计算通常很棘手(因为分母处的积分)并且需要使用近似技术,例如变分推理。
注意。 这里我们可以提到p(z)和p(x|z)都是高斯分布。 因此,如果我们有 E(x|z) = f(z) = z,则意味着 p(z|x) 也应该遵循高斯分布,并且理论上,我们“只能”尝试表达均值 以及 p(z|x) 相对于 p(z) 和 p(x|z) 均值和协方差矩阵的协方差矩阵。 然而,在实践中,这个条件并没有得到满足,我们需要使用像变分推理这样的近似技术,使该方法非常通用,并且对模型假设的某些变化更加鲁棒。
8.2 变分推理公式
在统计学中,变分推理 (VI) 是一种近似复杂分布的技术。 这个想法是设置一个参数化的分布族(例如高斯族,其参数是均值和协方差),并在该族中寻找目标分布的最佳近似值。 该族中最好的元素是最小化给定近似误差测量(大多数情况下近似值与目标之间的 Kullback-Leibler 散度)的元素,并且通过描述该族的参数的梯度下降来找到。 有关更多详细信息,请参阅我们关于变分推理的帖子和其中的参考文献。
在这里,我们将通过高斯分布 q_x(z) 来近似 p(z|x),其均值和协方差由参数 x 的两个函数 g 和 h 定义。 这两个函数应该分别属于稍后将指定的函数族 G 和 H,但应该进行参数化。 因此我们可以表示
因此,我们已经通过这种方式定义了变分推理的候选族,现在需要通过优化函数 g 和 h(实际上是它们的参数)来找到该族中的最佳近似值,以最小化近似值与 目标 p(z|x)。 换句话说,我们正在寻找最佳的 g* 和 h* 使得
在倒数第二个方程中,我们可以观察到在近似后验 p(z|x) 时,最大化“观察”的可能性(最大化第一项的预期对数似然)和保持不变之间存在权衡 接近先验分布(第二项 q_x(z) 和 p(z) 之间 KL 散度的最小化)。 这种权衡对于贝叶斯推理问题来说是很自然的,并且表达了我们对数据的置信度和我们对先验的置信度之间需要找到的平衡。
到目前为止,我们假设函数 f 已知且固定,并且我们已经证明,在这种假设下,我们可以使用变分推理技术来近似后验 p(z|x)。 然而,实际上定义解码器的函数 f 是未知的,也需要选择。 为此,让我们提醒一下,我们的最初目标是找到一种高性能的编码解码方案,其潜在空间足够规则,可用于生成目的。 如果规律性主要由潜在空间上假设的先验分布决定,则整个编码-解码方案的性能很大程度上取决于函数 f 的选择。 事实上,由于 p(z|x) 可以从 p(z) 和 p(x|z) 近似(通过变分推断),并且 p(z) 是一个简单的标准高斯分布,因此我们可以使用的仅有的两个杠杆 在我们的模型中进行优化的是参数 c (定义似然的方差)和函数 f (定义似然的均值)。
因此,让我们考虑一下,正如我们之前讨论的,我们可以获得 F 中的任何函数 f(每个函数定义不同的概率解码器 p(x|z))p(z|x) 的最佳近似,表示为 q*_x( z)。 尽管它具有概率性质,但我们正在寻找一种尽可能高效的编码-解码方案,然后,我们希望选择函数 f,当 z 从 q*_x(z 采样时,最大化给定 z 的 x 的预期对数似然 )。 换句话说,对于给定的输入 x,当我们从分布 q*_x(z) 中采样 z,然后从分布 p(x|z) 中采样 x̂ 时,我们希望最大化 x̂ = x 的概率。 因此,我们正在寻找最佳的 f* 使得
其中 q*_x(z) 取决于函数 f 并如前所述获得。 将所有部分收集在一起,我们正在寻找最佳的 f*、g* 和 h*,使得
我们可以在这个目标函数中识别上一节给出的 VAE 直观描述中引入的元素:x 和 f(z) 之间的重构误差以及 q_x(z) 和 p(z) 之间的 KL 散度给出的正则化项 )(这是标准高斯分布)。 我们还可以注意到常数 c 决定了前两项之间的平衡。 c 越高,我们对模型中的概率解码器假设 f(z) 周围的方差就越大,因此,我们越倾向于使用正则化项而不是重构项(如果 c 较低,则相反)。
8.3 将神经网络引入模型
到目前为止,我们已经建立了一个依赖于三个函数 f、g 和 h 的概率模型,并使用变分推理表达要解决的优化问题,以获得给出最优值的 f*、g* 和 h* 使用该模型的编码-解码方案。 由于我们无法轻松地优化整个函数空间,因此我们限制优化域并决定将 f、g 和 h 表示为神经网络。 因此,F、G 和 H 分别对应于网络架构定义的函数族,并且优化是在这些网络的参数上完成的。
实际上,g 和 h 并不是由两个完全独立的网络定义的,而是共享其架构和权重的一部分,因此我们有
由于它定义了 q_x(z) 的协方差矩阵,因此 h(x) 应该是方阵。 然而,为了简化计算并减少参数数量,我们额外假设 p(z|x) q_x(z) 的近似值是具有对角协方差矩阵的多维高斯分布(变量独立假设) 。 在此假设下,h(x) 只是协方差矩阵对角线元素的向量,并且具有与 g(x) 相同的大小。 然而,我们通过这种方式减少了我们考虑用于变分推理的分布族,因此,获得的 p(z|x) 的近似值可能不太准确。
与对 p(z|x) 进行建模的编码器部分相反,我们认为其均值和协方差均是 x(g 和 h)函数的高斯分布,我们的模型假设 p(x|z) 是具有固定值的高斯分布 协方差。 定义高斯均值的变量 z 的函数 f 由神经网络建模,可以表示如下
然后通过连接编码器和解码器部分获得整体架构。 然而,我们仍然需要非常小心在训练期间从编码器返回的分布中采样的方式。 采样过程必须以允许误差通过网络反向传播的方式表达。 一个简单的技巧,称为重新参数化技巧,用于使梯度下降成为可能,尽管随机采样发生在架构的中间,并且包括使用以下事实:如果 z 是遵循高斯分布的随机变量,平均值为 g(x) 且 协方差 H(x)=h(x).h^t(x) 则可以表示为
最后,以这种方式获得的变分自动编码器架构的目标函数由上一小节的最后一个方程给出,其中理论期望被或多或少精确的蒙特卡洛近似所取代,该近似在大多数情况下包含为 单抽。 因此,考虑到这种近似并表示 C = 1/(2c),我们恢复了上一节中直观导出的损失函数,该函数由重建项、正则化项和定义这两项相对权重的常数组成。
9、结束语
本文的主要内容是:
- 降维是减少描述某些数据的特征数量的过程(通过仅选择初始特征的子集或将它们组合成数量减少的新特征),因此可以视为编码过程
- 自动编码器是由编码器和解码器组成的神经网络架构,它们创建了数据通过的瓶颈,并经过训练以在编码解码过程中丢失最少的信息量(通过梯度下降迭代进行训练,目标是减少 重建误差)
- 由于过度拟合,自动编码器的潜在空间可能非常不规则(潜在空间中的接近点可能会给出非常不同的解码数据,潜在空间的某些点一旦解码可能会给出无意义的内容,...),因此,我们不能 真正定义一个生成过程,该过程简单地包括从潜在空间中采样一个点并使其通过解码器以获得新数据
- 变分自动编码器(VAE)是一种自动编码器,它通过使编码器返回潜在空间上的分布而不是单个点,并通过在返回的分布上添加一个正则化项来确保 更好地组织潜在空间
- 假设一个简单的底层概率模型来描述我们的数据,可以仔细推导由重建项和正则化项组成的非常直观的 VAE 损失函数,特别是使用变分推理的统计技术(因此称为“变分”) 自动编码器)
总而言之,我们可以概述一下,在过去几年中,GAN 受益于比 VAE 更多的科学贡献。 除其他原因外,社区对 GAN 表现出更高的兴趣可以部分解释为,与统治 GAN 的对抗训练概念的简单性相比,VAE 理论基础(概率模型和变分推理)的复杂性更高。 通过这篇文章,我们希望能够分享宝贵的直觉和强大的理论基础,使 VAE 更容易被新手使用,就像我们今年早些时候为 GAN 所做的那样。 然而,既然我们已经深入讨论了两者,那么仍然存在一个问题……你更喜欢 GAN 还是 VAE?
原文链接:Understanding Variational Autoencoders (VAEs)
BimAnt翻译整理,转载请标明出处