转自机器之心整理的,来自Goodfellow 在 NIPS 2016 的演讲和台大李弘毅的解释,完成原 GAN 的推导、证明与实现。

本文主要分四部分,第一部分描述 GAN 的直观概念,第二部分描述概念与优化的形式化表达,第三部分将对 GAN 进行详细的理论推导与分析,最后我们将实现前面的理论分析。

原文地址:https://baijiahao.baidu.com/s?id=1580024390078548003&wfr=spider&for=pc

GitHub项目地址:https://github.com/jiqizhixin/ML-Tutorial-Experiment

生成对抗网络基本概念

要理解生成对抗模型(GAN),首先要了解生成对抗模型可以拆分为两个模块:一个是判别模型,另一个是生成模型。简单来说就是:两个人比赛,看是 A 的矛厉害,还是 B 的盾厉害。比如,我们有一些真实数据,同时也有一把随机生成的假数据。A 拼命地把随手拿过来的假数据模仿成真实数据,并揉进真实数据里。B 则拼命地想把真实数据和假数据区分开。

这里,A 就是一个生成模型,类似于造假币的,一个劲地学习如何骗过 B。而 B 则是一个判别模型,类似于稽查警察,一个劲地学习如何分辨出 A 的造假技巧。

如此这般,随着 B 的鉴别技巧越来越厉害,A 的造假技巧也是越来越纯熟,而一个一流的假币制造者就是我们所需要的。虽然 GAN 背后的思想十分直观与朴素,但我们需要更进一步了解该理论背后的证明与推导。

总的来说,Goodfellow 等人提出来的 GAN 是通过对抗过程估计生成模型的新框架。在这种框架下,我们需要同时训练两个模型,即一个能捕获数据分布的生成模型 G 和一个能估计数据来源于真实样本概率的判别模型 D。生成器 G 的训练过程是最大化判别器犯错误的概率,即判别器误以为数据是真实样本而不是生成器生成的假样本。因此,这一框架就对应于两个参与者的极小极大博弈(minimax game)。在所有可能的函数 G 和 D 中,我们可以求出唯一均衡解,即 G 可以生成与训练样本相同的分布,而 D 判断的概率处处为 1/2,这一过程的推导与证明将在后文详细解释。

当模型都为多层感知机时,对抗性建模框架可以最直接地应用。为了学习到生成器在数据 x 上的分布 P_g,我们先定义一个先验的输入噪声变量 P_z(z),然后根据 G(z;θ_g) 将其映射到数据空间中,其中 G 为多层感知机所表征的可微函数。我们同样需要定义第二个多层感知机 D(s;θ_d),它的输出为单个标量。D(x) 表示 x 来源于真实数据而不是 P_g 的概率。我们训练 D 以最大化正确分配真实样本和生成样本的概率,因此我们就可以通过最小化 log(1-D(G(z))) 而同时训练 G。也就是说判别器 D 和生成器对价值函数 V(G,D) 进行了极小极大化博弈:

我们后一部分会对对抗网络进行理论上的分析,该理论分析本质上可以表明如果 G 和 D 的模型复杂度足够(即在非参数限制下),那么对抗网络就能生成数据分布。此外,Goodfellow 等人在论文中使用如下案例为我们简要介绍了基本概念。

上面比较精简地介绍了生成对抗网络的基本概念,下一节将会把这些概念形式化,并描述优化的大致过程。

概念与过程的形式化

理论完美的生成器

该算法的目标是令生成器生成与真实数据几乎没有区别的样本,即一个造假一流的 A,就是我们想要的生成模型。数学上,即将随机变量生成为某一种概率分布,也可以说概率密度函数为相等的:P_G(x)=P_data(x)。这正是数学上证明生成器高效性的策略:即定义一个最优化问题,其中最优生成器 G 满足 P_G(x)=P_data(x)。如果我们知道求解的 G 最后会满足该关系,那么我们就可以合理地期望神经网络通过典型的 SGD 训练就能得到最优的 G。

最优化问题

正如最开始我们了解的警察与造假者案例,定义最优化问题的方法就可以由以下两部分组成。首先我们需要定义一个判别器 D 以判别样本是不是从 P_data(x) 分布中取出来的,因此有:

其中 E 指代取期望。这一项是根据「正类」(即辨别出 x 属于真实数据 data)的对数损失函数而构建的。最大化这一项相当于令判别器 D 在 x 服从于 data 的概率密度时能准确地预测 D(x)=1,即:

