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

文章目录

        • 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)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

亚马逊云科技专家分享 | OPENAIGC开发者大赛能量加油站6月5日场预约开启~

由联想拯救者、AIGC开放社区、英特尔联合主办的“AI生成未来第二届拯救者杯OPENAIGC开发者大赛”自上线以来,吸引了广大开发者的热情参与。 为了向技术开发者、业务人员、高校学生、以及个体创业人员等参赛者们提供更充分的帮助与支持,AIGC开放社区特别…

一次编辑00

题目链接 一次编辑 题目描述 注意点 只能进行一次(或者零次)编辑 解答思路 首先判断两个字符串的长度,如果长度相差大于1,说明一次编辑无法通过一次编辑变换而来通过两个指针idx1和idx2指向first和second,初始idx1和idx2指向的都是同一个…

DOM学习

DOM学习 DOM全称是Document Object Model 文档对象模型,就是把文档中的标签,属性,文本,转换为对象来管理 大纲 HTML DOM(文档对象模型)document对象HTML DOM结点 具体案例 HTML DOM(文档对象模型) document对象 使用innerT…

《python本机环境多版本切换》-两种方式以及具体使用--venv/pyenv+pycharm测试

阿丹: source myenv/bin/activate 在开发使用rasa的时候发现自己安装的python环境是3.12的,和rasa不兼容,所以实践一下更换多python环境。 使用虚拟环境 在Python中使用虚拟环境来切换Python版本是一个常见的做法,这可以帮助你…

深入解析R语言的贝叶斯网络模型:构建、优化与预测;INLA下的贝叶斯回归;现代贝叶斯统计学方法;R语言混合效应(多水平/层次/嵌套)

目录 ①基于R语言的贝叶斯网络模型的实践应用 ②R语言贝叶斯方法在生态环境领域中的应用 ③基于R语言贝叶斯进阶:INLA下的贝叶斯回归、生存分析、随机游走、广义可加模型、极端数据的贝叶斯分析 ④基于R语言的现代贝叶斯统计学方法(贝叶斯参数估计、贝叶斯回归、…

Java中Stack的使用详解

Stack是一种运算受限的线性表,其特点在于仅允许在表的一端(即表尾)进行插入和删除操作。这一端被称为栈顶,而相对的另一端则称为栈底。向一个栈插入新元素的操作称为进栈或入栈,它将新元素放到栈顶元素的上面&#xff…

全球前五!ATFX 2024年Q1业绩狂飙,6240亿美元交易量彰显实力

5月,密集发布的报告显示,强者恒强是差价合约行业不变的竞争逻辑。而ATFX最新展现的业绩无疑是这一逻辑的有力例证。依照惯例,知名行业媒体Finance Magnates日前公布了全球经纪商最为关注的2024年第一季度行业报告。报告数据显示,A…

对未知程序所创建的带有折叠书签的 PDF 文件书签层级全展开导致丢失的一种解决方法

对需要经常查阅、或连续长时间阅读的带有折叠书签的 PDF 文档展开书签层级,提高阅览导航快捷是非常有必要的。 下面是两种常用书签层级全展开的方法 1、 FreePic2Pdf 1 - 2 - 3 - 4 - 5 - 6,先提取后回挂 2、PdgCntEditor 载入后,直接保存…

【必备工具】gitee上传-保姆级教程

目录 1.gitee是什么 2.gitee怎么注册 ​编辑 3.gitee怎么提交代码 4.gitee的三板斧 Clone仓库 Q&A 1. Gitee 只有三板斧吗? 2. Git 教了,Gitee 上没有绿点怎么办? 3. 用户名和密码输入错误怎么办? 4. 操作时不小心…

智慧校园建设规划方案

在信息化浪潮的推动下,智慧校园的建设已成为教育现代化的必然趋势。以创新科技赋能教育,打造智慧校园,旨在提升教学品质,优化管理流程,增强学生体验。构建智慧校园需要具有前瞻性的规划方案,它将以教育为核…

多波段光源 通过8种波长实现的成像解决方案

光源在机器视觉中的重要性不容小觑,它直接影响到图像的质量,进而影响整个系统的性能。光源的作用包括提供足够的照明,并确保被摄物体的特征能够被准确地捕捉到图像中,使被检测物体产生清晰的图像,提高图像的对比度和亮…

mars3d实现geojson文件xxx.json格式等实现贴地效果

说明: 1.mars3d.js我们的这个sdk内部参数clampToGround是异步计算贴地效果的,最好的贴地方式是,给json数据准确的带高度的经纬度值。 补充前置知识说明,本身的geojson数据格式每个字段代表的意思需要掌握, GeoJSON …

MIT提出基于Transformer的Cross-Layer Attention:江湖骗子还是奇思妙想

大模型技术论文不断,每个月总会新增上千篇。本专栏精选论文重点解读,主题还是围绕着行业实践和工程量产。若在某个环节出现卡点,可以回到大模型必备腔调重新阅读。而最新科技(Mamba,xLSTM,KAN)则提供了大模型领域最新技…

漫谈企业信息化安全 - 零信任架构

一、引言 《万物简史》的作者比尔布来森说,当他小的时候学科学的时候,好像这些科学家们都是有一种本领,把科学总是以一种让人看不懂的方式说得神乎其神,好像有藏着什么不可告人的秘密。因此,想要写一本让大家都能看得…

Apache CXF Aegis databinding SSRF 高危漏洞修复

一、漏洞修复 Apache CXF Aegis databinding SSRF漏洞 Spring Web UriComponentsBuilder URL解析不当漏洞 二、修复步骤 1、Apache CXF Aegis databinding SSRF漏洞修复 步骤: 进入服务器搜索 databinding find -name *databinding* 发现版本是3.1.6 果断…

Android关于service call 直接调用方法分析

1 背景 希望通过命令的方式控制蓝牙打开与关闭,通过网上搜索我们都能搜到 //打开蓝牙 adb shell service call bluetooth_manager 6 //关闭蓝牙 adb shell service call bluetooth_manager 8其中运用到的就是service call,其机制是通过 Android 的 Bin…

vue3 3D炫酷模型banner图

项目场景&#xff1a; 在官网首页展示3D炫酷动画模型&#xff0c;让整个模型都展示出来。 问题描述 主要是3D动画的展示效果&#xff0c;有些3d模型网站可以从51建模网站中获取。 案例代码&#xff1a; <script setup> import * as imgs from ../units/img import { o…

融资融券保证金比例,融资融券最低利率4.0%

融资融券保证金比例是指投资者交付的保证金与融资、融券交易金额的比例&#xff0c;用于控制投资者初始资金的放大倍数。这个比例分为融资保证金比例和融券保证金比例。 融资融券保证金比例的计算 1. 融资保证金比例是指投资者融资买入证券时交付的保证金与融资交易金额的比例…

穿越时空的工厂之旅:探索可视化三维场景的奥秘

在科技日新月异的今天&#xff0c;我们似乎总是在不断追求着更加高效、智能的生产方式。 传统的工厂管理方式往往依赖于平面图纸、纸质文档和现场巡查&#xff0c;这不仅效率低下&#xff0c;而且容易出错。而三维可视化技术通过3D建模和虚拟现实技术&#xff0c;将工厂内部的各…

苗情灾情监控系统—提高农业生产效率

TH-MQ2苗情灾情监控系统是一种用于监测农作物生长状况和灾情的设备&#xff0c;通过实时监测和数据分析&#xff0c;帮助农民及时了解作物生长情况&#xff0c;采取相应的管理措施&#xff0c;提高农业生产效率和降低生产成本。 该系统通常由多种传感器、摄像头、数据传输模块等…