如何在 Keras 中实现 GAN 技巧以训练稳定模型

生成对抗网络(GANs)训练起来很有挑战性。

这是因为其架构包含一个生成器模型和一个判别器模型,它们在一个零和博弈中竞争。这意味着一个模型的改进是以另一个模型的性能下降为代价的。结果是训练过程非常不稳定,经常导致失败,例如生成器总是生成相同的图像或生成无意义的图像。

因此,在配置和训练 GAN 模型时,可以使用许多启发式方法或最佳实践(称为“GAN 技巧”)。这些启发式方法是从业者多年来在各种问题上测试和评估了数百甚至数千种配置操作组合后,才艰难地获得的。

其中一些启发式方法实现起来很有挑战性,特别是对于初学者。

此外,对于给定项目,可能需要其中一些或全部,尽管可能不清楚应该采用哪种子集启发式方法,这需要进行实验。这意味着从业者必须随时准备好在短时间内实现给定的启发式方法。

在本教程中,您将学习如何实现一套最佳实践或 GAN 技巧,您可以直接复制粘贴到您的 GAN 项目中。

阅读本教程后,您将了解

  • 开发生成对抗网络时,实用启发式方法或技巧的最佳来源。
  • 如何从头开始为深度卷积 GAN 模型架构实现七个最佳实践。
  • 如何实现 Soumith Chintala 的 GAN 技巧演示和列表中的四个额外最佳实践。

通过我的新书《Python 生成对抗网络》**启动您的项目**,其中包括**分步教程**和所有示例的 **Python 源代码**文件。

让我们开始吧。

How to Implement Hacks to Train Stable Generative Adversarial Networks

如何实现技巧以训练稳定的生成对抗网络
图片由 BLM Nevada 拍摄,保留部分权利。

教程概述

本教程分为三个部分;它们是:

  1. 训练稳定 GAN 的启发式方法
  2. 深度卷积 GAN 的最佳实践
    1. 使用步进卷积进行下采样
    2. 使用步进卷积进行上采样
    3. 使用 LeakyReLU
    4. 使用批归一化
    5. 使用高斯权重初始化
    6. 使用 Adam 随机梯度下降
    7. 将图像缩放到 [-1,1] 范围
  3. Soumith Chintala 的 GAN 技巧
    1. 使用高斯潜在空间
    2. 分离真实和虚假图像批次
    3. 使用标签平滑
    4. 使用噪声标签

训练稳定 GAN 的启发式方法

GANs 难以训练。

在撰写本文时,关于如何设计和训练 GAN 模型还没有完善的理论基础,但已有大量的启发式方法或“**技巧**”,它们在实践中已被经验证明效果良好。

因此,在开发 GAN 模型时,需要考虑并实现一系列最佳实践。

也许最重要的两个建议配置和训练参数来源是:

  1. Alec Radford 等人于 2015 年发表的引入 DCGAN 架构的论文。
  2. Soumith Chintala 于 2016 年的演讲及相关的“**GAN 技巧**”列表。

在本教程中,我们将探讨如何实现这两个来源中最重要的最佳实践。

深度卷积 GAN 的最佳实践

在设计和训练稳定的 GAN 模型方面,也许最重要的进展之一是 Alec Radford 等人于 2015 年发表的题为《使用深度卷积生成对抗网络的无监督表征学习》的论文。

在论文中,他们描述了深度卷积 GAN(DCGAN)方法,该方法已成为 GAN 开发的事实标准。

在本节中,我们将介绍如何为 DCGAN 模型架构实现七个最佳实践。

1. 使用步进卷积进行下采样

判别器模型是一个标准的卷积神经网络模型,它将图像作为输入,并且必须输出一个二元分类,判断图像是真实的还是伪造的。

在深度卷积网络中,通常使用池化层来对输入和特征图进行下采样,以降低网络的深度。

DCGAN 不推荐这样做,而是建议使用步进卷积进行下采样。

这涉及像往常一样定义一个卷积层,但将默认的二维步长 (1,1) 更改为 (2,2)。这样做会使输入下采样,特别是将输入的宽度和高度减半,从而使输出特征图的面积变为四分之一。

下面的示例演示了使用单个隐藏卷积层实现这一点,该层通过将“`strides`”参数设置为 (2,2) 来使用下采样步进卷积。其效果是模型将输入从 64x64 下采样到 32x32。