另外一项是企图欺骗判别器的生成器 G。该项根据「负类」的对数损失函数而构建,即:

因为 x<1的对数为负,那么如果最大化该项的值,则需要令均值d(g(z))≈0,因此g并没有欺骗d。为了结合这两个概念,判别器的目标为最大化:< span="">

给定生成器 G,其代表了判别器 D 正确地识别了真实和伪造数据点。给定一个生成器 G,上式所得出来的最优判别器可以表示为

(下文用 D_G*表示)。定义价值函数为:

然后我们可以将最优化问题表述为:

现在 G 的目标已经相反了,当 D=D_G*时,最优的 G 为最小化前面的等式。在论文中,作者更喜欢求解最优化价值函的 G 和 D 以求解极小极大博弈:

对于 D 而言要尽量使公式最大化(识别能力强),而对于 G 又想使之最小(生成的数据接近实际数据)。整个训练是一个迭代过程。其实极小极大化博弈可以分开理解,即在给定 G 的情况下先最大化 V(D,G) 而取 D,然后固定 D,并最小化 V(D,G) 而得到 G。其中,给定 G,最大化 V(D,G) 评估了 P_G 和 P_data 之间的差异或距离。

最后,我们可以将最优化问题表达为:

上文给出了 GAN 概念和优化过程的形式化表达。通过这些表达,我们可以理解整个生成对抗网络的基本过程与优化方法。当然,有了这些概念我们完全可以直接在 GitHub 上找一段 GAN 代码稍加修改并很好地运行它。但如果我们希望更加透彻地理解 GAN,更加全面地理解实现代码,那么我们还需要知道很多推导过程。比如什么时候 D 能令价值函数 V(D,G) 取最大值、G 能令 V(D,G) 取最小值,而 D 和 G 该用什么样的神经网络(或函数),它们的损失函数又需要用什么等等。总之,还有很多理论细节与推导过程需要我们进一步挖掘。

理论推导

在原 GAN 论文中,度量生成分布与真实分布之间差异或距离的方法是 JS 散度,而 JS 散度是我们在推导训练过程中使用 KL 散度所构建出来的。所以这一部分将从理论基础出发再进一步推导最优判别器和生成器所需要满足的条件,最后我们将利用推导结果在数学上重述训练过程。这一部分为我们下一部分理解具体实现提供了强大的理论支持。

KL 散度

在信息论中,我们可以使用香农熵(Shannon entropy)来对整个概率分布中的不确定性总量进行量化:

如果我们对于同一个随机变量 x 有两个单独的概率分布 P(x) 和 Q(x),我们可以使用 KL 散度(Kullback-Leibler divergence)来衡量这两个分布的差异:

在离散型变量的情况下,KL 散度衡量的是,当我们使用一种被设计成能够使得概率分布 Q 产生的消息的长度最小的编码,发送包含由概率分布 P 产生的符号的消息时,所需要的额外信息量。

KL 散度有很多有用的性质,最重要的是它是非负的。KL 散度为 0 当且仅当 P 和 Q 在离散型变量的情况下是相同的分布,或者在连续型变量的情况下是 『几乎处处』 相同的。因为 KL 散度是非负的并且衡量的是两个分布之间的差异,它经常 被用作分布之间的某种距离。然而,它并不是真的距离因为它不是对称的:对于某些 P 和 Q,D_KL(P||Q) 不等于 D_KL(Q||P)。这种非对称性意味着选择 D_KL(P||Q) 还是 D_KL(Q||P) 影响很大。

在李弘毅的讲解中,KL 散度可以从极大似然估计中推导而出。若给定一个样本数据的分布 P_data(x) 和生成的数据分布 P_G(x;θ),那么 GAN 希望能找到一组参数θ使分布 P_g(x;θ) 和 P_data(x) 之间的距离最短,也就是找到一组生成器参数而使得生成器能生成十分逼真的图片。

现在我们可以从训练集抽取一组真实图片来训练 P_G(x;θ) 分布中的参数 θ 使其能逼近于真实分布。因此,现在从 P_data(x) 中抽取 m 个真实样本 {x^1,x^2,…,x^},其中符号「^」代表上标,即 x 中的第 i 个样本。对于每一个真实样本,我们可以计算 P_G(x^i;θ),即在由 θ 确定的生成分布中,x^i 样本所出现的概率。因此,我们就可以构建似然函数:

