风格迁移生成图片

前言

本文详细介绍了风格迁移图像生成的全部过程,模型方面主要是使用了现成的 VGG19 模型,效果符合预期。

数据处理

我们使用的基础图片如下

我们使用的风格图片如下

实现了两个函数 preprocess_image 和 deprocess_image 用来处理图像。

  1. preprocess_image: 这个函数负责对图像进行预处理。它接受一个图像路径作为输入,并返回一个预处理后的图像张量。具体步骤如下:

    • 使用 keras.utils.load_img 加载图像,并将其调整为指定的目标大小 (img_nrows, img_ncols)。
    • 使用 keras.utils.img_to_array 将图像转换为 NumPy 数组。
    • 使用 np.expand_dims 在数组的第一个维度上添加一个维度,将其变成形状为 (1, img_nrows, img_ncols, 3) 的张量,其中 3 表示图像通道数。
    • 使用 vgg19.preprocess_input 函数对图像进行 VGG19 模型的预处理,例如将像素值归一化到特定的范围。
  2. deprocess_image: 这个函数用于将经过处理的图像张量恢复为可视化图像。它接受一个图像张量作为输入,并返回一个经过反向处理的图像数组。具体步骤如下:

    • 将图像张量 x 重塑为形状为 (img_nrows, img_ncols, 3) 的张量。
    • 执行逆操作来撤消预处理步骤,例如对图像进行的平均值偏移操作。这些值在训练 VGG 模型时用于归一化图像。
    • 将图像从 BGR 格式转换为 RGB 格式,这通常是由于不同库或模型使用不同的通道顺序。
    • 使用 np.clip 将图像像素值限制在 0 到 255 之间,并将其转换为 uint8 类型,以确保图像值在正确的范围内。
ini 复制代码
def preprocess_image(image_path):
    img = keras.utils.load_img(image_path, target_size=(img_nrows, img_ncols))
    img = keras.utils.img_to_array(img)
    img = np.expand_dims(img, axis=0)
    img = vgg19.preprocess_input(img)
    return tf.convert_to_tensor(img)
def deprocess_image(x):
    x = x.reshape((img_nrows, img_ncols, 3))
    x[:, :, 0] += 103.939
    x[:, :, 1] += 116.779
    x[:, :, 2] += 123.68
    x = x[:, :, ::-1]
    x = np.clip(x, 0, 255).astype("uint8")
    return x

损失计算

我们定义了几个函数来计算模型的损失值,主要有以下几个部分:

  • gram_matrix :用于计算给定特征张量 x 的格拉姆矩阵,格拉姆矩阵是用来捕捉特征之间相关性的一种方式
  • style_loss :使用风格图像的格拉姆矩阵 S 和合成图像的格拉姆矩阵 C,计算两个格拉姆矩阵之间的均方差,作为风格损失的度量,将最后的结果通过归一化系数对损失进行缩放。
  • content_loss :计算合成图像与内容图像之间的像素级差异(均方差),这种损失直接反映了合成图像与内容图像之间的内容差异。
  • total_variation_loss :计算图像 x 在水平和垂直方向上相邻像素之间的差异的平方,对这些差异进行幂次处理以增强平滑度,对增强后的差异进行求和,作为总变差损失的度量。
  • compute_loss:用于计算图像风格迁移中的总损失,这个总损失由内容损失、风格损失和总变差损失三部分组成。
ini 复制代码
def gram_matrix(x):  # [400, 225, 64]
    x = tf.transpose(x, (2, 0, 1))  # [64, 400, 225,]
    features = tf.reshape(x, (tf.shape(x)[0], -1))  # [64, 90000]
    gram = tf.matmul(features, tf.transpose(features))  # [64, 64]
    return gram

def style_loss(style, combination):
    S = gram_matrix(style)
    C = gram_matrix(combination)
    channels = 3
    size = img_nrows * img_ncols
    return tf.reduce_sum(tf.square(S - C)) / (4. * (channels ** 2) * (size ** 2))

def content_loss(base, combination):
    return tf.reduce_sum(tf.square(combination - base))

def total_variation_loss(x):  # [1,400,225,3]
    a = tf.square(x[:, : img_nrows - 1, : img_ncols - 1, :] - x[:, 1:, : img_ncols - 1, :])  # [1,399,224,3]
    b = tf.square(x[:, : img_nrows - 1, : img_ncols - 1, :] - x[:, : img_nrows - 1, 1:, :])  # [1,399,224,3]
    return tf.reduce_sum(tf.pow(a + b, 1.25))

def compute_loss(combination_image, base_image, style_reference_image):
    input_tensor = tf.concat([base_image, style_reference_image, combination_image], axis=0)
    features = feature_extractor(input_tensor)
    loss = tf.zeros(shape=())
    layer_features = features[content_layer_name]
    base_image_features = layer_features[0, :, :, :]
    combination_features = layer_features[2, :, :, :]
    loss = loss + content_weight * content_loss(base_image_features, combination_features)
    for layer_name in style_layer_names:
        layer_features = features[layer_name]  # [3, 400, 255 ,64]
        style_reference_features = layer_features[1, :, :, :]  # [400, 255 ,64]
        combination_features = layer_features[2, :, :, :]  # [400, 255 ,64]
        sl = style_loss(style_reference_features, combination_features)
        loss += (style_weight / len(style_layer_names)) * sl
    loss += total_variation_weight * total_variation_loss(combination_image)
    return loss

