TiGa-RCE commited on
Commit
bc3f111
·
verified ·
1 Parent(s): 695f3b6

Add bounded ZeroGPU BF16 CUDA control

Browse files
Files changed (4) hide show
  1. README.md +12 -7
  2. __pycache__/app.cpython-313.pyc +0 -0
  3. app.py +143 -0
  4. requirements.txt +4 -0
README.md CHANGED
@@ -1,13 +1,18 @@
1
  ---
2
- title: Embedding Quantization Cuda Control
3
- emoji: 🏃
4
- colorFrom: gray
5
- colorTo: green
6
  sdk: gradio
7
- sdk_version: 6.20.0
8
- python_version: '3.12'
9
  app_file: app.py
10
  pinned: false
 
11
  ---
12
 
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
1
  ---
2
+ title: Embedding Quantization CUDA Control
3
+ emoji: 🔬
4
+ colorFrom: blue
5
+ colorTo: yellow
6
  sdk: gradio
7
+ sdk_version: 6.5.1
 
8
  app_file: app.py
9
  pinned: false
10
+ license: apache-2.0
11
  ---
12
 
13
+ # Embedding Quantization CUDA Control
14
+
15
+ A bounded ZeroGPU control lane for the matched local MLX embedding
16
+ quantization experiment. The first milestone reproduces the frozen
17
+ Qwen3-Embedding-0.6B BF16 vectors on CUDA and compares them with the saved MLX
18
+ BF16 vectors. CUDA results do not reproduce MLX/Metal performance.
__pycache__/app.cpython-313.pyc ADDED
Binary file (9.26 kB). View file
 
