Python深度学习基于Tensorflow(12)实战生成式模型

news2024/9/24 23:25:57

文章目录

        • Deep Dream
        • 风格迁移
        • 参考资料

Deep Dream

DeepDream 是一项将神经网络学习模式予以可视化展现的实验。与孩子们观察云朵并尝试解释随机形状相类似,DeepDream 会过度解释并增强其在图像中看到的图案。

DeepDream为了说明CNN学习到的各特征的意义,将采用放大处理的方式。具体来说就是使用梯度上升的方法可视化网络每一层的特征,即用一张噪声图像输入网络,反向更新的时候不更新网络权重,而是更新初始图像的像素值,以这种“训练图像”的方式可视化网络。DeepDream正是以此为基础。

DeepDream如何放大图像特征?这里我们先看一个简单实例。比如:有一个网络学习了分类猫和狗的任务,给这个网络一张云的图像,这朵云可能比较像狗,那么机器提取的特征可能也会像狗。假设对应一个特征最后输入概率为[0.6, 0.4], 0.6表示为狗的概率, 0.4表示为猫的概率,那么采用L2范数可以很好达到放大特征的效果。对于这样一个特征,L2 =〖x1〗2+〖x2〗2,若x1越大,x2越小,则L2越大,所以只需要最大化L2就能保证当x1>x2的时候,迭代的轮数越多x1越大,x2越小,所以图像就会越来越像狗。每次迭代相当于计算L2范数,然后用梯度上升的方法调整图像。优化的就不再是优化权重参数,而是特征值或像素点,因此,构建损失函数时,不使用通常的交叉熵,而是最大化特征值的L2范数。使图片经过网络之后提取的特征更像网络隐含的特征。

使用基本图像,它输入到预训练的CNN。 然后,正向传播到特定层。为了更好理解该层学到了什么,我们需要最大化通过该层激活值。以该层输出为梯度,然后在输入图像上完成渐变上升,以最大化该层的激活值。不过,光这样做并不能产生好的图像。为了提高训练质量,需要使用一些技术使得到的图像更好。可以进行高斯模糊以使图像更平滑,使用多尺度(又称为八度)的图片进行计算。先连续缩小输入图像,然后,再逐步放大,并将结果合并为一个图像输出。

首先使用预训练模型 InceptionV3 对图像特征进行提取,其中 mixed 表示的是 InceptionV3 中的 mixed 层的特征值;

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

layer_coeff = {
    "mixed4": 1.0,
    "mixed5": 1.5,
    "mixed6": 2.0,
    "mixed7": 2.5,
}

model = tf.keras.applications.inception_v3.InceptionV3(weights="imagenet", include_top=False)
outputs_dict = dict([(layer.name, layer.output) for layer in [model.get_layer(name) for name in layer_coeff.keys()]])
feature_extractor = tf.keras.Model(inputs=model.inputs, outputs=outputs_dict)

计算损失:

def compute_loss(input_image):
    features = feature_extractor(input_image)
    loss_list = []
    for name in features.keys():
        coeff = layer_settings[name]
        activation = features[name]
        # 通过仅在损失中包含非边界像素来避免边界伪影
        scaling = tf.reduce_prod(tf.cast(tf.shape(activation), "float32"))
        loss_list.append(coeff * tf.reduce_sum(tf.square(activation[:, 2:-2, 2:-2, :])) / scaling)
    return tf.reduce_sum(loss_list)

定义训练函数:

@tf.function
def train_step(img, learning_rate=1e-1):
    with tf.GradientTape() as tape:
        tape.watch(img)
        loss = compute_loss(img)
    grads = tape.gradient(loss, img)
    grads /= tf.math.reduce_std(grads)
    img += learning_rate * grads
    img = tf.clip_by_value(img, -1, 1)
    return loss, img

def train_loop(img, iterations, learning_rate=1e-1, max_loss=None):
	for i in range(iterations):
	        loss, img = gradient_ascent_step(img, learning_rate)
	        if max_loss is not None and loss > max_loss:
	            break
	return img

定义超参数:

# 缩放次数 多尺度次数 也即八度 每一次缩放 octave_scale
num_octave = 1
# 缩放倍数
octave_scale = 1.4
# train_loop 训练迭代次数
iterations = 80
# 最大损失
max_loss = 15
# 学习率
learning_rate = 1e-2

如下便是多尺度缩放的训练过程:

![[Pasted image 20240520015509.png]]

