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

如何用PyTorch构建音频条件GAN?生成样本白噪声问题排查

条件GAN生成数字音频故障排查

我正在构建一个可生成0-9数字人声音频的条件GAN,训练数据是已转换为Numpy数组的WAV文件,用librosa可正常回放清晰的数字发音。模型基于MNIST条件GAN修改,仅调整了输入形状,运行无报错,但训练时生成的样本回放为白噪声。我需要确定是模型未学习到有效特征,还是生成过程中样本被损坏。现有2700个尺寸为(256,64)的样本,相关代码如下:

数据加载代码

X_train = torch.tensor(X_train)
y_train = torch.tensor(y_train)
print("X_train Shape:", X_train.shape)
print("y_train Shape:", y_train.shape)
dataset = torch.utils.data.TensorDataset(X_train, y_train)

# 输出结果:
# X_train Shape: torch.Size([2700, 1, 256, 64])
# y_train Shape: torch.Size([2700])

loader = DataLoader(
    dataset,
    batch_size=30,
    shuffle=False,
)

判别器定义

class Discriminator(nn.Module):
    def __init__(self, channels, features_d, num_classes, x1_size, x2_size):
        super(Discriminator, self).__init__()
        self.x1_size = x1_size
        self.x2_size= x2_size
        self.disc = nn.Sequential(
            # input: N x channels x 64 x 64
            nn.Conv2d(channels+1, features_d, kernel_size=4, stride=2, padding=1), #in_channels = channels+1
            nn.LeakyReLU(0.2),
            # _block(in_channels, out_channels, kernel_size, stride, padding)
            self._block(features_d, features_d * 2, 4, 2, 1),
            self._block(features_d * 2, features_d * 4, 4, 2, 1),
            self._block(features_d * 4, features_d * 8, 4, 2, 1),
            # After all _block output is 4x4 (Conv2d below makes into 1x1)
            nn.Conv2d(features_d * 8, 1, kernel_size=4, stride=2, padding=0),
        )
        self.embed = nn.Embedding(num_classes, x1_size*x2_size) # Adds an additional channel

    def _block(self, in_channels, out_channels, kernel_size, stride, padding):
        return nn.Sequential(
            nn.Conv2d(
                in_channels, out_channels, kernel_size, stride, padding, bias=False,
            ),
            nn.InstanceNorm2d(out_channels, affine=True),
            nn.LeakyReLU(0.2),
        )

    def forward(self, x, labels):
        embedding = self.embed(labels).view(labels.shape[0], 1, self.x1_size, self.x2_size) # for sound, size will need to be 2 variables
        x = torch.cat([x, embedding], dim=1) # Num_samples x c x size(h) x size(w)
        return self.disc(x)

生成器定义

class Generator(nn.Module):
    def __init__(self, channels_noise, channels_img, features_g, num_classes, x1_size, x2_size, embed_size):
        super(Generator, self).__init__()
        self.x1_size = x1_size
        self.x1_size = x1_size
        self.net = nn.Sequential(
            # Input: N x channels_noise x 1 x 1
            self._block(channels_noise+embed_size, features_g * 16, (16,4), 1, 0),  # img: 4x1
            self._block(features_g * 16, features_g * 8, 4, 2, 1),  # img: 16x4
            self._block(features_g * 8, features_g * 4, 4, 2, 1),  # img: 32x8
            self._block(features_g * 4, features_g * 2, 4, 2, 1),  # img: 64x16
            nn.ConvTranspose2d(
                features_g * 2, channels_img, kernel_size=4, stride=2, padding=1
                
            ),
             #Output: N x channels_img x 64 x 64
            nn.Tanh(),
        )
        self.embed = nn.Embedding(num_classes, embed_size)
    def _block(self, in_channels, out_channels, kernel_size, stride, padding):
        return nn.Sequential(
            nn.ConvTranspose2d(
                in_channels, out_channels, kernel_size, stride, padding, bias=False,
            ),
            nn.BatchNorm2d(out_channels),
            nn.ReLU(),
        )

    def forward(self, x, labels):
        # latent vector z = num_samples x noise_dim x 1 x 1
        embedding = self.embed(labels).unsqueeze(2).unsqueeze(3)
        x = torch.cat([x, embedding], dim=1) 
        return self.net(x).to(device)

