import torch import torch.nn as nn class CRNN(nn.Module): def __init__(self, num_chars, rnn_hidden_size=256, rnn_layers=2, cnn_output_height=32): super(CRNN, self).__init__() self.cnn = nn.Sequential( nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1), nn.ReLU(True), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1), nn.ReLU(True), nn.MaxPool2d(kernel_size=2, stride=2), nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(128), nn.ReLU(True), nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1), nn.ReLU(True), nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 1), padding=(0, 1)), nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(512), nn.ReLU(True), nn.MaxPool2d(kernel_size=(2, 2), stride=(2, 1), padding=(0, 1)) ) self.map_to_sequence = nn.Linear(512 * 2, rnn_hidden_size) self.rnn = nn.LSTM( input_size=rnn_hidden_size, hidden_size=rnn_hidden_size, num_layers=rnn_layers, bidirectional=True, batch_first=True ) self.classifier = nn.Linear(rnn_hidden_size * 2, num_chars + 1) def forward(self, x): conv_features = self.cnn(x) batch, channels, height, width = conv_features.size() sequence = conv_features.permute(0, 3, 1, 2).contiguous() sequence = sequence.view(batch, width, channels * height) sequence = self.map_to_sequence(sequence) rnn_output, _ = self.rnn(sequence) output = self.classifier(rnn_output) return output