定义数据:

img = preprocess_image('./dog.jpg')
plt.imshow(deprocess(img[0]))

![[Pasted image 20240520015056.png]]

开始训练:

original_img = preprocess_image('./dog.jpg')
original_shape = original_img.shape[1:3]

successive_shapes = [original_shape]
for i in range(1, num_octave):
    shape = tuple([int(dim / (octave_scale ** i)) for dim in original_shape])
    successive_shapes.append(shape)
successive_shapes = successive_shapes[::-1]

shrunk_original_img = tf.image.resize(original_img, successive_shapes[0])

img = tf.identity(original_img)  # Make a copy
for i, shape in enumerate(successive_shapes):
    print("Processing octave %d with shape %s" % (i, shape))
    img = tf.image.resize(img, shape)
    img = train_loop(img, iterations=iterations, learning_rate=learning_rate, max_loss=max_loss)
    upscaled_shrunk_original_img = tf.image.resize(shrunk_original_img, shape)
    same_size_original = tf.image.resize(original_img, shape)
    lost_detail = same_size_original - upscaled_shrunk_original_img

    img += lost_detail
    shrunk_original_img = tf.image.resize(original_img, shape)

tf.keras.preprocessing.image.save_img('./dream-' + "dog.jpg", deprocess(img[0]))

![[Pasted image 20240520014920.png]]

总的来说,Deep Dream 相当于训练可视化,其不对参数进行梯度更新,而是对图像进行梯度更新,通过梯度上升让图像能够最大程度的激活目标层的输出结果;其模型实际意义不强,有稍微的模型解释性;

风格迁移

风格迁移的本质和 Deep Dream 是一样的,其主要还是因为风格转换涉及到的样本数量太少,基本就是两张图片之间进行转化,因此对参数进行梯度更新是不现实的,我们只能利用预训练模型,提取图片特征然后定义特征之间的损失进而进行操作;实现风格迁移的核心思想就是定义损失函数。

风格迁移的损失函数由内容损失和风格损失组成,这里用 O i m a g e O_{image} Oimage 表示原图, R i m a g e R_{image} Rimage 表示风格图, G i m a g e G_{image} Gimage 表示生成图,那么损失如下: L = d i s t a n c e ( s t y l e ( R i m a g e ) − s t y l e ( G i m a g e ) ) + d i s t a n c e ( c o n t e n t ( O i m a g e ) − c o n t e n t ( G i m a g e ) ) \mathcal{L} = distance(style(R_{image}) - style(G_{image})) + distance(content(O_{image}) - content(G_{image})) L=distance(style(Rimage)style(Gimage))+distance(content(Oimage)content(Gimage))
卷积神经网络不同层学到的图像特征是不一样的,靠近输入端的卷积层学到的是图像比较具体,局部的特征,如位置,形状,颜色,纹理等。靠近输出端的卷积层学到的是图像更全面,更抽象的特征,但会丢失图像的一些详细信息;

风格损失

风格损失是利用 Gram矩阵 来计算的,Gram矩阵 将图像的通道作为一个维度,将图像的宽和高合并作为一个维度,得到 X X X 的尺寸为 [ c h a n n e l , w ∗ h ] [channel, w*h] [channel,wh],然后计算 X ⋅ X T X \cdot X^T XXT ,用该值来衡量风格;

@tf.function
def gram_matrix(image):
    image = tf.transpose(image, (2, 0, 1))
    image = tf.reshape(image, [tf.shape(image)[0], -1])
    gram = tf.matmul(image, image, transpose_b=True)
    return gram
    
@tf.function
def compute_style_loss(r_image, g_image):
    r_w, r_h, r_c = tf.shape(r_image)
    g_w, g_h, g_c = tf.shape(g_image)
    r_gram = gram_matrix(r_image)
    g_gram = gram_matrix(g_image)
    style_loss = tf.reduce_sum(tf.square(r_gram - g_gram))/  (4 * (r_c * g_c) * (r_w * r_h * g_w * g_h))

内容损失

内容损失很简单,也就是生成图像和原来图像之间的区别;

@tf.function
def compute_content_loss(o_image, g_image):
    return tf.reduce_sum(tf.square(o_image - g_image))

这里不需要放缩是因为没有像风格损失一样经历过 Gram矩阵 计算,这就导致原本的内容并没有经过扩大,不过后面同样会给内容损失和风格损失分配权重;

总损失

