头图

 在研究深度学习时只了解一些常用的知识,比如卷积层、激活函数等,是无法完成一个和深度学习相关的项目的,这是因为一个深度学习项目中还包含对数据的预处理不同的模型怎么搭建如何调用GPU训练很多不同的loss function怎么搭建、训练时的超参数(比如batch size和learning rate)如何保存训练的结果如何调用预训练的模型等问题
这些问题其实可以简单地总结为如何让自己的模型跑起来,并且跑出不错的结果,我认为学习别人的深度学习项目代码时很有必要的,当前的有关深度学习的论文非常多,而且不少论文都开源了自己的代码,是很好的学习资源

根据这样的想法,从这篇博客开始,我想对多个深度学习相关的论文的开源代码进行学习,用博客来记录对项目的分析过程、不同代码的含义,首先从pix2pixHD开始

pix2pixHD项目概述

pix2pixHD是pix2pix的重要升级,可以实现高分辨率图像生成和图片的语义编辑,处于篇幅的考虑,对于pix2pixHD的基本原理再这里不做赘述,在代码中对应的论文部分我会把原文贴出来
pix2pixHD的项目Github链接如下:
NVIDIA/pix2pixHD

首先可以阅读一下README.md文件,对项目做一个总体的认识,可知开源的pix2pixHD项目采用Pytorch实现,可以生成高分辨率(比如2048*1024)的、真实的图像:
pix2pixHD项目的README文件

在给出了一些项目的示例结果后,README.md文件给出了一些环境的需求,开发环境也是深度学习中必不可少的一部分,pix2pixHD项目所需的环境如下:

  • Python 2 or 3
  • NVIDIA GPU(11G memory or larger) + CUDA cuDNN
  • Pytorch
  • dominate(dominate库用于创建和操作HTML文档)

最后,README.md文件给出了一些训练和测试的指南,包括多GPU的训练、采用自动混合精度(Automatic Mixed Precision,AMP)训练等,为了方便起见,这里就只考虑最简单的测试和训练

Testing

在README.md文件中对测试给出了如下几点的提示:

  • 一些Cityscapes测试图片已经包含在了datasets文件夹下
  • 给出了预训练的Cityscapes模型的链接,我下载后文件名为latest_net_G.pth,预训练模型文件需要放在./checkpoints/label2city_1024p/文件夹下
  • 测试模型可调用命令:bash ./scripts/test_1024p.sh

 其中需要对bash命令进行讲解,首先Shell是一个用c语言编写的程序,它是用户使用Linux的桥梁,Shell既是一种命令语言又是一种程序设计语言,因此Shell也指一种应用程序,这个应用程序提供了一个界面,用户通过界面访问操作系统内核的服务;其次Shell脚本是一种为Shell编写的脚本程序,Linux中的Shell种类众多,Bash就是其中的一种,即为Bourne Again Shell(/bin/bash)

test_1024p.sh脚本的内容如下所示:

#!/bin/bash
################################ Testing ################################
# labels only
python test.py --name label2city_1024p --netG local --ngf 32 --resize_or_crop none $@

可见脚本其实就是执行了Python命令以运行Python程序(test.py),至于命令里的具体参数,需要在程序中进行研究

README.md文件中关于Testing的部分最后给出了测试结果(html文件的存放路径):./results/label2city_1024p/test_latest/index.html

Training

在1024*512分辨率下进行训练可以调用命令:bash ./scripts/train_512p.sh,其中train_512p.sh脚本的内容如下:

### Using labels only
python train.py --name label2city_512p

可见脚本同样是执行了Python命令以运行Python程序(train.py)

README.md文件中关于Training的部分最后给出了训练结果的存放路径:./checkpoints/label2city_512p/web/index.html,同时如果安装了TensorTlow,可以在脚本中加入--tf_log选项,并在./checkpoints/label2city_512p/logs文件夹下查看tensorboard记录

pix2pixHD项目学习

对于pix2pixHD项目的学习同样分为两个部分,训练部分和测试部分,在上一节中,发现训练其实是运行了train.py,而测试其实是运行了test.py,因此可以从这两个Python文件入手

训练部分

出于篇幅的考虑,将训练部分放在另一篇博客中:
【深度学习个人笔记】从实际深度学习项目来学习深度学习1——pix2pixHD开源项目学习:训练部分

测试部分

在学习完项目的训练部分后,测试部分的学习会变得简单很多,pix2pixHD的测试部分从test.py入手,其代码同样按照命令行参数配置、数据集配置、创建模型、循环测试的顺序,因此将其分为四个部分分别进行讲解

test.py的第一部分——项目的参数设置

test.py的第一部分的代码如下所示:

class TestOptions(BaseOptions):
    def initialize(self):
        BaseOptions.initialize(self)
        self.parser.add_argument('--ntest', type=int, default=float("inf"), help='# of test examples.')
        self.parser.add_argument('--results_dir', type=str, default='./results/', help='saves results here.')
        self.parser.add_argument('--aspect_ratio', type=float, default=1.0, help='aspect ratio of result images')
        self.parser.add_argument('--phase', type=str, default='test', help='train, val, test, etc')
        self.parser.add_argument('--which_epoch', type=str, default='latest', help='which epoch to load? set to latest to use latest cached model')
        self.parser.add_argument('--how_many', type=int, default=50, help='how many test images to run')       
        self.parser.add_argument('--cluster_path', type=str, default='features_clustered_010.npy', help='the path for clustered results of encoded features')
        self.parser.add_argument('--use_encoded_image', action='store_true', help='if specified, encode the real image to get the feature map')
        self.parser.add_argument("--export_onnx", type=str, help="export ONNX model to a given file")
        self.parser.add_argument("--engine", type=str, help="run serialized TRT engine")
        self.parser.add_argument("--onnx", type=str, help="run ONNX model via TRT")        
        self.isTrain = False

在训练部分,命令行参数是通过调用TrainOptions().parse()来获得的,而在测试部分,就变成了调用TestOptions().parse(save=False),测试阶段不需要保存什么训练结果,因此这里save=False,其他的部分都是类似的,可参见训练部分,顶多是TestOptions()类自己定义了一些参数,这些参数等后面用到再说
最后test.py的第一部分还对一些参数进行了修改:

  • opt.nThreads=1:读取数据的线程数设置为1
  • opt.batchSize=1:测试部分的batch size设置为1
  • opt.serial_batches=True:测试部分不打乱数据,即在调用torch.utils.data.DataLoader时,shuffle参数设置为False(代码中是not opt.serial_batches)
  • opt.no_flip=True:在数据预处理阶段不用翻转作为数据增强的形式

test.py的第二部分——数据集相关定义以及一些可视化操作

test.py的第二部分代码如下所示:

data_loader = CreateDataLoader(opt)
dataset = data_loader.load_data()
visualizer = Visualizer(opt)
# create website
web_dir = os.path.join(opt.results_dir, opt.name, '%s_%s' % (opt.phase, opt.which_epoch))
webpage = html.HTML(web_dir, 'Experiment = %s, Phase = %s, Epoch = %s' % (opt.name, opt.phase, opt.which_epoch))

首先test.py的第二部分中的前两行代码就是数据集的相关定义,这些都在训练部分已经说过了,下面就主要关注测试部分和训练部分之间的一些细微差别,这些差别是在配置参数时部分参数在训练部分和测试部分的不一致而引起的,因此主要集中在AlignedDataset()类的定义中:

  • 在test_options.py文件中设置了use_encoded_image参数为False,同时opt.isTrain也是False,因此不会定义encode的图像
  • no_flip设置为True,因此在图像预处理阶段不会有图像翻转的操作
  • opt.resize_or_crop为"none",这一点来自于命令行输入的参数,即python test.py --name label2city_1024p --netG local --ngf 32 --resize_or_crop none中的--resize_or_crop none,因此测试阶段的图像预处理的操作列表由下面的代码来定义:

      if opt.resize_or_crop == 'none':
          base = float(2 ** opt.n_downsample_global)
          if opt.netG == 'local':
              base *= (2 ** opt.n_local_enhancers)
          transform_list.append(transforms.Lambda(lambda img: __make_power_2(img, base, method)))

    其中opt.n_downsample_global参数代表生成器网络中下采样层的数量,默认为4;opt.netG表示生成器网络采用的模式,默认为'global',在命令行中设置为'local';opt.n_local_enhancers表示使用的局部增强器的数量,默认为1。图像的变换函数采用匿名函数的形式,主要使用__make_power_2()函数,其代码如下所示:

    def __make_power_2(img, base, method=Image.BICUBIC):
      ow, oh = img.size        
      h = int(round(oh / base) * base)
      w = int(round(ow / base) * base)
      if (h == oh) and (w == ow):
          return img
      return img.resize((w, h), method)

    可见__make_power_2()函数根据图像原来的尺寸计算新的尺寸,并用.resize()方法将图像进行缩放为base参数的倍数,至于为什么要转换为base的倍数,这是为了保证图像的尺寸能被32整除,在项目中的README.md文件中也有提到,如下图所示:
    设置resize_or_crop为"none"的原因

test.py的第三部分

test.py的第四部分


Kazusa
5 声望7 粉丝

梦里不觉秋已深,余情岂是为他人