TensorFlow实时任意风格迁移,送女朋友的创意礼物有了,2024年Python社招面试题

接下来,我们需要将对卷积层进行少量但很重要的改进,以改善生成图像的外观。

通过反射填充(reflection padding)减少块伪影

当我们在卷积层中将填充( padding)应用于输入张量时,在张量周围填充常数零。但是,边界处的值突然下降会产生高频分量,并在生成的图像中导致块伪影。减少这些高频分量的一种方法是在网络训练中添加总变分损失( total variation loss )作为正则化器:

  1. 首先,通过将图像移动一个像素来计算高频分量,

  2. 然后减去原始图像以创建一个矩阵。

总变分损失是 L 1 L_1 L1​ 范数的总和。因此,训练将尝试最小化此损失函数,以减少高频分量。

还有另一种选择,就是用反射值替换填充中的常数零。例如,如果我们用零填充 [10, 8, 9] 的数组,则将得到 [0, 10, 8, 9, 0] ,我们可以看到0和它的邻居之间的值的变化十分突然。

如果我们使用反射填充,则填充数组将为 [8, 10, 8, 9, 8] ,这将向边界提供更平滑的过渡。但是,Keras Conv2D 不支持反射填充,因此我们需要使用 TensorFlow 创建自定义 Conv2D 。以下代码片段显示了在卷积之前向输入张量中添加反射填充:

class Conv2D(layers.Layer):

def init(self, in_channels, out_channels, kernel=3, use_relu=True):

super(Conv2D, self).init()

self.kernel = kernel

self.in_channels = in_channels

self.out_channels = out_channels

self.use_relu = use_relu

def build(self, input_shape):

self.w = self.add_weight(shape=[

self.kernel,

self.kernel,

self.in_channels,

self.out_channels],

initializer=‘glorot_normal’,

trainable=True, name=‘bias’)

self.b = self.add_weight(shape=(

self.out_channels,),

initializer=‘zeros’,

trainable=True,

name=‘bias’)

@tf.function

def call(self, inputs):

padded = tf.pad(inputs, [[0,0],[1,1],[1,1],[0,0]], mode=‘REFLECT’)

perform conv2d using low level API

output = tf.nn.conv2d(padded, self.w, strides=1, padding=‘VALID’) + self.b

if self.use_relu:

output = tf.nn.relu(output)

return output

解码器结构与实现

尽管编码器使用了4个 VGG 中的网络层( block1_conv1block4_conv1 ),但AdaIN仅使用编码器的最后一层 block4_conv1 。因此,解码器的输入张量与 block4_conv1 的激活层输出相同。解码器由卷积和上采样层组成,如以下代码所示:

def build_decoder(self):

block = tf.keras.Sequential([

Conv2D(512, 256, 3),

UpSampling2D((2,2)),

Conv2D(256,256,3),

Conv2D(256,256,3),

Conv2D(256,256,3),

Conv2D(256,128,3),

UpSampling2D((2,2)),

Conv2D(128,128,3),

Conv2D(128,64,3),

UpSampling2D((2,2)),

Conv2D(64,64,3),

Conv2D(64,3,3,use_relu=False)

], name=‘decoder’)

return block

Tips:前面的代码使用具有反射填充的自定义Conv2D。除不具有任何非线性激活函数的输出层外,所有层均使用ReLU激活函数。

现在,我们已经完成了AdaIN,编码器和解码器。接下来,可以继续进行图像预处理流程了。

VGG预处理

与我们之前构建的神经风格迁移一样,我们需要通过将颜色通道转换为BGR然后减去颜色均值来对图像进行预处理,代码如下:

def preprocess(self, image):

RGB to BGR

image = tf.reverse(image, axis=[-1])

return tf.keras.applications.vgg19.preprocess_input(image)

我们可以在后期处理中进行反向操作,即添加颜色均值并反转颜色通道。但是,这是解码器可能会学到的,因为颜色均值等效于输出层中的偏置。因此,我们将让训练过程来完成后期处理工作,而我们要做的仅仅是将像素裁剪至 [0,255] 范围:

def postprocess(self, image):

return tf.clip_by_value(image, 0., 255.)

现在,我们已经准备好所有构件,剩下要做的就是将它们放在一起以创建 STN 和训练过程。

实现风格迁移网络


构造 STN 非常简单,只需连接编码器AdaIN解码器即可,如前面的架构图所示。 STN 还是我们将用来执行推理的模型。执行此操作的代码如下:

“”"

Style Transfer Network

“”"

content_image = self.preprocess(content_image_input)

style_image = self.preprocess(style_image_input)

self.content_target = self.encoder(content_image)

self.style_target = self.encoder(style_image)

adain_output = AdaIN()([self.content_target[-1], self.style_target[-1]])

self.stylized_image = self.postprocess(self.decoder(adain_output))

self.stn = Model([content_image_input, style_image_input], self.stylized_image)

内容和样式图像经过预处理,然后馈入编码器。最后一个特征层 block4_conv1 进入AdaIN() 。然后风格化特征进入解码器以生成RGB风格化的图像。

实时任意风格迁移模型训练


像神经风格迁移一样,内容损失和风格损失是根据固定 VGG 提取的激活来计算的。内容损失也是 L 2 L_2 L2​ 范数,但是现在将生成的风格化图像的内容特征与 AdaIN 的输出进行比较,而不是与内容图像中的特征进行比较,如以下代码所示,这使收敛速度更快:

content_loss = tf.reduce_sum((output_features[-1]-adain_output)**2)

对于风格损失,将常用的 Gram 矩阵替换为均值和方差激活的 L 2 L_2 L2​ 范数。这产生的结果类似于 Gram 矩阵,以下是风格损失函数方程式:

L s = ∑ i = 1 L ∣ ∣ μ ( ϕ i ( s t y l i z e d ) ) − μ ( ϕ i ( s t y l e ) ) ∣ ∣ 2 + ∣ ∣ σ ( ϕ i ( s t y l i z e d ) ) − σ ( ϕ i ( s t y l e ) ) ∣ ∣ 2 \mathcal L_s = \sum_{i=1}^L||\mu( \phi_i(stylized) )-\mu(\phi_i(style))||_2+||\sigma( \phi_i(stylized) )-\sigma(\phi_i(style))||_2 Ls​=i=1∑L​∣∣μ(ϕi​(stylized))−μ(ϕi​(style))∣∣2​+∣∣σ(ϕi​(stylized))−σ(ϕi​(style))∣∣2​

此处, ϕ i \phi_i ϕi​ 表示 VGG-19 中用于计算风格损失的层。

我们在 AdaIN 层中使用 tf.nn.moments 来计算来自风格化图像和风格图像的特征之间的统计量和 L 2 L_2 L2​ 范数,我们对内容层的损失求均值,如下所示:

def calc_style_loss(self, y_true, y_pred):

n_features = len(y_true)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Python开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img



既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Python开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注Python)
img

一、Python所有方向的学习路线

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、学习软件

工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。

三、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

1a906b72cbf93031e6781512b.png)

三、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值