11# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22# SPDX-License-Identifier: Apache-2.0
33
4- """Hugging Face Transformers prefill forward used by the Rust crate."""
4+ """Complete Transformers prefill and checkpoint inference for the Rust crate."""
55
66from __future__ import annotations
77
8+ from pathlib import Path
89from typing import Any
910
1011
@@ -37,125 +38,148 @@ def _resolve_device(torch: Any, override: str | None) -> str:
3738
3839
3940class TransformersForward :
40- """Lazily load a causal LM and return pooled prefill hidden states ."""
41+ """Run encoder extraction and learned confidence inference in one pass ."""
4142
4243 def __init__ (
4344 self ,
44- model : str ,
45+ checkpoint_path : str | Path ,
4546 * ,
4647 device : str | None = None ,
4748 cache_dir : str | None = None ,
4849 ) -> None :
49- self ._model_path = model
50+ import numpy as np
51+ import torch
52+
53+ checkpoint = torch .load (checkpoint_path , map_location = "cpu" , weights_only = True )
54+ if checkpoint ["format_version" ] != 1 :
55+ raise ValueError ("unsupported checkpoint format_version" )
56+
57+ encoder = checkpoint ["encoder" ]
58+ architecture = checkpoint ["architecture" ]
59+ pipeline = checkpoint ["feature_pipeline" ]
60+ if encoder ["view" ] != "task_prompt_only" :
61+ raise ValueError ("checkpoint encoder view must be task_prompt_only" )
62+ if pipeline ["pooling" ] != "mean of independently standardized selected layers" :
63+ raise ValueError ("unsupported checkpoint feature pooling" )
64+ if architecture ["activation" ] != "ReLU" :
65+ raise ValueError ("checkpoint activation must be ReLU" )
66+ if architecture ["ensemble_reduction" ] != "mean(sigmoid(logits))" :
67+ raise ValueError ("unsupported checkpoint ensemble reduction" )
68+
69+ self ._numpy = np
70+ self ._torch = torch
71+ self ._model_path = str (encoder ["name" ])
72+ self ._expected_layers = int (encoder ["n_layers" ])
73+ self ._hidden_dim = int (encoder ["hidden_dim" ])
74+ self ._models = [str (model ) for model in checkpoint ["models" ]]
75+ self ._selected_layers = [int (layer ) for layer in pipeline ["selected_layers" ]]
76+ self ._layer_mean = torch .stack (
77+ [pipeline ["layer_mean" ][str (layer )].float () for layer in self ._selected_layers ]
78+ ).numpy ()
79+ self ._layer_std = torch .stack (
80+ [pipeline ["layer_std" ][str (layer )].float () for layer in self ._selected_layers ]
81+ ).numpy ()
82+ self ._scaler_mean = pipeline ["scaler_mean" ].numpy ()
83+ self ._scaler_scale = pipeline ["scaler_scale" ].numpy ()
84+ self ._pca_mean = pipeline ["pca_mean" ].numpy ()
85+ self ._pca_components = pipeline ["pca_components" ].numpy ()
86+ self ._states = checkpoint ["model_state_dicts" ]
5087 self ._cache_dir = cache_dir
5188 self ._device_override = device
5289 self ._model = None
5390 self ._tokenizer = None
54- self ._torch = None
55- self .n_layers = 0
56- self .hidden_dim = 0
5791
58- def _ensure_loaded (self ) -> str :
92+ if not self ._selected_layers or len (set (self ._selected_layers )) != len (
93+ self ._selected_layers
94+ ):
95+ raise ValueError ("checkpoint selected layers must be non-empty and unique" )
96+ if not self ._models or not self ._states :
97+ raise ValueError ("checkpoint must contain models and ensemble members" )
98+ if self ._layer_mean .shape != self ._layer_std .shape or self ._layer_mean .shape != (
99+ len (self ._selected_layers ),
100+ self ._hidden_dim ,
101+ ):
102+ raise ValueError ("checkpoint layer normalization shape is inconsistent" )
103+ if not bool (np .all (self ._layer_std > 0 )) or not bool (np .all (self ._scaler_scale > 0 )):
104+ raise ValueError ("checkpoint normalization scales must be positive" )
105+
106+ def metadata (self ) -> tuple [str , int ]:
107+ """Return the encoder and ordered output count consumed by Rust."""
108+ return self ._model_path , len (self ._models )
109+
110+ def _ensure_loaded (self ) -> None :
59111 if self ._model is not None :
60- return str ( self . _model . device )
112+ return
61113
62- import torch
63114 from transformers import AutoModelForCausalLM , AutoTokenizer
64115
65- self . _torch = torch
116+ torch = self . _torch
66117 device = _resolve_device (torch , self ._device_override )
67- if device == "cpu" :
68- dtype = torch .float32
69- elif device == "mps" :
70- dtype = torch .float16
71- else :
72- dtype = (
73- torch .bfloat16
74- if torch .cuda .get_device_capability (device )[0 ] >= 8
75- else torch .float16
76- )
77-
118+ dtype = (
119+ torch .float32
120+ if device == "cpu"
121+ else torch .float16
122+ if device == "mps"
123+ else torch .bfloat16
124+ if torch .cuda .get_device_capability (device )[0 ] >= 8
125+ else torch .float16
126+ )
127+ model_kwargs : dict [str , Any ] = {}
128+ if device == "cuda" :
129+ model_kwargs ["device_map" ] = "auto"
130+ elif device .startswith ("cuda:" ):
131+ model_kwargs ["device_map" ] = {"" : device }
78132 self ._tokenizer = AutoTokenizer .from_pretrained (
79133 self ._model_path ,
80134 cache_dir = self ._cache_dir ,
81135 )
82136 if self ._tokenizer .pad_token is None :
83137 self ._tokenizer .pad_token = self ._tokenizer .eos_token
84-
85- load_kwargs : dict [str , Any ] = {
86- "dtype" : dtype ,
87- "cache_dir" : self ._cache_dir ,
88- }
89-
90- self ._model = AutoModelForCausalLM .from_pretrained (
138+ causal_model = AutoModelForCausalLM .from_pretrained (
91139 self ._model_path ,
92- ** load_kwargs ,
140+ dtype = dtype ,
141+ cache_dir = self ._cache_dir ,
142+ ** model_kwargs ,
93143 )
94- if device != "cpu" :
144+ self ._model = causal_model .base_model
145+ del causal_model
146+ if device == "mps" :
95147 self ._model .to (device )
96148 self ._model .eval ()
97- self .n_layers = self ._model .config .num_hidden_layers
98- self .hidden_dim = self ._model .config .hidden_size
99- return str (self ._model .device )
149+ model_config = getattr (self ._model .config , "text_config" , self ._model .config )
150+ if (
151+ model_config .num_hidden_layers != self ._expected_layers
152+ or model_config .hidden_size != self ._hidden_dim
153+ ):
154+ raise ValueError ("loaded encoder dimensions do not match checkpoint metadata" )
100155
101- def extract_batch (
102- self ,
103- prompts : list [str ],
104- * ,
105- chat_template_kwargs : dict [str , Any ] | None = None ,
106- extract_layers : list [int ] | str = "upper_half" ,
107- pooling_modes : list [str ] | None = None ,
108- batch_size : int = 4 ,
109- max_length : int = 2048 ,
110- ) -> dict [str , Any ]:
111- """Extract pooled hidden states using the blueprint's direct indexing."""
156+ def forward (self , prompts : list [str ], batch_size : int , max_length : int ) -> bytes :
157+ """Return a row-major F32 probability matrix for ordered prompts."""
112158 self ._ensure_loaded ()
159+ if not prompts or any (not prompt for prompt in prompts ):
160+ raise ValueError ("prompts must be non-empty" )
161+ if batch_size <= 0 or max_length <= 0 :
162+ raise ValueError ("batch_size and max_length must be positive" )
113163
114- if extract_layers == "all" :
115- layers = list (range (self .n_layers ))
116- elif extract_layers == "upper_half" :
117- layers = list (range (self .n_layers // 2 , self .n_layers ))
118- elif isinstance (extract_layers , list ):
119- layers = [int (layer ) for layer in extract_layers ]
120- else :
121- raise ValueError (f"Unsupported layer selection: { extract_layers } " )
122- if not layers :
123- raise ValueError ("extract_layers resolved to an empty list" )
124- invalid = [layer for layer in layers if layer < 0 or layer >= self .n_layers ]
125- if invalid :
126- raise ValueError (
127- f"Requested indexes { invalid } are outside hidden-state range 0..{ self .n_layers - 1 } "
164+ formatted = [
165+ self ._tokenizer .apply_chat_template (
166+ [{"role" : "user" , "content" : prompt }],
167+ tokenize = False ,
168+ add_generation_prompt = True ,
128169 )
129-
130- pools = {"last" , "mean" } if pooling_modes is None else set (pooling_modes )
131- unknown_pools = pools - {"last" , "mean" }
132- if unknown_pools :
133- raise ValueError (f"Unknown pooling modes: { sorted (unknown_pools )} " )
134- if not pools :
135- raise ValueError ("At least one pooling mode is required" )
136-
137- template_kwargs = chat_template_kwargs or {}
138- conversations = [[{"role" : "user" , "content" : prompt }] for prompt in prompts ]
139- formatted = self ._tokenizer .apply_chat_template (
140- conversations ,
141- tokenize = False ,
142- add_generation_prompt = True ,
143- ** template_kwargs ,
144- )
145- all_last = {layer : [] for layer in layers } if "last" in pools else {}
146- all_mean = {layer : [] for layer in layers } if "mean" in pools else {}
147-
148- for batch_start in range (0 , len (formatted ), batch_size ):
170+ for prompt in prompts
171+ ]
172+ predictions = []
173+ for start in range (0 , len (formatted ), batch_size ):
149174 inputs = self ._tokenizer (
150- formatted [batch_start : batch_start + batch_size ],
175+ formatted [start : start + batch_size ],
151176 return_tensors = "pt" ,
152177 padding = True ,
153178 truncation = True ,
154179 max_length = max_length ,
155180 )
156181 input_ids = inputs ["input_ids" ].to (self ._model .device )
157182 attention_mask = inputs ["attention_mask" ].to (self ._model .device )
158-
159183 with self ._torch .inference_mode ():
160184 outputs = self ._model (
161185 input_ids = input_ids ,
@@ -164,45 +188,74 @@ def extract_batch(
164188 use_cache = False ,
165189 )
166190
167- hidden_states = outputs .hidden_states
168- token_mask = attention_mask .bool ()
169- token_count = token_mask .sum (dim = 1 , keepdim = True )
170- positions = self ._torch .arange (token_mask .shape [1 ], device = token_mask .device ).expand_as (
171- token_mask
191+ layers = []
192+ for layer in self ._selected_layers :
193+ hidden = outputs .hidden_states [layer ].float ()
194+ # The checkpoint consumes the last real token from each selected layer.
195+ token_mask = attention_mask .to (hidden .device ).bool ()
196+ positions = self ._torch .arange (hidden .shape [1 ], device = hidden .device )
197+ last_token = (
198+ positions .expand_as (token_mask ).masked_fill (~ token_mask , - 1 ).max (dim = 1 ).values
199+ )
200+ pooled = hidden [
201+ self ._torch .arange (hidden .shape [0 ], device = hidden .device ), last_token
202+ ]
203+ layers .append (pooled .cpu ().numpy ())
204+ predictions .append (self ._predict (layers ))
205+
206+ return self ._numpy .ascontiguousarray (
207+ self ._numpy .concatenate (predictions , axis = 0 ), dtype = self ._numpy .float32
208+ ).tobytes ()
209+
210+ def _predict (self , layers : list [Any ]) -> Any :
211+ np = self ._numpy
212+ torch = self ._torch
213+ stacked = np .stack (layers )
214+ if stacked .ndim != 3 or stacked .shape [0 ] != len (self ._selected_layers ):
215+ raise ValueError ("encoder returned invalid selected-layer features" )
216+ standardized = (stacked - self ._layer_mean [:, None , :]) / self ._layer_std [:, None , :]
217+ pooled = standardized .mean (axis = 0 )
218+ scaled = (pooled - self ._scaler_mean ) / self ._scaler_scale
219+ features = torch .from_numpy (
220+ np .ascontiguousarray (
221+ (scaled - self ._pca_mean ) @ self ._pca_components .T ,
222+ dtype = np .float32 ,
172223 )
173- last_index = positions .masked_fill (~ token_mask , - 1 ).max (dim = 1 ).values
174- batch_index = self ._torch .arange (token_mask .shape [0 ], device = token_mask .device )
175-
176- for layer in layers :
177- hidden = hidden_states [layer ].float ()
178- if "last" in pools :
179- all_last [layer ].append (hidden [batch_index , last_index ].cpu ())
180- if "mean" in pools :
181- masked = hidden .masked_fill (~ token_mask .unsqueeze (- 1 ), 0 )
182- all_mean [layer ].append ((masked .sum (dim = 1 ) / token_count ).cpu ())
183-
184- del outputs , hidden_states , input_ids , attention_mask
185-
186- return {
187- "hidden_last" : {
188- layer : self ._torch .cat (rows ).contiguous ().numpy ().tobytes ()
189- for layer , rows in all_last .items ()
190- },
191- "hidden_mean" : {
192- layer : self ._torch .cat (rows ).contiguous ().numpy ().tobytes ()
193- for layer , rows in all_mean .items ()
194- },
195- "n_layers" : self .n_layers ,
196- "hidden_dim" : self .hidden_dim ,
197- }
224+ )
225+
226+ members = []
227+ with torch .inference_mode ():
228+ for state in self ._states :
229+ logits = []
230+ for index in range (len (self ._models )):
231+ adapter = torch .nn .functional .relu (
232+ torch .nn .functional .linear (
233+ features ,
234+ state [f"adapters.{ index } .weight" ],
235+ state [f"adapters.{ index } .bias" ],
236+ )
237+ )
238+ trunk = torch .nn .functional .relu (
239+ torch .nn .functional .linear (
240+ adapter ,
241+ state ["trunk.0.weight" ],
242+ state ["trunk.0.bias" ],
243+ )
244+ )
245+ logits .append (
246+ torch .nn .functional .linear (
247+ trunk ,
248+ state [f"heads.{ index } .weight" ],
249+ state [f"heads.{ index } .bias" ],
250+ )
251+ )
252+ members .append (torch .sigmoid (torch .cat (logits , dim = 1 )))
253+ return torch .stack (members ).mean (dim = 0 ).contiguous ().numpy ()
198254
199255 def unload (self ) -> None :
200256 self ._model = None
201257 self ._tokenizer = None
202- self .n_layers = 0
203- self .hidden_dim = 0
204- if self ._torch is not None :
205- if self ._torch .cuda .is_available ():
206- self ._torch .cuda .empty_cache ()
207- if hasattr (self ._torch , "mps" ) and self ._torch .backends .mps .is_available ():
208- self ._torch .mps .empty_cache ()
258+ if self ._torch .cuda .is_available ():
259+ self ._torch .cuda .empty_cache ()
260+ if hasattr (self ._torch , "mps" ) and self ._torch .backends .mps .is_available ():
261+ self ._torch .mps .empty_cache ()
0 commit comments