#python #computer-vision #pytorch
Вопрос:
Пытаюсь адаптировать модель LPRNet для моего собственного набора данных. Оригинальная модель была установлена для изображений китайских номерных знаков размером 24×94 пикселя. Мой набор данных состоит из табличек только с номерами, изображения имеют размеры 64×128. Я получил ошибку при попытке заменить»сводка(lprnet, (3,24,94), устройство=» процессор») » на » сводка(lprnet, (3,64,128), устройство=»процессор»)». Первый код работает хорошо, второй получает ошибку времени выполнения: размеры тензоров должны совпадать, за исключением измерения 1. Получил 25 и 24 в измерении 3 (индекс нарушения равен 1)», это последняя строка кода. Я не вижу, где еще в коде я должен изменять параметры. Буду благодарен за любую подсказку! Оригинал: https://github.com/xuexingyu24/License_Plate_Detection_Pytorch/blob/master/LPRNet/model/LPRNET.py
# LPRNET model
import torch
import torch.nn as nn
from torchsummary import summary
class small_basic_block(nn.Module):
def __init__(self, ch_in, ch_out):
super(small_basic_block, self).__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.ReLU(),
nn.Conv2d(ch_out // 4, ch_out, kernel_size=1),
)
def forward(self, x):
return self.block(x)
class LPRNet(nn.Module):
def __init__(self, class_num, dropout_rate):
super(LPRNet, self).__init__()
self.class_num = class_num
self.backbone = nn.Sequential(
nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1), # 0
nn.BatchNorm2d(num_features=64),
nn.ReLU(), # 2
nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(1, 1, 1)),
small_basic_block(ch_in=64, ch_out=128), # *** 4 ***
nn.BatchNorm2d(num_features=128),
nn.ReLU(), # 6
nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(2, 1, 2)),
small_basic_block(ch_in=64, ch_out=256), # 8
nn.BatchNorm2d(num_features=256),
nn.ReLU(), # 10
small_basic_block(ch_in=256, ch_out=256), # *** 11 ***
nn.BatchNorm2d(num_features=256), # 12
nn.ReLU(),
nn.MaxPool3d(kernel_size=(1, 3, 3), stride=(4, 1, 2)), # 14
nn.Dropout(dropout_rate),
nn.Conv2d(in_channels=64, out_channels=256, kernel_size=(1, 4), stride=1), # 16
nn.BatchNorm2d(num_features=256),
nn.ReLU(), # 18
nn.Dropout(dropout_rate),
nn.Conv2d(in_channels=256, out_channels=class_num, kernel_size=(13, 1), stride=1), # 20
nn.BatchNorm2d(num_features=class_num),
nn.ReLU(), # *** 22 ***
)
self.container = nn.Sequential(
nn.Conv2d(in_channels=256 class_num 128 64, out_channels=self.class_num, kernel_size=(1,1), stride=(1,1)),
# nn.BatchNorm2d(num_features=self.class_num),
# nn.ReLU(),
# nn.Conv2d(in_channels=self.class_num, out_channels=self.lpr_max_len 1, kernel_size=3, stride=2),
# nn.ReLU(),
)
def forward(self, x):
keep_features = list()
for i, layer in enumerate(self.backbone.children()):
x = layer(x)
if i in [2, 6, 13, 22]: # [2, 4, 8, 11, 22]
keep_features.append(x)
global_context = list()
for i, f in enumerate(keep_features):
if i in [0, 1]:
f = nn.AvgPool2d(kernel_size=5, stride=5)(f)
if i in [2]:
f = nn.AvgPool2d(kernel_size=(4, 10), stride=(4, 2))(f)
f_pow = torch.pow(f, 2)
f_mean = torch.mean(f_pow)
f = torch.div(f, f_mean)
global_context.append(f)
x = torch.cat(global_context, 1)
x = self.container(x)
logits = torch.mean(x, dim=2)
return logits
CHARS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
if __name__ == "__main__":
lprnet = LPRNet(class_num=len(CHARS), dropout_rate=0)
print(lprnet)
summary(lprnet, (3,24,94), device="cpu")
#summary(lprnet, (3,64,128), device="cpu")
Ответ №1:
Проблема с вашим кодом заключается в том, что формы четырех тензоров в global_context различаются по размеру ввода (64, 128). Для фигуры (24, 94), в LRPNet
, авторы делают все тензоры (4, 18) размером со средним объединением, которое не относится к размеру вашего изображения. Чтобы сделать их одинакового размера, вам необходимо изменить конфигурации nn.AvgPool2d
при перечислении keep_features
. Вы можете обновлять их различными способами. Я обновил avgpool с приведенными ниже конфигурациями, и это сработало:
if i in [0, 1]:
f = nn.AvgPool2d(kernel_size=(11, 24), stride=(7, 4))(f)
elif i == 2:
f = nn.AvgPool2d(kernel_size=(9, 11), stride=(7, 2))(f)
elif i == 3:
f = nn.AvgPool2d(kernel_size=(7, 2), stride=(5, 1))(f)
f_pow = torch.pow(f, 2)
f_mean = torch.mean(f_pow)
f = torch.div(f, f_mean)
global_context.append(f)```
Комментарии:
1. Большое тебе спасибо, Лабиба! Это работает и для меня, не могли бы вы объяснить более подробно, как вы нашли решение? Я пытаюсь понять, как входной размер (24,94) связан с размером тензоров (4,18). И как вы узнали, что эти тензоры имеют размер (4,18)?
2. Во-первых, я получил формы тензоров global_context. В исходном коде они принимают все тензоры global_context для формирования (4, 18), выполняя среднее объединение. Однако в вашем случае фигуры были больше. Чтобы сделать их все (4, 18), потребуется сжать много информации. Поэтому я изменил все фигуры на (8, 26), выполнив усреднение. Выполняя среднее объединение, чтобы определить размер ядра и скорость выполнения каждой операции, я просто следовал математике для H_{out} и W_{out} с этой страницы: pytorch.org/docs/stable/generated/… Надеюсь, это поможет.
3. Это действительно помогает, большое вам спасибо за объяснение. Я использовал эти формулы и для решения другой проблемы!