最简单的示例,基本框架,方便改写。
大型案例,博客根本写不下。
# 导入依赖项
import os
import glob
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import matplotlib.pyplot as plt
%matplotlib inline
print("tensorflow版本号:", tf.__version__)
tensorflow版本号: 2.7.0
# 加载数据
(train_images, train_labels), (_, _) = tf.keras.datasets.mnist.load_data()
train_images.shape # 60000张28*28像素的图片
(60000, 28, 28)
train_images.dtype # 图片类型
dtype('uint8')
train_images = train_images.reshape(
train_images.shape[0], 28, 28, 1).astype('float32') # 数据类型改成float32
train_images.shape
(60000, 28, 28, 1)
train_images = (train_images-127.5)/127.5 # 归一化数据集
BATCH_SIZE = 256 # 批训练大小
BUFFRE_SIZE = 60000 # 数据取出
# 创建datasets数据集,只要图片。
datasets = tf.data.Dataset.from_tensor_slices(train_images)
datasets = datasets.shuffle(BUFFRE_SIZE).batch(BATCH_SIZE) # 数据打乱、数据批次
datasets
<BatchDataset shapes: (None, 28, 28, 1), types: tf.float32>
# 生成网络(最简单的写法,复杂的自行修改。)
def generator_model():
model = keras.Sequential()
model.add(layers.Dense(
256, # 输出形状
input_shape=(100,), # 输入形状
use_bias=False # 不要偏置参数,只要权重参数
))
model.add(layers.BatchNormalization()) # 归一化
model.add(layers.LeakyReLU()) # 激活层
model.add(layers.Dense(
512, # 输出形状
use_bias=False # 不要偏置参数,只要权重参数
))
model.add(layers.BatchNormalization()) # 归一化
model.add(layers.LeakyReLU()) # 激活层
model.add(layers.Dense(
28*28*1, # 输出形状
use_bias=False, # 不要偏置参数,只要权重参数
activation='tanh' # 激活函数
))
model.add(layers.BatchNormalization()) # 归一化
model.add(layers.Reshape((28, 28, 1))) # 生成图片形状
return model
# 鉴别网络
def discriminator_model():
model = keras.Sequential()
model.add(layers.Flatten()) # 输入的图片降成一维
model.add(layers.Dense(
512, # 输出形状
use_bias=False # 不要偏置参数,只要权重参数
))
model.add(layers.BatchNormalization()) # 归一化
model.add(layers.LeakyReLU()) # 激活层
model.add(layers.Dense(
256, # 输出形状
use_bias=False # 不要偏置参数,只要权重参数
))
model.add(layers.BatchNormalization()) # 归一化
model.add(layers.LeakyReLU()) # 激活层
model.add(layers.Dense(1)) # 二分类交叉熵损失函数需要。
return model
# 损失函数
cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)
# 鉴别网络损失函数
def discriminator_loss(
real_out, # image -> 鉴别网络 -> real_out
fake_out # noise -> 生成网络 -> 鉴别网络 -> fake_out
):
# 真实图片损失函数
real_loss = cross_entropy(
tf.ones_like(real_out), # 期望值是1
real_out # image -> 鉴别网络 -> real_out
)
# 生成图片损失函数
fake_loss = cross_entropy(
tf.zeros_like(fake_out), # 期望值是0
fake_out # noise -> 生成网络 -> 鉴别网络 -> fake_out
)
return real_loss + fake_loss # 真实图片和生成图片的loss的和(目标就是使这个loss值最小)
# 生成网络损失函数
def generator_loss(
fake_out # noise -> 生成网络 -> 鉴别网络 -> fake_out
):
return cross_entropy(
tf.ones_like(fake_out), # 期望值是1
fake_out # 真实图片
)
# 生成网络优化器
generator_opt = tf.keras.optimizers.Adam(
1e-4 # 学习率
)
discriminator_opt = tf.keras.optimizers.Adam(1e-4) # 鉴别网络优化器
EPOCHS = 100 # 训练次数
nosie_dim = 100 # 输入数据的维度
num_exp_to_generator = 16 # 生成图片数量
seed = tf.random.normal([num_exp_to_generator, nosie_dim]) # 输入的随机向量
# 创建生成网络和鉴别网络
generator = generator_model()
discriminator = discriminator_model()
# 训练步骤
def train_step(images):
noise = tf.random.normal([BATCH_SIZE, nosie_dim]) # 输入的随机向量
# 创建生成网络梯度和鉴别网络梯度
with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:
real_out = discriminator( # 鉴别网络鉴别真实图片
images, # 真实图片
training=True # 可训练的
)
gen_image = generator( # 生成网络生成图片
noise, # 随机生成的向量
training=True # 可训练的
)
fake_out = discriminator( # 鉴别网络鉴别生成图片
gen_image, # 生成图片
training=True # 可训练的
)
gen_loss = generator_loss(fake_out) # 生成网络损失值
disc_loss = discriminator_loss(real_out, fake_out) # 鉴别网络损失值
# 生成网络梯度值
gradient_gen = gen_tape.gradient(
gen_loss, # 生成网络损失值
generator.trainable_variables # 生成网络权重参数
)
# 鉴别网络梯度值
gradient_disc = disc_tape.gradient(
disc_loss, # 鉴别网络损失值
discriminator.trainable_variables # 鉴别网络权重参数
)
# 生成网络反向传播,优化权重参数
generator_opt.apply_gradients(zip(
gradient_gen, # 生成网络梯度值
generator.trainable_variables # 生成网络权重参数
))
# 鉴别网络反向传播,优化权重参数
discriminator_opt.apply_gradients(zip(
gradient_disc, # 鉴别网络梯度值
discriminator.trainable_variables # 鉴别网络权重参数
))
# 展示生成的图片
def generate_plot_image(
gen_model, # 生成器训练好的模型
test_noise # 输入的噪音向量
):
pre_images = gen_model(
test_noise, # 输入的噪音向量
training=False # 不可训练,不更新模型参数
)
# 绘图
fig = plt.figure(figsize=(4, 4))
for i in range(pre_images.shape[0]): # 遍历图片。
plt.subplot(4, 4, i+1) # 子图 4 * 4 从第1张开始
# 显示图片设置
plt.imshow(
# 取第i张图片,全部的宽,全部的高,第一张图片。
(pre_images[i, :, :, 0] + 1)/2, # /2:取0和1之间
cmap='gray' # 设置颜色为灰度图
)
# 一起显示图片
plt.show()
# 训练函数
def train(
dataset, # 数据集
epochs # 训练次数
):
for epoch in range(epochs): # 循环训练
for image_batch in dataset: # 遍历数据集
train_step(image_batch) # 训练步骤
print('.', end='') # 训练1次,出现一个点,打印不要换行
# 每一个epoch都绘图
generate_plot_image(
generator, # 生成器网络
seed # 随机输入向量
)
# 开始训练
train(datasets, EPOCHS)