Bootstrap

NIPS 2017 Spotlight论文Bayesian GAN的TensorFlow实现

用生成模型学习高维自然信号(比如图像、视频和音频)长期以来一直是机器学习的重要发展方向之一。来自 Uber AI Lab 的 Yunus Saatchi 等人今年五月提出了 Bayesian GAN——利用一个简单的贝叶斯公式进行端到端无监督/半监督 GAN 学习。该研究的论文已被列入 NIPS 2017 大会 Spotlight。最近,这篇论文的另一作者 Andrew Gordon Wilson 在 GitHub 上发布了 Bayesian GAN 的 TensorFlow 实现。


项目链接:https://github.com/andrewgordonwilson/bayesgan/


论文:Bayesian GAN




论文链接:https://arxiv.org/abs/1705.09558


摘要:生成对抗网络(GAN)可以隐性地学习难以用显性似然(explicit likelihood)建模的图像、音频和数据的丰富分布。我们展示了一种实际的贝叶斯公式,用 GAN 进行无监督和半监督学习。在该框架下,我们使用随机梯度哈密尔顿蒙特卡罗(Hamiltonian Monte Carlo)来边缘化生成器和判别器的权重。得到的方法很直接,且可在没有标准干预(如特征匹配或小批量判别)的情况下达到不错的性能。通过探索生成器参数具有表达性的后验,贝叶斯 GAN 避免了模式崩溃(mode-collapse),输出可解释的多种候选样本,在 SVHN、CelebA 和 CIFAR-10 等多个基准数据集上取得了顶尖的半监督学习量化结果,优于 DCGAN、Wasserstein GAN 和 DCGAN。

介绍

在贝叶斯 GAN 中,我们提出了生成器和判别器权重的条件后验,通过随机梯度哈密尔顿蒙特卡罗边缘化这些后验。贝叶斯 GAN 的主要特性有:(1)在半监督学习问题上的准确预测;(2)对优秀性能的最小干预;(3)响应对抗反馈的推断的概率公式;(4)避免模式崩溃;(5)展示多个互补的生成和判别模型,形成一个概率集成(probabilistic ensemble)。

我们介绍了一个生成器参数的多模态后验。这些参数的每个设置对应数据的不同生成假设。这里我们将展示两种权重向量设置下生成的样本,不同的权重向量设置对应不同的写作风格。贝叶斯 GAN 保留该参数分布。相反,标准 GAN 用点估计(类似最大似然解决方案)来展示整个分布,降低了数据的可解释性。




环境需求

该代码有以下依赖项(版本号很关键)

  • python 2.7
  • tensorflow==1.0.0

在 Linux 上安装 TensorfFow 1.0.0,请按照 https://www.tensorflow.org/versions/r1.0/install/说明进行操作。

  • scikit-learn==0.17.1

你可以使用下列命令安装 scikit-learn 0.17.1:

        
  
  
  1. pip install scikit-learn==0.17.1

或者,使用提供的 environment.yml 文件创建 conda 环境,并进行设置:

        
  
  
  1. conda env create -f environment.yml -n bgan

然后,使用下列命令加载环境:

        
  
  
  1. source activate bgan

训练选项