运行示例显示了卷积层输出的形状,其中特征图的面积是四分之一。

2. 使用步进卷积进行上采样

生成器模型必须根据来自潜在空间的随机点作为输入来生成输出图像。

实现此目的的推荐方法是使用带有步进卷积的转置卷积层。这是一种特殊类型的层,它执行反向卷积操作。直观地,这意味着将步长设置为 2x2 将产生相反的效果,即上采样输入而不是在正常卷积层的情况下进行下采样。

通过堆叠带有步进卷积的转置卷积层,生成器模型能够将给定输入缩放到所需的输出尺寸。

下面的示例演示了使用单个隐藏转置卷积层来实现这一点,该层通过将“`strides`”参数设置为 (2,2) 来使用上采样步进卷积。

其效果是模型将输入从 64x64 上采样到 128x128。

运行示例显示了卷积层输出的形状,其中特征图的面积是四倍。

想从零开始开发GAN吗?

立即参加我为期7天的免费电子邮件速成课程(附示例代码)。

点击注册,同时获得该课程的免费PDF电子书版本。

3. 使用 LeakyReLU

修正线性激活单元(简称 ReLU)是一种简单的计算,它直接返回提供的输入值,如果输入值小于或等于 0.0,则返回 0.0。

它已成为开发深度卷积神经网络的一般最佳实践。

GAN 的最佳实践是使用 ReLU 的变体,该变体允许一些小于零的值,并学习每个节点中的截止点。这称为泄漏修正线性激活单元,简称 LeakyReLU。

可以为 LeakyReLU 指定负斜率,建议默认值为 0.2。

最初,建议在生成器模型中使用 ReLU,在判别器模型中使用 LeakyReLU,但最近,建议在两个模型中都使用 LeakyReLU。

下面的示例演示了在判别器模型的卷积层之后使用默认斜率为 0.2 的 LeakyReLU。

运行示例演示了模型的结构,其中单个卷积层后跟着激活层。

4. 使用批归一化

批归一化将前一层的激活标准化为零均值和单位方差。这具有稳定训练过程的效果。

批归一化分别在判别器和生成器模型中卷积和转置卷积层的激活之后使用。

它被添加到模型中,在隐藏层之后,但在激活层(如 LeakyReLU)之前。

下面的示例演示了在判别器模型的 Conv2D 层之后但在激活层之前添加 Batch Normalization 层。

运行示例显示了批量归一化在卷积层输出和激活函数之间所需的用法。

5. 使用高斯权重初始化

在训练神经网络之前,必须将模型权重(参数)初始化为小的随机变量。

论文中报告的 DCAGAN 模型的最佳实践是使用均值为零、标准差为 0.02 的零中心高斯分布(正态或钟形分布)初始化所有权重。

下面的示例演示了如何定义一个均值为 0,标准差为 0.02 的随机高斯权重初始化器,用于生成器模型中的转置卷积层。

同一个权重初始化器实例可以用于给定模型中的每个层。

6. 使用 Adam 随机梯度下降

随机梯度下降,简称 SGD,是用于优化卷积神经网络模型权重的标准算法。

训练算法有许多变体。训练 DCGAN 模型的最佳实践是使用 Adam 版本的随机梯度下降,学习率为 0.0002,beta1 动量值为 0.5,而不是默认值 0.9。

当优化判别器和生成器模型时,推荐使用此配置的 Adam 优化算法。

下面的示例演示了如何配置 Adam 随机梯度下降优化算法以训练判别器模型。

7. 将图像缩放到 [-1,1] 范围

建议使用双曲正切激活函数作为生成器模型的输出。

因此,还建议将用于训练判别器的真实图像缩放,使其像素值在 [-1,1] 范围内。这样,判别器将始终接收像素值在相同范围内的真实和伪造图像作为输入。

通常,图像数据作为 NumPy 数组加载,像素值是 8 位无符号整数 (uint8) 值,范围为 [0, 255]。

首先,必须将数组转换为浮点值,然后重新缩放到所需范围。

下面的示例提供了一个函数,该函数将适当地将 NumPy 数组中加载的图像数据缩放到所需的 [-1,1] 范围。

Soumith Chintala 的 GAN 技巧

