File size: 4,739 Bytes
7845694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env python3
"""
SemIf ๋ฅผ ์ด Linux CPU PC์—์„œ ๋กœ์ปฌ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ์–‡์€ shim.

SemIf( github.com/TheoLeeCJ/SemIf )์˜ ์œ ์ผํ•œ GPU ๊ฐ•์ œ ์ง€์ ์€
core.load_causal_model() ๋ฟ์ด๋‹ค. ์Šค์ฝ”์–ด๋ง ๋กœ์ง(direct.score / shared.score_shared)์€
device = next(model.parameters()).device ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฏ€๋กœ CPU์—์„œ ๊ทธ๋Œ€๋กœ ๋™์ž‘ํ•œ๋‹ค.
์—ฌ๊ธฐ์„œ๋Š” CUDA ๋กœ๋” ๋Œ€์‹  CPU(float32) ๋กœ๋”๋ฅผ ์จ์„œ ๋ชจ๋ธ์„ ์˜ฌ๋ฆฌ๊ณ ,
SemIf ์˜ ์‹ค์ œ direct.score() ๋ฅผ ํ˜ธ์ถœํ•ด '์˜ต์…˜ ํ™•๋ฅ (semantic if)'์„ ์ฝ๋Š”๋‹ค.

์ „์ œ:
  - SemIf ์ €์žฅ์†Œ๊ฐ€ /tmp/SemIf ์— clone ๋˜์–ด ์žˆ์Œ (SEMIF_DIR ๋กœ ๋ณ€๊ฒฝ ๊ฐ€๋Šฅ)
  - pip install torch transformers accelerate  (CPU)

์‚ฌ์šฉ:
  python semif_cpu.py
"""
import os
import sys
import time

# SemIf ์†Œ์Šค ์œ„์น˜ ํƒ์ง€: 1) SEMIF_DIR ํ™˜๊ฒฝ๋ณ€์ˆ˜, 2) ์ด ํŒŒ์ผ๊ณผ ๊ฐ™์€ ๋ ˆํฌ์˜ ./src,
# 3) /tmp/SemIf (๊ฐœ๋ฐœ์šฉ clone). ์ฒ˜์Œ ๋ฐœ๊ฒฌ๋˜๋Š” ๊ณณ์„ ์‚ฌ์šฉํ•œ๋‹ค.
_HERE = os.path.dirname(os.path.abspath(__file__))
_CANDIDATES = [
    os.environ.get("SEMIF_DIR"),
    _HERE,                # ๋ ˆํฌ ๋ฃจํŠธ์— src/semif_phase1 ์ด ์žˆ๋Š” ๊ฒฝ์šฐ (JEV-CPU)
    "/tmp/SemIf",         # ๊ฐœ๋ฐœ์šฉ clone
]
for _base in _CANDIDATES:
    if _base and os.path.isdir(os.path.join(_base, "src", "semif_phase1")):
        SEMIF_DIR = _base
        break
else:
    raise RuntimeError(
        "SemIf ์†Œ์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. SEMIF_DIR ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•˜์„ธ์š” "
        "(src/semif_phase1 ๋ฅผ ํฌํ•จํ•ด์•ผ ํ•จ)."
    )
sys.path.insert(0, os.path.join(SEMIF_DIR, "src"))

import torch
import transformers
from semif_phase1.direct import score as direct_score


# openjev.com/SemIf ๊ฐ€ ์“ฐ๋Š” ๊ฐ€์žฅ ์ž‘์€ ๋ชจ๋ธ. ์›๊ฒฉ ๋กœ๋“œ๋Š” 40์ž ์ปค๋ฐ‹ revision ์„ ์š”๊ตฌํ•œ๋‹ค.
MODEL = "Qwen/Qwen3-0.6B"
REVISION = os.environ.get("QWEN_REV", "main")  # ํ•„์š”์‹œ 40์ž ์ปค๋ฐ‹ ํ•ด์‹œ๋กœ ๊ณ ์ •


def load_causal_model_cpu(source: str, revision: str):
    """core.load_causal_model ์˜ CPU ๋ฒ„์ „ (CUDA ๊ฒ€์‚ฌ/ device_map ์ œ๊ฑฐ)."""
    common = {"trust_remote_code": False}
    if revision and revision != "main":
        common["revision"] = revision
    config = transformers.AutoConfig.from_pretrained(source, **common)
    tokenizer = transformers.AutoTokenizer.from_pretrained(source, **common)
    model = transformers.AutoModelForCausalLM.from_pretrained(
        source,
        config=config,
        dtype=torch.float32,      # CPU ์•ˆ์ •์„ฑ ์šฐ์„ 
        low_cpu_mem_usage=True,
        **common,
    )
    model.eval()
    metadata = {
        "source": source,
        "revision": revision,
        "dtype": "float32",
        "device": "cpu",
        "torch_version": torch.__version__,
        "transformers_version": transformers.__version__,
    }
    return model, tokenizer, metadata


def main():
    print(f"[load] {MODEL} @ {REVISION}  (CPU / float32)")
    t0 = time.time()
    model, tokenizer, meta = load_causal_model_cpu(MODEL, REVISION)
    print(f"[load] done in {time.time()-t0:.1f}s "
          f"(params={sum(p.numel() for p in model.parameters())/1e9:.2f}B, "
          f"transformers={transformers.__version__})")

    # SemIf ์˜ ๊ฒฐ์ •(row) ์Šคํ‚ค๋งˆ: state(์ฆ๊ฑฐ) + question(๊ธฐ์ค€) + options(2~16๊ฐœ)
    rows = [
        {
            "id": "sentiment",
            "state": "๋ฐฐ์†ก์ด 3์ผ์ด๋‚˜ ๋Šฆ์—ˆ๊ณ  ๊ณ ๊ฐ์„ผํ„ฐ๋Š” ์—ฐ๊ฒฐ๋„ ์•ˆ ๋์–ด์š”. ์ •๋ง ์‹ค๋ง์ž…๋‹ˆ๋‹ค.",
            "question": "Classify the customer's sentiment.",
            "options": [
                {"id": "positive", "description": "Positive / satisfied"},
                {"id": "neutral", "description": "Neutral"},
                {"id": "negative", "description": "Negative / dissatisfied"},
            ],
        },
        {
            "id": "route",
            "state": "I was double charged and need a refund before Friday.",
            "question": "Which team should handle this ticket?",
            "options": [
                {"id": "billing", "description": "Billing / payments"},
                {"id": "tech", "description": "Technical support"},
                {"id": "sales", "description": "Sales"},
            ],
        },
    ]

    for row in rows:
        print(f"\n=== decision: {row['id']} ===")
        r = direct_score(model, tokenizer, row, meta)
        pairs = sorted(zip(r["option_ids"], r["probabilities"]),
                       key=lambda x: -x[1])
        winner = pairs[0][0]
        print(f"  โ†’ ์„ ํƒ: {winner}")
        for oid, p in pairs:
            bar = "โ–ˆ" * int(p * 30)
            print(f"    {oid:10s} {p*100:5.1f}%  {bar}")
        print(f"  (forward {r['forward_seconds']:.1f}s, {r['input_tokens']} tok, "
              f"readout: {r['readout']})")


if __name__ == "__main__":
    main()