niqun123123 commited on
Commit
410ca9f
·
verified ·
1 Parent(s): e5f2c18

Upload modeling_autojev.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. modeling_autojev.py +86 -0
modeling_autojev.py ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """AutoJev-style full-weight decision model. No autoregressive generation head.
2
+
3
+ The checkpoint's backbone is copied byte-for-byte from Qwen, while readout rows
4
+ are selected from its original LM head. T is used in postprocessing, not CE loss.
5
+ """
6
+ from dataclasses import dataclass
7
+ import torch
8
+ import torch.nn.functional as F
9
+ from transformers.utils import ModelOutput
10
+ from transformers.models.qwen3_5.modeling_qwen3_5 import Qwen3_5Model, Qwen3_5PreTrainedModel
11
+ from .configuration_autojev import AutoJevConfig
12
+
13
+
14
+ @dataclass
15
+ class AutoJevOutput(ModelOutput):
16
+ loss: torch.Tensor | None = None
17
+ logits: torch.Tensor | None = None
18
+
19
+
20
+ class AutoJevForDecisionClassification(Qwen3_5PreTrainedModel):
21
+ config_class = AutoJevConfig
22
+ base_model_prefix = "backbone"
23
+
24
+ def __init__(self, config):
25
+ super().__init__(config)
26
+ self.backbone = Qwen3_5Model(config)
27
+ self.readout = torch.nn.Linear(config.text_config.hidden_size, config.max_options, bias=False)
28
+ self.post_init()
29
+
30
+ def get_input_embeddings(self):
31
+ return self.backbone.get_input_embeddings()
32
+
33
+ def set_input_embeddings(self, value):
34
+ self.backbone.set_input_embeddings(value)
35
+
36
+ def forward(self, input_ids=None, attention_mask=None, option_counts=None,
37
+ labels=None, return_dict=True, **kwargs):
38
+ if input_ids is None or input_ids.ndim != 2 or input_ids.shape[1] == 0:
39
+ raise ValueError("input_ids must be a nonempty [batch, length] tensor")
40
+ if input_ids.shape[1] > self.config.max_input_length:
41
+ raise ValueError("Input exceeds max_input_length; truncation is not allowed")
42
+ if attention_mask is None:
43
+ attention_mask = torch.ones_like(input_ids)
44
+ if attention_mask.shape != input_ids.shape or not bool((attention_mask[:, -1] == 1).all()):
45
+ raise ValueError("Left padding required: last prompt position must be valid")
46
+ if option_counts is None:
47
+ raise ValueError("option_counts is required for each input")
48
+ counts = torch.as_tensor(option_counts, device=input_ids.device)
49
+ if counts.dtype == torch.bool or counts.is_floating_point() or counts.shape != (input_ids.shape[0],):
50
+ raise ValueError("option_counts must contain one integer per row")
51
+ if not bool(((counts >= 1) & (counts <= self.config.max_options)).all()):
52
+ raise ValueError("Each question must contain 1..255 options")
53
+ if kwargs.pop("use_cache", False) or kwargs.get("past_key_values") is not None:
54
+ raise ValueError("Decision forward does not accept KV-cache decoding")
55
+ output = self.backbone(input_ids=input_ids, attention_mask=attention_mask,
56
+ use_cache=False, return_dict=True, **kwargs)
57
+ # Qwen3_5Model.last_hidden_state is AFTER language_model.norm (RMSNorm).
58
+ hidden = output.last_hidden_state[:, -1, :]
59
+ logits = self.readout(hidden).float()
60
+ invalid = torch.arange(self.config.max_options, device=logits.device)[None] >= counts[:, None]
61
+ logits = logits.masked_fill(invalid, -1e9)
62
+ loss = None
63
+ if labels is not None:
64
+ labels = labels.to(logits.device)
65
+ if labels.shape == (len(counts),):
66
+ if labels.is_floating_point() or labels.dtype == torch.bool or not bool(((labels >= 0) & (labels < counts)).all()):
67
+ raise ValueError("Hard targets must be valid option indices")
68
+ loss = F.cross_entropy(logits, labels.long())
69
+ elif labels.shape == logits.shape:
70
+ target = labels.float()
71
+ if not bool(torch.isfinite(target).all()) or bool((target < 0).any()):
72
+ raise ValueError("Invalid soft targets")
73
+ if not torch.allclose(target.sum(-1), torch.ones(len(counts), device=target.device), atol=1e-6, rtol=0):
74
+ raise ValueError("Soft targets must sum to one")
75
+ if bool((target.masked_select(invalid) != 0).any()):
76
+ raise ValueError("Soft targets assign mass to invalid options")
77
+ loss = -(target * F.log_softmax(logits, dim=-1)).sum(-1).mean()
78
+ else:
79
+ raise ValueError("labels must be [batch] or [batch,255]")
80
+ if not return_dict:
81
+ return (loss, logits) if loss is not None else (logits,)
82
+ return AutoJevOutput(loss=loss, logits=logits)
83
+
84
+
85
+ AutoJevConfig.register_for_auto_class()
86
+ AutoJevForDecisionClassification.register_for_auto_class("AutoModel")