精华内容
下载资源
问答
  • StyleGAN代码学习】StyleGAN模型架构

    千次阅读 多人点赞 2019-12-10 19:19:20
    完整StyleGAN笔记:http://www.gwylab.com/pdf/Note_StyleGAN.pdf 基于StyleGAN的一个好玩的网站:www.seeprettyface.com —————————————————————————————————    第二章 Style...

    完整StyleGAN笔记:http://www.gwylab.com/pdf/Note_StyleGAN.pdf

    基于StyleGAN的一个好玩的网站:www.seeprettyface.com
    —————————————————————————————————
      

    第二章 StyleGAN代码解读(上)

      这一章将对StyleGAN的代码进行非常细致的分析和解读。一方面有助于对StyleGAN的架构和原理有更深的认识,另一方面是觉得AdaIN的思想很有价值,希望把它写代码的技巧学习下来,以后应该在GANs中会有很多能用得上的地方(其它paper里挺多出现了AdaIN的地方)。含有中文注释的代码可以在这里获得。

    2.1 StyleGAN代码架构总览

    在这里插入图片描述
          图2.1 StyleGAN官方代码架构

      如图2.1所示,StyleGAN代码的封装与解耦做的非常细致,可见作者的代码功底是非常扎实的。简单来说,在dnnlib文件夹下封装了日志提交工具、tensorflow环境配置与网络处理工具以及一些杂项实用类函数,这个文件夹尽量不要去动;在metrics文件夹下定义了许多指标计算方法,包括FID、LS、PPL指标以及一些GANs的通用指标计算方法;而training文件夹是需重点关注的部分,里面包含了数据处理、模型架构、损失函数和训练过程等基于StyleGAN的核心内容,在接下来的笔记中也会重点对这一部分进行细致讲解;最后,在主目录下,有一些全局配置、功能展示和运行接口的代码,其中train.py值得细读一下,它是训练StyleGAN网络的主要切入点。
      在接下来的笔记中,将从三个部分解读StyleGAN的代码,分别是:模型架构、损失函数和训练过程。至于其它部分的代码,由于我并不是特别关注,就不再赘述了。

    2.2 网络架构代码解读

      StyleGAN的网络架构全都写在training/networks_stylegan.py下,主要包括四个组成部分(代码302行-659行):G_style(),G_mapping(),G_synthesis()和D_basic()。
    在这里插入图片描述
      如上图所示,G_style表示整个生成器的网络架构,它由两个子网络组成,分别是映射网络G_mapping和合成网络G_synthesis;然后D_basic表示整个判别器的网络架构,它沿用了ProGAN中的模型设计。

    2.2.1 G_style网络

      G_style网络位于代码302-379行。在G_style中定义的组件包括:参数验证->设置子网络->设置变量->计算映射网络输出->更新W的移动平均值->执行样式混合正则化->应用截断技巧->计算合成网络输出。其中设置子网络就是调用构建G_mapping和G_synthesis的过程,两个子网络的定义将在下两节介绍。
      · G_style输入参数(line303-315)
    在这里插入图片描述
      输入参数包括512维的Z码向量和条件标签(在FFHQ数据集上没有使用标签),和一些可选的参数,包括截断参数、计算移动平均值W时的参数、样式混合参数、网络状态参数和子网络的参数们等。

      · 参数验证(line318-330)
    在这里插入图片描述
      对输入参数进行验证,主要是对网络状态和其对截断率、W平均值衰减率和样式混合概率的关系之间进行验证。

      · 设置子网络(line333-338)
    在这里插入图片描述
      直接使用tflib.Network()类(充当参数化网络构建功能的便捷包装,提供多种实用方法并方便地访问输入/输出/权重)创建两个子网络,子网络的内容在后面的函数(func_name = G_synthesis或func_name = G_mapping)中被定义。

      · 设置变量(line341-342)
    在这里插入图片描述
      设置两个变量lod_in和dlatent_avg。前者决定当前处在第几层分辨率,即lod=resolution_log2–res(其中res表示当前层对应的分辨率级别(2-10));后者决定截断操作的基准,即生成人脸的dlatent码的平均值。

      · 计算映射网络输出(line345)
    在这里插入图片描述
      得到映射网络的输出,即中间向量W’。

      · 更新W的移动平均值(line348-353)
    在这里插入图片描述
      把batch的dlatent平均值朝着总dlatent平均值以dlatent_avg_beta步幅靠近,作为新的人脸dlatent平均值,即dlatent_avg。

      · 执行样式混合正则化(line356-366)
    在这里插入图片描述
      样式混合正则化其实很好理解,就是随机创建一个新的潜码,这个潜码以一定概率与原始潜码交换某一部分,对于交换后的混合潜码,其生成的图片也要能够逼真,这就是样式混合正则化的实现。

      · 应用截断技巧(line369-374)
    在这里插入图片描述
      截断是指,用平均脸dlatent_avg朝着当前脸dlatents以coefs步幅靠近,得到的结果就是截断的dlatents。

      · 计算合成网络输出(line377-379)
    在这里插入图片描述
      将截断的dlatents传给G_synthesis网络进行合成,得到的结果就是整个生成网络G_style的输出结果。

    2.2.2 G_mapping网络

    在这里插入图片描述
      G_mapping网络位于代码384-435行。如上图所示,G_mapping网络实现了从初始生成码到中间向量的映射过程。在G_mapping中定义的组件包括:输入->连接标签->归一化潜码->映射层->广播->输出。其中映射层由8个全连接层组成。

      · G_mapping输入参数(line385-398)
    在这里插入图片描述
      输入参数包括512维的Z码向量和条件标签(在FFHQ数据集上没有使用标签),和一些可选的参数,包括初始向量Z参数、中间向量W参数、映射层设置、激活函数设置、学习率设置以及归一化设置等。

      · 网络输入(line403-407)
    在这里插入图片描述
      处理好latent的大小和格式后,其值赋给x,即用x标识网络的输入。

      · 连接标签(line410-414)
    在这里插入图片描述
      原始StyleGAN是无标签训练集,这部分不会被调用。

      · 归一化潜码(line417-418)
    在这里插入图片描述
      pixel_norm()(line239-242)
    在这里插入图片描述
      逐像素归一化的实现方式为:x=x/√(1/N ∑_(i=0)(N-1)▒〖x_i〗2 +ϵ),其中ϵ=10^-8。
      为何要使用pixel_norm呢? Pixel norm,它是local response normalization的变种,具有避免生成器梯度爆炸的作用。Pixel norm沿着channel维度做归一化(axis=1),这样归一化的一个好处在于,feature map的每个位置都具有单位长度。这个归一化策略与作者设计的Generator输出有较大关系,注意到Generator的输出层并没有Tanh或者Sigmoid激活函数。

      · 映射层(line421-426)
    在这里插入图片描述
      构建了mapping_layers层映射层,每个映射层有三个组成部分:全连接层dense()、偏置函数apply_bias()和激活函数act()。
      1)全连接层dense()(line 154-159)
    在这里插入图片描述
      dense()函数中首先将输出全部展平以计算输出维度,然后调用get_weight()创建全连接层w,最后返回x与w的矩阵相乘的结果,作为dense()层的输出。
      get_weight()(line 135-149)
    在这里插入图片描述
      get_weight()函数是用来创建卷积层或完全连接层,且获取权重张量的函数。
      值得注意的是,get_weight()采用了He的初始化方法。He的初始化方法能够确保网络初始化的时候,随机初始化的参数不会大幅度地改变输入信号的强度。StyleGAN中不仅限初始状态scale而且也是实时scale。
      2)添加偏置apply_bias()(line 213-218)
    在这里插入图片描述
      对给定的激活张量施加偏差。
      3)激活函数act()(line 400)
    在这里插入图片描述
      激活函数采用mapping_nonlinearity的值,StyleGAN中选用’lrelu’,且增益值为√2。
      注意这儿的gain是一个增益值,增益值是指的非线性函数稳态时输入幅度与输出幅度的比值,通常被用来乘在激活函数之后使激活函数更加稳定。常见的增益值包括:Sigmoid推荐的增益值是1,Relu推荐的增益值是√2,LeakyRelu推荐的增益值是√(2/(1+〖negative_slope〗^2 ))

      · 广播(line429-431)
    在这里插入图片描述

      这儿只定义了简单的复制扩充,广播前x的维度是(?,512),广播后x的维度是(?,18,512)。

      · 输出(line 434-435)
    在这里插入图片描述
      广播后的中间向量,就是G_mapping网络的最终输出。

    2.2.3 G_synthesis网络

    在这里插入图片描述
      G_synthesis网络位于代码441-560行。如上图所示,G_synthesis网络实现了从广播得到的中间向量到生成图片的合成过程。在G_synthesis中定义的组件包括:预处理->主要输入->噪音输入->★每层层末的调制功能->早期层(4*4)结构->剩余层的block块->★网络增长变换过程->输出。其中,每层层末的调制功能是指的在卷积之后,融入噪音与样式控制的过程(上图的⊕与AdaIN过程);网络增长变换过程是指的在训练时期,合成网络的架构动态增长,以生成更高分辨率图片的过程。上述两个内容是重点值得学习的部分。

      · G_synthesis输入参数(line441-462)
    在这里插入图片描述
      输入参数包括512维的中间向量(W)和输出图片的分辨率及通道,和一些可选的参数,包括各层特征图的设置、样式/网络起始值/噪音设置、激活函数设置、数据处理设置以及网络增长架构的设置等。

      · 预处理(line464-474)
    在这里插入图片描述
      预处理部分除了进一步细化网络配置以外,还定义了两个函数——nf()返回在第stage层中特征图的数量;blur()对图片进行滤波模糊操作,有利于降噪,其中blur的函数实现方式为blur2d()。
      blur2d ()(line 96-106)
    在这里插入图片描述
      在blur2d()里定义了模糊的返回函数为_blur2d(),同时blur2d()的一阶导和二阶导也被定义了出来,都是直接使用_blur2d()函数作为近似。
      _blur2d ()(line 22-49)
    在这里插入图片描述
      _blur2d ()的实现主要有两个部分,第一个部分是对于卷积核的处理,包括维度的规范和归一化处理;第二个部分是模糊的实现,即用卷积核对x实行depthwise_conv2d卷积。
      注意:depthwise_conv2d与普通的卷积有些不同。普通的卷积对卷积核每一个out_channel的两个通道分别和输入的两个通道做卷积相加,得到feature map的一个channel,而depthwise_conv2d卷积对每一个对应的in_channel,分别卷积生成两个out_channel,所以获得的feature map的通道数量可以用in_channel * channel_multiplier来表达,这个channel_multiplier,就可以理解为卷积核的第四维。参见博客:https://blog.csdn.net/mao_xiao_feng/article/details/78003476

      · 主要输入(line 477-479)
    在这里插入图片描述
      主要输入除了dlatents_in之外,还有一个lod_in参数。lod_in是一个指定当前输入分辨率级别的参数,规定lod = resolution_log2 – res。lod_in在递归构建模型架构的部分中被使用。

      · 创建噪音(line 482-487)
    在这里插入图片描述
      最初创建噪音时,只是依据对应层的分辨率创建对应的shape,然后随机初始化即为一个噪音。

      · ★层末调制(含AdaIN,line490-501)
    在这里插入图片描述
      层末调制,是在每个block的卷积之后对特征的处理,包含6种(可选)内容:应用噪音apply_noise()、应用偏置apply_bias()、应用激活函数act()、逐像素归一化pixel_norm()、实例归一化instance_norm()和样式调制(AdaIN)style_mod()。其中apply_bias()、act()与pixel_norm()在前文中已提及过,下面将不再赘述。
      1)apply_noise()(line 270-278)
    在这里插入图片描述
      应用噪音,直接将噪音加在特征x上就行了,注意按channel叠加。
      2)instance_norm()(line 247-256)
    在这里插入图片描述
      实例归一化是一个在生成模型中应用非常广泛的归一化方式,它的主要特点是仅对特征的HW(高和宽)维度做归一化,对图像的风格影响明显。
      3)★style_mod ()(line 261-265)
    在这里插入图片描述
      样式控制(AdaIN)的代码只有3行。第1行是仿射变化A,它通过全连接层将dlatent扩大一倍;第2行将扩大后的dlatent转换为放缩因子y_(s,i)和偏置因子y_(b,i);第3行是将这两个因子对卷积后的x实施自适应实例归一化。

      · 早期层结构(line 504-514)
    在这里插入图片描述
      由于StyleGAN的网络结构随训练进行是动态变化的,所以代码中定义了训练最开始时的网络结构,即4*4分辨率的生成网络。StyleGAN的生成起点选用维度为(1,512,4,4)的常量,通过一个卷积层(conv2d)得到了通道数为nf(1)(即512维)的特征图。
      · conv2d(line 164-168)
    在这里插入图片描述
      conv2d通过简单的卷积实现,将x的通道数由x.shape[1]变为fmaps,而x的大小不变。

      · 剩余层的block块(line 517-527)
    在这里插入图片描述
      StyleGAN将剩余分辨率的网络层封装成了block函数,方便在训练过程中依据输入的res(由lod_in计算出来)实时构建及调整网络的架构。其中每个block都包括了一个上采样层(upscaled_conv2d)和一个卷积层,上采样层后置滤波处理与层末调制,卷积层后置层末调制。另外在训练过程中网络需实时输出图片,StyleGAN中定义了torgb()函数,负责将对应分辨率的特征图转换为RGB图像。
      · upscaled_conv2d()(line 174-191)
    在这里插入图片描述
      upscaled_conv2d利用tf.nn.conv2d_transpose反卷积操作实现将特征图放大一倍。其中一个值得注意的操作是,其卷积核被轻微平移了四次并对自身做了叠加,这样或许对于提取特征有帮助,但我查阅不到相关资料证明这一点。

      · ★网络增长变换过程(line 530-556)
      StyleGAN的生成网络需具备动态变换的能力,代码中定义了三种结构组合方式,分别是:固定结构、线性结构与递归结构。
      1)固定结构(line 530-533)
    在这里插入图片描述
      固定结构构建了直达1024*1024分辨率的生成器网络,简单高效但不支持渐进式增长。
      2)线性结构(line 536-544)
    在这里插入图片描述
      线性结构构建了upscale2d()的上采样层,能将当前分辨率放大一倍。另外在不同分辨率间变换时,线性结构采用了含大小值裁剪的线性插值,实现了不同分辨率下的平滑过渡。
      upscale2d()(line 108-118)
    在这里插入图片描述
      在upscale2d()里定义了上采样的返回函数为_upscale2d(),同时upscale2d()的一阶导和二阶导也被定义了出来,都是直接使用_upscale2d()函数作为近似。
      _upscale2d()(line 51-68)
    在这里插入图片描述
      _upscale2d()的实现使用了tf.tile()的骚操作,其实很简单,就是复制扩展了像素值。总而言之,线性结构的实现简单但效率低下。

      3)递归结构(line 547-556)
    在这里插入图片描述
      递归结构下定义了递归函数grow(),使得只需要调用一次grow()就能够实现所有分辨率层的构建。它的实现逻辑主要是:比较lod_in和lod的关系——当lod_in超过lod时,在同一层级上实现分辨率的线性扩增;当lod_in小于lod且不是最后一层时,跳转到下一级的分辨率层上。

      · 输出(line 558-559)
    在这里插入图片描述
      网络的最终输出为之前结构中得到的images_out。

      · G_style架构总览
      最后,通过一张G_style的完整网络架构图,让我们对各个层的名称、参数量、输入维度和输出维度有更具体的理解。
    在这里插入图片描述

    2.2.4 D_basic网络

    在这里插入图片描述
      D_basic网络位于代码566-661行。如上图所示,D_basic网络实现区分合成图片与真实图片的功能,沿用了ProGAN判别器的架构,基本上是生成器反过来的样子。在D_basic中定义的组件包括:预处理->构建block块->★网络增长变换过程->标签计算->输出。其中,网络增长变换过程是指的在训练时期,随着生成图片的分辨率提升,判别网络的架构动态增长的过程。另外,标签计算是指在训练集使用了含标签数据时,会将标签值与判别分数的乘积作为最终判别网络的输出值。

      · D_basic输入参数(line565-582)
    在这里插入图片描述
      输入参数包括图片、标签以及这二者的相关配置,和一些可选的参数,包括各层特征图的设置、激活函数设置、小批量标准偏差层设置、数据处理设置以及网络增长架构的设置等。

      · 预处理(line584-596)
    在这里插入图片描述
      预处理主要包括细化网络配置、输入数据的处理以及输出数据的定义,包含内容与G_synthesis中的预处理过程类似。

      · 构建block块(line 599-618)
    在这里插入图片描述
      在训练过程中网络需实时处理图片,StyleGAN中定义了fromrgb()函数,负责将对应分辨率的RGB图像转换为特征图。
      在block函数中,当分辨率不低于88时,一个block包含一个卷积层和一个下采样层(conv2d_downscale2d);而当分辨率为最开始的44时,一个block包含一个小批量标准偏差层(minibatch_stddev_layer)、一个卷积层和两个全连接层。
      conv2d_downscale2d()(line 193-208)
    在这里插入图片描述
      conv2d_downscale2d利用tf.nn.conv2d卷积操作实现将特征图缩小一倍。其中一个值得注意的操作是,其卷积核被轻微平移了四次并对自身做了叠加然后取平均值,这样或许对于提取特征有帮助,但我查阅不到相关资料证明这一点。
      minibatch_stddev_layer()(line 283-296)
    在这里插入图片描述
      在4*4分辨率的block中,构建了一个小批量标准偏差层,将特征图标准化处理,这样能让判别网络收敛得更快。

      · ★网络增长变换过程(line 621-650)
      StyleGAN的判别网络需具备动态变换的能力,代码中定义了三种结构组合方式,分别是:固定结构、线性结构与递归结构。
      1)固定结构(line 621-625)
    在这里插入图片描述
      固定结构构建了直达10241024分辨率的判别器网络,简单高效但不支持渐进式增长。
      2)线性结构(line 628-638)
    在这里插入图片描述
      线性结构构建了downscale2d()的下采样层,能将当前分辨率缩小一倍。另外在不同分辨率间变换时,线性结构采用了含大小值裁剪的线性插值,实现了不同分辨率下的平滑过渡。
      downscale2d()(line 120-130)
    在这里插入图片描述
      在downscale2d()里定义了下采样的返回函数为_downscale2d(),同时downscale2d()的一阶导和二阶导也被定义了出来,都是直接使用_downscale2d ()函数作为近似。
      _downscale2d()(line 70-90)
    在这里插入图片描述
      _downscale2d()中,如果卷积核大小为2
    2,则直接返回_blur2d()的结果;否则采用平均池化的方式实现下采样。

      3)递归结构(line 641-650)
    在这里插入图片描述
      递归结构下定义了递归函数grow(),使得只需要调用一次grow()就能够实现所有分辨率层的构建。它的实现逻辑比较复杂,请参见代码注释;值得注意的是,构建判别网络时是lod从大往小构建,所以递归的过程是与生成器相反的。
      · 标签计算(line 653-655)
    在这里插入图片描述
      如果使用了标签的话,将标签值与判别分数的乘积作为最终判别网络的输出值。

      · 输出(line 657-659)
    在这里插入图片描述
      网络的最终输出为scores_out。

      · D_basic架构总览
      最后,通过一张D_basic的完整网络架构图,让我们对各个层的名称、参数量、输入维度和输出维度有更具体的理解。
    在这里插入图片描述

    展开全文
  • StyleGAN 架构解读(重读StyleGAN )精细

    万次阅读 多人点赞 2021-05-01 16:29:50
    StyleGAN 的前身——ProGAN 上图是 ProGAN 的网络结构图。这项技术首先通过学习即使在低分辨率图像中也可以显示的基本特征,来创建图像的基本部分,并且随着分辨率的提高和时间的推移,学习越来越多的细节。低...

    目录

    StyleGAN 的前身——ProGAN

    StyleGAN 算法总体预览

    1.2 StyleGAN 架构解读

    1.2.1 增加映射网络Mapping Network==》为输入向量的特征解缠提供一条学习的通路

    1.2.2 样式模块(AdaIN)==》使得精确控制样式信息,而保留图片的关键信息

    1.2.3 删除传统输入

    1.2.4 随机变化(类似于 AdaIN 机制的方式添加噪声)

    1.2.5 样式混合(通过混合正则化)

    1.2.6 在 W 中的截断技巧

    1.2.7 微调超参数

    2. 量化解缠结的方法

    2.1 感知路径长度

    5.2 线性可分性


    StyleGAN 的前身——ProGAN

    上图是 ProGAN 的网络结构图。这项技术首先通过学习即使在低分辨率图像中也可以显示的基本特征,来创建图像的基本部分,并且随着分辨率的提高和时间的推移,学习越来越多的细节。低分辨率图像的训练不仅简单、快速,而且有助于更高级别的训练,因此,整体的训练也就更快。

    特别值得注意的是,上图 Generator 中的网络结构不是指的从 4*4 网络连接到 8*8 网 络,再连接到 16*16 网络依次输出,而是指的从 4*4 网络变化到 8*8 网络,再变化到 16*16 网络。也就是说,Generator 内部的网络只有一个,但是在训练过程中网络的结构是在动态变化的。事实上,前面那种依次连接的网络模型叫做 StackGAN,但是 StackGAN 不适合用来做超清图片生成,因为会特别慢。

    不过,ProGAN 网络结构的动态变化是如何做到的呢?因为如果从 4×4 的输出直接变为 8×8 的输出的话,网络层数的突变会造成 GANs 原有参数失效,导致急剧不稳定,这会影响模型训练的效率。为了解决这一问题,PGGAN 提出了一种平滑过渡技术

    如上图所示,当把生成器和判别器的分辨率加倍时,会平滑地增大新的层。我们以从16 × 16 像素的图片转换到 32 × 32 像素的图片为例。在转换(b)过程中,把在更高分辨 率上操作的层视为一个残缺块,权重 α 从 0 到 1 线性增长。当 α 为 0 的时候,相当于图(a),当 α 为 1 的时候,相当于图(c)。所以,在转换过程中,生成样本的像素,是从 16x16 到 32x32 转换的。同理,对真实样本也做了类似的平滑过渡,也就是,在这个阶段的某个 训练 batch,真实样本是:

    • 上图中的 2× 和 0.5× 指利用最近邻卷积和平均池化分别对图片分辨率加倍和折半。
    • toRGB 表示将一个层中的特征向量投射到 RGB 颜色空间中,
    • fromRGB 正好是相反的过程; 这两个过程都是利用 1 × 1 卷积。

    当训练判别器时,插入下采样后的真实图片去匹配网络中 的当前分辨率。在分辨率转换过程中,会在两张真实图片的分辨率之间插值,类似于将两个分辨率结合到一起用生成器输出。详细的过程可以参见 ProGAN 论文。 上述就是 ProGAN 的模型设计介绍了,接下来我们反思一下 ProGAN 有什么缺陷。由于 ProGAN 是逐级直接生成图片,我们没有对其增添控制,我们也就无法获知它在每一级上学 到的特征是什么,这就导致了它控制所生成图像的特定特征的能力非常有限。(即ProGAN 容易发生特征纠缠,则使用下面的映射网络Mapping Network)换句话说,这些特性是互相关联的,因此尝试调整一下输入,即使是一点儿,通常也会同时影响多个特性。 我们希望有一种更好的模型,能让我们控制住输出的图片是长什么样的,也就是在生成 图片过程中每一级的特征,要能够特定决定生成图片某些方面的表象,并且相互间的影响尽 可能小。于是,在 ProGAN 的基础上,StyleGAN 作出了进一步的改进与提升

    StyleGAN 算法总体预览

    StyleGAN 用风格(style)来影响人脸的姿态、身份特征等,用噪声 ( noise ) 来影响头发丝、皱纹、肤色等细节部分。

    StyleGAN 的网络结构包含两个部分,第一个是Mapping network,即下图 (b)中的左部分,由隐藏变量 z 生成 中间隐藏变量 w的过程,这个 w 就是用来控制生成图像的style,即风格,为什么要多此一举将 z 变成 w 呢,后面会详细讲到。 第二个是Synthesis network,它的作用是生成图像,创新之处在于给每一层子网络都喂了 A 和 B,A 是由 w 转换得到的仿射变换,用于控制生成图像的风格,B 是转换后的随机噪声,用于丰富生成图像的细节即每个卷积层都能根据输入的A来调整"style",通过B来调整细节。整个网络结构还是保持了 PG-GAN (progressive growing GAN) 的结构。最后论文还提供了一个高清人脸数据集FFHQ。

    此外,传统的GAN网络输入是一个随机变量或者隐藏变量 z,但是StyleGAN 将 z 单独用 mapping网络将z变换成w,再将w投喂给 Synthesis network的每一层,因此Synthesis network中最开始的输入变成了常数张量,见下图b中的Const 4x4x512。

    1.2 StyleGAN 架构解读

    StyleGAN 首先重点关注了 ProGAN 的生成器网络,它发现,渐进层的一个的好处是如果使用得当,它们能够控制图像的不同视觉特征层和分辨率越低,它所影响的特征就越粗糙。简要将这些特征分为三种类型:

    • 1、粗糙的——分辨率不超过82,影响姿势、一般发型、面部形状等;
    • 2、中等的——分辨率为162至322,影响更精细的面部特征、发型、眼睛的睁开或是闭合等;
    • 3、高质的——分辨率为642到10242,影响颜色(眼睛、头发和皮肤)和微观特征;

    然后,StyleGAN 就在 ProGAN 的生成器的基础上增添了很多附加模块以实现样式上更细微和精确的控制。

    1.2.1 增加映射网络Mapping Network==》为输入向量的特征解缠提供一条学习的通路

    Mapping network 要做的事就是对隐藏空间(latent space)进行解耦
    首先理解一些概念:
    latent code 简单理解就是,为了更好的对数据进行分类或生成,需要对数据的特征进行表示,但是数据有很多特征,这些特征之间相互关联,耦合性较高,导致模型很难弄清楚它们之间的关联,使得学习效率低下,因此需要寻找到这些表面特征之下隐藏的深层次的关系,将这些关系进行解耦,得到的隐藏特征,即latent code。由 latent code组成的空间就是 latent space。

    StyleGAN的第一点改进是给Generator的输入加上了由8个全连接层组成的Mapping Network,并且 Mapping Network 的输出W′与输入层(512×1)的大小相同。

    1.添加 Mapping Network 的目标将输入向量编码转为中间向量,并且中间向量后续会传给生成网络得到 18 个控制向量,使得该控制向量的不同元素能够控制不同的视觉特征。

    2.为何要加 Mapping Network 呢?因为如果不加这个 Mapping Network 的话,后续得到的 18个控制向量之间会存在特征纠缠的现象——比如说我们想调节 8*8 分辨率上的控制向量(假 设它能控制人脸生成的角度),但是我们会发现 32*32 分辨率上的控制内容(譬如肤色)也被改变了,这个就叫做特征纠缠。所以 Mapping Network 的作用就是为输入向量的特征解缠提供一条学习的通路

    3.为何 Mapping Network 能够学习到特征解缠呢?简单来说,如果仅使用输入向量来控制视觉特征,能力是非常有限的,因此它必须遵循训练数据的概率密度。例如,如果黑头发 的人的图像在数据集中更常见,那么更多的输入值将会被映射到该特征上。因此,该模型无法将部分输入(向量中的元素)映射到特征上,这就会造成特征纠缠。然而,通过使用另一个神经网络,该模型可以生成一个不必遵循训练数据分布的向量,并且可以减少特征之间的相关性

    1.2.2 样式模块(AdaIN)==》使得精确控制样式信息,而保留图片的关键信息

    StyleGAN 的第二点改进是,将特征解缠后的中间向量W′变换为样式控制向量,从而参与影响生成器的生成过程。

    生成器由于从 4*4,变换到 8*8,并最终变换到 1024*1024,所以它由 9 个生成阶段组成,而每个阶段都会受两个控制向量(A)对其施加影响,其中一个控制向量在 Upsample之后对其影响一次,另外一个控制向量在 Convolution 之后对其影响一次,影响的方式都采用 AdaIN自适应实例归一化)。因此,中间向量W′总共被变换成 18 个控制向量(A)传给生成器。

    其中 AdaIN 的具体实现过程如上右图所示:将W′通过一个可学习的仿射变换(A,实际上是一个全连接层)扩变为放缩因子与偏差因子,这两个因子会与标准化之后的卷积输出做一个加权求和,就完成了一次W′影响原始输出xi的过程。而这种影响方式能够实现样式控制主要是因为它让W′(即变换后的)影响图片的全局信息(注意标准化抹去了对图片局部信息的可见性),而保留生成人脸的关键信息由上采样层和卷积层来决定,因此W′只能够影响到图片的样式信息

    Xi 表示每个特征图

    1.2.3 删除传统输入

    既然 StyleGAN 生成图像的特征是由 𝑊 AdaIN 控制的,那么生成器的初始输入可以 被忽略,并用常量值4×4×512输入替代。这样做的理由是,首先可以降低由于初始输入取值不当而生成出 一些不正常的照片的概率(这在 GANs 中非常常见),另一个好处是它有助于减少特征纠缠, 对于网络在只使用𝑊 不依赖于纠缠输入向量的情况下更容易学习。

    1.2.4 随机变化(类似于 AdaIN 机制的方式添加噪声

    人们的脸上有许多小的特征,可以看作是随机的,例如:雀斑、发髻线的准确位置、皱纹、使图像更逼真的特征以及各种增加输出的变化将这些小特征插入 GAN 图像的常用方法是 在输入向量中添加随机噪声 (即 通过在每次卷积后添加噪声 )。为了控制噪声仅影响图片样式上细微的变化, StyleGAN 采用类似于 AdaIN 机制的方式添加噪声(噪声输入是由不相关的高斯噪声组成的单通道数据,它们被馈送到生成网络的每一层)即在 AdaIN 模块之前向每个通道添加一个缩放过的噪声,并稍微改变其操作的分辨率级别特征的视觉表达方式。 加入噪声后的生成人脸往往更 加逼真与多样
    风格影响的是整体(改变姿势、身份等),噪音影响无关紧要的随机变化(头发、胡须等)。

    1.2.5 样式混合(通过混合正则化)

    为了进一步明确风格控制,StyleGAN采用混合正则化手段,即在训练过程中使用两个随机潜码W而不仅仅是一个。在生成图像时,只需在 synthesis network 中随机选一个中间的交叉点,把一个潜码切换到另一个潜码(称为风格混合)即可。具体来说,通过映射网络运行两个潜码z1和z2,得到相应的W1和W2(分别代表两种不同的 style)控制风格,然后W1被用在网络所被选择的位置点之前,W2在该位置点之后使用。

    StyleGAN 生成器在合成网络的每个级别中使用了中间向量,这有可能导致网络学习到这些级别是相关的。为了降低相关性,模型随机选择两个输入向量,并为它们生成了中间向量𝑊 。然后,它用第一个输入向量来训练一些网络级别,然后(在一个随机点中)切换到另 一个输入向量来训练其余的级别。随机的切换确保了网络不会学习并依赖于一个合成网络级 别之间的相关性。 虽然它并不会提高所有数据集上的模型性能,但是这个概念有一个非常有趣的副作用——它能够以一种连贯的方式来组合多个图像。 该模型生成了两个图像 A 和 B(第一行的第一张图片和第二行的第一张图片),然后通过从 A 中提取低级别的特征并从 B 中提取其余特征再组合这两个图像,这样能生成出混合了 A 和 B 的样式特征的新人脸
    根据交叉点选取位置的不同,style组合的结果也不同。下图中分为三个部分,
    • 第一部分是 Coarse styles from source B,分辨率(4x4 - 8x8)的网络部分使用B的style,其余使用A的style, 可以看到图像的身份特征随souce B,但是肤色等细节随source A;
    • 第二部分是 Middle styles from source B,分辨率(16x16 - 32x32)的网络部分使用B的style,这个时候生成图像不再具有B的身份特性,发型、姿态等都发生改变,但是肤色依然随A;
    • 第三部分 Fine from B,分辨率(64x64 - 1024x1024)的网络部分使用B的style,此时身份特征随A,肤色随B。
    由此可以 大致推断低分辨率的style 控制姿态、脸型、配件 比如眼镜、发型等style,高分辨率的style控制肤色、头发颜色、背景色等style

    1.2.6 在 W 中的截断技巧

    Truncation Trick 不是StyleGAN提出来的,它很早就在GAN里用于图像生成了。从数据分布来说,低概率密度的数据在网络中的表达能力很弱,直观理解就是,低概率密度的数据出现次数少,能影响网络梯度的机会也少,但并不代表低概率密度的数据不重要。可以提高数据分布的整体密度,把分布稀疏的数据点都聚拢到一起,类似于PCA,做法很简单,首先找到数据中的一个平均点,然后计算其他所有点到这个平均点的距离,对每个距离按照统一标准进行压缩,这样就能将数据点都聚拢了(相当于截断了中间向量𝑊′,迫使它保持接近“平均”的中间向量𝑊′ 𝑎𝑣𝑔),但是又不会改变点与点之间的距离关系。

    在生成模型中的一个挑战,是处理在训练数据中表现不佳的地方。这导致了生成器无法学习和创建与它们类似的图像(相反,它会创建效果不好的图像)。为了避免生成较差的图像, StyleGAN 截断了中间向量𝑊′,迫使它保持接近“平均”的中间向量 (上图左 4)。 对模型进行训练之后,通过选择多个随机的输入,用映射网络生成它们的中间向量,并 计算这些向量的平均值,从而生成“中间向量”的平均值 𝑊 ′ 𝑎𝑣𝑔 当生成新的图像时,不用直接使用映射网络(Mapping NetWork)的输出,而是将值𝑊′转换为𝑊′ 𝑛𝑒𝑤 = 𝑊′ 𝑎𝑣𝑔 +𝞧(𝑊′ − 𝑊′ 𝑎𝑣𝑔) ,其中 𝞧 的值定义了图像与“平均”图像的差异量(以及输出的多样性)。有趣的是,在仿射转换块之前,通过对每个级别使用不同的𝞧 ,模型可以控制每个级别上的特征值与平均特征值的差异量。

    1.2.7 微调超参数

    StyleGAN 的另外一个改进措施是更新几个网络超参数,例如训练持续时间和损失函数, 并将图片最接近尺度的缩放方式替换为双线性采样。 综上,加入了一系列附加模块后得到的 StyleGAN 最终网络模型结构图如下:

    上述就是 StyleGAN 的完整模型的介绍了。不得不说,不论是在理论方法上,还是工程实践上,StyleGAN 都是一篇具有突破性的论文,它不仅可以生成高质量的和逼真的图像, 而且还可以对生成的图像进行较好的控制和理解。

    2. 量化解缠结的方法

    2.1 感知路径长度

    图像生成其实是学习从一个分布到目标分布的迁移过程,如下图,已知input latent code 是z1,或者说白色的狗所表示的latent code是z1,目标图像是黑色的狗,黑狗图像的latent code 是 z2,图中紫色的虚线是z1 到 z2 最快的路径,绿色的曲线是我们不希望的路径,在紫色的路径中的中间图像应该是z1 和 z2 的组合,假设这种组合是线性的(当特征充分解耦的时候),紫色路径上生成的中间图像也是狗( 符合 latent-space interpolation),但是绿色的曲线由于偏离路径太多,生成的中间图像可能是其他的,比如图上的卧室,这是我们不希望的结果。

    补充一下,我们可以通过训练好的生成模型得到给定图像的latent code,假设我们有一个在某个数据集上训练好的styleGAN模型,现在要找到一张图像 x 在这个模型中的latent code,设初始latent code 是 z,生成的初始图像是p,通过 p 和 x 之间的差距 设置损失函数,通过损失不断去迭代 z,最后得到图像x的latent code。


    Perceptual path length 是一个指标,用于判断生成器是否选择了最近的路线(比如上图紫色虚线),用训练过程中相邻时间节点上的两个生成图像的距离来表示,公式如下:

    g 表示生成器,d 表示判别器,  表示mapping netwrok,(Z1)表示由latent code Z1得到的中间隐藏码W,间点,lerp 表示线性插值 (linear interpolation),即在 latent space上进行插值。

    • 潜在空间向量的插值可能会在图像中产生令人意想不到的非线性变化。例如,插值端点中不存在的图像元素可能会出现在线性插值路径的中间,这就表明潜在空间有纠缠现象、因子未能正确分离。为了量化这种现象,可以计算在潜在空间中执行插值时图像经历的变化程度。直观地,纠缠程度较小的潜在空间应比纠缠程度较高的潜在空间在感知上过渡更自然平滑

    • 作为度量标准的基础,使用基于感知的成对图像距离,该距离是通过计算两个VGG16的嵌入特征之间的距离得出。如果将潜在空间插值路径细分为线性段,则可以将这些路径段的距离之和定义为总感知长度。感知路径长度的自然定义是无限细分下所有路径段的极限,但实际上使用较小的细分来进行近似计算。

    • 因此,在所有可能的端点上,潜在空间Z中的平均感知路径长度如下所示,其中t〜U(0; 1),G是生成器,而d(·;·)评估结果图像之间的感知距离,在这里表示球面插值,这是在归一化输入潜伏中进行插值的最合适方法空间。在人脸数据上,为专注于面部特征而不是背景,将生成的图像裁剪为仅包含脸部。指标d是二次方,

    • 计算W中的平均感知路径长度以类似的方式执行,唯一的区别是插值发生在W空间。因为W中的向量未归一化,使用线性插值(lerp)。表3表明,该全路径(细分距离段)长度实际上对带有噪声输入的StyleGAN来说更短,这表明W比Z更线性可分一些。如果W确实是Z的一个更解纠缠、“展平”的映射(Z可能包含训练数据分布不存在的因子,生成器会生成不合理的数据),因此可预期如果将测度限制为路径终点,对变小,而不受影响。如表3所示,实验也证实了这一点。

    • 表4显示了映射网络如何影响路径长度:无论是传统的和基于风格的生成器,映射网络都能让它们变得更好。

    5.2 线性可分性

    • 如果潜在空间的“纠缠”解开,则应该有可能找到对应于各个变化因子的方向向量。StyleGAN的作者们也提出了另一个度量标准,通过测量在潜在空间的点可由线性超平面分为两个不同集合的程度来进行量化,以便每个集合都对应于图像的某种二分类属性。

    • 为得到有标签的生成图像,针对许多二分类类别训练了辅助分类网络,例如男性和女性面孔。其中,分类器与判别器具有相同的架构,并使用CELEBA-HQ数据集进行训练,该数据集保留了原始CelebA数据集中的40个类别属性。为了测量一个类别属性的可分离性,在z〜P(z)上采样通过GAN生成200,000张图像,并用辅助分类网络对其进行分类。然后,根据分类器的置信度对样本进行排序,并去除最低置信度的一半,从而产生100,000个带标记的潜在空间向量。

    • 对于每个属性,使用线性SVM来基于潜在空间点(传统的z和基于样式的w)来预测标签。然后,计算条件熵H(Y|X),其中X是SVM预测的类,Y是预训练分类器确定的类;它告诉我们确定样本的真实类别还需要多少其他信息,较低的值表明对应的变化因子具有一致的潜在空间方向。将最终的可分离性得分计算为,其中i列举了40个属性。与 inception scor相似,幂运算将值从对数域扩展到线性域,以便于比较。表3和表4表明W始终比Z具有更好的可分离性,即表明纠缠程度较小。

    图片


    reference:StyleGAN 和 StyleGAN2 的深度理解 - 知乎

    展开全文
  • StyleGAN2 解释

    千次阅读 多人点赞 2020-10-21 15:10:39
    的说法, 此博客讨论的是StyleGAN2的诸如weight demodulation, path length regularization和去掉progressive growing等信息。虽然我去年底自己复现过StyleGAN2的pytorch版, 但对这些内容也有些忘记了,借此机会复习...

    本文是[1]的译文, 按照作者Connor Shorten
    的说法, 此博客讨论的是StyleGAN2的诸如weight demodulation, path length regularization和去掉progressive growing等信息。虽然我去年底自己复现过StyleGAN2的pytorch版, 但对这些内容也有些忘记了,借此机会复习下。
    对于StyleGAN不了解的小伙伴,建议先看下别人写的关于StyleGAN的基本介绍,然后再来看本文,相信会收获更多~

    0. 前言

    来自Nvidia 赫尔辛基实验室的Karras等人提出的StyleGAN1的架构在Flicker-Faces-HQ (FFHQ)等数据集上表现非常惊人,相比之前的DCGAN和Conditional GAN等结构。

    以FFHQ数据集为例,StyleGAN不但可以生成逼真的人脸(几乎无懈可击),而且能够对人脸进行解耦, 以便对人脸进行编辑(19年的论文,截至2020年10月中旬,引用已破千(截至2020年10月20日,是1232.),在twitter上也经常有用StyleGAN的latent space做文章的工作,比较典型的厉害人物有CUHK的沈宇军和周博磊)。

    在这里插入图片描述

    StyleGAN生成的人脸图像

    在StyleGAN中, Frechet Inception Distance (FID) 是最常用的衡量图片真实性的指标(由法国科学家提出,也称遛狗绳距离)。
    在这里插入图片描述

    第一代StyleGAN[2]的实验表,可见,StyleGAN1在FFHQ最好的FID为4.40,FID越低越好。

    在这里插入图片描述

    第二代StyleGAN[3]的实验表,可见,StyleGAN2在FFHQ上的表现比第一代更好,其中,FID值由4.40提升到2.84. 算的上是巨大的提升了。

    本文主要讨论StyleGAN2相比StyleGAN1在架构上的改变,正是这些改变使得FID指标有了显著提升~,定性观察上面,StyleGAN2的artifacts出现频率也显著比StyleGAN1低。

    并基于很多人对latent space进行魔改的需求,对latent space进行平滑操作。

    原作者搞了个17分钟的解释StyleGAN2的视频在下面,如果感兴趣的小伙伴,可以饭墙去看看[4]

    在这里插入图片描述

    1. 重大改进

    1.1 Weight Demodulation

    karras和ming-yu liu等大佬非常擅长用改造的normalization层进行image synthesis任务(如GauGAN和StyleGAN)。如GauGAN中的SPADE和StyleGAN的AdaIN

    对StyleGAN,karras等人使用AdaIN (adaptive instance normalization)来控制source vector w w w对生成人脸的影响程度。

    对StyleGAN2来讲,作者们调整了AdaIN的使用,从而有效的避免了水印artifacts(water droplet artifacts)

    AdaIN是被用于快速Neural Style Transfer的normalization层。在Neural Style Transfer任务中,研究者们发现:AdaIN可以显著的解耦(remarkable disentanglement) low-level的"style"特征high-level的"content"特征

    在这里插入图片描述

    图像来自<Arbitrary Style Transfer in real-time with Adaptive Instance Normalization> authored by Xun Huang and Serge Belongie.

    不同于一般的风格迁移(Style Transfer)任务,AdaIN的出现使得风格迁移任务从受限于一种风格或者需要lengthy optimization process的情况中摆脱了出来。

    AdaIN表明,仅通过归一化统计就可以将风格(style)和内容(content)结合起来。

    Karras等人在StyleGAN2中解释了AdaIN这种归一化方法会"discard information in feature maps encoded in the relative magnitudes of activations"。

    生成器(Generator)通过将信息sneaking在这些层中来克服信息丢失的问题,但是这却带来了水印问题(water-droplet artifacts)

    对于为什么鉴别器(Discriminator)不能识别水印,作者与读者有同样的困惑。

    在StyleGAN2中,AdaIN被重构为Weight Demodulation, 如下所示:

    • AdaIN 层的含义: 同BN层类似,其目的是对网络中间层的输出结果进行scale和shift,以增加网络的学习效果,避免梯度消失。相对于BN是学习当前batch数据的mean和variance,Instance Norm则是采用了单张图片。AdaIN则是使用learnable的scale和shift参数去对齐特征图中的不同位置。
      在这里插入图片描述

    a,b为StyleGAN的细节图,c和d为StyleGAN2的细节图。可以看出[5]normalization中不再需要mean,只计算std即可。并将noise模块移除style box中,如下所示[5]

    在这里插入图片描述

    Weight demodulation的处理流程如下

    • ① 如上图里面的©所示,Conv 3x3后面的Mod std被用于对卷积层的权重进行scaling(缩放)
      w i j k ′ = s i × w i j k w_{ijk}^{'} = s_{i} \times w_{ijk} wijk=si×wijk, 这里的 i i i表示第 i i i个特征图。

    • ② 接着对卷积层的权重进行demod
      σ j = ( ∑ i , k ( w i j k ′ ) 2 ) \sigma_j = \sqrt (\sum_{i,k} (w_{ijk}^{'})^2) σj=( i,k(wijk)2)
      那么,得到新的卷积层权重为
      在这里插入图片描述
      加一个小的 ϵ \epsilon ϵ是为了避免分母为0,保证数值稳定性。尽管这种方式与Instance Norm并非在数学上完全等价,但是weight demodulation同其它normalization 方法一样,使得输出特征图有着standard的unit和deviation。

      此外,将scaling参数挪为卷积层的权重使得计算路径可以更好的并行化。这种方式使得训练加速了约40%(从每秒处理37张图片到每秒处理61张图片—不知道作者用的是什么机器)。

    1.2 Progressive growth

    StyleGAN图像对鼻子和眼睛等面部特征有很强的位置偏好。作者Karras等人将此归因于progressive growing training (同Karras作品PGGAN[6],18年的论文,引用已经有2200左右了,Karras太强了。。。)

    Progressive growing指的是:先训一个小分辨率的图像,训好了之后再逐步过渡到更高分辨率的图像。然后稳定训练当前分辨率,再逐步过渡到下一个更高的分辨率。

    尽管对研究者来说,复现progressive growing非常令人头大(因为Karras他们全都是用tensorflow 1.x写的这些网络)。这需要复杂的循环和策略设计。但是总的来说,progressive growing还是属于一种比较直观的对高分辨率图像合成coarse-to-fine的方式。这是因为一般的GAN在训练超高分辨率( 102 4 2 1024^2 10242)的图像生成上面相当不稳定,按照作者的话说:

    The discriminator will easily distinguish real and fake images, resulting in the generator unable to learn anything during training.

    不同于StyleGAN第一代使用progressive growing的策略,StyleGAN2开始寻求其它的设计以便于让网络更深,并有着更好的训练稳定性。
    对Resnet结构而言,网络加深是通过skip connection实现的。所以StyleGAN2采用了类似ResNet的残差连接结构(residual block)。对于这些设计,我们使用双线性滤波对前一层进行上/下采样,并尝试学习下一层的残差值(residual value)

    如下图所示,Karras等人使用来自TomTom公司和Adobe研究院的作者提出的“Multi-Scale Gradients for Generative Adversarial Networks” MSG-GAN[7]来revisit之前的progressive growing的方式,从而更好的利用不同尺度的信息。

    正是受MSG-GAN的启发,StyleGAN2设计了一个新的架构来利用图像生成的多个尺度信息(不需要像progressive growing那样麻烦了),他们通过一个resnet风格的跳跃连接在低分辨率的特征映射到最终生成的图像(下图的绿色block)

    在这里插入图片描述

    在这里插入图片描述

    StyleGAN2的网络结构(受MSG-GAN启发)。

    在这里插入图片描述

    Here is the performance improvement using different approaches. FID越低越好,可以看出对G output加skip和对D 增加residual的组合效果最好。

    作者表明MSG-GAN的方式同progressive growing类似,训练的早期更多地依赖低频/分辨率来对最终的输出产生影响。下图显示了特征图对最后输出的贡献情况。对这一点的研究促使Karras等人扩大网络规模,使1024x1024的分辨率对最终输出贡献更大。

    在这里插入图片描述

    1.3 Lazy Regularization

    StyleGAN1对FFHQ数据集使用了R1正则化。实验结果表明,在评估计算代价的时候,regularization是可以忽略的。实际上,即使每隔16个mini-batch使用regularization的方式,模型效果依旧很不错,因此,在StyleGAN2中,我们可以使用lazy regularization的策略,即对数据分布开始跑偏的时候才使用R1 regularization,其它时候不使用。

    1.4 Path Length Regularization

    Path Length Regularization的意义是使得latent space的插值变得更加smooth和线性。简单来说,当在latent space中对latent vector进行插值操作时,我们希望对latent vector的等比例的变化直接反映到图像中去。即:“在latent space和image space应该有同样的变化幅度(线性的latent space)”(比如说,当你对某一组latent vector进行了5个degree的偏移,那么反映在最后的生成图像中,应该是同样的效果, 如下图所示)。
    在这里插入图片描述
    Karras等人通过对生成器(Generator) 增加了一个loss项来达到这个目标。
    在这里插入图片描述
    代码如下,简单来说就是计算生成器生成的图像对其latent vector的梯度(Jacobian矩阵), ∣ ∣ J w T y ∣ ∣ 2 ||J_w^Ty||_2 JwTy2就是代码中的pl_lengths, a a apl_mean_var的移动平均: pl_mean_var= pl_mean_var + 0.01 * ( m e a n mean mean(pl_lengths) - pl_mean_var)。

    这种方法"dramatically facilitates projecting images back into the latent space"(让图像得到更加线性的对应latent vector)。

    #----------------------------------------------------------------------------
    # Non-saturating logistic loss with path length regularizer from the paper
    # "Analyzing and Improving the Image Quality of StyleGAN", Karras et al. 2019
    
    def G_logistic_ns_pathreg(G, D, opt, training_set, minibatch_size, pl_minibatch_shrink=2, pl_decay=0.01, pl_weight=2.0):
        _ = opt
        latents = tf.random_normal([minibatch_size] + G.input_shapes[0][1:])
        labels = training_set.get_random_labels_tf(minibatch_size)
        fake_images_out, fake_dlatents_out = G.get_output_for(latents, labels, is_training=True, return_dlatents=True)
        fake_scores_out = D.get_output_for(fake_images_out, labels, is_training=True)
        loss = tf.nn.softplus(-fake_scores_out) # -log(sigmoid(fake_scores_out))
    
        # Path length regularization.
        with tf.name_scope('PathReg'):
    
            # Evaluate the regularization term using a smaller minibatch to conserve memory.
            if pl_minibatch_shrink > 1:
                pl_minibatch = minibatch_size // pl_minibatch_shrink
                pl_latents = tf.random_normal([pl_minibatch] + G.input_shapes[0][1:])
                pl_labels = training_set.get_random_labels_tf(pl_minibatch)
                fake_images_out, fake_dlatents_out = G.get_output_for(pl_latents, pl_labels, is_training=True, return_dlatents=True)
    
            # Compute |J*y|.
            pl_noise = tf.random_normal(tf.shape(fake_images_out)) / np.sqrt(np.prod(G.output_shape[2:]))
            pl_grads = tf.gradients(tf.reduce_sum(fake_images_out * pl_noise), [fake_dlatents_out])[0]
            pl_lengths = tf.sqrt(tf.reduce_mean(tf.reduce_sum(tf.square(pl_grads), axis=2), axis=1))
            pl_lengths = autosummary('Loss/pl_lengths', pl_lengths)
    
            # Track exponential moving average of |J*y|.
            with tf.control_dependencies(None):
                pl_mean_var = tf.Variable(name='pl_mean', trainable=False, initial_value=0.0, dtype=tf.float32)
            pl_mean = pl_mean_var + pl_decay * (tf.reduce_mean(pl_lengths) - pl_mean_var)
            pl_update = tf.assign(pl_mean_var, pl_mean)
    
            # Calculate (|J*y|-a)^2.
            with tf.control_dependencies([pl_update]):
                pl_penalty = tf.square(pl_lengths - pl_mean)
                pl_penalty = autosummary('Loss/pl_penalty', pl_penalty)
    
            # Apply weight.
            #
            # Note: The division in pl_noise decreases the weight by num_pixels, and the reduce_mean
            # in pl_lengths decreases it by num_affine_layers. The effective weight then becomes:
            #
            # gamma_pl = pl_weight / num_pixels / num_affine_layers
            # = 2 / (r^2) / (log2(r) * 2 - 2)
            # = 1 / (r^2 * (log2(r) - 1))
            # = ln(2) / (r^2 * (ln(r) - ln(2))
            #
            reg = pl_penalty * pl_weight
    
        return loss, reg
    
    #----------------------------------------------------------------------------
    

    2. 感谢阅读

    感谢阅读StyleGAN2的重要特性分析,谢谢~

    参考文献

    [1] StyleGAN2–medium
    [2] StyleGAN: A Style-Based Generator Architecture for Generative Adversarial Networks
    [3] StyleGAN2: Analyzing and Improving the Image Quality of StyleGAN
    [4] StyleGANv2 Explained!
    [5] GAN — StyleGAN & StyleGAN2 – Jonathan Hui
    [6] PGGAN
    [7] MSG-GAN
    [8] StyleGAN2-pytorch

    展开全文
  • Android Style和自定义属性

    千次阅读 2019-03-07 17:46:59
    Theme1.1 基本概念1.1.1 Style(样式)1.1.2 Theme(主题)1.2 创建和应用style1.3 扩展和自定义style1.4 创建和应用theme1.5 扩展和自定义theme1.6 添加指定版本的style1.7 Style层级1.7.1 TextAppearance2 Android ...

    1. Android Style & Theme

    1.1 基本概念

    Styles and themes on Android allow you to separate the details of your app design from the UI structure and behavior, similar to stylesheets in web design.

    Android上的style和theme允许你将应用中设计的详细细节与UI结构和行为进行分离,类似于web设计中的样式表。

    1.1.1 Style(样式)

    A style is a collection of attributes that specify the appearance for a single View. A style can specify attributes such as font color, font size, background color, and much more.

    Style是一些可以指定单个View外观的属性集合,一个style可以指定一些属性比如字体颜色,字体大小,背景颜色等等。

    1.1.2 Theme(主题)

    A theme is a type of style that’s applied to an entire app, activity, or view hierarchy—not just an individual view. When you apply your style as a theme, every view in the app or activity applies each style attribute that it supports. Themes can also apply styles to non-view elements, such as the status bar and window background.

    Theme是一种应用于整个app,activity或者view层次的style,而不仅仅是单独的view。当你应用你的style作为theme时,每一个app或者activity中的view将应用它支持的每个style属性。theme还可以将style应用于非view元素,例如状态栏和窗口背景。

    Style和theme定义在res/values/文件夹下,通常命名为styles.xml(也可以根据需求命名为其他文件名)。

    1.2 创建和应用style

    打开res/values/styles.xml文件

    1. 添加一个以独特ID命名的<style>元素
    2. 为每个你想要定义的style属性添加<item>元素

    举个栗子:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <style name="GreenText" parent="TextAppearance.AppCompat">
            <item name="android:textColor">#00FF00</item>
        </style>
    </resources>
    

    使用方法如下:

    <TextView
        ...
        style="@style/GreenText"
        ... />
    

    每个style中定义的view所支持的属性会被应用到view中。view会忽略掉它所不支持的属性。

    注意:
    只有添加style属性的元素才会接受这些属性,任何子view不会应用这些style。如果你想要子视图继承style,取而代之的是使用android:theme属性的style。

    1.3 扩展和自定义style

    为了保持与平台UI的兼容性,在创建自己style的时候,通常继承自framework或support库中已经存在的style。如果要继承style,需要在style中指定parent属性。之后,你可以覆盖继承style的属性并添加一个新的。
    举个栗子:

    <style name="GreenText" parent="@android:style/TextAppearance">
        <item name="android:textColor">#00FF00</item>
    </style>
    

    然而,通常应用的核心style是从Android Support库中继承的。support库中的style通过针对每个版本中可用的UI属性进行了优化,提供了与Android 4.0(API 14)和更高版本的兼容性。Support库中的style通常有一个与framework中的style相似的名称,但是包含“AppCompat”。例如:

    <style name="GreenText" parent="TextAppearance.AppCompat">
        <item name="android:textColor">#00FF00</item>
    </style>
    

    你也可以通过点符号拓展style名称来继承style(平台的style除外),代替使用parent属性。也就是说,将你想要继承的style名称作为前缀,以点号分隔。当你继承自自己的style,而非其他库时,通常这么做。例如下面的例子,继承自GreenText并增加了文本大小。

    <style name="GreenText.Large">
        <item name="android:textSize">22dp</item>
    </style>
    

    你可以不断继承style很多次只要你愿意链接更多的名字。例如为GreenText增加一个大写style

    <style name="GreenText.Large.AllCaps">
        <item name="android:textAllCaps">true</item>
    </style>
    

    注意:
    如果你使用点符号来拓展style,并且使用了parent属性,这时parent属性会覆盖掉所有你继承自点符号的属性。
    例如定义一个BlueText style

    <style name="BlueText" parent="TextAppearance.AppCompat">
        <item name="android:textColor">#0000FF</item>
    </style>
    

    修改GreenText.Large.AllCaps属性继承自BlueText

    <style name="GreenText.Large.AllCaps" parent="BlueText">
        <item name="android:textAllCaps">true</item>
    </style>
    

    在View类文件的"XML attributes"表(例如TextView的"XML attributes"表)中,你可以找到以<item>标签定义的各种属性。所有的view都支持基类view中的"XML attributes",大部分view都可以添加自己特殊的属性。

    1.4 创建和应用theme

    创建theme的方法与创建style的方法相同,不同的地方在于如何应用。应用style是在view中定义一个style属性,应用theme是在AndroidManifest.xml中的<application>或者<activity>标签中添加android:theme属性。
    例如,以下是将support库中采用材料设计的"dark"theme应用到整个app。

    <manifest ... >
        <application android:theme="@style/Theme.AppCompat" ... >
        </application>
    </manifest>
    

    这段是将"Light"theme应用到activity上。

    <manifest ... >
        <application ... >
            <activity android:theme="@style/Theme.AppCompat.Light" ... >
            </activity>
        </application>
    </manifest>
    

    现在app或者activity中的每个view都应用了给定theme的style。如果一个view仅支持style中定义的部分属性,它会应用这些属性并舍弃那些它不支持的。
    从Android 5.0(API 21)和Android Support Library v22.1开始,你也可以在布局中给view定义android:theme属性。它会修改当前view及子view的theme,这对于改变界面特定部分的theme非常有用。
    但通常我们会自定义一个theme应用到我们的app中。最好的方法是拓展support库中的style并覆写某些属性。我们稍后会讲到。

    1.5 扩展和自定义theme

    当你使用Android Studio创建一个工程的时候,它会对你的应用使用一个默认的材料设计theme,定义在了项目的styles.xml文件中。这个theme继承自Support库中的theme并且包含了被用作关键UI元素的颜色属性的覆盖,例如应用栏(app bar)和浮动动作按钮(floating action button)。
    如下是style.xml文件中的定义:

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
    

    应该注意到,style值引用自其他颜色资源文件,定义在工程中res/values/colors.xml文件中,你可以通过修改这个文件来修改颜色。在开始修改颜色之前,可以使用Material Color Tool来预览颜色,这个工具可以帮助你从材料调色板中选择颜色并且预览它在app中的显示效果。
    你可以覆盖theme中你想要修改的style属性,例如,你可以修改activity背景颜色:

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        ...
        <item name="android:windowBackground">@color/activityBackground</item>
    </style>
    

    你可以参考R.styleable.Theme来查看可以修改的theme属性。当对布局中的view添加style时,可以查看view类引用中的“XML attributes”表。在R.styleable.Theme中列出的一些theme属性适用于activity中的窗口,而非布局中的view。例如,windowBackground修改了窗口背景,windowEnterTransition定义了activity的入场动画。
    Android Support Library也提供了其他属性,你可以使用它们自定义theme。
    注意:
    从Android Support Library中继承的theme修改属性时不需要加"android:"前缀。这个前缀只用于继承自Android framework的theme。

    1.6 添加指定版本的style

    如果你想要在Andorid新版本上添加theme属性。你可以将它们添加到你的theme中,并保持与旧版本的兼容性。你需要的是保存在其他包含资源版本限定符的values文件夹下的styles.xml文件。例如:

    res/values/styles.xml        # themes for all versions
    res/values-v21/styles.xml    # themes for API level 21+ only
    

    由于values/styles.xml文件中的styles对全版本可见,所以定义在res/values-v21/styles.xml中的style可以继承自他们。你可以在style文件中定义一个base开头的theme并在特定版本的styles中拓展它,这样可以避免重复的style定义。
    例如,在Android 5.0(API 21)或者更高版本发布了窗口转变的属性(windowActivityTransitions),如果你想要使用这个属性,你可以在res/values/styles.xml这样定义:

    <resources>
        <!-- base set of styles that apply to all versions -->
        <style name="BaseAppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <item name="colorPrimary">@color/primaryColor</item>
            <item name="colorPrimaryDark">@color/primaryTextColor</item>
            <item name="colorAccent">@color/secondaryColor</item>
        </style>
    
        <!-- declare the theme name that's actually applied in the manifest file -->
        <style name="AppTheme" parent="BaseAppTheme" />
    </resources>
    

    在res/values-v21/styles.xml中这样定义:

    <resources>
        <!-- extend the base theme to add styles available only with API level 21+ -->
        <style name="AppTheme" parent="BaseAppTheme">
            <item name="android:windowActivityTransitions">true</item>
            <item name="android:windowEnterTransition">@android:transition/slide_right</item>
            <item name="android:windowExitTransition">@android:transition/slide_left</item>
        </style>
    </resources>
    

    这时你可以在manifest文件中使用AppTheme这个theme了。

    1.7 Style层级

    Android提供了多样的方式去设置Android App中的属性,例如你可以在layout中直接设置属性,也可以对view设置style,也可以对layout应用theme,甚至可以在代码中设置。
    当针对你的应用选择何种style时,需要注意style的层级。一般地,你应当尽可能地保持style与theme的一致。如果你在不同的地方定义了相同的属性,下面的列表会决定哪个属性会最终被应用。列表的优先级由高到低。

    1. Applying character- or paragraph-level styling via text spans to TextView-derived classes
      使用text spans将字符或段落级的style应用于TextView及其派生类
    2. Applying attributes programmatically
      在程序中应用属性
    3. Applying individual attributes directly to a View
      将单个属性直接应用于view
    4. Applying a style to a View
      将一个style应用于view
    5. Default styling
      默认的style
    6. Applying a theme to a collection of Views, an activity, or your entire app
      将theme应用于一个view集,一个activity或者整个应用
    7. Applying certain View-specific styling, such as setting a TextAppearance on a TextView
      应用特定于view的style,例如对TextView设置TextAppearance属性

    关于这七种方式更详细的介绍,我们在第三节具体讲解。

    注意:
    如果你正在设计你的app但是并没有看到你期望的效果,可能是因为其他的style覆盖了你的修改。例如如果你将一个theme应用于你的app,同时将一个style应用于单个view,对于这个view,style属性会覆盖任何匹配到的theme属性。注意,任何没有被style覆盖的theme属性仍然会被使用。

    1.7.1 TextAppearance

    style的一个限制是只能对view定义一个style。然而对于TextView,你可以再定义一个TextAppearance属性,这个属性类似于style,如下例所示:

    <TextView
        ...
        android:textAppearance="@android:style/TextAppearance.Material.Headline"
        android:text="This text is styled via textAppearance!" />
    

    TextAppearance允许您定义特定于文本的style,同时保留view的style供其他用途使用。然而,注意,如果你直接在view中或style中定义了任何文本属性,这些属性值将会覆盖TextAppearance值。
    例如对TextView添加

    android:textColor="@color/colorPrimary"
    

    则该文本颜色会覆盖掉TextAppearance中定义的文本颜色。

    TextAppearance支持TextView所提供的style属性子集。一些一般的TextView属性没有被包含,比如:lines,lineHeight,breakStrategy,hyphenationFrequency等。TextAppearance工作在字符级而不是段落级,所以不支持影响全局的属性。

    2 Android 自定义属性

    2.1 创建自定义属性步骤

    1. 创建class CustomView
    public class CustomView extends TextView {
    
        public CustomView(Context context) {
            this(context, null);
        }
    
        public CustomView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            this(context, attrs, defStyleAttr, 0);
        }
    
        public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    }
    
    1. 在res/value/attrs.xml中添加自定义属性
    <declare-styleable name="CustomView">
        <attr name="Custom_Text" format="string"/>
        <attr name="Custom_TextSize" format="dimension"/>
        <attr name="Custom_TextColor" format="color"/>
    </declare-styleable>
    
    1. 布局文件中使用自定义属性
    <android.support.constraint.ConstraintLayout
        ...
        xmlns:CustomView="http://schemas.android.com/apk/res-auto"
        ...>
    
        <com.example.demo.demostyle.CustomView
            ...
            CustomView:Custom_Text="Test"
            CustomView:Custom_TextSize="@dimen/text_size"
            CustomView:Custom_TextColor="#FF4081"
            .../>
    
    </android.support.constraint.ConstraintLayout>
    
    1. 在CustomView的构造方法中通过TypedArray获取自定义的属性
    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomView, defStyleAttr, 0);
    mText = typedArray.getString(R.styleable.CustomView_Custom_Text);
    mTextSize = typedArray.getDimension(R.styleable.CustomView_Custom_TextSize, DEFAULT_TEXT_SIZE);
    mTextColor = typedArray.getColor(R.styleable.CustomView_Custom_TextColor, DEFAULT_TEXT_COLOR);
    typedArray.recycle();
    this.setText(mText);
    this.setTextSize(mTextSize);
    this.setTextColor(mTextColor);
    

    2.2 AttributeSet

    AttributeSet是一个接口,里面提供了诸多获取属性的方法。它的实现类是android.content.res.XmlBlock.Parser,该类实现自XmlResourceParser,而XmlResourceParser又继承自AttributeSet。通常我们在代码中是不会直接使用该接口的。

    官方API描述文档如下:

    A collection of attributes, as found associated with a tag in an XML document. Often you will not want to use this interface directly, instead passing it to {@link android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int) Resources.Theme.obtainStyledAttributes()} which will take care of parsing the attributes for you. In particular, the Resources API will convert resource references (attribute values such as “@string/my_label” in the original XML) to the desired type for you; if you use AttributeSet directly then you will need to manually check for resource references (with {@link #getAttributeResourceValue(int, int)}) and do the resource lookup yourself if needed. Direct use of AttributeSet also prevents the application of themes and styles when retrieving attribute values.
    This interface provides an efficient mechanism for retrieving data from compiled XML files, which can be retrieved for a particular XmlPullParser through {@link Xml#asAttributeSet Xml.asAttributeSet()}. Normally this will return an implementation of the interface that works on top of a generic XmlPullParser, however it is more useful in conjunction with compiled XML resources:
    XmlPullParser parser = resources.getXml(myResource);
    AttributeSet attributes = Xml.asAttributeSet(parser);
    The implementation returned here, unlike using the implementation on top of a generic XmlPullParser, is highly optimized by retrieving pre-computed information that was generated by aapt when compiling your resources. For example, the {@link #getAttributeFloatValue(int, float)} method returns a floating point number previous stored in the compiled resource instead of parsing at runtime the string originally in the XML file.
    This interface also provides additional information contained in the compiled XML resource that is not available in a normal XML file, such as {@link #getAttributeNameResource(int)} which returns the resource identifier associated with a particular XML attribute name.
    @see XmlPullParser

    翻译:AttributeSet是一个与XML文档中的标签相关联的属性集合。通常不会直接使用这个接口,而是将它传递给android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int),obtainStyledAttributes会负责解析属性。特别是,Resources API会将资源引用(源XML中定义的"@string/my_label"等属性值)转化为所需类型;如果直接使用AttributeSet则需要手动检查资源索引(使用getAttributeResourceValue(int, int))并且在需要时从资源中自行查找。直接使用AttributeSet还会在检索属性值时阻止应用theme和style。
    这个接口提供了一个从编译的XML文件中检索数据的有效机制,通过Xml.asAttributeSet()为特定的XmlPullParser检索数据。通常,这会返回一个在通用XmlPullParser之上工作的接口实现,然而,它与编译的XML资源结合起来更有用:

    XmlPullParser parser = resources.getXml(myResource);
    AttributeSet attributes = Xml.asAttributeSet(parser);
    

    与在通用XmlPullParser之上使用实现不同,此处返回的AttributeSet实现通过检索在编译资源时被aapt生成的预先计算的信息而得到高度优化。例如,getAttributeFloatValue(int, float)方法返回一个预先存储在编译资源中的浮点数值而不是在运行时解析XML文件中的源字符串。
    此接口还提供了编译的XML资源中包含的其他信息,这些信息在普通XML文件中是不可用的,例如 getAttributeNameResource(int) 返回与特定XML属性名称相关联的资源ID。

    在构造方法中添加如下代码:

    int count = attrs.getAttributeCount();
    for (int i = 0; i < count; i++) {
      String attrName = attrs.getAttributeName(i);
      String attrVal = attrs.getAttributeValue(i);
      Log.e(TAG, "name : " + attrName + ", value : " + attrVal);
    }
    

    打印Log如下:

    01-30 10:23:31.690 29910 29910 E ZXN_CustomView: name : textAppearance, value : @16974327
    01-30 10:23:31.690 29910 29910 E ZXN_CustomView: name : layout_width, value : -2
    01-30 10:23:31.690 29910 29910 E ZXN_CustomView: name : layout_height, value : -2
    01-30 10:23:31.690 29910 29910 E ZXN_CustomView: name : layout_constraintBottom_toBottomOf, value : 0
    01-30 10:23:31.690 29910 29910 E ZXN_CustomView: name : layout_constraintLeft_toLeftOf, value : 0
    01-30 10:23:31.690 29910 29910 E ZXN_CustomView: name : layout_constraintRight_toRightOf, value : 0
    01-30 10:23:31.690 29910 29910 E ZXN_CustomView: name : layout_constraintTop_toTopOf, value : 0
    01-30 10:23:31.690 29910 29910 E ZXN_CustomView: name : Custom_Text, value : Test
    01-30 10:23:31.690 29910 29910 E ZXN_CustomView: name : Custom_TextSize, value : @2131165282
    01-30 10:23:31.691 29910 29910 E ZXN_CustomView: name : Custom_TextColor, value : #ffff4081
    

    2.3 TypedArray

    从上面的Log中,心细的同学已经发现了一个问题,布局中直接赋值的属性可以直接获取,但是通过引用而得到的是"@+数字符"的ID,很不方便我们使用。此时,需要一个简便的工具,来解析AttributeSet中的属性。TypedArray便应运而生。TypedArray中定义了很多通过索引获取属性值的方法。
    官方API描述文档如下:

    Container for an array of values that were retrieved with {@link Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)} or {@link Resources#obtainAttributes}. Be sure to call {@link #recycle} when done with them.
    The indices used to retrieve values from this structure correspond to the positions of the attributes given to obtainStyledAttributes.

    翻译:TypedArray是使用Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int)或者Resources#obtainAttributes检索出来的值数组的容器。当使用完时必须调用recycle。 用于从此结构检索值的索引对应于赋予obtainStyledAttributes的属性的位置。

    2.4 declare-styleable

    declare-styleable从字面意思看是可声明样式。它是定义在XML文件中的标签。用来声明一些属性的合集。declare-styleable是非必须定义的,我们在自定义属性时可以不使用。不过为了方便,一般都会采用。
    不使用declare-styleable,需要如下修改:
    attrs.xml

    <resources>
        <attr name="Custom_Attr_Text" format="string"/>
        <attr name="Custom_Attr_TextSize" format="dimension"/>
        <attr name="Custom_Attr_TextColor" format="color"/>
    </resources>
    

    布局文件:

    <android.support.constraint.ConstraintLayout
        ...>
    
        <com.example.demo.demostyle.CustomView
            ...
            app:Custom_Attr_Text="AttrTest"
            app:Custom_Attr_TextSize="@dimen/text_size"
            app:Custom_Attr_TextColor="#FF4081"
            .../>
    </android.support.constraint.ConstraintLayout>
    

    CustomView.java

    private int[] custom_attrs = {R.attr.Custom_Attr_Text, R.attr.Custom_Attr_TextSize, R.attr.Custom_Attr_TextColor};
    
    public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
            ...
            TypedArray typedArray = context.obtainStyledAttributes(attrs, custom_attrs);
            mText = typedArray.getString(0);
            mTextSize = typedArray.getDimension(1, DEFAULT_TEXT_SIZE);
            mTextColor = typedArray.getColor(2, DEFAULT_TEXT_COLOR);
            typedArray.recycle();
    
            this.setText(mText);
            this.setTextSize(mTextSize);
            this.setTextColor(mTextColor);
            ...
        }
    

    2.5 obtainStyledAttributes

    obtainStyledAttributes函数总共有四个,分别为

    • Resources#obtainAttributes(AttributeSet set, int[] attrs)
    • Resources#Theme#obtainStyledAttributes(int[] attrs)
    • Resources#Theme#obtainStyledAttributes(int resId,int[] attrs)
    • Resources#Theme#obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)

    2.5.1 obtainAttributes(AttributeSet set, int[] attrs)

    /**
     * Retrieve a set of basic attribute values from an AttributeSet, not performing styling of them using a theme and/or style resources.
     * 从AttributeSet检索一组基本属性值,而不是使用theme和/或style资源执行它们的style。
     *
     * @param set The current attribute values to retrieve.
     *            当前需要检索的属性集合
     *
     * @param attrs The specific attributes to be retrieved. These attribute IDs must be sorted in ascending order.
     *              指定所要检索的属性组,这些属性ID必须按照升序排列
     *
     * @return Returns a TypedArray holding an array of the attribute values.
     *         返回一个包含属性值数组的TypedArray。
     *
     * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when done with it.
     * 确保在使用完后调用TypedArray.recycle()。
     */
    public TypedArray obtainAttributes(AttributeSet set, @StyleableRes int[] attrs) {
        int len = attrs.length;
        TypedArray array = TypedArray.obtain(this, len);
        XmlBlock.Parser parser = (XmlBlock.Parser)set;
        mResourcesImpl.getAssets().retrieveAttributes(parser, attrs, array.mData, array.mIndices);
        array.mXml = parser;
        return array;
    }
    

    2.5.2 obtainStyledAttributes(int[] attrs)

    /**
     * Return a TypedArray holding the values defined by <var>Theme</var> which are listed in <var>attrs</var>.
     * 返回一个TypedArray,其中包含由attrs中列出的Theme定义的值。
     *
     * @param attrs The desired attributes. These attribute IDs must be sorted in ascending order.
     *              所需的属性。 必须按升序对这些属性ID进行排序。
     *
     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
     *                           如果ID不存在,抛出NotFoundException异常。
     *
     * @return Returns a TypedArray holding an array of the attribute values.
     *         返回一个包含属性值数组的TypedArray。
     *
     * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when done with it.
     * 确保在使用完后调用TypedArray.recycle()。
     */
    public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
        return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0);
    }
    

    2.5.3 obtainStyledAttributes(int resId,int[] attrs)

    /**
     * Return a TypedArray holding the values defined by the style resource <var>resid</var> which are listed in <var>attrs</var>.
     * 返回一个TypedArray,其中包含由attrs中列出的style资源resid定义的值。
     *
     * @param resId The desired style resource.
     *              所需的style资源。
     *
     * @param attrs The desired attributes in the style. These attribute IDs must be sorted in ascending order.
     *              所需style中的属性。 必须按升序对这些属性ID进行排序。
     *
     * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
     *                           如果ID不存在,抛出NotFoundException异常。
     *
     * @return Returns a TypedArray holding an array of the attribute values.
     *         返回一个包含属性值数组的TypedArray。
     *
     * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when done with it.
     * 确保在使用完后调用TypedArray.recycle()。
     */
    public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs) throws NotFoundException {
        return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId);
    }
    

    2.5.4 obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)

    /**
     * Return a TypedArray holding the attribute values in <var>set</var> that are listed in <var>attrs</var>.  In addition, if the given AttributeSet specifies a style class (through the "style" attribute), that style will be applied on top of the base attributes it defines.
     * 返回一个TypedArray,其中包含"attrs"中列出的"set"中的属性值(即obtainStyledAttributes会按照attrs中列出的属性值去set中进行查找,将结果写入TypedArray并返回)。另外,如果给定的AttributeSet定义了一个style类(通过"style"属性),则style将会被应用于它定义的基础属性之上。
     *
     * <p>When determining the final value of a particular attribute, there are four inputs that come into play:</p>
     * 确定特定属性的最终值时,有四个输入起作用:
     *
     * <ol>
     *     <li> Any attribute values in the given AttributeSet.
     *          给定AttributeSet中的任何属性值
     *     <li> The style resource specified in the AttributeSet (named "style").
     *          AttributeSet中定义的style资源(命名为"style")
     *     <li> The default style specified by <var>defStyleAttr</var> and <var>defStyleRes</var>
     *          "defStyleAttr"和"defStyleRes"定义的默认style
     *     <li> The base values in this theme.
     *          Theme中的默认值
     * </ol>
     *
     * <p>Each of these inputs is considered in-order, with the first listed taking precedence over the following ones.  In other words, if in the AttributeSet you have supplied <code>&lt;Button textColor="#ff000000"&gt;</code>, then the button's text will <em>always</em> be black, regardless of what is specified in any of the styles.
     * 这些输入中的每一个都需要考虑顺序,首先列出的输入优先于下一个输入。换句话说,如果在AttributeSet中你已经定义了Button textColor="#ff000000",那么按钮的文本将始终是黑色,无论你在任何style中再指定。
     *
     * @param set The base set of attribute values. May be null.
     *            属性值的基类,可能为空。
     *
     * @param attrs The desired attributes to be retrieved. These attribute IDs must be sorted in ascending order.
     *              要检索的所需属性。 必须按升序对这些属性ID进行排序。
     *
     * @param defStyleAttr An attribute in the current theme that contains a reference to a style resource that supplies defaults values for the TypedArray. Can be 0 to not look for defaults.
     *                     当前theme中的一个属性。它包含了为TypedArray提供默认值的style资源的引用。可以为0以查找默认值。
     *
     * @param defStyleRes A resource identifier of a style resource that supplies default values for the TypedArray, used only if defStyleAttr is 0 or can not be found in the theme.  Can be 0 to not look for defaults.
     *                    为TypedArray提供默认值的style资源的资源ID,只有在defStyleAttr为0或者在Theme中找不到时才会被使用。可以为0以查找默认值。
     *
     * @return Returns a TypedArray holding an array of the attribute values.
     * 返回一个包含属性值数组的TypedArray。
     *
     * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()} when done with it.
     * 确保在使用完后调用TypedArray.recycle()。
     */
    public TypedArray obtainStyledAttributes(AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
        return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
    }
    

    注:
    关于attrs,文档中要求ID按照升序排列,意思是在R.java文件中生成的ID必须按照升序排列。
    例如,在Attrs.xml文件中定义的declare-styleable

    <declare-styleable name="CustomViewStyle">
        <attr name="Custom_TextSize" format="dimension"/>
        <attr name="Custom_TextColor" format="color"/>
        <attr name="Custom_Text" format="string"/>
    </declare-styleable>
    

    查看编译后的R.java文件

    ...
    public static final int Custom_Text=0x7f0100d0;
    public static final int Custom_TextColor=0x7f0100cf;
    public static final int Custom_TextSize=0x7f0100ce;
    ...
    public static final int[] CustomViewStyle = {0x7f0100ce, 0x7f0100cf, 0x7f0100d0};
    ...
    

    3 几种赋值属性方法

    在第一章中,提到了七种Style层级,也即七种赋值属性的方法,分别如下:

    1. Applying character- or paragraph-level styling via text spans to TextView-derived classes
      使用text spans将字符或段落级的style应用于TextView及其派生类
    2. Applying attributes programmatically
      在程序中应用属性
    3. Applying individual attributes directly to a View
      将单个属性直接应用于view
    4. Applying a style to a View
      将一个style应用于view
    5. Default styling
      默认的style
    6. Applying a theme to a collection of Views, an activity, or your entire app
      将theme应用于一个view集,一个activity或者整个应用
    7. Applying certain View-specific styling, such as setting a TextAppearance on a TextView
      应用特定于view的style,例如对TextView设置TextAppearance属性

    以上七种方式中,加粗字体的为我们需要详细讨论的,其他的由于使用场景有限或非重点,暂不讨论。
    对于第五种方法,可以细分为使用defStyleAttr和defStyleRes来设置默认的style,所以以上方法可以进一步划分为如下方法:

    1. 将单个属性直接应用于view
    2. 将一个style应用于view
    3. 通过defStyleAttr设置默认style
    4. 通过defStyleRes设置默认style
    5. 将theme应用于一个view集,一个activity或者整个应用

    在讲解这几种方式之前,我们先在attrs.xml中定义CustomViewStyle,并且自定义View:CustomView

    <resources>
        <declare-styleable name="CustomViewStyle">
            <attr name="Custom_Text" format="string"/>
            <attr name="Custom_TextSize" format="dimension"/>
            <attr name="Custom_TextColor" format="color"/>
        </declare-styleable>
    </resources>
    
    public class CustomView extends TextView {
    
        private static final int DEFAULT_TEXT_SIZE = 20;
        private static final int DEFAULT_TEXT_COLOR = Color.BLUE;
    
        private String mText;
        private float mTextSize;
        private int mTextColor;
    
        public CustomView(Context context) {
            this(context, null);
        }
    
        public CustomView(Context context, @Nullable AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            this(context, attrs, defStyleAttr, 0);
        }
    
        public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
    
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomViewStyle, defStyleAttr, 0);
            mText = typedArray.getString(R.styleable.CustomViewStyle_Custom_Text);
            if (!TextUtils.isEmpty(mText)) {
                this.setText(mText);
            }
            mTextSize = typedArray.getDimensionPixelSize(R.styleable.CustomViewStyle_Custom_TextSize, DEFAULT_TEXT_SIZE);
            this.setTextSize(mTextSize);
            mTextColor = typedArray.getColor(R.styleable.CustomViewStyle_Custom_TextColor, DEFAULT_TEXT_COLOR);
            this.setTextColor(mTextColor);
            typedArray.recycle();
        }
    }
    

    3.1 将单个属性直接应用于view

    在布局文件中直接对属性进行赋值,可以为Android提供系统属性,也可以为自定义属性。

    <com.example.demo.demostyle.CustomView
        ...
        app:Custom_Text="Test"
        app:Custom_TextSize="30sp"
        app:Custom_TextColor="#00FF00"
        android:text="Test"
        android:textSize="30sp"
        android:textColor="#00FF00"
        .../>
    

    3.2 将一个style应用于view

    为了方便管理,我们常把某一些特定的属性抽取出来汇聚到一个style文件中进行管理。从而使一些控件有相同的风格。

    1. 在styles.xml文件中定义一个特定的style
    <resources>
        ...
        <style name="SpecialTextStyle">
            <item name="Custom_Text">"SpecialTextStyle"</item>
            <item name="Custom_TextSize">10sp</item>
            <item name="Custom_TextColor">#FF00FF</item>
            <item name="android:text">"SpecialTextStyle"</item>
            <item name="android:textSize">10sp</item>
            <item name="android:textColor">#FF00FF</item>
            <item name="android:textAllCaps">true</item>
        </style>
        ...
    </resources>
    
    1. 将定义的style赋值给自定义View
    <android.support.constraint.ConstraintLayout
        ...>
        <com.example.demo.demostyle.CustomView
            ...
            style="@style/SpecialTextStyle"
            .../>
        <TextView
            ...
            style="@style/SpecialTextStyle"
            .../>
        <Button
            ...
            style="@style/SpecialTextStyle"
            .../>
    </android.support.constraint.ConstraintLayout>
    

    此时,这几个控件便具有了相同的文本,文本大小,文本颜色以及文本大写

    3.3 通过defStyleAttr设置默认style

    1. 在attrs.xml中定义默认style和默认属性
    <resources>
        <style name="default_text_style">
            <item name="Custom_Text">"Default Text Style"</item>
            <item name="Custom_TextSize">40sp</item>
            <item name="Custom_TextColor">#00FFFF</item>
        </style>
    
        <attr name="defaultTextViewStyle" format="reference"/>
    </resources>
    
    1. 在styles.xml文件中自定义一个theme,并且给defaultTextViewStyle属性赋予我们自定义的默认style的引用
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        ...
        <item name="defaultTextViewStyle">@style/default_text_style</item>
    </style>
    
    1. 在AndroidManifest.xml文件中将我们自定义的theme应用在application或activity上
    <application
        ...
        android:theme="@style/AppTheme">
        ...
    </application>
    
    1. 在CustomView.java文件中修改构造函数,将obtainStyledAttributes函数中的defStyleAttr参数修改为R.attr.defaultTextViewStyle
    public class CustomView extends TextView {
        ...
        public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            ...
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomViewStyle, R.attr.defaultTextViewStyle, 0);
            ...
        }
    }
    

    通过以上几个步骤,便将我们定义的defaultTextViewStyle应用到CustomView中。

    3.4 通过defStyleRes设置默认style

    在第三种的基础上,假如我们没有设置defStyleAttr,或者设置为Theme中查到不到的style,第四个参数defStyleRes就起作用了。
    在CustomView.java文件中修改构造函数,将obtainStyledAttributes函数中的defStyleAttr修改为0,defStyleRes修改为R.style.default_text_style

    public class CustomView extends TextView {
        ...
        public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            ...
            TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomViewStyle, 0, R.style.default_text_style);
            ...
        }
    }
    

    此时,CustomView中将会应用default_text_style作为默认style。

    3.5 将theme应用于一个view集,一个activity或者整个应用

    在Theme中添加一些属性,并将Theme设置到Application或Activity上,使得Application或Activity内的空间默认属性为定义的属性,可以理解为一个全局默认属性

    1. 在styles.xml文件中自定义一个theme,并添加一些属性
    <resources>
        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            ...
            <item name="Custom_Text">"Theme Default Text"</item>
            <item name="Custom_TextSize">30sp</item>
            <item name="Custom_TextColor">#F06F58</item>
            <item name="android:text">"Theme Default Text"</item>
            <item name="android:textSize">30sp</item>
            <item name="android:textColor">#F06F58</item>
            ...
        </style>
    </resources>
    
    1. 在AndroidManifest.xml文件中将我们自定义的theme应用在application或activity上
    <application
        ...
        android:theme="@style/AppTheme">
        ...
    </application>
    

    这样当你布局中的视图未设置这几个属性时,将默认使用Theme中定义的属性。

    注意:经过验证,以上几个方式的优先级由高到低

    展开全文
  • 一文让你彻底弄懂 “vue-style-loader” 跟 “style-loader” 区别 简介 用过 vue-cli 脚手架搭建 vue 项目都知道,vue-cli 中内置了 vue-style-loader 去加载样式模块,最后通过 <style> 标签把样式加载到...
  • LVGL风格Style介绍 样式用于设置对象的外观。lvgl 中的样式受 CSS 启发很大。简而言之,概念如下: 样式是一个 lv_style_t 可以保存属性的变量,例如边框宽度,文本颜色等。与 class CSS 类似。 并非必须指定...
  • 1万地形图的ArcGIS符号库(Style文件)

    热门讨论 2015-10-10 20:34:00
    ArcGIS建立的1万地形图的ArcGIS符号库(Style文件)
  • LVGL lv_style样式(6)

    千次阅读 2020-12-29 17:04:14
    lv_style 每一个基础对象都会有一个lv_style样式,对于复杂些的对象,比如lv_btn按钮就会有多个样式,因为它是由多个基础对象组合而成。利用样式对对象进行重绘来达到UI设计效果,不同的样式来形成主题Theme,相关...
  • html style属性

    千次阅读 2019-05-06 15:55:26
    在html 中 style 用于为 HTML 文档定义样式信息。...style> 当做一个标签使用 下面修改自己颜色为例 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title...
  • Pandas Style 为数据表格美颜

    千次阅读 2020-07-20 10:00:00
    df2 = -df style1 = df.style.applymap(color_negative_red) style1 style2 = df2.style style2.use(style1.export()) style2 7. 其他样式 精度set_precision df.style.applymap(color_negative_red).apply...
  • 完整StyleGAN笔记:http://www.gwylab.com/pdf/Note_StyleGAN.pdf 基于StyleGAN的一个好玩的网站:www.seeprettyface.com ————————————————————...  StyleGAN的损失函数写在training/loss.p...
  • style常见属性

    千次阅读 多人点赞 2018-05-12 12:52:52
    div style="width:200px;height:200px;background-color:Black;"&gt; &lt;/div&gt; 3、margin:用于设置DIV的外延边距,也就是到父容器的距离。 例: 复制代码代码如下:&lt;div style=...
  • style属性的获取和修改 在DOM当中,如果想设置样式,有两种形式: className(针对内嵌样式) style(针对行内样式) 这篇文章,我们就来讲一下style。 需要注意的是:style是一个对象,只能获取行内样式,不...
  • 在上一篇文章里,我们下载了StyleGAN Encoder的源代码和相关资源,可以实现对真实人脸特征码的提取,内容请参考: https://blog.csdn.net/weixin_41943311/article/details/103030194 那么,针对我们感兴趣的话题...
  • ol.style 属性及子类3. ol.style使用栗子 1. 写在前面 地图样式是由 style 类控制的,其包含了地图样式的方方面面,例如,填充色、图标样式、图片样式、规则图形样式、边界样式、文字样式等,样式一般针对矢量要素...
  • POI 边框样式BorderStyle

    千次阅读 2020-03-24 14:33:46
    POI 边框样式BorderStyle 1. 单元格边框样式 单元格边框样式包含框线样式和边框颜色,可以对单元格的四边设置不同的样式 设置单元格样式: style.setBorderBottom(BorderStyle.DOUBLE); style....
  • StyleGAN如何定制人脸生成

    千次阅读 2021-04-28 09:12:24
    方法三 借助InfoGAN的思想修改StyleGAN的架构 定制人脸生成   这一部分会介绍基于StyleGAN,进一步地做定制人脸生成使用的方法。目前采用过的方法有三种: 第一种是从源头上通过控制生成码Z的分布范围,从而控制...
  • StyleGAN中的style借用自图像风格迁移,之前也看过风格迁移的论文,图像的Gram矩阵一般可以表示它的风格也就是style。这篇文章是PG-GAN之后的,主要改变了生成器的结构实现无监督地生成可控性强的图像。 PG-GAN中是...
  • Style-GAN encoder 详解

    千次阅读 2019-07-27 22:13:24
    Image2StyleGAN: How to Embed Images Into the StyleGAN Latent Space? 摘要 本文使用一种有效的算法,能够将图片映射到styleGAN的潜在空间,使用FFHD训练好的styleGAN作为实例,演示风格转化,表达转化等。通过...
  • DOM样式的修改,对象.style.属性名=属性值; CSS样式和DOM样式在js用法区别 CSS DOM width width height height background-color backgroundColor font-size fontSize ...
  • 列表的样式在CSS中,列表元素是一个块框,列表中的每个表项也是一个块框,只是在表项前面多了一个项目符号。列表的格式化,主要由浏览器完成,而不是由设计人员...list-style属性的语法格式为:list-style:[ list-...
  • CSS list-style 属性

    千次阅读 2019-01-11 10:32:59
    list-style:square inside url('/i/arrow.gif'); } 可以按顺序设置如下属性: list-style-type list-style-position list-style-image 一、list-style-type 属性 list-style-type 属性设置列表项标记的类型。 ...
  • AGPBI: {"kind":"error","text":"error: resource style/AppTheme.AppBarOverlay (aka com.xxx.xxx:style/AppTheme.AppBarOverlay) not found.
  • 什么是Android应用的风格style?什么又是Android应用的主题theme?它们俩有什么联系和区别?怎么定义和使用我们自己的风格和主体呢?本文将详细的介绍它们的来历与关系,让你豁然开朗。
  • eclipse-java-google-style

    千次下载 热门讨论 2013-04-01 14:03:18
    eclipse-java-google-style android eclipse 代码规范 欢迎大家使用
  • 【GANs学习笔记】(二十四)StyleGAN

    万次阅读 多人点赞 2019-03-25 14:52:46
    ————————————————————————————————...本章借鉴内容:https://towardsdatascience.com/explained-a-style-based-generator-architecture-for-gans-generating-and-tuning-realisti...
  • xlsx-style的用法

    千次阅读 热门讨论 2020-10-22 08:45:27
    如何通过xlsx-style 修改导出excel的样式 实现导出的excel是带有边框的,满足打印的时候可以尽可能的铺满A纸 安装 xlsx-style npm install xlsx-style --save 修改xlsx-style 源码 解决报错 在\node_modules\xlsx-...
  • Tensorflow实现Neural Style图像风格转移

    万次阅读 多人点赞 2018-01-08 21:02:15
      文章中的代码和图片已上传到GitHub(https://github.com/Quanfita/Neural-Style)。 什么是图像风格迁移?   以下每一张图都是一种不同的艺术风格。从直观上我们很难找出这些不同风格的图片有什么可以用...
  • matplotlib绘图样式(style)初探

    万次阅读 2021-01-03 10:20:45
    Styles are predefined sets ...Customizing Matplotlib with style sheets and rcParams describes the mechanism and usage of styles. The Style sheets reference gives an overview of the builtin styles. matpl
  • stylegan-encoder代码执行步骤和解释

    千次阅读 2021-05-08 15:48:39
    (三)从对齐的人脸头像提取特征码并生成StyleGAN头像: (四)用别人的特征码修饰你的照片特征码,并生成混合后的StyleGAN头像: 在github.com 上有若干开源项目提供了源代码,我选用的开源项目是:pbaylies/...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,290,237
精华内容 916,094
关键字:

style