Darwin-397B-ZTC / handler.py
SeaWolf-AI's picture
VERITAS λΆ€μ°©: λ‹΅+λ§ˆμ§€λ§‰μΈ΅ 은닉 λ™μ‹œ λ°˜ν™˜ ν•Έλ“€λŸ¬
59cede3 verified
Raw
History Blame Contribute Delete
5.15 kB
# -*- coding: utf-8 -*-
"""VERITAS λΆ€μ°© ν•Έλ“€λŸ¬ β€” JGOS-398B-fp8 (9-νŒ€μž₯ 2026-09-17)
무엇을 ν•˜λ‚˜
ν•œ 번의 호좜둜 **λ‹΅κ³Ό 속 μ‹ ν˜Έλ₯Ό 같이** λŒλ €μ€€λ‹€.
속 μ‹ ν˜Έ = λ§ˆμ§€λ§‰ μΈ΅Β·λ§ˆμ§€λ§‰ ν† ν°μ˜ 은닉벑터(가곡 μ•ˆ 된 원본값).
이것이 VERITAS κ°€ μ½λŠ” λ°”λ‘œ κ·Έ 값이며, **토큰을 ν•œ κ°œλ„ 더 μ“°μ§€ μ•ŠλŠ”λ‹€**
(이미 κ³„μ‚°λœ 것을 κΊΌλ‚΄ 올 뿐이닀).
두 κ°€μ§€ λͺ¨λ“œ
mode="generate" : λ‹΅ 생성 + κ·Έ λ‹΅κΉŒμ§€ ν¬ν•¨ν•œ 은닉 (λ¬Έν•­ ν’€μ΄μš©)
mode="embed" : μ£Όμ–΄μ§„ κΈ€μžμ—΄μ˜ μ€λ‹‰λ§Œ (이미 뽑아 λ‘” 닡을 채점할 λ•Œ)
πŸ”΄ 규율
- 잘림(length)을 결과에 λ°˜λ“œμ‹œ ν‘œμ‹œν•œλ‹€. μžμ› μ†Œμ§„μ„ μ˜€λ‹΅μœΌλ‘œ μ„Έμ§€ μ•ŠκΈ° μœ„ν•΄μ„œλ‹€.
- 은닉은 μ •κ·œν™”ν•˜μ§€ μ•ŠλŠ”λ‹€. μ •κ·œν™”ν•˜λ©΄ VERITAS κ°€ μ“°λŠ” 크기 정보가 λ‚ μ•„κ°„λ‹€.
- 생성뢄이 reasoning μͺ½μœΌλ‘œ λΉ μ§€λŠ” ν…œν”Œλ¦Ώμ΄λ©΄ κ·Έκ²ƒκΉŒμ§€ 합쳐 λŒλ €μ€€λ‹€(버리지 μ•ŠλŠ”λ‹€).
"""
from __future__ import annotations
from typing import Any, Dict, List
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
class EndpointHandler:
def __init__(self, path: str = ""):
self.tok = AutoTokenizer.from_pretrained(path)
if self.tok.pad_token is None:
self.tok.pad_token = self.tok.eos_token
self.tok.padding_side = "left" # πŸ”΄ 디코더 λͺ¨λΈ 배치의 ν•„μˆ˜ 쑰건
self.model = AutoModelForCausalLM.from_pretrained(
path, dtype="auto", device_map="auto"
).eval()
cfg = self.model.config
cfg = cfg.get_text_config() if hasattr(cfg, "get_text_config") else cfg
self.n_layers = cfg.num_hidden_layers
# ---- λ‚΄λΆ€: λ§ˆμ§€λ§‰ μΈ΅Β·λ§ˆμ§€λ§‰ 토큰 은닉 ------------------------------
@torch.no_grad()
def _hidden(self, ids) -> List[List[float]]:
out = self.model(**ids, output_hidden_states=True, use_cache=False)
h = out.hidden_states[-1] # λ§ˆμ§€λ§‰ μΈ΅
mask = ids["attention_mask"]
last = mask.sum(dim=1) - 1 # μ’ŒνŒ¨λ”©μ΄λΌ μ‹€μ œ λ§ˆμ§€λ§‰ μœ„μΉ˜
picked = h[torch.arange(h.size(0), device=h.device), last, :]
return picked.float().cpu().tolist()
def __call__(self, data: Dict[str, Any]) -> Dict[str, Any]:
inputs = data.get("inputs")
if isinstance(inputs, str):
inputs = [inputs]
p = data.get("parameters") or {}
mode = p.get("mode", "generate")
# ── μ€λ‹‰λ§Œ ──────────────────────────────────────────────────
if mode == "embed":
ids = self.tok(inputs, return_tensors="pt", padding=True,
truncation=True, max_length=p.get("max_length", 32768))
ids = {k: v.to(self.model.device) for k, v in ids.items()}
return {"hidden": self._hidden(ids), "layer": self.n_layers,
"normalized": False}
# ── 생성 + 은닉 ─────────────────────────────────────────────
max_new = int(p.get("max_new_tokens", 16384))
n = int(p.get("n", 1))
temp = float(p.get("temperature", 0.0))
texts = []
for s in inputs:
if p.get("chat", True):
msgs = [{"role": "user", "content": s}]
kw = {}
if p.get("enable_thinking") is not None:
kw["enable_thinking"] = p["enable_thinking"]
try:
texts.append(self.tok.apply_chat_template(
msgs, tokenize=False, add_generation_prompt=True, **kw))
except TypeError:
texts.append(self.tok.apply_chat_template(
msgs, tokenize=False, add_generation_prompt=True))
else:
texts.append(s)
enc = self.tok(texts, return_tensors="pt", padding=True)
enc = {k: v.to(self.model.device) for k, v in enc.items()}
gen_kw = dict(max_new_tokens=max_new, pad_token_id=self.tok.pad_token_id)
if temp > 0:
gen_kw.update(do_sample=True, temperature=temp, num_return_sequences=n)
else:
gen_kw.update(do_sample=False)
with torch.no_grad():
g = self.model.generate(**enc, **gen_kw)
plen = enc["input_ids"].shape[1]
new = g[:, plen:]
outs = self.tok.batch_decode(new, skip_special_tokens=True)
ntok = (new != self.tok.pad_token_id).sum(dim=1).tolist()
# πŸ”΄ 잘림 ν‘œμ‹œ β€” μžμ› μ†Œμ§„μ„ μ˜€λ‹΅μœΌλ‘œ μ„Έμ§€ μ•ŠκΈ° μœ„ν•΄ 결과에 남긴닀
hit_cap = [int(t >= max_new - 2) for t in ntok]
att = torch.ones_like(g)
att[g == self.tok.pad_token_id] = 0
hid = self._hidden({"input_ids": g, "attention_mask": att})
return {"generated": outs, "hidden": hid, "n_tokens": ntok,
"hit_cap": hit_cap, "layer": self.n_layers, "normalized": False}