| """ |
| Custom TextCNN model made Hugging Face Hub compatible. |
| Architecture inferred from checkpoint weights: |
| - Embedding: (30522 vocab, 140 dim) |
| - 3 parallel Conv1d branches: kernel sizes 3, 4, 5 — each with 100 output channels |
| - Final FC layer: (300 -> 1) [300 = 100*3 concatenated conv outputs] |
| """ |
|
|
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
| from huggingface_hub import PyTorchModelHubMixin |
|
|
|
|
| class TextCNNConfig: |
| def __init__( |
| self, |
| vocab_size: int = 30522, |
| embed_dim: int = 140, |
| num_filters: int = 100, |
| kernel_sizes: list = [3, 4, 5], |
| num_classes: int = 1, |
| **kwargs, |
| ): |
| self.vocab_size = vocab_size |
| self.embed_dim = embed_dim |
| self.num_filters = num_filters |
| self.kernel_sizes = kernel_sizes |
| self.num_classes = num_classes |
|
|
|
|
| class TextCNN(nn.Module, PyTorchModelHubMixin): |
| """ |
| TextCNN for MCQ scoring, pushable to / loadable from the Hugging Face Hub. |
| |
| Usage: |
| # Save + push |
| model = TextCNN(config) |
| model.load_state_dict(torch.load("original_state_dict.pt")) |
| model.push_to_hub("your-username/cnn-mcq-model") |
| |
| # Load back |
| model = TextCNN.from_pretrained("your-username/cnn-mcq-model") |
| """ |
|
|
| def __init__(self, config: dict = None): |
| super().__init__() |
| if config is None: |
| config = {} |
| cfg = TextCNNConfig(**config) |
| self.config = config if config else cfg.__dict__ |
|
|
| self.embedding = nn.Embedding(cfg.vocab_size, cfg.embed_dim) |
| self.convs = nn.ModuleList([ |
| nn.Conv1d(in_channels=cfg.embed_dim, out_channels=cfg.num_filters, kernel_size=k) |
| for k in cfg.kernel_sizes |
| ]) |
| self.fc = nn.Linear(cfg.num_filters * len(cfg.kernel_sizes), cfg.num_classes) |
|
|
| def forward(self, input_ids): |
| |
| x = self.embedding(input_ids) |
| x = x.permute(0, 2, 1) |
| conv_outs = [F.relu(conv(x)) for conv in self.convs] |
| pooled = [F.max_pool1d(c, c.size(2)).squeeze(2) for c in conv_outs] |
| cat = torch.cat(pooled, dim=1) |
| out = self.fc(cat) |
| return out |
|
|