python - 欠拟合单个批次:不能导致自动编码器过拟合多样本批次的一维数据。如何调试?
问题描述
TL;博士
我无法使用自动编码器对包含多个样本的批次进行过度拟合。
全连接解码器似乎比 conv 解码器每批处理更多的样本,但是当样本数量增加时也会失败。 为什么会发生这种情况,以及如何调试?
深入
我正在尝试在 size 的一维数据点上使用自动编码器(n, 1, 1024)
,其中n
是批次中的样本数。
我正试图过度适应那一批。
使用卷积解码器,我只能拟合单个样本 ( n=1
),并且当n>1
我无法将损失 (MSE) 降至 0.2 以下时。
蓝色:预期输出(=输入),橙色:重建。
使用多个样本,我们可以看到网络学习了输入(=输出)信号的一般形状,但大大错过了偏差。
使用完全连接的解码器确实可以重建多个样本的批次:
相关代码:
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 个样本
conv 解码器可能有什么问题?
如何调试这个或使 conv 解码器工作?
解决方案
垂死的 ReLU
- 我认为你的情况下拟合不足的主要原因是Dying Relu问题。您的网络是简单的自动编码器,没有跳过/剩余连接。所以瓶颈中的代码应该编码足够的关于数据偏差的信息,以使解码器学习。
- 因此,如果使用ReLU激活函数,由于 Dying ReLU 问题,可能会丢失Negative Biased数据信息。解决方案是使用更好的激活函数,如LeakyReLU、ELU、MISH等。
线性与转化
在您的情况下,您在单个批次上过度拟合。由于线性层将具有比卷积层更多的参数,因此它们可能很容易记住给定的小数据。
批量大小
由于您在单个批次上过度拟合,因此小批量数据将使其非常容易记住另一方面,对于大批量而言,每批次更新一次网络(在过度拟合期间)使网络学习广义抽象特征。(如果有更多的批次和大量的数据,这会更好)
我尝试使用简单的高斯数据重现您的问题。只需使用LeakyReLU代替具有适当学习率的ReLU即可解决问题。使用您给出的相同架构。
超参数:
批量大小 = 16
历元 = 100
lr = 1e-3
优化器 = 亚当
损失(使用ReLU训练后)= 0.27265918254852295
损失(使用LeakyReLU训练后)= 0.0004763789474964142
与 Relu
使用泄漏的 Relu
推荐阅读
- javascript - 如何使用反应钩子清理 useEffect 中的 setInterval
- c++ - 如何使用由指向视频数据的指针创建的 cv::Mat imgbuf
- reactjs - 如何在 Input 标签中为 Bootstrap 滑块定义格式化程序函数?
- python - 批处理文件无法识别并运行第二个(下一个)命令
- chart.js - ChartJS:删除由刻度标签引起的图表右侧的填充
- apache-camel - 如何将未编组的数据处理为原始数据?
- php - 将 textFile 日期保存到 MySQL
- c++ - 如何在另一个类中重载运算符 ==
- python - 使用参考列在数据框中的行值之间进行选择?
- python - 带有 for 循环的 Python 代码不起作用