其中「∏」代表累乘、P_G(x^i;θ) 代表第 i 个样本在生成分布出现的概率。从该似然函数可知,我们抽取的 m 个真实样本在 P_G(x;θ) 分布中全部出现的概率值可以表达为 L。又因为若 P_G(x;θ) 分布和 P_data(x) 分布相似,那么真实数据很可能就会出现在 P_G(x;θ) 分布中,因此 m 个样本都出现在 P_G(x;θ) 分布中的概率就会十分大。

下面我们就可以最大化似然函数 L 而求得离真实分布最近的生成分布(即最优的参数θ):

在上面的推导中,我们希望最大化似然函数 L。若对似然函数取对数,那么累乘 ∏ 就能转化为累加 ∑,并且这一过程并不会改变最优化的结果。因此我们可以将极大似然估计化为求令 log[P_G(x;θ)] 期望最大化的 θ,而期望 E[logP_G(x;θ)] 可以展开为在 x 上的积分形式:∫P_data(x)logP_G(x;θ)dx。又因为该最优化过程是针对 θ 的,所以我们添加一项不含 θ 的积分并不影响最优化效果,即可添加 -∫P_data(x)logP_data(x)dx。添加该积分后,我们可以合并这两个积分并构建类似 KL 散度的形式。该过程如下:

这一个积分就是 KL 散度的积分形式,因此,如果我们需要求令生成分布 P_G(x;θ) 尽可能靠近真实分布 P_data(x) 的参数 θ,那么我们只需要求令 KL 散度最小的参数 θ。若取得最优参数 θ,那么生成器生成的图像将显得非常真实。

推导存在的问题

下面,我们必须证明该最优化问题有唯一解 G*,并且该唯一解满足 P_G=P_data。不过在开始推导最优判别器和最优生成器之前,我们需要了解 Scott Rome 对原论文推导的观点,他认为原论文忽略了可逆条件,因此最优解的推导不够完美。

在 GAN 原论文中,有一个思想和其它很多方法都不同,即生成器 G 不需要满足可逆条件。Scott Rome 认为这一点非常重要,因为实践中 G 就是不可逆的。而很多证明笔记都忽略了这一点,他们在证明时错误地使用了积分换元公式,而积分换元却又恰好基于 G 的可逆条件。Scott 认为证明只能基于以下等式的成立性:

该等式来源于测度论中的 Radon-Nikodym 定理,它展示在原论文的命题 1 中,并且表达为以下等式:

我们看到该讲义使用了积分换元公式,但进行积分换元就必须计算 G^(-1),而 G 的逆却并没有假定为存在。并且在神经网络的实践中,它也并不存在。可能这个方法在机器学习和统计学文献中太常见了,因此我们忽略了它。

最优判别器D

在极小极大博弈的第一步中,给定生成器 G,最大化 V(D,G) 而得出最优判别器 D。其中,最大化 V(D,G) 评估了 P_G 和 P_data 之间的差异或距离。因为在原论文中价值函数可写为在 x 上的积分,即将数学期望展开为积分形式:

其实求积分的最大值可以转化为求被积函数的最大值。而求被积函数的最大值是为了求得最优判别器 D,因此不涉及判别器的项都可以看作为常数项。如下所示,P_data(x) 和 P_G(x) 都为标量,因此被积函数可表示为 a*D(x)+b*log(1-D(x))。

若令判别器 D(x) 等于 y,那么被积函数可以写为:

为了找到最优的极值点,如果 a+b≠0,我们可以用以下一阶导求解:

如果我们继续求表达式 f(y) 在驻点的二阶导:

其中 a,b∈(0,1)。因为一阶导等于零、二阶导小于零,所以我们知道 a/(a+b) 为极大值。若将 a=P_data(x)、b=P_G(x) 代入该极值,那么最优判别器 D(x)=P_data(x)/(P_data(x)+P_G(x))。

最后我们可以将价值函数表达式写为:

如果我们令 D(x)=P_data/(P_data+P_G),那么我们就可以令价值函数 V(G,D) 取极大值。因为 f(y) 在定义域内有唯一的极大值,最优 D 也是唯一的,并且没有其它的 D 能实现极大值。

其实该最优的 D 在实践中并不是可计算的,但在数学上十分重要。我们并不知道先验的 P_data(x),所以我们在训练中永远不会用到它。另一方面,它的存在令我们可以证明最优的 G 是存在的,并且在训练中我们只需要逼近 D。