bayesian_gan_hmc.py 具备以下训练选项。

  • --out_dir:文件夹路径,用于存储输出
  • --n_save: 每 n_save 次迭代存储的样本和权重;默认值 100
  • --z_dim: 生成器 z 向量的维度;默认值 100
  • --data_path:数据路径;具体讨论详见 https://github.com/andrewgordonwilson/bayesgan/#data-preparation;该参数是必需的
  • --dataset:可以是 mnist、cifar、svhn 或 celeb;默认 mnist
  • --gen_observed: 生成器「观察到」的数据;影响噪声变量和先验的缩放;默认值 1000
  • --batch_size:训练的批量大小;默认值 64
  • --prior_std:权重先验分布的 std;默认值 1
  • --numz:和论文中的 J 一样; z 的样本数,实现整合;默认值 1
  • --num_mcmc: 和论文中的 M 一样;每个 z 的 MCMC NN 权重样本数;默认值 1
  • --lr: Adam 优化器使用的学习率;默认值 0.0002
  • --optimizer:使用的优化方法:adam (tf.train.AdamOptimizer) 或 sgd (tf.train.MomentumOptimizer);默认 adam
  • --semi_supervised:进行半监督学习
  • --N:半监督学习所需标注样本数量
  • --train_iter:训练迭代次数;默认值 50000
  • --save_samples:保存训练过程中生成的样本
  • --save_weights:训练过程中,保存权重
  • --random_seed:随机种子;如果使用 GPU,那么注意设置该种子不会引起 100% 的可复现结果

你还可以用--wasserstein 运行 WGAN,或用--ml_ensemble <num_dcgans> 训练 <num_dcgans> DCGAN 的集成。尤其是,你可以使用--ml_ensemble 1 训练一个 DCGAN。

使用

安装

1. 安装所需依赖项

2. 复制该 repository

合成数据

你可以使用 bgan_synth 脚本运行论文中的合成实验。例如,以下命令用于训练贝叶斯 GAN(D=100,d=10),进行 5000 次迭代,并把结果保存在<results_path>。

        
  
  
  1. ./bgan_synth.py --x_dim 100 --z_dim 10 --numz 10 --out <results_path>

运行以下命令使用相同的数据运行 ML GAN:

        
  
  
  1. ./bgan_synth.py --x_dim 100 --z_dim 10 --numz 1 --out <results_path>

bgan_synth 的参数有 --save_weights、--out_dir、--z_dim、--numz、--wasserstein、--train_iter 和 --x_dim。x_dim 控制观测数据(论文中的 x)的维度。通过这个链接查看其它参数的说明:https://github.com/andrewgordonwilson/bayesgan/#training-option。

运行了上面的两个命令之后,你可以在<results_path>里查看每 100 次迭代后的输出。例如,第 900 次迭代的贝叶斯 GAN 的输出结果如下:

相对地,标准 GAN(numz=1,强制执行 ML 评估)的输出结果如下:

可以清晰地看到在这个合成数据的例子中,标准 GAN 出现了模式崩溃的趋势,而贝叶斯 GAN 完全没有这样的问题。

你可以查看 synth.iptnb,进一步探索合成实验,并生成詹森-香农差异图。

MNIST、CIFAR10、CELEBA、SVHN

bayesian_gan_hmc 脚本允许在标准和自定义数据集上训练模型。下面,我们将介绍如何使用该脚本。

数据准备

