首页 > 解决方案 > 欠拟合单个批次:不能导致自动编码器过拟合多样本批次的一维数据。如何调试?

问题描述

TL;博士

我无法使用自动编码器对包含多个样本的批次进行过度拟合。

全连接解码器似乎比 conv 解码器每批处理更多的样本,但是当样本数量增加时也会失败。 为什么会发生这种情况,以及如何调试?


深入

我正在尝试在 size 的一维数据点上使用自动编码器(n, 1, 1024),其中n是批次中的样本数。

我正试图过度适应那一批。

使用卷积解码器,我只能拟合单个样本 ( n=1),并且当n>1我无法将损失 (MSE) 降至 0.2 以下时。

蓝色:预期输出(=输入),橙色:重建。

单个样品,单个批次:
转换1样本

多样品,单批次,损失不会下降: Conv4samples

使用多个样本,我们可以看到网络学习了输入(=输出)信号的一般形状,但大大错过了偏差。


使用完全连接的解码器确实可以重建多个样本的批次:

Fc4样本


相关代码:

class Conv1DBlock(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size):
        super().__init__()
        self._in_channels = in_channels
        self._out_channels = out_channels
        self._kernel_size = kernel_size

        self._block = nn.Sequential(
                nn.Conv1d(
                        in_channels=self._in_channels,
                        out_channels=self._out_channels,
                        kernel_size=self._kernel_size,
                        stride=1,
                        padding=(self._kernel_size - 1) // 2,
                ),
                # nn.BatchNorm1d(num_features=out_channels),
                nn.ReLU(True),
                nn.MaxPool1d(kernel_size=2, stride=2),
        )

    def forward(self, x):
        for layer in self._block:
            x = layer(x)
        return x


class Upsample1DBlock(nn.Module):
    def __init__(self, in_channels, out_channels, factor):
        super().__init__()
        self._in_channels = in_channels
        self._out_channels = out_channels
        self._factor = factor

        self._block = nn.Sequential(
                nn.Conv1d(
                        in_channels=self._in_channels,
                        out_channels=self._out_channels,
                        kernel_size=3,
                        stride=1,
                        padding=1
                ),  # 'same'
                nn.ReLU(True),
                nn.Upsample(scale_factor=self._factor, mode='linear', align_corners=True),
        )

    def forward(self, x):
        x_tag = x
        for layer in self._block:
            x_tag = layer(x_tag)
        # interpolated = F.interpolate(x, scale_factor=0.5, mode='linear') # resnet idea
        return x_tag

编码器:

self._encoder = nn.Sequential(
            # n, 1024
            nn.Unflatten(dim=1, unflattened_size=(1, 1024)),
            # n, 1, 1024
            Conv1DBlock(in_channels=1, out_channels=8, kernel_size=15),
            # n, 8, 512
            Conv1DBlock(in_channels=8, out_channels=16, kernel_size=11),
            # n, 16, 256
            Conv1DBlock(in_channels=16, out_channels=32, kernel_size=7),
            # n, 32, 128
            Conv1DBlock(in_channels=32, out_channels=64, kernel_size=5),
            # n, 64, 64
            Conv1DBlock(in_channels=64, out_channels=128, kernel_size=3),
            # n, 128, 32
            nn.Conv1d(in_channels=128, out_channels=128, kernel_size=32, stride=1, padding=0),  # FC
            # n, 128, 1
            nn.Flatten(start_dim=1, end_dim=-1),
            # n, 128
        )

转换解码器:

self._decoder = nn.Sequential(
    nn.Unflatten(dim=1, unflattened_size=(128, 1)),  # 1
    Upsample1DBlock(in_channels=128, out_channels=64, factor=4),  # 4
    Upsample1DBlock(in_channels=64, out_channels=32, factor=4),  # 16
    Upsample1DBlock(in_channels=32, out_channels=16, factor=4),  # 64
    Upsample1DBlock(in_channels=16, out_channels=8, factor=4),  # 256
    Upsample1DBlock(in_channels=8, out_channels=1, factor=4),  # 1024
    nn.ReLU(True),
    nn.Conv1d(in_channels=1, out_channels=1, kernel_size=3, stride=1, padding=1),
    nn.ReLU(True),
    nn.Flatten(start_dim=1, end_dim=-1),
    nn.Linear(1024, 1024)
)

FC解码器:

self._decoder = nn.Sequential(
    nn.Linear(128, 256),
    nn.ReLU(True),
    nn.Linear(256, 512),
    nn.ReLU(True),
    nn.Linear(512, 1024),
    nn.ReLU(True),
    nn.Flatten(start_dim=1, end_dim=-1),
    nn.Linear(1024, 1024)
)

另一个观察结果是,当批量增加更多时,比如 16,FC 解码器也开始失败。

在图像中,我试图过拟合的 16 个样本批次中的 4 个样本

fc16样品


conv 解码器可能有什么问题?

如何调试这个或使 conv 解码器工作?

标签: pythondeep-learningpytorchconv-neural-networkautoencoder

解决方案


垂死的 ReLU

  • 我认为你的情况下拟合不足的主要原因是Dying Relu问题。您的网络是简单的自动编码器,没有跳过/剩余连接。所以瓶颈中的代码应该编码足够的关于数据偏差的信息,以使解码器学习。
  • 因此,如果使用ReLU激活函数,由于 Dying ReLU 问题,可能会丢失Negative Biased数据信息。解决方案是使用更好的激活函数,如LeakyReLUELUMISH等。

线性与转化

在您的情况下,您在单个批次上过度拟合。由于线性层将具有比卷积层更多的参数,因此它们可能很容易记住给定的小数据。

批量大小

由于您在单个批次上过度拟合,因此小批量数据将使其非常容易记住另一方面,对于大批量而言,每批次更新一次网络(在过度拟合期间)使网络学习广义抽象特征。(如果有更多的批次和大量的数据,这会更好)

我尝试使用简单的高斯数据重现您的问题。只需使用LeakyReLU代替具有适当学习率的ReLU即可解决问题。使用您给出的相同架构。

超参数:

批量大小 = 16

历元 = 100

lr = 1e-3

优化器 = 亚当

损失(使用ReLU训练后)= 0.27265918254852295

损失(使用LeakyReLU训练后)= 0.0004763789474964142

与 Relu

带relu

使用泄漏的 Relu

带有泄漏的 relu


推荐阅读