总损失让生成的图像具有连续性,不要这里一块那里一块;

def compute_variation_loss(x):
    a = tf.square(x[:, :tf.shape(x)[1]-1, :tf.shape(x)[2]-1, :] - x[:, 1:, :tf.shape(x)[2]-1, :])
    b = tf.square(x[:, :tf.shape(x)[1]-1, :tf.shape(x)[2]-1, :] - x[:, :tf.shape(x)[1]-1, 1:, :])
    return tf.reduce_sum(tf.pow(a+b, 1.25))

这里还是以上面的小狗图片作为原图片,风格图片采取梵高的星空图片;

![[Pasted image 20240520202401.png]]

首先导入预训练模型 VGG19,以及图像处理函数 preprocess_image deprocess_image

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt


def preprocess_image(image_path):
    img = tf.keras.preprocessing.image.load_img(image_path, target_size=(400, 600))
    img = tf.keras.preprocessing.image.img_to_array(img)
    img = np.expand_dims(img, axis=0)
    img = tf.keras.applications.vgg19.preprocess_input(img)
    return tf.convert_to_tensor(img)

def deprocess_image(x):
    x = x.reshape((400, 600, 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


# 用于风格损失的网络层列表
style_layer_names = [
    "block1_conv1",
    "block2_conv1",
    "block3_conv1",
    "block4_conv1",
    "block5_conv1",
]
# 用于内容损失的网络层
content_layer_names = [
    "block5_conv2",
]

model = tf.keras.applications.vgg19.VGG19(weights="imagenet", include_top=False)
outputs_dict = dict([(layer.name, layer.output) for layer in model.layers if layer.name in style_layer_names + content_layer_names])
feature_extractor = tf.keras.Model(inputs=model.inputs, outputs=outputs_dict)

定义三个损失:compute_style_loss compute_content_loss compute_variation_loss

def gram_matrix(image):
    image = tf.transpose(image, (2, 0, 1))
    image = tf.reshape(image, [tf.shape(image)[0], -1])
    gram = tf.matmul(image, image, transpose_b=True)
    return gram
    
def compute_style_loss(r_image, g_image):
    r_w, r_h, r_c = tf.cast(tf.shape(r_image)[0], tf.float32), tf.cast(tf.shape(r_image)[1], tf.float32), tf.cast(tf.shape(r_image)[2], tf.float32)
    g_w, g_h, g_c = tf.cast(tf.shape(g_image)[0], tf.float32), tf.cast(tf.shape(g_image)[1], tf.float32), tf.cast(tf.shape(g_image)[2], tf.float32)
    r_gram = gram_matrix(r_image)
    g_gram = gram_matrix(g_image)
    style_loss = tf.reduce_sum(tf.square(r_gram - g_gram))/  (4 * (r_c * g_c) * (r_w * r_h * g_w * g_h))
    return style_loss

def compute_content_loss(o_image, g_image):
    return tf.reduce_sum(tf.square(o_image - g_image))

def compute_variation_loss(x):
    a = tf.square(x[:, :tf.shape(x)[1]-1, :tf.shape(x)[2]-1, :] - x[:, 1:, :tf.shape(x)[2]-1, :])
    b = tf.square(x[:, :tf.shape(x)[1]-1, :tf.shape(x)[2]-1, :] - x[:, :tf.shape(x)[1]-1, 1:, :])
    return tf.reduce_sum(tf.pow(a+b, 1.25))

定义损失比例以及总损失计算函数 compute_loss

total_weight = 1e-6
style_weight = 1e-6
content_weight = 2.5e-8

def compute_loss(o_image, r_image, g_image):
    X = tf.concat([o_image, r_image, g_image], axis=0)
    features = feature_extractor(X)
    loss_list = []
    
    for content_layer_name in content_layer_names:
        temp = features[content_layer_name]
        o_image_ = temp[0,:,:,:]
        g_image_ = temp[2,:,:,:]
        loss = compute_content_loss(o_image_, g_image_)
        loss_list.append(loss*content_weight/len(content_layer_names))
    
    for style_layer_name in style_layer_names:
        temp = features[style_layer_name]
        r_image_ = temp[1,:,:,:]
        g_image_ = temp[2,:,:,:]
        loss = compute_style_loss(r_image_, g_image_)
        loss_list.append(loss*style_weight/len(style_layer_names))

    loss = compute_variation_loss(g_image)
    loss_list.append(loss*total_weight)
        
    return tf.reduce_sum(loss_list)

定义优化器,图片以及开始训练:

o_image = preprocess_image('./dog.jpg')
r_image = preprocess_image('./start-night.png')
g_image = tf.Variable(o_image)

optimizer = tf.keras.optimizers.Adam(learning_rate=1)


def train_step():
    with tf.GradientTape() as tape:
        loss = compute_loss(o_image, r_image, g_image)
    grads = tape.gradient(loss, g_image)
    optimizer.apply_gradients([(grads, g_image)])
    return loss

for epoch in range(100):
    plt.imshow(deprocess_image(g_image.numpy()))
    plt.axis('off')
    plt.savefig('image_at_epoch_{:04d}.png'.format(epoch))
    plt.show()
    tf.print(train_step())

最后将 生成的图片 转化为 GIF

import imageio
from PIL import Image
import os
import numpy as np

# 这里与 for epoch in range(100): 中的图片名称对应 image_at_epoch_{:04d}.png
converted_images = [np.array(Image.open(item)) for item in [file for file in os.listdir('./') if file.startswith('image')]]
imageio.mimsave("animation.gif", converted_images, fps=15)

得到如下结果:
![[animation 2.gif]]

参考资料

DeepDream | TensorFlow Core (google.cn)

【数学-20】格拉姆矩阵(Gram matrix)详细解读 - 知乎 (zhihu.com)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1701290.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SQL使用函数给多个分表添加同一字段

数据库中分表时,往往需要向多个分表中添加同一个字段,可以定义一个函数,每次调用这个函数向多个份表中添加同意字段。 1、创建函数示例: 在PostgreSQL中创建一个简单的函数 以下是一个在PostgreSQL中创建函数的简单示例&#x…

PXE + Kickstart 无人值守装机

目录 一、简介 二、PXE工作流程 三、搭建 PXE 远程安装服务器 1.安装包准备 2.环境准备 3.搭建PXE远程安装服务器 (1)关闭 firewalld 和 selinux (2)配置双网卡 1)添加硬件网卡 2)编辑网卡配置文…

