File size: 2,424 Bytes
ab331fa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | """
pred.py - predictor for evaluation
"""
import json
import pickle
from typing import List, Tuple
import numpy as np
import torch
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
from torch import nn
class SkillClassifier(nn.Module):
def __init__(self, input_dim, num_labels, hidden_dim=32, dropout=0.3):
super().__init__()
self.net = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.Dropout(dropout),
nn.Linear(hidden_dim, num_labels),
)
def forward(self, x):
return self.net(x)
def JobAnalyze_6k(job_desc: str = "", role: str = "", job_type: str = "", top_k: int = 50) -> List[Tuple[str, float]]:
"""
Predict top-k skills.
Current top-k = 48
"""
prep_dir = ROOT / "model" / "prep"
if not prep_dir.exists():
alt = ROOT / "prep"
if alt.exists():
prep_dir = alt
label_path = prep_dir / "label_vocab.json"
vector_path = prep_dir / "vectorizer.pkl"
weights_path = ROOT / "model_out" / "skill_classifier.pt"
if not label_path.exists():
raise FileNotFoundError(
f"Missing {label_path}. Make sure you ran data_prep and model training."
)
if not vector_path.exists():
raise FileNotFoundError(
f"Missing {vector_path}. Make sure you ran data_prep."
)
if not weights_path.exists():
raise FileNotFoundError(
f"Missing {weights_path}. Make sure you ran model/model.py."
)
with open(label_path, encoding="utf-8") as f:
label_vocab = json.load(f)
with open(vector_path, "rb") as f:
vectorizer = pickle.load(f)
input_dim = int(getattr(vectorizer, "vocabulary_", {}).__len__()) or vectorizer.transform([""]).shape[1]
model = SkillClassifier(input_dim, len(label_vocab))
model.load_state_dict(torch.load(weights_path, map_location="cpu"))
model.eval()
combined_text = f"{job_desc} {role} {job_type}"
X = vectorizer.transform([combined_text]).toarray().astype(np.float32)
with torch.no_grad():
logits = model(torch.tensor(X))
probs = torch.sigmoid(logits).numpy()[0]
ranked = sorted(zip(label_vocab, probs), key=lambda x: -x[1])
return ranked[:top_k]
|