asdf98 commited on
Commit
e689e18
·
verified ·
1 Parent(s): 679bd14

Add standalone inference notebook cell

Browse files
Files changed (1) hide show
  1. INFERENCE_CELL.md +161 -0
INFERENCE_CELL.md ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Standalone Inference Cell
2
+
3
+ Paste this as the **last cell** in Kaggle/Colab after training, or run it in a fresh notebook. It is independent of previous training cells.
4
+
5
+ ## Configure paths
6
+
7
+ Set:
8
+
9
+ ```python
10
+ BASE_MODEL_ID = "LiquidAI/LFM2.5-1.2B-Instruct"
11
+ ADAPTER_PATH = "./lfm25-stable-qlora-cybersecurity-adapter"
12
+ ```
13
+
14
+ For Unsloth-trained adapters, examples:
15
+
16
+ ```python
17
+ BASE_MODEL_ID = "unsloth/LFM2.5-1.2B-Instruct"
18
+ ADAPTER_PATH = "./lfm25-lora-adapter"
19
+ ```
20
+
21
+ ```python
22
+ BASE_MODEL_ID = "unsloth/Qwen3-4B-Instruct-2507-unsloth-bnb-4bit"
23
+ ADAPTER_PATH = "./qwen3-lora-adapter"
24
+ ```
25
+
26
+ If you pushed adapter to Hub:
27
+
28
+ ```python
29
+ ADAPTER_PATH = "your-username/your-adapter-repo"
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Complete independent cell
35
+
36
+ ```python
37
+ # ============================================================
38
+ # Standalone LoRA Adapter Inference / Chat Cell
39
+ # Works in fresh Kaggle/Colab notebook too.
40
+ # ============================================================
41
+ !pip install -q -U "transformers>=4.56.0" "peft>=0.18.0" "accelerate>=1.0.0" "bitsandbytes>=0.45.0" "huggingface_hub>=0.25.0"
42
+
43
+ import torch
44
+ from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
45
+ from peft import PeftModel
46
+
47
+ # -------------------- CONFIG --------------------
48
+ # Use the SAME base model used during training.
49
+ BASE_MODEL_ID = "LiquidAI/LFM2.5-1.2B-Instruct"
50
+
51
+ # Local adapter folder OR HF repo id.
52
+ # Common local paths:
53
+ # ./lfm25-lora-adapter
54
+ # ./qwen3-lora-adapter
55
+ # ./gemma4-lora-adapter
56
+ # ./lfm25-stable-qlora-cybersecurity-adapter
57
+ ADAPTER_PATH = "./lfm25-stable-qlora-cybersecurity-adapter"
58
+
59
+ LOAD_IN_4BIT = True
60
+ MAX_NEW_TOKENS = 512
61
+ TEMPERATURE = 0.7
62
+ TOP_P = 0.9
63
+ SYSTEM_PROMPT = "You are a helpful assistant. For cybersecurity topics, provide ethical, defensive, authorized guidance only."
64
+ # ------------------------------------------------
65
+
66
+ compute_dtype = torch.float16
67
+
68
+ bnb_config = None
69
+ if LOAD_IN_4BIT:
70
+ bnb_config = BitsAndBytesConfig(
71
+ load_in_4bit=True,
72
+ bnb_4bit_quant_type="nf4",
73
+ bnb_4bit_use_double_quant=True,
74
+ bnb_4bit_compute_dtype=compute_dtype,
75
+ )
76
+
77
+ print("Loading tokenizer...")
78
+ tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL_ID, trust_remote_code=True, use_fast=True)
79
+ if tokenizer.pad_token is None:
80
+ tokenizer.pad_token = tokenizer.eos_token
81
+ tokenizer.padding_side = "right"
82
+
83
+ print("Loading base model...")
84
+ base_model = AutoModelForCausalLM.from_pretrained(
85
+ BASE_MODEL_ID,
86
+ quantization_config=bnb_config,
87
+ device_map="auto",
88
+ trust_remote_code=True,
89
+ low_cpu_mem_usage=True,
90
+ )
91
+
92
+ print("Loading LoRA adapter...")
93
+ model = PeftModel.from_pretrained(base_model, ADAPTER_PATH, is_trainable=False)
94
+ model.eval()
95
+
96
+ if torch.cuda.is_available():
97
+ print(f"VRAM loaded: {torch.cuda.memory_allocated()/1e9:.2f} GB / {torch.cuda.get_device_properties(0).total_memory/1e9:.2f} GB")
98
+ print("✅ Model + adapter ready")
99
+
100
+
101
+ def build_prompt(messages):
102
+ try:
103
+ return tokenizer.apply_chat_template(
104
+ messages,
105
+ tokenize=False,
106
+ add_generation_prompt=True,
107
+ )
108
+ except Exception:
109
+ text = ""
110
+ for m in messages:
111
+ text += f"<{m['role']}>\n{m['content']}\n</{m['role']}>\n"
112
+ text += "<assistant>\n"
113
+ return text
114
+
115
+
116
+ def ask(prompt, history=None):
117
+ if history is None:
118
+ history = [{"role": "system", "content": SYSTEM_PROMPT}]
119
+ messages = history + [{"role": "user", "content": prompt}]
120
+ full_prompt = build_prompt(messages)
121
+ inputs = tokenizer(full_prompt, return_tensors="pt").to(model.device)
122
+ with torch.no_grad():
123
+ output = model.generate(
124
+ **inputs,
125
+ max_new_tokens=MAX_NEW_TOKENS,
126
+ do_sample=True,
127
+ temperature=TEMPERATURE,
128
+ top_p=TOP_P,
129
+ pad_token_id=tokenizer.pad_token_id,
130
+ eos_token_id=tokenizer.eos_token_id,
131
+ )
132
+ new_tokens = output[0][inputs["input_ids"].shape[1]:]
133
+ reply = tokenizer.decode(new_tokens, skip_special_tokens=True).strip()
134
+ return reply
135
+
136
+ # Single test prompt
137
+ reply = ask("Explain how parameterized queries prevent SQL injection with a safe Python example.")
138
+ print("Assistant:\n", reply)
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Optional interactive chat loop
144
+
145
+ Run this after the cell above:
146
+
147
+ ```python
148
+ history = [{"role": "system", "content": SYSTEM_PROMPT}]
149
+
150
+ while True:
151
+ user = input("You: ").strip()
152
+ if user.lower() in {"exit", "quit", "q"}:
153
+ break
154
+ if not user:
155
+ continue
156
+
157
+ reply = ask(user, history)
158
+ print("Assistant:", reply, "\n")
159
+ history.append({"role": "user", "content": user})
160
+ history.append({"role": "assistant", "content": reply})
161
+ ```