强化学习,第 2 部分:政策评估和改进

目录 一、介绍 二、关于此文章 三、求解贝尔曼方程 四、策略评估 4.1 更新变体 4.2 例描述 五、策略改进 5.1 V函数描述 5.2 政策改进定理 六、策略迭代 七、值迭代 7.1 算法描述 7.2 异步值迭代 八、广义策略迭代 九、结论 一、介绍 R强化学习是机器学习中的一…

一屏万象,场景无限:蓝牙墨水屏标签多功能多场景应用带您领略未来

在数字化浪潮汹涌澎湃的今天,智能科技产品层出不穷,它们不仅极大地改变了我们的生活方式,更在无形中拓宽了我们的视野。而今,一款融合了创新技术与实用性于一体的蓝牙墨水屏标签,正以其多功能多场景应用的特性&#xf…

【C++/STL】vector(常见接口、模拟实现、迭代器失效)

🌈个人主页:秦jh_-CSDN博客🔥 系列专栏: https://blog.csdn.net/qinjh_/category_12575764.html?spm1001.2014.3001.5482 目录 简单使用 常见接口 find insert vector模板 模拟实现 尾插 构造 迭代器失效 使用memcpy拷贝问…

Web漏洞:网络安全的隐形杀手

随着互联网的深入发展,Web应用程序已成为企业和个人生活中不可或缺的一部分。然而,随着Web应用的普及,网络安全问题也日益凸显,其中Web漏洞是网络安全领域面临的重大挑战之一。本文将详细探讨一些常见的Web漏洞及其潜在的危害&…

使用 Azure DevOps 和 Azure Web Apps 进行 .NET Core 应用的 CI/CD

概览 在现代软件开发中,快速部署和高效的版本控制系统是非常关键的。通过利用 Azure DevOps 和 Azure Web Apps,开发团队可以实现自动化的持续集成和持续部署(CI/CD),从而加快从开发到生产的过程。接下来我们一步步来…

深入探索MySQL SELECT查询:从基础到高级,解锁数据宝藏的密钥

系列文章目录 更新ing... MySQL操作全攻略:库、表、数据、事务全面指南深入探索MySQL SELECT查询:从基础到高级,解锁数据宝藏的密钥MySQL SELECT查询实战:练习题精选,提升你的数据库查询技能PyMySQL:连接P…

灯塔工厂产业数字化平台解决方案(50页PPT)

