风格迁移0-06:stylegan-源码无死角解读(2)-数据预处理process_reals

以下链接是个人关于stylegan所有见解,如有错误欢迎大家指出,我会第一时间纠正,如有兴趣可以加微信:a944284742相互讨论技术。若是帮助到了你什么,一定要记得点赞奥!因为这是对我最大的鼓励。
风格迁移0-00:stylegan-目录-史上最全:https://blog.csdn.net/weixin_43013761/article/details/100895333

数据处理

在上篇博客中,我给大家注释了一下根目录下的training/training_loop.py文件,了解一下大致的流程,这小节我们就来讲解一下数据的预处理,即process_reals函数,该函数也存在于training/training_loop.py文件中,其实该函数花费了我好些心思才理解过来。:

def training_loop()
	......
    # 加载训练数据,其会把所有分辨率的数据都加载进来
    training_set = dataset.load_dataset(data_dir=config.data_dir, verbose=True, **dataset_args)
    ......
    ......
            # 获得训练数据图片和标签
            reals, labels = training_set.get_minibatch_tf()
            # 对训练数据的真实图片进行处理,主要把图片分成多个区域进行平滑,注意这里的reals包含多张图片,分别对应不同的分辨率,
            # 其实这里说是分辨率不太合适,总的来说,他们分辨率都是1024,但是平滑插值不一样.其不是用来训练的数据,是用来求损失用的,具体细节后面分析,也属于一个比较重要的地方
            reals = process_reals(reals, lod_in, mirror_augment, training_set.dynamic_range, drange_net)  

现在我们来看看process_reals函数:

def process_reals(x, lod, mirror_augment, drange_data, drange_net):
    """

    :param x: 该为输入的图片,(batch_size, 3, 1024, 1024)
    :param lod: 该值从零开始,随着训练图片的张数,更改变为0,1,2,3,4,5,6,7,8
    :param mirror_augment: # 是否进行镜像翻转
    :param drange_data: #数据动态变化的范围[0,255],输入
    :param drange_net: #数据动态变化的网络[-1,1],输出
    :return:
    """
    with tf.name_scope('ProcessReals'):
        with tf.name_scope('DynamicRange'):
            x = tf.cast(x, tf.float32)
            # 把原来的像素先缩小到2/255然后减去1
            x = misc.adjust_dynamic_range(x, drange_data, drange_net)

        if mirror_augment:
            with tf.name_scope('MirrorAugment'):
                s = tf.shape(x)
                # 随机产生(batch_size, 1, 1, 1)维度的数组,其值为0到1之间
                mask = tf.random_uniform([s[0], 1, 1, 1], 0.0, 1.0)
                # 对前面产生的像素,进行复制,复制之后的维度为[batch_size, 3, 1024, 1024]
                mask = tf.tile(mask, [1, s[1], s[2], s[3]])
                #小于0.5的返回原值,否则返回对第三维进行翻转之后的值(经过一位小伙伴的提醒,进行了修改)
                x = tf.where(mask < 0.5, x, tf.reverse(x, axis=[3]))


        with tf.name_scope('FadeLOD'): # Smooth crossfade between consecutive levels-of-detail.
            # (batch_size, 3, 1024, 1024)
            s = tf.shape(x)
            # 把每张(1024, 1024)的图片图片分割成4快区域,每块区域为512*512个像素
            y = tf.reshape(x, [-1, s[1], s[2]//2, 2, s[3]//2, 2])

            # 对3,5维度取均值,即4个512*512的区域,每个区域都用他们的平均像素代替,注意,是一个像素代替512个,
            # 所以这里已经降维,变成(3,4,4)的图片
            y = tf.reduce_mean(y, axis=[3, 5], keepdims=True)
            # 对像素进行复制,复原到(3,1024,1024),因为是复制而来,复原到4快区域,但是每块区域对应的像素都是之前的均值
            y = tf.tile(y, [1, 1, 1, 2, 1, 2])
            y = tf.reshape(y, [-1, s[1], s[2], s[3]])

            # 进行像素插值,当lod为0的时候,不进行任何改变,依旧为上面计算出来的四块区域,所有像素都用均值代替
            # lod越大,则越接近原图,其主要目的就是把原图损失的像素值补回来,当lod围殴10,即2的10次方插值,此时和原图一样
            x = tflib.lerp(x, y, lod - tf.floor(lod))

        # 和前面类似的操作,把图片区域化,使用均值像素代替,但是这里会分成factor*factor块区域,不仅仅是4快。
        with tf.name_scope('UpscaleLOD'): # Upscale to match the expected input/output size of the networks.
            s = tf.shape(x)
            factor = tf.cast(2 ** tf.floor(lod), tf.int32)
            x = tf.reshape(x, [-1, s[1], s[2], 1, s[3], 1])
            x = tf.tile(x, [1, 1, 1, factor, 1, factor])
            x = tf.reshape(x, [-1, s[1], s[2] * factor, s[3] * factor])
        return x

其中函数adjust_dynamic_range实现如下:

def adjust_dynamic_range(data, drange_in, drange_out):
    """
    :param data:
    :param drange_in:[0,255]
    :param drange_out:[-1,1]
    :return:
    """
    if drange_in != drange_out:
        # scale = ([1]-[-1])/([255]-[0]) = 2/255
        scale = (np.float32(drange_out[1]) - np.float32(drange_out[0])) / (np.float32(drange_in[1]) - np.float32(drange_in[0]))
        # bias = (-1) - (0 * scale) = -1
        bias = (np.float32(drange_out[0]) - np.float32(drange_in[0]) * scale)

        # 把原来的像素先缩小到2/255然后减去1
        data = data * scale + bias
    return data

其实,对于上面的

with tf.name_scope('DynamicRange'):
	......
if mirror_augment:
	......

不是很了解,暂时不知道他为什么要这样做,如果忽略掉上面的代码,其原理很好理解的。当lod为3的时候,输出如下:
风格迁移0-06:stylegan-源码无死角解读(2)-数据预处理process_reals_第1张图片
当lod为4的时候输出如下:
风格迁移0-06:stylegan-源码无死角解读(2)-数据预处理process_reals_第2张图片
前面提到,当能是图片像素为1024时,几乎和原图一样,类似于下(该还和原图又差距,大约为512x512):

对于前面不懂得地方,估计是和求损失的部分有关联,当然只是猜测而已,如果有弄懂得朋友,希望能够告诉我,我也很想明白。

下面我来说说,为什么需要这种把一副图像分成多个区域,然后使用均值代替那一篇区域,其类似于下采样但是又不是下采样。再前面也提到过,目的是为了让机器分步生成图片,先生成轮廓再生成细节。这里的process_real处理的图片,估计是计算损失所使用,真相是否如此,请看后面的分析。

你可能感兴趣的:(风格迁移)