You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决DCGAN生成T恤设计时的模式崩溃与损失收敛问题?

T恤设计生成DCGAN的模式崩溃与收敛问题

我在完成MNIST数据集的DCGAN实验后,尝试将其应用到T恤设计生成这一更复杂的场景中。搭建模型时严格遵循DCGAN论文的架构准则:

  • 用步幅卷积(判别器)和分数步幅卷积(生成器)替代池化层
  • 生成器和判别器中均使用BatchNorm
  • 移除深层架构的全连接隐藏层
  • 生成器除输出层用Tanh外,其余层用ReLU
  • 判别器全层使用LeakyReLU

但目前生成的输出完全一致,疑似出现模式崩溃,同时无法确定是否存在梯度消失或收敛失败问题。我已尝试调整学习率、修改架构、标签平滑、分开训练真假样本等方法,且多次在损失为0或波动剧烈时提前终止训练,但问题仍未解决。

数据集与实验结果

  • 真实训练样本:
    真实训练样本
  • 生成样本:
    生成样本
  • 损失曲线:
    损失曲线

模型代码

import matplotlib.pyplot as plt
import numpy as np
import os

from tensorflow.keras.layers import Conv2D, Conv2DTranspose, Dense, Dropout, Flatten, BatchNormalization, Input, Reshape, LeakyReLU, ReLU
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.utils import img_to_array, load_img

def discriminator(input_shape=(128, 128, 3)):
    model = Sequential([
        Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=input_shape, kernel_initializer='glorot_uniform'), # kernel initializer was removed
        LeakyReLU(alpha=0.2),

        Conv2D(128, (5, 5), strides=(2, 2), padding='same', kernel_initializer='glorot_uniform'),
        BatchNormalization(momentum=0.5),
        LeakyReLU(alpha=0.2),

        Conv2D(256, (5, 5), strides=(2, 2), padding='same', kernel_initializer='glorot_uniform'),
        BatchNormalization(momentum=0.5),
        LeakyReLU(alpha=0.2),

        Conv2D(512, (5, 5), strides=(2, 2), padding='same', kernel_initializer='glorot_uniform'),
        BatchNormalization(momentum=0.5),
        LeakyReLU(alpha=0.2),

        # Output => 8 * 8 * 512
        Flatten(),
        Dense(1, activation='sigmoid')
    ])

    opt = Adam(learning_rate=0.0002, beta_1=0.5)
    model.compile(loss='binary_crossentropy', optimizer=opt, metrics=None)

    return model

def generator():
    model = Sequential([
        Dense(8*8*512, input_shape=(100,), kernel_initializer='glorot_uniform'),
        Reshape((8, 8, 512)),
        BatchNormalization(momentum=0.5),
        ReLU(),

        Conv2DTranspose(256, (5, 5), strides=(2, 2), padding='same', kernel_initializer='glorot_uniform'),
        BatchNormalization(momentum=0.5),
        ReLU(),

        Conv2DTranspose(128, (5, 5), strides=(2, 2), padding='same', kernel_initializer='glorot_uniform'),
        BatchNormalization(momentum=0.5),
        ReLU(),

        Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', kernel_initializer='glorot_uniform'),
        BatchNormalization(momentum=0.5),
        ReLU(),

        Conv2DTranspose(3, (5, 5), strides=(2, 2), padding='same', activation='tanh', kernel_initializer='glorot_uniform'),
    ])

    return model

def gan(gen_model, disc_model):
    disc_model.trainable = False

    model = Sequential([
        gen_model,
        disc_model
    ])

    opt = Adam(learning_rate=0.0002, beta_1=0.5)
    model.compile(loss='binary_crossentropy', optimizer=opt)

    return model

def load_dataset(directory="/content/tshirt-resized", target_size=(128, 128)):
    images = []
    for filename in os.listdir(directory):
        img = load_img(os.path.join(directory, filename), target_size=target_size)
        images.append(img_to_array(img))

    dataset = np.array(images)
    dataset = dataset.astype('float32')
    dataset /= 255.0

    return dataset

def generate_real_samples(dataset, num_samples):
    ix = np.random.randint(0, dataset.shape[0], num_samples)

    X = dataset[ix]
    y = np.ones((num_samples, 1)) - 0.1  # Label smoothing


    return X, y

def generate_latent_points(num_samples): # gen model input
    x_input = np.random.randn(100 * num_samples)
    x_input = x_input.reshape(num_samples, 100)

    return x_input

def generate_fake_samples(gen_model, num_samples): # gen model output
    x_input = generate_latent_points(num_samples)

    X = gen_model.predict(x_input)
    y = np.zeros((num_samples, 1)) + 0.1  # Label smoothing


    return X, y

def train(gen_model, disc_model, gan_model, dataset, epochs=200, batch_size=128):
    num_batches_per_epoch = int(dataset.shape[0] / batch_size)
    d1_loss_hist = []
    d2_loss_hist = []
    gan_loss_hist = []
    for i in range(epochs):
        for j in range(num_batches_per_epoch):
            X_real, y_real = generate_real_samples(dataset, batch_size // 2)
            d1_loss = disc_model.train_on_batch(X_real, y_real)

            X_fake, y_fake = generate_fake_samples(gen_model, batch_size // 2)
            d2_loss = disc_model.train_on_batch(X_fake, y_fake)

            X_gan = generate_latent_points(batch_size)
            y_gan = np.ones((batch_size, 1))
            gan_loss = gan_model.train_on_batch(X_gan, y_gan)

            print('>%d, %d/%d, d1=%.3f, d2=%.3f, g=%.3f' % (i+1, j+1, num_batches_per_epoch, d1_loss, d2_loss, gan_loss))

        d1_loss_hist.append(d1_loss)
        d2_loss_hist.append(d2_loss)
        gan_loss_hist.append(gan_loss)
        if (i+1) % 50 == 0:
            filename = 'generator_model_%03d.keras' % (i + 1)
            gen_model.save(filename)

    plt.plot(d1_loss_hist, label='d-real')
    plt.plot(d2_loss_hist, label='d-fake')
    plt.plot(gan_loss_hist, label='gan')
    plt.legend()
    plt.savefig("Loss Plot.png")

disc_model = discriminator()
gen_model = generator()
gan_model = gan(gen_model, disc_model)
dataset = load_dataset()

train(gen_model, disc_model, gan_model, dataset)

内容的提问来源于stack exchange,提问作者Adit Desai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 05:22:44