最优生成器G

当然 GAN 过程的目标是令 P_G=P_data。这对最优的 D 意味着什么呢?我们可以将这一等式代入 D_G*的表达式中:

这意味着判别器已经完全困惑了,它完全分辨不出 P_data 和 P_G 的区别,即判断样本来自 P_data 和 P_G 的概率都为 1/2。基于这一观点,GAN 作者证明了 G 就是极小极大博弈的解。该定理如下:

「当且仅当 P_G=P_data,训练标准 C(G)=maxV(G,D) 的全局最小点可以达到。」

以上定理即极大极小博弈的第二步,求令 V(G,D*) 最小的生成器 G(其中 G*代表最优的判别器)。之所以当 P_G(x)=P_data(x) 可以令价值函数最小化,是因为这时候两个分布的 JS 散度 [JSD(P_data(x) || P_G(x))] 等于零,这一过程的详细解释如下。

原论文中的这一定理是「当且仅当」声明,所以我们需要从两个方向证明。首先我们先从反向逼近并证明 C(G) 的取值,然后再利用由反向获得的新知识从正向证明。设 P_G=P_data(反向指预先知道最优条件并做推导),我们可以反向推出:

该值是全局最小值的候选,因为它只有在 P_G=P_data 的时候才出现。我们现在需要从正向证明这一个值常常为最小值,也就是同时满足「当」和「仅当」的条件。现在放弃 P_G=P_data 的假设,对任意一个 G,我们可以将上一步求出的最优判别器 D* 代入到 C(G)=maxV(G,D) 中:

因为已知 -log4 为全局最小候选值,所以我们希望构造某个值以使方程式中出现 log2。因此我们可以在每个积分中加上或减去 log2,并乘上概率密度。这是一个十分常见并且不会改变等式的数学证明技巧,因为本质上我们只是在方程加上了 0。

采用该技巧主要是希望能够构建成含 log2 和 JS 散度的形式,上式化简后可以得到以下表达式:

因为概率密度的定义,P_G 和 P_data 在它们积分域上的积分等于 1,即:

此外,根据对数的定义,我们有:

因此代入该等式,我们可以写为:

现在,如果读者阅读了前文的 KL 散度(Kullback-Leibler divergence),那么我们就会发现每一个积分正好就是它。具体来说:

KL 散度是非负的,所以我们马上就能看出来 -log4 为 C(G) 的全局最小值。

如果我们进一步证明只有一个 G 能达到这一个值,因为 P_G=P_data 将会成为令 C(G)=log4 的唯一点,所以整个证明就能完成了。

从前文可知 KL 散度是非对称的,所以 C(G) 中的 KL(P_data || (P_data+P_G)/2) 左右两项是不能交换的,但如果同时加上另一项 KL(P_G || (P_data+P_G)/2),它们的和就能变成对称项。这两项 KL 散度的和即可以表示为 JS 散度(Jenson-Shannon divergence):

假设存在两个分布 P 和 Q,且这两个分布的平均分布 M=(P+Q)/2,那么这两个分布之间的 JS 散度为 P 与 M 之间的 KL 散度加上 Q 与 M 之间的 KL 散度再除以 2。

JS 散度的取值为 0 到 log2。若两个分布完全没有交集,那么 JS 散度取最大值 log2;若两个分布完全一样,那么 JS 散度取最小值 0。

因此 C(G) 可以根据 JS 散度的定义改写为:

这一散度其实就是 Jenson-Shannon 距离度量的平方。根据它的属性:当 P_G=P_data 时,JSD(P_data||P_G) 为 0。综上所述,生成分布当且仅当等于真实数据分布式时,我们可以取得最优生成器。

收敛

现在,该论文的主要部分已经得到了证明:即 P_G=P_data 为 maxV(G,D) 的最优点。此外,原论文还有额外的证明白表示:给定足够的训练数据和正确的环境,训练过程将收敛到最优 G,我们并不详细讨论这一块。

重述训练过程

下面是推导的最后一步,我们会重述整个参数优化过程,并简要介绍实际训练中涉及的各个过程。

1.参数优化过程

若我们需要寻找最优的生成器,那么给定一个判别器 D,我们可以将 maxV(G,D) 看作训练生成器的损失函数 L(G)。既然设定了损失函数,那么我们就能使用 SGD、Adam 等优化算法更新生成器 G 的参数,梯度下降的参数优化过程如下:

