pandora / src /models /bert_regressor.py
Deployment Bot
Fix nested src directory structure causing ModuleNotFoundError
4df95ad
Raw
History Blame Contribute Delete
2.66 kB
# ─────────────────────────────────────────────────────────────────────────────
# Fine-Tuned BERT Regressor Architecture
# src/models/bert_regressor.py
# ─────────────────────────────────────────────────────────────────────────────
import torch
import torch.nn as nn
from transformers import BertModel, BertTokenizer
class BertRegressorModel(nn.Module):
"""
End-to-end fine-tuned BERT Regression model for Extraversion prediction.
Architecture:
bert-base-uncased β†’ [CLS] hidden state (768-dim)
β†’ Dropout(0.3)
β†’ Linear(768, 256)
β†’ ReLU
β†’ Dropout(0.2)
β†’ Linear(256, 1)
β†’ Sigmoid * 99 (output in 0–99 range)
"""
def __init__(self, dropout1: float = 0.3, dropout2: float = 0.2):
super().__init__()
self.bert = BertModel.from_pretrained("bert-base-uncased")
hidden = self.bert.config.hidden_size # 768
self.regressor = nn.Sequential(
nn.Dropout(dropout1),
nn.Linear(hidden, 256),
nn.ReLU(),
nn.Dropout(dropout2),
nn.Linear(256, 1),
nn.Sigmoid() # β†’ (0, 1); we multiply by 99 at inference
)
def forward(self, input_ids, attention_mask, token_type_ids=None):
outputs = self.bert(
input_ids=input_ids,
attention_mask=attention_mask,
token_type_ids=token_type_ids,
output_attentions=True # expose attention weights for heatmap
)
cls_vec = outputs.last_hidden_state[:, 0, :] # [B, 768]
attentions = outputs.attentions # tuple of 12 layers
score = self.regressor(cls_vec).squeeze(-1) # [B]
score = score * 99.0 # scale to 0–99
return score, attentions
def get_tokenizer():
return BertTokenizer.from_pretrained("bert-base-uncased")
def load_bert_regressor(model_path: str, device: str = "cpu") -> BertRegressorModel:
"""Load a saved BertRegressorModel from disk."""
model = BertRegressorModel()
model.load_state_dict(torch.load(model_path, map_location=device))
model.eval()
model.to(device)
return model