模型训练

  1. 模型加载与特征提取器创建 : 使用 VGG19 模型作为特征提取器,通过遍历模型的层,创建一个字典,其中键是层的名称,值是层的输出张量,使用 keras.Model 创建一个新的模型,该模型接受原始 VGG19 模型的输入,并输出特定层的特征张量。

  2. 损失函数与梯度计算函数 : compute_loss_and_grads 函数计算给定组合图像、基础图像和风格参考图像的总损失,并计算相对于组合图像的梯度。并采用了 SGD 优化器,对由损失计算出的梯度进行优化。

  3. 迭代优化: 对基础图像和风格参考图像进行预处理,以适应 VGG19 模型的输入要求,将基础图像作为初始的组合图像。通过 10000 次迭代优化过程,不断更新组合图像以最小化损失,在每次迭代中计算损失和梯度,并应用梯度更新组合图像,每 100 次迭代输出一次损失值,并保存当前的组合图像。

ini 复制代码
model = vgg19.VGG19(weights="imagenet", include_top=False)
output_dict = dict([(layer.name, layer.output) for layer in model.layers])
feature_extractor = keras.Model(inputs=model.inputs, outputs=output_dict)
style_layer_names = ["block1_conv1", "block2_conv1", "block3_conv1", "block4_conv1", "block5_conv1", ]
content_layer_name = "block5_conv2"
def compute_loss_and_grads(combination_image, base_image, style_reference_image):
    with tf.GradientTape() as tape:
        loss = compute_loss(combination_image, base_image, style_reference_image)
    grads = tape.gradient(loss, combination_image)
    return loss, grads
optimizer = keras.optimizers.SGD(keras.optimizers.schedules.ExponentialDecay(initial_learning_rate=100.0, decay_steps=100, decay_rate=0.96))

base_image = preprocess_image(base_image_path)
style_reference_image = preprocess_image(style_reference_image_path)
combination_image = tf.Variable(preprocess_image(base_image_path))
iterations = 10000
for i in range(1, iterations + 1):
    loss, grads = compute_loss_and_grads(combination_image, base_image, style_reference_image)
    optimizer.apply_gradients([(grads, combination_image)])
    if i % 100 == 0:
        print("Iteration %d: loss=%.2f" % (i, loss))
        img = deprocess_image(combination_image.numpy())
        fname = result_prefix + "_at_iteration_%d.png" % i
        keras.utils.save_img(fname, img)

训练过程消耗 9G 左右显存,日志打印:

ini 复制代码
Iteration 100: loss=8640.24
Iteration 200: loss=7211.42
Iteration 300: loss=6196.27
...
Iteration 9800: loss=3071.73
Iteration 9900: loss=3071.40
Iteration 10000: loss=3071.09

结果展示,风格发生了变化,生成了毕加索风格的图片。

参考

github.com/wangdayaya/...

相关推荐
智圣新创017 分钟前
教育数据要素流通刚需下 智圣新创高校数据中台解决方案的全域建设落地框架
大数据·人工智能·物联网
xianghongtao011611 分钟前
如何选择一台适合你的本地 AI 硬件设备?Lucy AI Studio——从本地 AI 办公到家庭影音的完整指南
人工智能·端脑科技·本地ai硬件设备·kickstarter众筹项目·lucy ai studio·lucy aios
ZhangJun9518 分钟前
Mobike 共享单车分析项目
人工智能·python·算法·kmeans·聚类·knn
互联网资讯21 分钟前
本地创业者入局 AI 短剧,本地化部署怎么选更省钱
大数据·人工智能
唐维康23 分钟前
昆工计算机408考研2027招285人,比去年少6人
人工智能·考研·昆明理工大学
Martina_032126 分钟前
AI生成的过山车轨道导入后频繁脱轨?用5步检查样条、轨距与碰撞
图像处理·人工智能·游戏·3d·材质·游戏策划·关卡设计
小猴子爱上树31 分钟前
跨马翻译:批量图片翻译+视频字幕+智能抠图,跨境电商在线图片翻译工具
大数据·人工智能·python·音视频
佳瑞Jarrett31 分钟前
从 0 到 1 手搓 AI 调解训练系统:双 NPC 实时语音 + AI 自动评分(FastAPI + Qwen-Audio Realtime 实战)
人工智能
W***259231 分钟前
2026 企业 AI 办公工具怎么选:选型框架与平台全景分析
大数据·人工智能
薛定e的猫咪34 分钟前
(AISTATS 2023)BaCaDI 逐章阅读
人工智能·深度学习·算法·机器学习