其中求 L(G) 对θ_G 的偏导数涉及到求 max{V(G,D)} 的偏导数,这种对 max 函数求微分的方式是存在且可用的。

现在给定一个初始 G_0,我们需要找到令 V(G_0,D) 最大的 D_0*,因此判别器更新的过程也就可以看作损失函数为-V(G,D) 的训练过程。并且由前面的推导可知,V(G,D) 实际上与分布 P_data(x) 和 P_G(x) 之间的 JS 散度只差了一个常数项。因此这样一个循环对抗的过程就能表述为:

给定 G_0,最大化 V(G_0,D) 以求得 D_0*,即 max[JSD(P_data(x)||P_G0(x)];

固定 D_0*,计算θ_G1 ← θ_G0 η(dV(G,D_0*) /dθ_G) 以求得更新后的 G_1;

固定 G_1,最大化 V(G_1,D_0*) 以求得 D_1*,即 max[JSD(P_data(x)||P_G1(x)];

固定 D_1*,计算θ_G2 ← θ_G1 η(dV(G,D_0*) /dθ_G) 以求得更新后的 G_2;

。。。

2.实际训练过程

根据前面价值函数 V(G,D) 的定义,我们需要求两个数学期望,即 E[log(D(x))] 和 E[log(1-D(G(z)))],其中 x 服从真实数据分布,z 服从初始化分布。但在实践中,我们是没有办法利用积分求这两个数学期望的,所以一般我们能从无穷的真实数据和无穷的生成器中做采样以逼近真实的数学期望。

若现在给定生成器 G,并希望计算 maxV(G,D) 以求得判别器 D,那么我们首先需要从 P_data(x) 采样 m 个样本 {x^1,x^2,…,x^m},从生成器 P_G(x) 采样 m 个样本

。因此最大化价值函数 V(G,D) 就可以使用以下表达式近似替代:

若我们需要计算上述的极大化过程,可以采用等价形式的训练方法。若我们有一个二元分类器 D(参数为 θ_d),当然该分类器可以是深度神经网络,那么极大化过程的输出就为该分类器 D(x)。现在我们从 P_data(x) 抽取样本作为正样本,从 P_G(x) 抽取样本作为负样本,同时将逼近负 V(G,D) 的函数作为损失函数,因此我们就将其表述为一个标准的二元分类器的训练过程:

在实践中,我们必须使用迭代和数值计算的方法实现极小极大化博弈过程。在训练的内部循环中完整地优化 D 在计算上是不允许的,并且有限的数据集也会导致过拟合。因此我们可以在 k 个优化 D 的步骤和一个优化 G 的步骤间交替进行。那么我们只需慢慢地更新 G,D 就会一直处于最优解的附近,这种策略类似于 SML/PCD 训练的方式。

综上,我们可以描述整个训练过程,对于每一次迭代:

从真实数据分布 P_data 抽取 m 个样本

从先验分布 P_prior(z) 抽取 m 个噪声样本

将噪声样本投入 G 而生成数据

,通过最大化 V 的近似而更新判别器参数θ_d,即极大化

,且判别器参数的更新迭代式为

以上是学习判别器 D 的过程。因为学习 D 的过程是计算 JS 散度的过程,并且我们希望能最大化价值函数,所以该步骤会重复 k 次。

从先验分布 P_prior(z) 中抽取另外 m 个噪声样本 {z^1,...,z^m}

通过极小化 V^tilde 而更新生成器参数θ_g,即极大化

,且生成器参数的更新迭代式为

以上是学习生成器参数的过程,这一过程在一次迭代中只会进行一次,因此可以避免更新太多而令 JS 散度上升。

转载于:https://www.cnblogs.com/noahzhixiao/p/10172210.html

GAN 的推导、证明与实现。相关推荐

  1. 普通最小二乘法的推导证明

    最小二乘法 1.什么是最小二乘思想? ​ 简单地说,最小二乘的思想就是要使得观测点和估计点的距离的平方和达到最小.这里的"二乘"指的是用平方来度量观测点与估计点的远近(在古汉语中& ...

  2. 【寒假每日一题】剪绳子(个人练习)详细题解+推导证明(第六天)

    文章目录 前言 题目 详细题解 写法1 O(nlogn)O(nlogn)O(nlogn) 推导证明 举一反三 总结 前言 今天终于出核酸检测的结果,还好大家都没事,不然怕是要封城了!!! 今天还是寒假 ...

  3. 【寒假每日一题】分巧克力(个人练习)详细题解+推导证明(第八天)附带转载程序员壁纸

    文章目录 前言 题目 详细题解 写法1 O(nlogn)O(nlogn)O(nlogn) 推导证明 举一反三 总结 前言 话说今天开始准备搞一个秋招的GitHub,算是复习一遍了. 今天还是寒假每日一 ...

  4. 【寒假每日一题】十三号星期五(个人练习)详细题解+推导证明(第十三天)

    文章目录 前言 题目 详细题解 写法1 O(n)O(n)O(n) 推导证明 举一反三 总结 前言 这一周的题,真的是很扎实的基础题. 今天的题目是来自usaco training 1.2. 最近在家呆 ...

  5. 斐波那契数列通项公式的推导证明----举一反三

    斐波那契数列通项公式的推导证明----举一反三 1-前言 2-斐波那契 2-1-什么是斐波那契 2-2-通项公式的证明 2-3-举一反三 1-前言 2021年5月20号的那天,有对象的都忙着约会秀恩爱 ...

  6. 【寒假每日一题】数字三角形(个人练习)详细题解+推导证明(第二天)

    文章目录 前言 题目 详细题解 写法1 O ( n 2 ) O(n^2) O(n2) 推导证明 写法2 O ( n 2 ) O(n^2) O(n2) 推导证明 举一反三 总结 前言 昨天真是人生中奇葩 ...

  7. 【寒假每日一题】棋盘挑战(个人练习)详细题解+推导证明(第十六天)

    文章目录 前言 题目 详细题解 写法1 推导证明 举一反三 总结 前言 今天是经典的深度优先搜索问题,即八皇后问题. 作为经典问题,我发现了一种新的写法,不需要开二维数组即可完成. 题目 给定一个 N ...

  8. 【寒假每日一题】找硬币(个人练习)详细题解+推导证明(第十二天)

    文章目录 前言 题目 详细题解 写法1 O ( n ) O(n) O(n) 推导证明 写法2 O ( n l o g n ) O(nlogn) O(nlogn) 推导证明 举一反三 总结 前言 这个寒 ...

  9. GAN理论推导(知乎转载)

    GAN理论推导 在知乎上看到一个对GAN推导得十分仔细的文章,写得非常好,我准备按照他的思路推导一下GAN的理论.可以理解为这篇文章转载自:https://zhuanlan.zhihu.com/p/2 ...

最新文章

  1. 在ASP.NET中指定出错页面,不让代码外泄!
  2. 马云/牛根生经典语录
  3. Hibernate组件(Component)映射
  4. cefsharp 手机模式_微信“蓝光模式”保护眼睛
  5. Activity动态增加Fragment
  6. 转:java中static、final、static final的区别
  7. 算法竞赛进阶指南——后缀数组
  8. c语言中字符串 x,使用c语言解析字符串176x144中的数字
  9. Spring Boot整合Servlet,Filter,Listener,访问静态资源
  10. SQL事务处理实验报告
  11. Ubuntu16.04如何设置静态IP地址
  12. SLAM中本质矩阵E,基础矩阵F,单应矩阵H总结
  13. Metric模块源码解析
  14. Win11如何开启移动热点?Win11开启移动热点的方法
  15. Java WebSocket编程与网页简易聊天室
  16. 自己制作脚手架——完整版
  17. 华硕dhd24简单分析硬件检测思路
  18. 生态保护重要性评价之生态脆弱性评价
  19. 这款键盘你真的要考虑一下!——Keychron K3测评
  20. 消息推送系统——(零)推倒萝莉之术

热门文章

  1. 实例27:python
  2. pcm压缩 java,Java C.PcmEncoding方法代码示例
  3. python灰色模型代码_几行代码搞定ML模型,低代码机器学习Python库正式开源
  4. MFC版链表实现稀疏多项式相加减
  5. python对excel的操作
  6. AngularJS移动端页面input无法输入
  7. XidianOJ 1099 A simple problem
  8. BZOJ 2324: [ZJOI2011]营救皮卡丘(带上下限的最小费用最大流)
  9. magento -- 修改文件来手动控制编译的开启和关闭
  10. WCF 第八章 安全 客户端认证