辅助函数

def gradient_penalty(critic, labels, real, fake, device="cpu"):
    BATCH_SIZE, C, H, W = real.shape
    alpha = torch.rand((BATCH_SIZE, 1, 1, 1)).repeat(1, C, H, W).to(device)
    interpolated_images = real * alpha + fake * (1 - alpha)

    # Calculate critic scores
    mixed_scores = critic(interpolated_images, labels)

    # Take the gradient of the scores with respect to the images
    gradient = torch.autograd.grad(
        inputs=interpolated_images,
        outputs=mixed_scores,
        grad_outputs=torch.ones_like(mixed_scores),
        create_graph=True,
        retain_graph=True,
    )[0]
    gradient = gradient.view(gradient.shape[0], -1)
    gradient_norm = gradient.norm(2, dim=1)
    gradient_penalty = torch.mean((gradient_norm - 1) ** 2)
    return gradient_penalty


def save_checkpoint(state, filename="celeba_wgan_gp.pth.tar"):
    print("=> Saving checkpoint")
    torch.save(state, filename)


def load_checkpoint(checkpoint, gen, disc):
    print("=> Loading checkpoint")
    gen.load_state_dict(checkpoint['gen'])
    disc.load_state_dict(checkpoint['disc'])

训练循环代码

gen.train()
critic.train()

for epoch in range(NUM_EPOCHS):
    
    for batch_idx, (real, labels) in enumerate(loader):
        #print(batch_idx)
        real = real.to(device)
        cur_batch_size = real.shape[0]
        labels = labels.to(device)
        np.save(f"/content/drive/My Drive/Pytorch_Real/Real_array_{epoch}", real.detach().cpu().numpy())
        # Train Critic: max E[critic(real)] - E[critic(fake)]
        # equivalent to minimizing the negative of that
        for _ in range(CRITIC_ITERATIONS):
            noise = torch.randn(cur_batch_size, Z_DIM, 1, 1).to(device)
            fake = gen(noise, labels).to(device)
            np.save(f"/content/drive/My Drive/Pytorch_Fake/Fake_array_{epoch}", fake.detach().cpu().numpy())
            critic_real = critic(real, labels).reshape(-1).to(device)
            critic_fake = critic(fake, labels).reshape(-1).to(device)
            gp = gradient_penalty(critic, labels, real, fake, device=device)
            loss_critic = (
                -(torch.mean(critic_real) - torch.mean(critic_fake)) + LAMBDA_GP * gp
            )
            critic.zero_grad()
            loss_critic.backward(retain_graph=True)
            opt_critic.step()

        # Train Generator: max E[critic(gen_fake)] <-> min -E[critic(gen_fake)]
        gen_fake = critic(fake, labels).reshape(-1)
        loss_gen = -torch.mean(gen_fake)
        gen.zero_grad()
        loss_gen.backward()
        opt_gen.step()

        # Print losses occasionally and print to tensorboard
        if batch_idx % 10 == 0 and batch_idx > 0:
            print(
                f"Epoch [{epoch}/{NUM_EPOCHS}] Batch {batch_idx}/{len(loader)} \n                  Loss D: {loss_critic:.4f}, loss G: {loss_gen:.4f}"
            )

            with torch.no_grad():
                fake = gen(noise, labels)
                # take out (up to) 32 examples
                img_grid_real = torchvision.utils.make_grid(real[:32], normalize=True)
                img_grid_fake = torchvision.utils.make_grid(fake[:32], normalize=True)

                writer_real.add_image("Real", img_grid_real, global_step=step)
                writer_fake.add_image("Fake", img_grid_fake, global_step=step)

            step += 1

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 06:40:43