图像生成:从手写数字到字母及文本转换
在图像生成领域,我们可以利用深度学习模型来生成手写数字、字母,甚至将打印文本转换为个性化的手写文本。下面将详细介绍实现这些功能的具体步骤和代码。
手写数字图像生成
首先,我们来看看如何生成手写数字图像。
数据准备
我们使用
tensorflow.keras.datasets.mnist
加载 MNIST 数据集,并筛选出标签为 9 的图像。
import matplotlib.pyplot as plt
import tensorflow as tf
import numpy as np
import time
from tensorflow import keras
from tensorflow.keras import layers
import os
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()
digit9_images = []
for i in range(len(train_images)):
if train_labels[i] == 9:
digit9_images.append(train_images[i])
train_images = np.array(digit9_images)
# 显示部分图像
n = 10
f = plt.figure()
for i in range(n):
f.add_subplot(1, n, i + 1)
plt.subplot(1, n, i + 1).axis("off")
plt.imshow(train_images[i])
plt.show()
# 数据预处理
train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')
train_images = (train_images - 127.5) / 127.5
train_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(train_images.shape[0]).batch(32)
构建生成器和判别器模型
- 生成器模型 :通过一系列的全连接层和卷积转置层,将随机噪声向量转换为 28x28 的图像。
gen_model = tf.keras.Sequential()
gen_model.add(tf.keras.layers.Dense(7*7*256, use_bias=False, input_shape=(100,)))
gen_model.add(tf.keras.layers.BatchNormalization())
gen_model.add(tf.keras.layers.LeakyReLU())
gen_model.add(tf.keras.layers.Reshape((7, 7, 256)))
gen_model.add(tf.keras.layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
gen_model.add(tf.keras.layers.BatchNormalization())
gen_model.add(tf.keras.layers.LeakyReLU())
gen_model.add(tf.keras.layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
gen_model.add(tf.keras.layers.BatchNormalization())
gen_model.add(tf.keras.layers.LeakyReLU())
gen_model.add(tf.keras.layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
gen_model.summary()
tf.keras.utils.plot_model(gen_model)
# 测试生成器
noise = tf.random.normal([1, 100])
generated_image = gen_model(noise, training=False)
plt.imshow(generated_image[0, :, :, 0], cmap='gray')
generated_image.shape
- 判别器模型 :通过卷积层和全连接层,判断输入图像是真实图像还是生成的假图像。
discri_model = tf.keras.Sequential()
discri_model.add(tf.keras.layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1]))
discri_model.add(tf.keras.layers.LeakyReLU())
discri_model.add(tf.keras.layers.Dropout(0.3))
discri_model.add(tf.keras.layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
discri_model.add(tf.keras.layers.LeakyReLU())
discri_model.add(tf.keras.layers.Dropout(0.3))
discri_model.add(tf.keras.layers.Flatten())
discri_model.add(tf.keras.layers.Dense(1))
discri_model.summary()
tf.keras.utils.plot_model(discri_model)
# 测试判别器
decision = discri_model(generated_image)
print(decision)
定义损失函数和优化器
- 生成器损失函数 :希望生成的图像能让判别器认为是真实图像。
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)
def generator_loss(generated_output):
return cross_entropy(tf.ones_like(generated_output), generated_output)
- 判别器损失函数 :需要正确区分真实图像和生成的假图像。
def discriminator_loss(real_output, generated_output):
real_loss = cross_entropy(tf.ones_like(real_output), real_output)
generated_loss = cross_entropy(tf.zeros_like(generated_output), generated_output)
total_loss = real_loss + generated_loss
return total_loss
- 优化器 :使用 Adam 优化器。
gen_optimizer = tf.optimizers.Adam(1e-4)
discri_optimizer = tf.optimizers.Adam(1e-4)
训练模型
在训练过程中,我们使用
gradient_tuning
函数进行梯度调整,并在每个 epoch 结束时生成并保存图像,同时保存模型的检查点。
epoch_number = 0
EPOCHS = 100
noise_dim = 100
seed = tf.random.normal([1, noise_dim])
checkpoint_dir = '/content/drive/My Drive/GAN1/Checkpoint'
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
checkpoint = tf.train.Checkpoint(generator_optimizer=gen_optimizer, discriminator_optimizer=discri_optimizer, generator=gen_model, discriminator=discri_model)
from google.colab import drive
drive.mount('/content/drive')
cd '/content/drive/My Drive/GAN1'
def gradient_tuning(images):
noise = tf.random.normal([16, noise_dim])
with tf.GradientTape() as generator_tape, tf.GradientTape() as discriminator_tape:
generated_images = gen_model(noise, training=True)
real_output = discri_model(images, training=True)
fake_output = discri_model(generated_images, training=True)
gen_loss = generator_loss(fake_output)
disc_loss = discriminator_loss(real_output, fake_output)
gen_gradients = generator_tape.gradient(gen_loss, gen_model.trainable_variables)
discri_gradients = discriminator_tape.gradient(disc_loss, discri_model.trainable_variables)
gen_optimizer.apply_gradients(zip(gen_gradients, gen_model.trainable_variables))
discri_optimizer.apply_gradients(zip(discri_gradients, discri_model.trainable_variables))
def generate_and_save_images(model, epoch, test_input):
global epoch_number
epoch_number = epoch_number + 1
predictions = model(test_input, training=False)
fig = plt.figure(figsize=(4, 4))
for i in range(predictions.shape[0]):
plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray')
plt.axis('off')
plt.savefig('image_at_epoch_{:01d}.png'.format(epoch_number))
plt.show()
def train(dataset, epochs):
for epoch in range(epochs):
start = time.time()
for image_batch in dataset:
gradient_tuning(image_batch)
generate_and_save_images(gen_model, epoch + 1, seed)
checkpoint.save(file_prefix=checkpoint_prefix)
print('Time for epoch {} is {} sec'.format(epoch + 1, time.time() - start))
train(train_dataset, EPOCHS)
处理运行中断情况
如果训练过程中出现中断,可以从最近的检查点恢复模型并继续训练。
try:
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
except Exception as error:
print("Error loading in model : {}".format(error))
train(train_dataset, EPOCHS)
训练结果显示,网络在 20 - 30 个 epoch 后就能生成可接受的输出,70 个 epoch 及以上时,图像质量最佳。以下是不同 epoch 生成的数字 9 图像示例:
| Epoch | 图像 |
| ---- | ---- |
| epoch_1 | 略 |
| epoch_5 | 略 |
| epoch_10 | 略 |
| epoch_20 | 略 |
| epoch_30 | 略 |
| epoch_40 | 略 |
| epoch_50 | 略 |
| epoch_60 | 略 |
| epoch_70 | 略 |
| epoch_80 | 略 |
| epoch_90 | 略 |
| epoch_100 | 略 |
手写字母图像生成
接下来,我们介绍如何生成手写字母图像。
数据下载和加载
我们使用
extra-keras-datasets
包中的
emnist
数据集。
# 安装包
pip install extra-keras-datasets
# 导入包并加载数据
from extra_keras_datasets import emnist
(train_images, train_labels), (test_images, test_labels) = emnist.load_data(type='letters')
# 显示一个图像及其标签
plt.imshow(train_images[1])
print("label: ", train_labels[1])
创建单个字母的数据集
我们以字母 G 为例,筛选出标签为 7 的图像。
letter_G_images = []
for i in range(len(train_images)):
if train_labels[i] == 7:
letter_G_images.append(train_images[i])
train_images = np.array(letter_G_images)
# 验证筛选结果
n = 10
f = plt.figure()
for i in range(n):
f.add_subplot(1, n, i + 1)
plt.subplot(1, n, i + 1).axis("off")
plt.imshow(train_images[i])
plt.show()
后续的数据预处理、模型定义、损失函数、优化器和训练步骤与手写数字图像生成的步骤基本相同。以下是完整的训练过程:
# 数据预处理
train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')
train_images = (train_images - 127.5) / 127.5
train_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(train_images.shape[0]).batch(32)
# 生成器模型
gen_model = tf.keras.Sequential()
gen_model.add(tf.keras.layers.Dense(7*7*256, use_bias=False, input_shape=(100,)))
gen_model.add(tf.keras.layers.BatchNormalization())
gen_model.add(tf.keras.layers.LeakyReLU())
gen_model.add(tf.keras.layers.Reshape((7, 7, 256)))
gen_model.add(tf.keras.layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False))
gen_model.add(tf.keras.layers.BatchNormalization())
gen_model.add(tf.keras.layers.LeakyReLU())
gen_model.add(tf.keras.layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False))
gen_model.add(tf.keras.layers.BatchNormalization())
gen_model.add(tf.keras.layers.LeakyReLU())
gen_model.add(tf.keras.layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh'))
gen_model.summary()
tf.keras.utils.plot_model(gen_model)
# 判别器模型
discri_model = tf.keras.Sequential()
discri_model.add(tf.keras.layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1]))
discri_model.add(tf.keras.layers.LeakyReLU())
discri_model.add(tf.keras.layers.Dropout(0.3))
discri_model.add(tf.keras.layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'))
discri_model.add(tf.keras.layers.LeakyReLU())
discri_model.add(tf.keras.layers.Dropout(0.3))
discri_model.add(tf.keras.layers.Flatten())
discri_model.add(tf.keras.layers.Dense(1))
discri_model.summary()
tf.keras.utils.plot_model(discri_model)
# 损失函数和优化器
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)
def generator_loss(generated_output):
return cross_entropy(tf.ones_like(generated_output), generated_output)
def discriminator_loss(real_output, generated_output):
real_loss = cross_entropy(tf.ones_like(real_output), real_output)
generated_loss = cross_entropy(tf.zeros_like(generated_output), generated_output)
total_loss = real_loss + generated_loss
return total_loss
gen_optimizer = tf.optimizers.Adam(1e-4)
discri_optimizer = tf.optimizers.Adam(1e-4)
# 训练参数
epoch_number = 0
EPOCHS = 100
noise_dim = 100
seed = tf.random.normal([1, noise_dim])
checkpoint_dir = '/content/drive/My Drive/GAN2/Checkpoint'
checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt")
checkpoint = tf.train.Checkpoint(generator_optimizer=gen_optimizer, discriminator_optimizer=discri_optimizer, generator=gen_model, discriminator=discri_model)
from google.colab import drive
drive.mount('/content/drive')
cd '/content/drive/My Drive/GAN2'
def gradient_tuning(images):
noise = tf.random.normal([16, noise_dim])
with tf.GradientTape() as generator_tape, tf.GradientTape() as discriminator_tape:
generated_images = gen_model(noise, training=True)
real_output = discri_model(images, training=True)
fake_output = discri_model(generated_images, training=True)
gen_loss = generator_loss(fake_output)
disc_loss = discriminator_loss(real_output, fake_output)
gen_gradients = generator_tape.gradient(gen_loss, gen_model.trainable_variables)
discri_gradients = discriminator_tape.gradient(disc_loss, discri_model.trainable_variables)
gen_optimizer.apply_gradients(zip(gen_gradients, gen_model.trainable_variables))
discri_optimizer.apply_gradients(zip(discri_gradients, discri_model.trainable_variables))
def generate_and_save_images(model, epoch, test_input):
global epoch_number
epoch_number = epoch_number + 1
predictions = model(test_input, training=False)
fig = plt.figure(figsize=(4, 4))
for i in range(predictions.shape[0]):
plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray')
plt.axis('off')
plt.savefig('image_at_epoch_{:01d}.png'.format(epoch_number))
plt.show()
def train(dataset, epochs):
for epoch in range(epochs):
start = time.time()
for image_batch in dataset:
gradient_tuning(image_batch)
generate_and_save_images(gen_model, epoch + 1, seed)
checkpoint.save(file_prefix=checkpoint_prefix)
print('Time for epoch {} is {} sec'.format(epoch + 1, time.time() - start))
train(train_dataset, EPOCHS)
# 处理运行中断情况
try:
checkpoint.restore(tf.train.latest_checkpoint(checkpoint_dir))
except Exception as error:
print("Error loading in model : {}".format(error))
train(train_dataset, 100)
不同 epoch 生成的字母图像同样在训练初期快速提升,100 个 epoch 后能得到高质量的输出。以下是不同 epoch 生成的字母图像示例:
| Epoch | 图像 |
| ---- | ---- |
| epoch_1 | 略 |
| epoch_5 | 略 |
| epoch_10 | 略 |
| epoch_20 | 略 |
| epoch_30 | 略 |
| epoch_40 | 略 |
| epoch_50 | 略 |
| epoch_60 | 略 |
| epoch_70 | 略 |
| epoch_80 | 略 |
| epoch_90 | 略 |
| epoch_100 | 略 |
打印文本到手写文本转换
我们还可以通过训练网络,将打印文本转换为个性化的手写文本。具体做法是,使用自己手写的 a - z、A - Z 和数字 0 - 9 的图像来训练模型。训练好的模型可以将任何打印文本转换为自己风格的手写文本。例如,使用训练好的网络中的一些字符来个性化书写单词 “tensor”。
综上所述,通过深度学习模型,我们可以实现手写数字、字母的图像生成,以及打印文本到手写文本的转换。这些技术不仅有趣,还在许多实际应用中具有重要价值。
图像生成:从手写数字到字母及文本转换
技术原理深入剖析
在前面我们详细介绍了手写数字和字母图像生成以及打印文本到手写文本转换的具体实现步骤,下面我们深入剖析其中的技术原理。
生成对抗网络(GAN)原理
生成对抗网络(GAN)由生成器(Generator)和判别器(Discriminator)两个部分组成,它们通过对抗训练的方式相互博弈,不断提升性能。
-
生成器
:其目标是将随机噪声向量转换为尽可能逼真的图像。在我们的代码中,生成器通过一系列的全连接层和卷积转置层逐步将输入的随机噪声扩展为 28x28 的图像。例如,首先将 100 维的随机噪声向量通过全连接层映射到 7x7x256 的特征图,然后通过卷积转置层逐步上采样,最终得到 28x28 的图像。
-
判别器
:负责判断输入的图像是真实图像还是生成器生成的假图像。判别器通过卷积层提取图像特征,然后通过全连接层输出一个标量值,表示输入图像为真实图像的概率。在训练过程中,判别器不断学习区分真实图像和假图像的能力。
生成器和判别器在训练过程中相互对抗,生成器试图生成更逼真的图像来欺骗判别器,而判别器则努力提高自己的判别能力。这种对抗训练的方式使得生成器能够不断学习到数据的分布,从而生成高质量的图像。
损失函数的作用
损失函数在 GAN 的训练中起着至关重要的作用,它指导生成器和判别器的优化方向。
-
生成器损失函数
:生成器的目标是让判别器将其生成的图像判断为真实图像,因此生成器的损失函数衡量的是生成器生成的图像被判别器判断为假图像的程度。在我们的代码中,使用二元交叉熵损失函数,将生成器生成的图像的判别结果与全为 1 的标签进行比较,希望生成器生成的图像能够让判别器输出接近 1 的值。
-
判别器损失函数
:判别器的目标是正确区分真实图像和生成的假图像,因此判别器的损失函数由两部分组成:真实图像的损失和假图像的损失。真实图像的损失衡量的是判别器将真实图像判断为假图像的程度,假图像的损失衡量的是判别器将生成的假图像判断为真实图像的程度。判别器的总损失是这两部分损失的和。
优化器的选择
优化器用于更新生成器和判别器的参数,使得损失函数的值不断减小。在我们的代码中,使用 Adam 优化器,它结合了 AdaGrad 和 RMSProp 的优点,能够自适应地调整每个参数的学习率,从而加快收敛速度。Adam 优化器的学习率设置为 1e - 4,这个值是经过实验验证的比较合适的学习率。
实际应用场景拓展
图像生成技术在许多实际应用场景中具有重要价值,下面我们介绍一些常见的应用场景。
-
艺术创作
:艺术家可以利用图像生成技术生成独特的艺术作品,为创作提供灵感。例如,通过训练不同风格的图像生成模型,可以生成具有特定艺术风格的绘画、插画等。
-
数据增强
:在机器学习和深度学习中,数据量的大小和多样性对模型的性能有着重要影响。图像生成技术可以用于生成额外的训练数据,从而增强数据集的多样性,提高模型的泛化能力。例如,在图像分类任务中,可以使用生成器生成不同姿态、光照条件下的图像,增加训练数据的多样性。
-
虚拟现实和游戏
:在虚拟现实和游戏领域,图像生成技术可以用于生成逼真的场景、角色和道具。例如,通过训练生成器模型,可以生成具有不同风格和主题的游戏地图、角色形象等,为玩家带来更加丰富的游戏体验。
-
医学影像
:在医学领域,图像生成技术可以用于生成模拟的医学影像,帮助医生进行疾病诊断和治疗方案的制定。例如,通过训练生成器模型,可以生成不同病情下的医学影像,为医生提供更多的参考信息。
未来发展趋势
图像生成技术在近年来取得了显著的进展,但仍然存在一些挑战和问题,未来的发展趋势主要集中在以下几个方面。
-
提高图像质量
:尽管目前的图像生成技术已经能够生成高质量的图像,但在一些细节和真实感方面仍然存在不足。未来的研究将致力于提高图像的分辨率、清晰度和真实感,生成更加逼真的图像。
-
多模态图像生成
:目前的图像生成技术主要集中在单一模态的图像生成,未来的研究将探索多模态图像生成,例如结合文本、音频等信息生成更加丰富和多样化的图像。例如,根据一段文字描述生成对应的图像,或者根据音频信息生成具有特定氛围的图像。
-
可解释性和可控性
:目前的图像生成模型大多是黑盒模型,缺乏可解释性和可控性。未来的研究将致力于提高模型的可解释性和可控性,使得用户能够更好地理解模型的决策过程,并对生成的图像进行精确的控制。例如,用户可以通过调整一些参数来控制生成图像的风格、内容等。
-
跨领域应用
:图像生成技术将与其他领域的技术进行更深入的融合,拓展其应用范围。例如,与计算机视觉、自然语言处理、机器人等领域的技术相结合,实现更加智能和高效的系统。
总结与展望
通过本文的介绍,我们详细了解了手写数字和字母图像生成以及打印文本到手写文本转换的实现方法和技术原理。图像生成技术作为人工智能领域的一个重要分支,具有广阔的应用前景和发展潜力。在未来,随着技术的不断进步和创新,图像生成技术将在更多的领域得到应用,为我们的生活和工作带来更多的便利和惊喜。
同时,我们也应该认识到图像生成技术可能带来的一些潜在风险和挑战,例如虚假图像的传播、隐私泄露等问题。因此,在推动技术发展的同时,我们也需要加强相关的法律法规和伦理道德建设,确保技术的健康和可持续发展。
希望本文能够帮助读者更好地理解图像生成技术,并激发大家对这一领域的兴趣和研究热情。让我们共同期待图像生成技术在未来的发展中取得更加辉煌的成就。
超级会员免费看
3819

被折叠的 条评论
为什么被折叠?