app.py ADDED
@@ -0,0 +1,143 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import time
6
+ from pathlib import Path
7
+
8
+ import gradio as gr
9
+ import numpy as np
10
+ import spaces
11
+ import torch
12
+ import torch.nn.functional as F
13
+ from transformers import AutoModel, AutoTokenizer
14
+
15
+
16
+ MODEL_PATH = Path("/models/qwen3-embedding-0.6b")
17
+ DATA_ROOT = Path(os.environ.get("REPRO_DATA_ROOT", "/data"))
18
+ INPUT_PATH = DATA_ROOT / "inputs/retrieval_pairs.json"
19
+ MLX_REFERENCE = DATA_ROOT / "local-reference/qwen3-embedding-0.6b/bf16.npz"
20
+ OUTPUT_DIR = DATA_ROOT / "cloud-results/qwen3-embedding-0.6b"
21
+ TASK = (
22
+ "Given a natural-language search query, retrieve the single passage "
23
+ "that best answers it"
24
+ )
25
+
26
+
27
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH, padding_side="left")
28
+ model = AutoModel.from_pretrained(
29
+ MODEL_PATH,
30
+ torch_dtype=torch.bfloat16,
31
+ trust_remote_code=True,
32
+ ).to("cuda").eval()
33
+
34
+
35
+ def detailed_instruction(query: str) -> str:
36
+ return f"Instruct: {TASK}\nQuery:{query}"
37
+
38
+
39
+ def encode(text: str) -> np.ndarray:
40
+ batch = tokenizer(text, return_tensors="pt", truncation=True, max_length=32768)
41
+ batch = {key: value.to("cuda") for key, value in batch.items()}
42
+ with torch.inference_mode():
43
+ output = model(**batch)
44
+ vector = F.normalize(output.last_hidden_state[:, -1, :].float(), p=2, dim=-1)
45
+ return vector[0].cpu().numpy()
46
+
47
+
48
+ def retrieval_metrics(queries: np.ndarray, documents: np.ndarray) -> tuple[dict, np.ndarray, np.ndarray]:
49
+ scores = queries @ documents.T
50
+ order = np.argsort(-scores, axis=1)
51
+ ranks = np.array([
52
+ int(np.where(order[index] == index)[0][0]) + 1
53
+ for index in range(len(queries))
54
+ ])
55
+ positive = np.diag(scores)
56
+ negative = scores.copy()
57
+ np.fill_diagonal(negative, -np.inf)
58
+ margins = positive - negative.max(axis=1)
59
+ return {
60
+ "pair_count": len(queries),
61
+ "top1": float(np.mean(ranks == 1)),
62
+ "recall_at_5": float(np.mean(ranks <= 5)),
63
+ "mrr": float(np.mean(1.0 / ranks)),
64
+ "mean_margin": float(margins.mean()),
65
+ "minimum_margin": float(margins.min()),
66
+ "mean_rank": float(ranks.mean()),
67
+ "worst_rank": int(ranks.max()),
68
+ }, scores, ranks
69
+
70
+
71
+ @spaces.GPU(duration=300)
72
+ def run_bf16_control() -> dict:
73
+ pairs = json.loads(INPUT_PATH.read_text())
74
+ query_texts = [detailed_instruction(item["query"]) for item in pairs]
75
+ document_texts = [item["document"] for item in pairs]
76
+
77
+ if torch.cuda.is_available():
78
+ torch.cuda.reset_peak_memory_stats()
79
+ torch.cuda.synchronize()
80
+ started = time.perf_counter()
81
+ queries = np.stack([encode(text) for text in query_texts])
82
+ documents = np.stack([encode(text) for text in document_texts])
83
+ if torch.cuda.is_available():
84
+ torch.cuda.synchronize()
85
+ elapsed = time.perf_counter() - started
86
+ metrics, scores, ranks = retrieval_metrics(queries, documents)
87
+ metrics.update({
88
+ "lane": "cuda-zerogpu-bf16",
89
+ "model": "Qwen/Qwen3-Embedding-0.6B",
90
+ "source_revision": "97b0c614be4d77ee51c0cef4e5f07c00f9eb65b3",
91
+ "elapsed_seconds": elapsed,
92
+ "texts_per_second": len(query_texts + document_texts) / elapsed,
93
+ "torch_version": torch.__version__,
94
+ "cuda_device": torch.cuda.get_device_name(0) if torch.cuda.is_available() else None,
95
+ "cuda_peak_bytes": torch.cuda.max_memory_allocated() if torch.cuda.is_available() else None,
96
+ })
97
+
98
+ comparison = None
99
+ if MLX_REFERENCE.exists():
100
+ reference = np.load(MLX_REFERENCE)
101
+ ref_all = np.concatenate([reference["queries"], reference["documents"]])
102
+ cuda_all = np.concatenate([queries, documents])
103
+ aligned = np.sum(ref_all * cuda_all, axis=1)
104
+ score_delta = scores - reference["scores"]
105
+ comparison = {
106
+ "mean_aligned_cosine_cuda_vs_mlx_bf16": float(aligned.mean()),
107
+ "minimum_aligned_cosine_cuda_vs_mlx_bf16": float(aligned.min()),
108
+ "score_rmse_cuda_vs_mlx_bf16": float(np.sqrt(np.mean(score_delta ** 2))),
109
+ "queries_with_rank_change": int(np.count_nonzero(ranks - reference["ranks"])),
110
+ }
111
+
112
+ result = {"metrics": metrics, "mlx_bf16_comparison": comparison}
113
+ OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
114
+ np.savez_compressed(
115
+ OUTPUT_DIR / "cuda-bf16.npz",
116
+ queries=queries,
117
+ documents=documents,
118
+ scores=scores,
119
+ ranks=ranks,
120
+ metrics=np.array(json.dumps(metrics)),
121
+ )
122
+ (OUTPUT_DIR / "cuda-bf16.json").write_text(json.dumps(result, indent=2) + "\n")
123
+ return result
124
+
125
+
126
+ with gr.Blocks() as demo:
127
+ gr.Markdown(
128
+ "# Embedding Quantization CUDA Control\n"
129
+ "Runs one bounded 48-text BF16 control and writes the result to the attached private bucket. "
130
+ "The requested GPU duration is capped at five minutes."
131
+ )
132
+ run_button = gr.Button("Run 0.6B BF16 CUDA control", variant="primary")
133
+ output = gr.JSON(label="Result")
134
+ run_button.click(
135
+ fn=run_bf16_control,
136
+ outputs=output,
137
+ concurrency_limit=1,
138
+ api_name="run_bf16_control",
139
+ )
140
+
141
+
142
+ if __name__ == "__main__":
143
+ demo.queue(default_concurrency_limit=1).launch()
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ transformers>=4.51,<5
2
+ numpy>=2,<3
3
+ spaces>=0.45
4
+ torch>=2.8