方案介绍: 随着工业4.0和智能制造的快速发展,传统工厂正面临着转型升级的迫切需求。为了提升生产效率、优化资源配置、增强市场竞争力,我们推出了灯塔工厂产业数字化平台解决方案。该方案旨在通过先进的信息技术手段,将传统工厂转…

感谢信∣高成长型动力电池供应商『华鼎国联』采购管理平台项目上线,企企通SRM加速新能源汽车发展新质生产力

近日,企企通收到来自华鼎国联四川动力电池有限公司(以下简称“华鼎国联”)的感谢信,对企企通团队在采购数字化项目实施中所付出的努力表示感谢。 华鼎国联在感谢信中特别指出,回首披荆斩棘的2023年,企企通的…

通过css实现------简单边框流动特效

效果展示 代码部分 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice…

阿里云产品DTU评测报告(三)

这阿里云产品DTU评测报告&#xff08;三&#xff09; 连接物联网平台创建项目 连接物联网平台 在开始连接物联网平台之前&#xff0c;首先需要下载开发工具Visual Studio Code 开发工具&#xff0c;开发工具可以到https://code.visualstudio.com/ 去查找下载&#xff0c;下载完…

9.Redis之list类型

list相当于链表、数据表 1.list类型基本介绍 列表中的元素是有序的"有序"的含义,要根据上下文区分~~有的时候,谈到有序,指的是"升序","降序”有的时候,谈到的有序,指的是, 顺序很关键~~如果把元素位置颠倒,顺序调换.此时得到的新的 List 和之前的 Li…

神奇动物在哪里?斯洛文尼亚旅游之野生动物寻踪

不仅拥有优美动人的自然风光&#xff0c;斯洛文尼亚还以其丰富的生物多样性而闻名。得益于国家对大自然开展的保护工作&#xff0c;斯洛文尼亚超过三分之一的国土面积都被规划为保护区&#xff0c;拥有约1.5万种动物和6000种植物&#xff0c;其中不乏众多特有、稀有和濒危动植物…

如何选择一款开放式耳机?六大独家选购技巧超详细汇总!

​喜欢户外活动的朋友们&#xff0c;你们都是懂得享受生活的达人吧&#xff01;想象一下&#xff0c;在户外活动时&#xff0c;如果能有一副既适合场景又提供超棒音乐体验的耳机&#xff0c;那该多完美啊&#xff01;这时候&#xff0c;开放式耳机就闪亮登场了&#xff01;它的…

存储方式 - 前端学习

1. cookie是什么&#xff1f;你了解cookie吗&#xff1f; 在计算机领域中&#xff0c;特指一种由服务器发送到用户浏览器并保存在用户计算机上的小型文本文件。这个文件可以被服务器用来识别用户身份、跟踪用户活动、保存用户设置等。它通常由名称、值、域名、路径、过期时间等…

外贸邮箱怎么注册

外贸邮箱指的是用于外贸业务的电子邮箱&#xff0c;其功能比一般的电子邮箱更加专业化。注册外贸邮箱既能提高工作效率&#xff0c;又能展示企业的专业性。那么如何注册外贸邮箱呢&#xff1f;本文将详细介绍注册外贸邮箱的步骤和注意事项。 一、选择邮箱服务商 注册外贸邮箱首…

【408真题】2009-19

“接”是针对题目进行必要的分析&#xff0c;比较简略&#xff1b; “化”是对题目中所涉及到的知识点进行详细解释&#xff1b; “发”是对此题型的解题套路总结&#xff0c;并结合历年真题或者典型例题进行运用。 涉及到的知识全部来源于王道各科教材&#xff08;2025版&…

byzer plugin install log

离线插件参考地址&#xff1a; Byzer Documentation 离线安装方式&#xff08;错误过程记录&#xff09;&#xff1a; 参考文档&#xff1a;https://docs.byzer.org/#/byzer-lang/zh-cn/extension/README Byzer-lang 支持插件安装&#xff0c;删除&#xff0c;获取列表等。安装…

力扣hot100:146. LRU 缓存

力扣hot100&#xff1a;146. LRU 缓存 听说华为实习笔试考了这题 如何使得插入操作时 O ( 1 ) O(1) O(1)呢&#xff1f;我们需要维护一个时间的长短&#xff0c;以便于取出离现在最长的时间&#xff0c;这个时间比较容易实现&#xff0c;我们维护一个time表示当前时间&#x…