为了重现在 MNIST、CIFAR10、CelebA 和 SVHN 数据集上的实验,你需要准备这些数据,并使用一个正确的——data_path。

  • 对于 MNIST,你不需要准备数据,并可以提供任意的——data_path;
  • 对于 CIFAR10,请从该地址(https://www.cs.toronto.edu/~kriz/cifar.html)下载和获取数据的 Python 版本;然后使用包含 cifar-10-batchs-py 的目录的路径作为——data_path;
  • 对于 SVHN,请从该地址(http://ufldl.stanford.edu/housenumbers/)下载 train_32x32.mat 和 test_32x32.mat 文件,并使用包含这些文件的目录的路径作为——data_path;
  • 对于 CelebA,你需要安装 OpenCV。数据下载地址:http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html。你需要创建 celebA 文件夹,该文件夹包含 Anno 和 img_align_celeba 子文件夹。其中 Anno 必须包含 list_attr_celeba.txt,img_align_celeba 必须包含.jpg 文件。你还需要通过在——data_path <path>(其中<path>是包含了 celebA 的文件夹的路径)中运行 datasets/crop_faces.py 脚本对图像进行剪裁。训练模型的时候,你需要在——data_path 中使用相同的<path>。


无监督学习


你可以在没有 -- semi 参数的情况下通过运行 bayesian_gan_hmc 脚本对模型进行无监督训练。例如,使用以下命令:

        
  
  
  1. ./bayesian_gan_hmc.py --data_path <data_path> --dataset svhn --numz 1 --num_mcmc 10 --out_dir

  2. <results_path> --train_iter 75000 --save_samples --n_save 100

在 SVHN 数据集上训练模型。该命令会使用这个方法执行 75000 次迭代,每 100 次迭代保存样本。这里<results_path>必须是保存结果的目录。可查看数据准备部分,了解如何设置<data_path>。可查看训练选项部分,了解其它训练选项。



半监督训练


你可以使用--semi 选项来运行 bayesian_gan_hmc,对模型进行半监督训练。使用-N 参数设置训练所用标注样本的数量。例如,使用

        
  
  
  1. ./bayesian_gan_hmc.py --data_path <data_path> --dataset cifar --numz 1 --num_mcmc 10

  2. --out_dir <results_path> --train_iter 75000 --N 4000 --semi --lr 0.00005

在 CIFAR10 数据集上用 4000 个标注样本训练该模型。该命令使训练经历 75000 次迭代,输出结果储存在<results_path> 文件夹中。

要想在 MNIST 数据集上使用 200 个标注样本训练该模型,你需要使用以下命令:

        
  
  
  1. ./bayesian_gan_hmc.py --data_path <data_path>/ --dataset mnist --numz 5 --num_mcmc 5

  2. --out_dir <results_path> --train_iter 30000 -N 200 --semi --lr 0.001

自定义数据

要想在自定义数据集上训练该模型,你需要用特定的接口定义类别。假设我们想在 digits 数据集上训练模型。该数据集包含 8x8 数字图像。假设数据的储存格式为 x_tr.npy、y_tr.npy、x_te.npy 和 y_te.npy。我们假设 x_tr.npy 和 x_te.npy 的形态为 (?, 8, 8, 1)。然后在 bgan_util.py 中定义该数据集对应的类别,如下所示:

        
  
  
  1. class Digits:

  2.    def __init__(self):

  3.        self.imgs = np.load('x_tr.npy')

  4.        self.test_imgs = np.load('x_te.npy')

  5.        self.labels = np.load('y_tr.npy')

  6.        self.test_labels = np.load('y_te.npy')

  7.        self.labels = one_hot_encoded(self.labels, 10)

  8.        self.test_labels = one_hot_encoded(self.test_labels, 10)

  9.        self.x_dim = [8, 8, 1]

  10.        self.num_classes = 10

  11.    @staticmethod

  12.    def get_batch(batch_size, x, y):

  13.        """Returns a batch from the given arrays.

  14.        """

  15.        idx = np.random.choice(range(x.shape[0]), size=(batch_size,), replace=False)

  16.        return x[idx], y[idx]

  17.    def next_batch(self, batch_size, class_id=None):

  18.        return self.get_batch(batch_size, self.imgs, self.labels)

  19.    def test_batch(self, batch_size):

  20.        return self.get_batch(batch_size, self.test_imgs, self.test_labels)

该类别必须具备 next_batch 和 test_batch,以及 imgs、labels、test_imgs、test_labels、x_dim 和 num_classes。

现在,我们可以把 Digits 类输入到 bayesian_gan_hmc.py:

        
    
    
  1. from bgan_util import Digits

将下列行添加至处理--dataset 参数的代码中:

        
    
    
  1. if args.dataset == "digits":

  2.    dataset = Digits()

准备过程完成后,我们可以使用以下命令训练模型:

        
    
    
  1. ./bayesian_gan_hmc.py --data_path <any_path> --dataset digits --numz 1 --num_mcmc 10

  2. --out_dir <results path> --train_iter 5000 --save_samples




;