AI绘画入门:基于TensorFlow-v2.15的简单图像生成模型实践

AI绘画入门:基于TensorFlow-v2.15的简单图像生成模型实践 AI绘画入门基于TensorFlow-v2.15的简单图像生成模型实践你是不是也刷到过那些由AI生成的、天马行空却又无比精美的画作心里痒痒的也想自己动手试试但一看到“生成对抗网络”、“变分自编码器”这些术语就觉得头大感觉离自己太遥远别担心今天我们就来打破这个门槛。我不讲那些复杂的数学公式和让人眼花缭乱的论文就用最直白的话带你亲手搭建一个能“画画”的AI。我们将使用TensorFlow-v2.15这个强大的工具箱从零开始一步步构建一个最简单的图像生成模型。你不需要是数学天才也不需要有多年的编程经验只要跟着做就能亲眼看到AI从一片混沌的“噪声”中创造出有模有样的“作品”。这篇文章的目标很简单让你在30分钟内理解AI绘画的基本原理并运行起你的第一个图像生成程序。我们会用代码说话用结果证明AI绘画入门真的没那么难。1. 环境准备为什么选择TensorFlow-v2.15镜像在开始写代码之前一个稳定、省心的开发环境是成功的第一步。自己从零搭建Python、TensorFlow、CUDA如果你用GPU的环境就像玩一个复杂的“打地鼠”游戏版本冲突、依赖缺失等问题会一个接一个冒出来非常打击初学者的热情。1.1 开箱即用的深度学习“工作室”TensorFlow-v2.15镜像就是为你准备好的、拎包入住的深度学习工作室。它解决了三大痛点环境配置归零镜像里已经预装了TensorFlow 2.15、NumPy、Matplotlib、Jupyter等所有必需的软件包和库。你不需要再操心“pip install”哪个版本才不会报错。一致性保证你在这台“工作室”里写的代码运行的结果和任何其他使用相同镜像的人都是一样的。彻底告别“为什么在我电脑上能跑在你那就出错”的尴尬。两种方式随心切换镜像提供了两种进入“工作室”的方式适应不同的工作习惯。Jupyter Notebook网页版适合初学者和快速实验。就像一个有计算能力的笔记本你可以在网页里分段写代码、运行、并立刻看到文字、图表结果交互体验非常好。启动后用浏览器打开提供的链接就能用。SSH命令行版适合更深入、更自动化的开发。通过SSH工具连接后你就获得了一个完整的Linux命令行环境可以运行复杂的脚本、使用Git管理代码进行长时间的训练任务。对于本次入门实践我强烈推荐使用Jupyter Notebook方式。它能让你清晰地看到每一步代码的输出特别是生成图片的过程体验更直观。1.2 我们的第一个目标生成手写数字为了降低入门难度我们不会一上来就挑战生成高清的人像或风景画。我们的第一个目标是让AI学会生成MNIST数据集风格的手写数字图片。MNIST是一个经典的数据集包含了6万张28x28像素的灰度手写数字图片。虽然简单但它包含了图像生成的所有核心概念。通过它我们能快速验证想法看到成果建立信心。2. 原理极简说AI是怎么“学会”画画的在写代码前我们用三句话理解核心思想想象有两个角色一个叫生成器Generator简称G一个叫判别器Discriminator简称D。生成器G是个“伪造者”它的工作是把一堆随机数字噪声当成颜料努力画出一张以假乱真的图片。判别器D是个“鉴定专家”它的工作是看一张图片然后判断“这是真的手写数字来自MNIST数据集”还是“这是生成器G画的假货”。对抗训练G和D在不断博弈中共同进步。G画得越好D就要变得更厉害才能识别出来D越厉害就逼着G必须画得更好才能骗过D。这个过程就像古董造假者和鉴定专家在互相较量中不断提升技艺。最终当G强大到连最厉害的D都无法区分其作品和真品时我们就得到了一个优秀的图像生成器。这就是生成对抗网络的核心思想。下面我们就用代码把这两个角色创造出来。3. 实战构建你的第一个生成对抗网络打开你的Jupyter Notebook我们开始写代码。整个过程分为准备材料数据、创造角色定义模型、安排训练编写训练循环、欣赏成果生成图片。3.1 准备材料加载并观察数据首先我们引入必要的工具包并把MNIST数据“搬”进来看看。import tensorflow as tf import numpy as np import matplotlib.pyplot as plt # 1. 加载MNIST数据集 (train_images, _), (_, _) tf.keras.datasets.mnist.load_data() # 我们不需要标签只关心图片本身 # 2. 数据预处理这是关键步骤 # 将图片像素值从0-255缩放到-1到1之间这对GAN训练的稳定性非常重要 train_images train_images.reshape(train_images.shape[0], 28, 28, 1).astype(float32) train_images (train_images - 127.5) / 127.5 # 归一化到 [-1, 1] # 3. 创建TensorFlow数据集方便批量读取 BUFFER_SIZE 60000 BATCH_SIZE 256 train_dataset tf.data.Dataset.from_tensor_slices(train_images).shuffle(BUFFER_SIZE).batch(BATCH_SIZE) # 4. 让我们看一眼真实的手写数字长什么样 print(f数据集形状: {train_images.shape}) # 应该是 (60000, 28, 28, 1) plt.figure(figsize(6, 6)) for i in range(25): plt.subplot(5, 5, i1) plt.imshow(train_images[i].reshape(28, 28) * 127.5 127.5, cmapgray) # 显示时反归一化 plt.axis(off) plt.suptitle(真实的MNIST手写数字样本) plt.show()运行这段代码你会看到25个0-9的手写数字。这就是我们的“真品”也是判别器D要学习的目标。3.2 创造角色定义生成器和判别器接下来我们用TensorFlow的Keras API来搭建G和D。我们使用最简单的全连接网络Dense层。# 定义生成器 Generator def make_generator_model(): model tf.keras.Sequential([ # 输入一个100维的随机噪声向量 tf.keras.layers.Dense(7*7*256, use_biasFalse, input_shape(100,)), tf.keras.layers.BatchNormalization(), tf.keras.layers.LeakyReLU(), # 使用LeakyReLU激活函数防止梯度消失 # 将向量重塑成7x7x256的特征图 tf.keras.layers.Reshape((7, 7, 256)), # 上采样部分通过转置卷积Conv2DTranspose逐步放大图像 tf.keras.layers.Conv2DTranspose(128, (5, 5), strides(1, 1), paddingsame, use_biasFalse), tf.keras.layers.BatchNormalization(), tf.keras.layers.LeakyReLU(), tf.keras.layers.Conv2DTranspose(64, (5, 5), strides(2, 2), paddingsame, use_biasFalse), tf.keras.layers.BatchNormalization(), tf.keras.layers.LeakyReLU(), # 最后一层输出28x28x1的图片用tanh激活将值约束在[-1,1]对应我们预处理后的数据范围 tf.keras.layers.Conv2DTranspose(1, (5, 5), strides(2, 2), paddingsame, use_biasFalse, activationtanh), ]) return model # 定义判别器 Discriminator def make_discriminator_model(): model tf.keras.Sequential([ # 输入一张28x28x1的图片 tf.keras.layers.Conv2D(64, (5, 5), strides(2, 2), paddingsame, input_shape[28, 28, 1]), tf.keras.layers.LeakyReLU(), tf.keras.layers.Dropout(0.3), # Dropout层防止过拟合 tf.keras.layers.Conv2D(128, (5, 5), strides(2, 2), paddingsame), tf.keras.layers.LeakyReLU(), tf.keras.layers.Dropout(0.3), # 展平后输出一个概率值通过sigmoid激活 tf.keras.layers.Flatten(), tf.keras.layers.Dense(1, activationsigmoid) # 输出0假到1真之间的概率 ]) return model # 创建模型实例 generator make_generator_model() discriminator make_discriminator_model() # 让我们看看生成器面对随机噪声最初能“画”出什么此时还没训练输出是乱码 noise tf.random.normal([1, 100]) generated_image generator(noise, trainingFalse) plt.imshow(generated_image[0, :, :, 0] * 127.5 127.5, cmapgray) plt.title(未经训练的生成器输出一片混沌) plt.axis(off) plt.show()3.3 安排训练编写对抗训练循环现在让G和D开始“博弈”。我们需要定义他们如何计算得失损失函数以及如何从错误中学习优化器。# 定义损失函数和优化器 cross_entropy tf.keras.losses.BinaryCrossentropy(from_logitsFalse) def discriminator_loss(real_output, fake_output): # 判别器的目标对真实图片输出1对生成图片输出0 real_loss cross_entropy(tf.ones_like(real_output), real_output) # 真实图片标签为1 fake_loss cross_entropy(tf.zeros_like(fake_output), fake_output) # 生成图片标签为0 total_loss real_loss fake_loss return total_loss def generator_loss(fake_output): # 生成器的目标骗过判别器让判别器对生成图片输出1 return cross_entropy(tf.ones_like(fake_output), fake_output) # 为两个模型分别创建优化器 generator_optimizer tf.keras.optimizers.Adam(1e-4) discriminator_optimizer tf.keras.optimizers.Adam(1e-4) # 训练循环 EPOCHS 50 # 训练轮数可以调整。越多效果越好但耗时越长。 noise_dim 100 num_examples_to_generate 16 # 固定一组随机噪声用于在训练过程中观察生成器的进步 seed tf.random.normal([num_examples_to_generate, noise_dim]) # 定义一个训练步骤一步 tf.function # 这个装饰器会将函数编译成图加速执行 def train_step(images): noise tf.random.normal([BATCH_SIZE, noise_dim]) with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape: # 生成器根据噪声生成图片 generated_images generator(noise, trainingTrue) # 判别器分别判断真实图片和生成图片 real_output discriminator(images, trainingTrue) fake_output discriminator(generated_images, trainingTrue) # 计算两者的损失 gen_loss generator_loss(fake_output) disc_loss discriminator_loss(real_output, fake_output) # 计算梯度并更新模型参数 gradients_of_generator gen_tape.gradient(gen_loss, generator.trainable_variables) gradients_of_discriminator disc_tape.gradient(disc_loss, discriminator.trainable_variables) generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables)) discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables)) # 定义一个函数用于在训练过程中定期生成并保存图片 def generate_and_save_images(model, epoch, test_input): predictions model(test_input, trainingFalse) fig plt.figure(figsize(4, 4)) for i in range(predictions.shape[0]): plt.subplot(4, 4, i1) plt.imshow(predictions[i, :, :, 0] * 127.5 127.5, cmapgray) plt.axis(off) plt.suptitle(fEpoch {epoch1}) plt.savefig(fimage_at_epoch_{epoch1:04d}.png) plt.show() print(开始训练...) for epoch in range(EPOCHS): for image_batch in train_dataset: train_step(image_batch) # 每5个epoch生成一次图片观察进度 if (epoch 1) % 5 0: generate_and_save_images(generator, epoch, seed) print(fEpoch {epoch1} 完成) print(训练完成)运行这段训练代码可能需要一些时间取决于你的电脑配置。你会看到每隔5轮程序就会输出一张由16个固定噪声生成的图片。仔细观察你会发现这些图片从最初的模糊噪点逐渐变得越来越像清晰的手写数字3.4 欣赏成果让AI为你作画训练完成后我们的生成器已经“学成出师”了。现在你可以随时让它根据新的随机噪声创作。# 使用训练好的生成器创造新数字 def generate_new_digits(num10): noise tf.random.normal([num, noise_dim]) generated_images generator(noise, trainingFalse) plt.figure(figsize(10, int(num/2))) for i in range(num): plt.subplot(int(num/5), 5, i1) plt.imshow(generated_images[i, :, :, 0] * 127.5 127.5, cmapgray) plt.axis(off) plt.suptitle(AI生成的新手写数字) plt.tight_layout() plt.show() # 生成10个新的数字看看 generate_new_digits(10)运行上面的代码你就能看到AI为你“画”出的10个全新的、独一无二的手写数字。虽然可能有些歪歪扭扭但请记住这是它从一堆完全随机的数字里自己“想”出来的4. 从入门到进阶下一步可以做什么恭喜你你已经完成了AI绘画最核心的入门实践。这个简单的GAN模型就像你学会了骑自行车虽然还不能玩特技但已经掌握了平衡前进的基本原理。接下来你可以尝试这些方向让你的AI画得更好、更精彩换个更复杂的“画板”把MNIST数据集换成Fashion-MNIST服装图片、CIFAR-10彩色小物体甚至尝试小尺寸的CelebA人脸数据集。你需要调整模型的输入输出尺寸和层数。升级你的“画笔”我们用的是最简单的DCGAN结构。可以尝试更强大的架构如StyleGAN能精细控制风格、CycleGAN实现图像风格转换比如把马变成斑马。使用更强大的“颜料”探索扩散模型这是当前AI绘画的主流技术如DALL-E、Stable Diffusion的核心。它的原理不再是“对抗”而是“去噪”通常能生成更清晰、更多样的图片。在TensorFlow-v2.15镜像里探索更多这个镜像环境已经为你准备好了探索上述所有可能性的基础。你可以直接安装额外的库如tensorflow_hub来使用预训练模型开始你的进阶之旅。5. 总结回顾一下我们今天的旅程环境搭建零痛苦我们利用了TensorFlow-v2.15预构建镜像跳过了繁琐的环境配置直接进入了核心的模型构建环节。原理理解很直观我们用“伪造者”和“鉴定专家”的比喻轻松理解了生成对抗网络的核心思想——对抗中进步。动手实践有成果我们一步步写出了生成器和判别器的代码定义了它们的训练规则并最终训练出了一个能生成手写数字的AI模型。你亲眼见证了AI从无到有的“学习”过程。代码运行即所得所有的代码块都是完整可运行的你在Jupyter Notebook里依次执行就能复现全部结果。AI绘画的世界大门已经向你敞开。这个简单的GAN模型是一个完美的起点。它所有的核心概念——噪声输入、生成网络、对抗训练——都是更复杂模型的基础。希望这次实践能给你带来信心和兴趣鼓励你去生成更丰富、更美丽的图像用代码创造出属于你自己的数字艺术。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。