Soumith Chintala 是 DCGAN 论文的共同作者之一,他在 2016 年 NIPS 会议上发表了题为《如何训练 GAN?》的演讲,总结了许多技巧和窍门。

该视频可在 YouTube 上观看,强烈推荐。这些技巧的摘要也以 GitHub 仓库的形式提供,名为《如何训练 GAN?使 GAN 工作的小贴士和技巧》。

这些技巧借鉴了 DCGAN 论文以及其他地方的建议。

在本节中,我们将回顾如何实现上一节中未涵盖的四个额外的 GAN 最佳实践。

1. 使用高斯潜在空间

潜在空间定义了生成器模型输入的形状和分布,用于生成新图像。

DCGAN 建议从均匀分布中采样,这意味着潜在空间的形状是一个超立方体。

最新的最佳实践是从标准高斯分布中采样,这意味着潜在空间的形状是一个超球面,均值为零,标准差为一。

下面的示例演示了如何从 100 维潜在空间中生成 500 个随机高斯点,这些点可以用作生成器模型的输入;每个点都可以用来生成一张图像。

运行示例总结了 500 个点的生成,每个点包含 100 个随机高斯值,均值接近零,标准差接近 1,例如标准高斯分布。

2. 分离真实和虚假图像批次

判别器模型使用随机梯度下降与小批量进行训练。

最佳实践是使用单独的真实和虚假图像批次更新判别器,而不是将真实和虚假图像合并到单个批次中。

这可以通过对 `train_on_batch()` 函数进行两次单独的调用来更新判别器模型的权重来实现。

下面的代码片段演示了如何在训练判别器模型的内部代码循环中执行此操作。

3. 使用标签平滑

在训练判别器模型时,通常使用类别标签 1 表示真实图像,类别标签 0 表示虚假图像。

这些被称为硬标签,因为标签值是精确或清晰的。

一种好的做法是使用软标签,例如对于真实图像使用略大于或小于 1.0 的值,对于虚假图像使用略大于 0.0 的值,其中每个图像的变动是随机的。

这通常被称为标签平滑,在训练模型时可以起到正则化作用

下面的示例演示了如何定义 1,000 个正类标签(class=1),并按照推荐将标签值统一平滑到 [0.7,1.2] 范围。

运行示例总结了平滑值的最小值和最大值,表明它们接近预期值。

有一些建议认为只需要对正类标签进行平滑,并且要将其值小于 1.0。然而,您也可以平滑负类标签。

下面的示例演示了生成 1,000 个负类标签(class=0),并按照推荐将标签值统一平滑到 [0.0, 0.3] 范围。

4. 使用噪声标签

训练判别器模型时使用的标签始终是正确的。

这意味着假图像总是标记为类别 0,真实图像总是标记为类别 1。

建议在这些标签中引入一些错误,即一些假图像被标记为真实,一些真实图像被标记为假。

如果您使用单独的批次更新判别器以处理真实和虚假图像,这可能意味着随机将一些虚假图像添加到真实图像批次中,或者随机将一些真实图像添加到虚假图像批次中。

如果您使用真实和虚假图像的组合批次更新判别器,这可能涉及随机翻转某些图像上的标签。

下面的示例通过创建 1,000 个真实(class=1)标签样本并以 5% 的概率翻转它们来演示这一点,然后对 1,000 个虚假(class=0)标签样本进行相同的操作。

尝试运行几次示例。

结果显示,大约 50 个“1”被翻转为正标签的 1(例如,1,0000 的 5%),大约 50 个“0”被翻转为负标签的 1。

进一步阅读

如果您想深入了解,本节提供了更多关于该主题的资源。

论文

API

文章

总结

在本教程中,您学习了如何实现一套最佳实践或 GAN 技巧,您可以直接复制粘贴到您的 GAN 项目中。

具体来说,你学到了:

  • 开发生成对抗网络时,实用启发式方法或技巧的最佳来源。
  • 如何从头开始为深度卷积 GAN 模型架构实现七个最佳实践。
  • 如何实现 Soumith Chintala 的 GAN 技巧演示和列表中的四个额外最佳实践。

你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。

立即开发生成对抗网络!

Generative Adversarial Networks with Python

在几分钟内开发您的GAN模型

...只需几行python代码

在我的新电子书中探索如何实现
使用 Python 构建生成对抗网络

