teuchi's picture
Upload 12 files
e53e505 verified
Raw History Blame Contribute Delete
4.29 kB
import torch
import torch.nn as nn
class CNN(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(1, 64, kernel_size=3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(64, 128, kernel_size=3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2),
nn.Conv2d(128, 256, kernel_size=3, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.Conv2d(256, 256, kernel_size=3, padding=1),
nn.BatchNorm2d(256),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=(2, 1)),
nn.Conv2d(256, 512, kernel_size=3, padding=1),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.Conv2d(512, 512, kernel_size=3, padding=1),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=(2, 1)),
nn.Conv2d(512, 512, kernel_size=(2, 1), padding=0),
nn.BatchNorm2d(512),
nn.ReLU(inplace=True),
)
def forward(self, x):
return self.features(x)
class CRNN(nn.Module):
def __init__(
self,
num_classes: int = 37, # 36 символов + бланк
hidden_size: int = 256,
num_layers: int = 2,
):
super().__init__()
self.cnn = CNN()
self.lstm = nn.LSTM(
input_size=512,
hidden_size=hidden_size,
num_layers=num_layers,
batch_first=True,
bidirectional=True,
dropout=0.3,
)
self.classifier = nn.Linear(hidden_size * 2, num_classes)
def forward(self, x: torch.Tensor) -> torch.Tensor:
features = self.cnn(x)
features = features.squeeze(2)
features = features.permute(0, 2, 1)
lstm_out, _ = self.lstm(features)
logits = self.classifier(lstm_out)
logits = logits.permute(1, 0, 2)
return logits
def get_model(num_classes: int = 37, device: str = "cpu") -> CRNN:
model = CRNN(num_classes=num_classes)
model = model.to(device)
return model
def count_parameters(model: nn.Module) -> int:
return sum(p.numel() for p in model.parameters() if p.requires_grad)
# ── Запуск для проверки ─────────────────────────────────────────────────────
if __name__ == "__main__":
print("=== Тест model.py ===\n")
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Устройство: {device}")
# создаём модель
model = get_model(num_classes=37, device=device)
# считаем параметры
params = count_parameters(model)
print(f"Параметров модели: {params:,}") # написало примерно 8 млн
# тестовый проход
batch_size = 4
dummy_input = torch.randn(batch_size, 1, 32, 128).to(device)
print(f"\nВход: {list(dummy_input.shape)}")
with torch.no_grad():
output = model(dummy_input)
print(f"Выход: {list(output.shape)}") # [32, 4, 37]
print(f" T=32 — временных шагов (позиций символов)")
print(f" B=4 — размер батча")
print(f" C=37 — классов (символов)")
# Проверка что ctc loss работает
print("\nПроверка CTC Loss...")
ctc_loss = nn.CTCLoss(blank=0, reduction="mean", zero_infinity=True)
log_probs = output.log_softmax(2)
input_lengths = torch.full((batch_size,), 32, dtype=torch.long)
targets = torch.tensor([1, 2, 3, 4, 5, 6], dtype=torch.long)
target_lengths = torch.tensor([3, 3], dtype=torch.long)
# Только для 2 примеров из батча
loss = ctc_loss(
log_probs[:, :2, :],
targets,
input_lengths[:2],
target_lengths,
)
print(f"CTC Loss: {loss.item():.4f}")
print("\n✓ еее работает")