我在 keras 和 pytorch 中实现了这篇论文中的 LPRNet。对于 pytorch,使用此代码作为示例。它没有在任何版本中收敛。损失从 30 开始,即使在 150000 个 epoch 之后也达到 27。在 pytorch 版本中,我没有使用验证,以加快训练速度。
我尝试了什么:
- 使用 xavier_uniform_、xavier_normal 和我在 torch.nn.init 中找到的所有其他参数初始化 conv2d 权重
- 使用另一个数据集,其中包含其他人使用的 50 张清晰图像,用于他们的 rcnn ocr 模型
- 尝试了 sgd 而不是亚当
带有 pytorch 的完整 colab 在这里,我的数据集在这里
在 keras 中,我曾经成功地将模型过度拟合到训练集上。我的训练集只有 50 张图像,但我应用了随机效果以防止过度拟合。在他们的论文中,作者没有具体说明他们使用了多大的数据集。可能是模型实现中的问题?此外,原始论文包含我没有使用的空间变换器网络,因为他们告诉它是可选的,但它的缺失会是一个问题吗?
class Softmax(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
#se aplica pt torch.Size([1, 30, 1, 74])
return torch.nn.functional.log_softmax(x, 3)
class Reshape(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x):
# se aplica pt torch.Size([1, 30, 1, 74])
#pentru CTCloss
#trebuie sa fie (T,N,C) , where T=input length, N=batch size, C=number of classes
x = x.permute(3, 0, 1, 2)
return x.view(x.shape[0], x.shape[1], x.shape[2])
def init_weights(m):
if type(m) == nn.Conv2d:
torch.nn.init.xavier_uniform_(m.weight)
#m.bias.data.fill_(0.01)
class small_basic_block(nn.Module):
def __init__(self, ch_in, ch_out):
super().__init__()
self.block = nn.Sequential(
nn.Conv2d(ch_in, ch_out//4, kernel_size=1),
nn.ReLU(),
nn.Conv2d(ch_out//4, ch_out//4, kernel_size=(3,1), padding=(1,0)),
nn.ReLU(),
nn.Conv2d(ch_out//4, ch_out//4, kernel_size=(1,3), padding=(0,1)),
nn.Conv2d(ch_out//4, ch_out, kernel_size=1)
)
self.block.apply(init_weights)
def forward(self, x):
return self.block(x)
class LPRNet(nn.Module):
def __init__(self, class_num):
super().__init__()
self.lprnet = nn.Sequential(
nn.Conv2d(3, 64, kernel_size=3, stride=1),
nn.BatchNorm2d(num_features=64),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3, stride=1),
small_basic_block(ch_in=64, ch_out=128),
nn.BatchNorm2d(num_features=128),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(2, 2, 1)),
small_basic_block(ch_in=64, ch_out=256),
nn.BatchNorm2d(num_features=256),
nn.ReLU(),
small_basic_block(ch_in=256, ch_out=256),
nn.BatchNorm2d(num_features=256),
nn.ReLU(),
nn.MaxPool3d(kernel_size=(1,3,3), stride=(4,2,1)),
nn.Dropout(0.5),
nn.Conv2d(64, 256, kernel_size=(4,1), stride=1),
nn.BatchNorm2d(num_features=256),
nn.ReLU(),
nn.Dropout(0.5),
nn.Conv2d(256, class_num, kernel_size=(1,13), stride=1),
nn.BatchNorm2d(num_features=class_num),
nn.ReLU(), # torch.Size([1, 30, 1, 74])
Softmax(),
Reshape()
)
self.lprnet.apply(init_weights)
def forward(self, x):
return self.lprnet(x)
ctc_loss = nn.CTCLoss(blank=alphabet.index('$'))
model = LPRNet(len(alphabet)+1)
model.to(dev)
opt = optim.Adam(model.parameters())
scheduler = optim.lr_scheduler.StepLR(opt, step_size=100000, gamma=0.1)
def train(epochs):
for i in range(epochs):
X_data, Y_data, X_data_len, Y_data_len = train_set.next_batch()
X_data = model(X_data)
loss = ctc_loss(X_data, Y_data, X_data_len, Y_data_len)
loss.backward()
opt.step()
opt.zero_grad()
scheduler.step()