它提供了关于以下内容的自学教程端到端项目
DCGAN条件GAN图像翻译Pix2PixCycleGAN
以及更多...

最终将GAN模型引入您的视觉项目

跳过学术理论。只看结果。

查看内容

对《如何在 Keras 中实现 GAN 技巧以训练稳定模型》的 45 条回复

  1. sukhpal 2019 年 6 月 24 日上午 12:16 #

    先生,如果我们将 GAN 应用于用于分类的数值而不是图像,或者 GAN 仅作用于图像吗?

    • Jason Brownlee 2019 年 6 月 24 日上午 6:34 #

      大部分工作都集中在使用 GANs 处理图像数据。

      在其他数据上也有一些应用,例如文本和时间序列。

      • P.G. 2020 年 9 月 15 日上午 7:24 #

        那么为什么要使用 GAN 进行分类呢?假设我们想要高分类精度,那么判别器就会被迫在生成质量较差的图像上进行训练,因为我们希望判别器“赢得比赛”以获得更好的分类。我是否遗漏了什么,或者这有点计算浪费?如果我们不训练生成器,我们也不会使用大量生成的数据(这应该是使用 SGAN 的重点),因为我们想要强制提前停止,对吗?那么有没有办法既能做好分类器又能做好生成器呢?你能用一个糟糕的生成器做出一个好的分类器而不称之为计算浪费吗??顺便再次感谢您的出色工作!

        • Jason Brownlee 2020 年 9 月 15 日上午 7:44 #

          当所有其他模型都失败时,GAN 适用于分类。它们可用于半监督学习,当您有大量未标记数据和少量已标记数据时。

          GANs 的关键是对两个模型进行对抗性训练。当你孤立地训练一个模型时,例如只训练生成器或只训练判别器,它就无法工作。

          如果你想训练一个单一模型,你可以直接训练一个分类模型。你应该把它作为比较点,并且只有当 GAN 表现更好时才使用它。

  2. Chad 2019 年 7 月 23 日上午 4:35 #

    真是一篇有帮助的帖子!我将它们应用到了生成狗图像的 Kaggle 竞赛中。虽然我没有得到完美逼真的狗,但这些 GAN 技巧显著提高了结果。

    谢谢!

  3. Chad 2019 年 7 月 31 日上午 4:46 #

    嗨,Jason,

    我想知道是否有推荐的批次大小以提高性能。目前我比较了 32 和 256。批次大小为 32 的训练时间更长,结果也比批次大小为 256 的差。这背后有什么原因吗?

    • Jason Brownlee 2019 年 7 月 31 日上午 6:58 #

      很好的问题!

      在大多数问题上,较小的批量似乎更好,例如 32、64。

      过多的数据似乎会导致一个模型比另一个模型学习得更快,例如它变得不稳定并且出现故障模式。

      • Chad 2019 年 7 月 31 日上午 7:51 #

        我明白了,谢谢。但是,较小的批量是否意味着每个 epoch 的训练时间更长?

  4. Masayo 2019 年 8 月 21 日下午 2:39 #

    关于 3. 使用标签平滑的问题。

    如果值大于 1,这会影响损失函数吗?
    我假设像交叉熵这样的东西会给出不同的结果?

    至于使用噪声标签,有什么直觉可以解释为什么这更好?

    • Jason Brownlee 2019 年 8 月 22 日上午 6:19 #

      这个想法是为了操纵损失函数对问题的看法,从而对其进行偏置。

    • Gledson Melotti 2019 年 9 月 3 日上午 8:10 #

      你好 Jason?我可以用 GAN 来分类吗?

      • Jason Brownlee 2019 年 9 月 3 日下午 2:06 #

        您可以使用判别器作为通过迁移学习进行判别的基础。

        • Gledson Melotti 2019 年 9 月 3 日下午 6:46 #

          非常感谢。

  5. Jason Salas 2019 年 8 月 24 日下午 3:51 #

    嗨,Jason,

    很棒的文章!我对正类标签的平滑感到好奇,使用了您电子书中 train() 方法的结构。在 generate_real_samples() 辅助方法中应用此技术时,在 train() 方法中创建反转标签以鼓励更好的输出图像时,也应该使用平滑吗?

    这似乎是合乎逻辑的。您的想法?

    感谢您的帮助!(顺便说一句,您的电子书太棒了!)

    • Jason Brownlee 2019 年 8 月 25 日上午 6:33 #

      好问题。

      嗯...也许吧。

      也许可以尝试有和没有的情况,并确认一下。

      • Jason Salas 2019 年 8 月 25 日上午 9:01 #

        我刚刚在几个实验中运行了它,它似乎有点正则化。酷!

  6. Fraask 2019 年 12 月 4 日上午 1:23 #

    当我应用标签平滑时,判别器在真实样本上的准确率等于零。有没有什么原因?

    • Jason Brownlee 2019 年 12 月 4 日上午 5:38 #

      忽略准确度,专注于损失,特别是学习曲线。

      还要关注周期性生成的图像,比如每隔几个 epoch。

      • Max 2020 年 12 月 2 日上午 12:55 #

        我也有同样的问题,想知道这是为什么;也许我遗漏了一些基本的东西?

        Jason,你有什么想法,为什么会这样?

  7. Dang Tuan Hoang 2019 年 12 月 18 日下午 8:27 #

    你好 Jason,感谢你的精彩文章!
    建议同时使用标签平滑和噪声标签吗?
    另外,我读到 Soumith (https://github.com/soumith/ganhacks) 推荐判别器使用 SGD,生成器使用 Adam。你对此有什么看法?

    • Jason Brownlee 2019 年 12 月 19 日上午 6:29 #

      也许在您的特定 GAN 模型上尝试一下。

      我没有发现需要使用它们中的任何一个。

  8. Siddarth Venkateswaran 2020 年 5 月 8 日下午 12:18 #

    你好 Jason,一如既往的精彩博客。

    这些原则也可以应用于训练自动编码器吗?例如
    1) 编码器层使用 ReLU,解码器层使用 LeakyReLU
    2) 解码器网络最后一层使用 ‘tanh’ 激活函数等。

    • Jason Brownlee 2020 年 5 月 8 日下午 1:04 #

      通常情况下,不是。这些技巧主要针对 GANs 及其不稳定的训练过程。

      自编码器训练起来非常稳定。

  9. Ujjayant Sinha 2020 年 7 月 3 日下午 9:31 #

    在模式崩溃和稳定性方面,浅层判别器网络是否比深层判别器网络表现更好?例如,您 pix2pix 帖子中的判别器与具有更多层的判别器相比。

    另外,这篇帖子非常有帮助。谢谢。

    • Jason Brownlee 2020 年 7 月 4 日上午 5:59 #

      这真的取决于模型的配置和数据集的具体情况。

      • Ujjayant Sinha 2020 年 7 月 16 日上午 12:04 #

        在我的案例中,更深层次的模型发挥了作用。
        此外,如果我们翻转标签,会导致判别器产生偏差/混淆,从而阻止生成器创建相同的特征来欺骗判别器。我对于翻转部分标签(4. 使用噪声标签)背后的直觉是否正确?

        • Jason Brownlee 2020 年 7 月 16 日上午 6:41 #

          一点点噪音是好的——它能让模型持续学习,太多的噪音会让人困惑。

  10. Juan 2020 年 8 月 27 日上午 2:33 #

    你好 Jason,教程太棒了!!!

    我刚刚购买了您的书,并且正在尝试您推荐的一些技巧。按照您提供的完整代码运行后,得到了以下学习曲线(不是很理想)

    https://drive.google.com/file/d/1C6rJP0NfynCpyV5THhfz_INphLH6E3Pn/view?usp=sharing

    然后我将其更改为判别器使用 SGD,生成器使用 ReLU,但没有明显的改进。
    https://drive.google.com/file/d/1uv-u8dePjApo8gC1N-bipfbUAwUbNfm_/view?usp=sharing

    获得最佳提升的是使用标签平滑和噪声标签(在之前的更改之后)
    1. 仅使用标签平滑
    https://drive.google.com/file/d/1bbUkzODyF6m_qb1IinO_bt9dkRJWVEj5/view?usp=sharing

    2. 同时使用标签平滑和噪声标签
    https://drive.google.com/file/d/118b72LaAuCtq9zfmofIBGyPIXxUkb1Ke/view?usp=sharing

    但生成器损失仍趋近于零,这让我认为它可能以某种方式用垃圾欺骗了判别器,这可能吗?我认为这最后一种设置生成的图像证实了我的信念。

    https://drive.google.com/file/d/1mCOpn7Vj7-PqERXY9tHnfIpSoLkyo4xU/view?usp=sharing

    尽管你看到中间有些东西试图成为一个八,但在我看来它仍然超级嘈杂,甚至重复。

    我仍然在努力将生成器损失提高到 1.0 以上,正如你所建议的,有什么想法吗?

    • Juan 2020 年 8 月 27 日上午 2:39 #

      我认为判别器未能检测到虚假样本的情况多于未能检测到真实样本的情况,这也许就是为什么生成器容易用垃圾欺骗判别器,也许只在一个批次(真实或虚假)上应用噪声会有所帮助。我假设两个判别器损失应该大致相似。

    • Jason Brownlee 2020 年 8 月 27 日上午 6:23 #

      进展不错,胡安!

      也许模型对您的数据集来说太小/不够强大?

      尝试大幅度扩展它们,或者从另一个类似项目中获取可行的模型架构作为起点?

      也许尝试减少您的数据集(大小或复杂性),看看是否可以开始一些工作。

      尝试各种方法来更多地了解困难的原因。

      告诉我进展如何。

      • Juan 2020 年 8 月 27 日上午 7:56 #

        我忘了说我所有的实验都使用了 MNIST (数字 8) 数据集,抱歉。我在生成噪声标签时犯了一些错误,但我纠正了它们,得到了这个结果

        https://drive.google.com/file/d/1fTvUrWsaddvxM8gx6aM24gCVAkvF1arg/view?usp=sharing

        判别器在虚假样本上的损失仍然远高于 MNIST 示例的“可接受值”,生成器仍然趋向于零,我将尝试调整一些超参数,或者我将尝试使用一个不太复杂的数字,例如 1,看看是否能得到更好的结果

        谢谢

        • Jason Brownlee 2020 年 8 月 27 日下午 1:34 #

          暂时忽略准确率,专注于损失和生成图像的质量。

  11. Kadd 2020 年 9 月 21 日下午 1:33 #

    好文!
    我想知道在训练生成器时,生成图像的标签是否也应该使用平滑和噪声标签?

    • Jason Brownlee 2020 年 9 月 21 日下午 2:37 #

      噪声标签在某些情况下会有帮助。也许在你的模型上尝试一下,比较结果。

  12. Zohre 2020 年 11 月 17 日上午 3:28 #

    嗨,Jason,
    感谢您的精彩教程。我阅读了您所有关于 GANs 的教程。我想将 GAN 用于我的论文中的数据增强。我发现判别器和生成器收敛到大约 0.7, 0.8 的学习率。但是经过多次迭代后,生成器没有产生好的结果。它只生成图像的全局结构,没有任何细节。我不明白这意味着什么?

  13. Dhruvam Panchal 2021 年 6 月 30 日下午 3:48 #

    嗨,Jason,

    我正在为一个项目研究 AnoVAEGAN,您的资源非常有帮助。

    然而,我注意到在大约 60-70 个 epoch 后,生成器和判别器的损失值达到平衡。结果不如预期,我希望生成器能进一步改进。(生成更清晰细致的图像)

    向判别器输入图像添加噪声和标签平滑会有帮助吗?您还有其他技巧建议尝试吗?

    • Jason Brownlee 2021 年 7 月 1 日上午 5:00 #

      也许可以尝试上面的某些方法,看看哪种在您的特定情况下效果最好。

  14. Divya Bhatia 2021 年 9 月 18 日上午 6:20 #

    嗨,Jason,
    我正在处理多分类问题(4 个类别),我不明白如何在独热编码标签上应用标签平滑,例如 1 0 0 0 应该变成什么?

    • Adrian Tam
      Adrian Tam 2021 年 9 月 19 日上午 6:24 #

      例如,[1.3, 0.2, 0.14, 0.19]
      只需添加一个非常小的随机数即可。

  15. Ahmed Gamal Habashy 2022 年 6 月 5 日下午 5:05 #

    你好 jason,
    你的文章很棒。我有一个关于批归一化的问题
    每当我添加批归一化时,结果就会变差,模型无法收敛!!!!
    我发现这个问题反复出现,但没有公认的解决方案
    (Python 3.9 - Spyder 的实现)

发表回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。