Alex W. commited on
Commit
f56c2df
ยท
1 Parent(s): 357d754

add function to wright analyze result into sqlite.

Browse files
Files changed (1) hide show
  1. ui/tab_analyze.py +115 -18
ui/tab_analyze.py CHANGED
@@ -4,15 +4,16 @@ Tab2๏ผšๅˆ†ๆžๅ•ไธชๆจกๅž‹
4
  - ไฝฟ็”จ LayerProfile ่‡ชๅŠจๆŽจๆ–ญ็ป“ๆž„
5
  - start_layer / end_layer ๆŒ‰ๅŽŸๅง‹ๅฑ‚ๅท่ฟ‡ๆปค
6
  - ้€ๅคด่ฎก็ฎ—ไบ”ๅฎšๅพ‹ๅ…จๆŒ‡ๆ ‡
7
- - ็ป“ๆžœๅ†™ๅ…ฅ SQLite๏ผˆPhase 2 ๅฎŒๆˆๅŽๆŽฅๅ…ฅ๏ผ‰
8
  """
9
 
10
  import gradio as gr
11
  import requests
12
  import pandas as pd
13
  import numpy as np
14
- from core.debug import dlog
15
 
 
16
  from core.fetcher import (
17
  load_all_shard_headers,
18
  load_tensor_remote,
@@ -26,6 +27,16 @@ from core.layer_profile import (
26
  )
27
  from core.metrics import analyze_layer, summarize_records
28
 
 
 
 
 
 
 
 
 
 
 
29
 
30
  SIDEBAR_MD = """
31
  ### โœ… ๆŽจ่ๆจกๅž‹
@@ -36,7 +47,6 @@ Qwen/Qwen2.5-14B-Instruct
36
  deepseek-ai/DeepSeek-R1-Distill-Qwen-14B
37
  meta-llama/Meta-Llama-3-8B
38
 
39
-
40
  ### ๅฑ‚ๅท่ฏดๆ˜Ž
41
  - ๅฑ‚ๅท = safetensors key ไธญ `layers.{N}` ็š„ **N**
42
  - **ไธๆŒ‰็ป„ไปถ้‡ๆŽ’**๏ผŒๅŽŸๅง‹ๅ€ผ็›ดๆŽฅ่พ“ๅ‡บ
@@ -74,12 +84,17 @@ def run_analysis(
74
  token = hf_token.strip() or None
75
  start_l = int(start_layer)
76
  end_l = int(end_layer)
77
- log = [
 
 
78
  f"๐Ÿ” ๅˆ†ๆž๏ผš{model_id} ๅฑ‚ {start_l}~{end_l}\n"
79
  f"{'โ•'*80}\n"
80
  ]
81
  all_records: list[dict] = []
82
 
 
 
 
83
  # โ”€โ”€ ้‡ๅŒ–ๆฃ€ๆต‹ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
84
  progress(0.02, desc="้‡ๅŒ–ๆฃ€ๆต‹...")
85
  blocked, qmsg = check_quantization(model_id, token)
@@ -90,6 +105,7 @@ def run_analysis(
90
  # โ”€โ”€ config.json โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
91
  progress(0.05, desc="่ฏปๅ– config...")
92
  config_params = {}
 
93
  try:
94
  r = requests.get(
95
  f"https://huggingface.co/{model_id}/resolve/main/config.json",
@@ -97,7 +113,8 @@ def run_analysis(
97
  timeout=15
98
  )
99
  if r.status_code == 200:
100
- config_params = extract_config_params(r.json())
 
101
  log.append(
102
  f"๐Ÿ“‹ config๏ผšmodel_type={config_params.get('model_type')} "
103
  f"head_dim={config_params.get('head_dim')}\n"
@@ -106,6 +123,10 @@ def run_analysis(
106
  except Exception:
107
  log.append("โš ๏ธ ๆ— ๆณ•่ฏปๅ– config.json\n")
108
 
 
 
 
 
109
  # โ”€โ”€ ่ฏปๅ–ๆ‰€ๆœ‰ shard headers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
110
  progress(0.08, desc="่ฏปๅ– shard headers...")
111
  try:
@@ -127,6 +148,34 @@ def run_analysis(
127
  if not profiles:
128
  return "".join(log) + "โš ๏ธ ๆœชๅ‘็Žฐไปปไฝ• Q/K/V ๅฑ‚\n", None
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  # โ”€โ”€ ๆŒ‰ๅŽŸๅง‹ๅฑ‚ๅท่ฟ‡ๆปค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
131
  filtered = {
132
  (pfx, idx): prof
@@ -135,13 +184,12 @@ def run_analysis(
135
  }
136
 
137
  if not filtered:
138
- # ๆ‰“ๅฐๅฎž้™…ๅฑ‚ๅทไพ›ๅ‚่€ƒ
139
- by_pfx: dict[str, list] = {}
140
  for (pfx, idx) in profiles:
141
- by_pfx.setdefault(pfx, []).append(idx)
142
  info = "\n".join(
143
  f" '{p}': {sorted(v)}"
144
- for p, v in sorted(by_pfx.items())
145
  )
146
  return (
147
  "".join(log) +
@@ -149,26 +197,50 @@ def run_analysis(
149
  f"ๅฎž้™…ๅฑ‚ๅท๏ผš\n{info}\n", None
150
  )
151
 
152
- # ๆ‰“ๅฐๅฐ†ๅˆ†ๆž็š„ๅฑ‚
 
 
 
 
 
 
153
  by_pfx2: dict[str, list] = {}
154
  for (pfx, idx) in filtered:
155
  by_pfx2.setdefault(pfx, []).append(idx)
156
- log.append(f"๐Ÿ“ ๅฐ†ๅˆ†ๆž๏ผš\n")
 
 
157
  for pfx, idxs in sorted(by_pfx2.items()):
158
- log.append(f" '{pfx}' โ†’ ๅฑ‚ {sorted(idxs)}\n")
 
 
 
 
 
 
 
159
  log.append(f"{'โ•'*80}\n")
160
 
 
 
 
161
  # โ”€โ”€ ้€ๅฑ‚ๅˆ†ๆž โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
162
  sorted_items = sorted(filtered.items(), key=lambda x: (x[0][0], x[0][1]))
163
  total = len(sorted_items)
164
 
165
  for i, ((pfx, idx), prof) in enumerate(sorted_items):
 
 
 
 
 
 
166
  progress(
167
  0.15 + 0.80 * i / max(total, 1),
168
  desc=f"{pfx.split('.')[-2] if '.' in pfx else pfx} L{idx}..."
169
  )
170
 
171
- # ๅŠ ่ฝฝ Q/K/V
172
  try:
173
  q_url = get_file_url(model_id, prof.q.shard)
174
  k_url = get_file_url(model_id, prof.k.shard)
@@ -190,7 +262,6 @@ def run_analysis(
190
  W_k = load_tensor_remote(k_url, prof.k.key, k_hdr, k_hs, token)
191
 
192
  if prof.kv_shared:
193
- # K=V ๅ…ฑไบซ๏ผš็›ดๆŽฅๅค็”จ
194
  W_v = W_k.clone()
195
  else:
196
  v_url = get_file_url(model_id, prof.v.shard)
@@ -205,22 +276,47 @@ def run_analysis(
205
  log.append(f"[{pfx}] Layer {idx}: โš ๏ธ tensor ไธบ None\n")
206
  continue
207
 
208
- # ่ฎก็ฎ—ไบ”ๅฎšๅพ‹
209
  try:
210
  records, layer_log = analyze_layer(W_q, W_k, W_v, prof)
211
  all_records.extend(records)
212
  log.append(layer_log)
 
 
 
 
 
 
 
 
 
 
 
213
  except Exception as e:
214
  log.append(f"[{pfx}] Layer {idx}: โŒ ่ฎก็ฎ—ๅคฑ่ดฅ๏ผš{e}\n")
215
  finally:
216
  del W_q, W_k, W_v
217
 
 
 
 
 
 
 
 
 
218
  # โ”€โ”€ ๆฑ‡ๆ€ป โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
219
  if not all_records:
220
- return "".join(log) + "\nโŒ ๆœช่Žทๅพ—ไปปไฝ•ๆœ‰ๆ•ˆ็ป“ๆžœ\n", None
 
 
 
 
 
221
 
222
  summary = summarize_records(all_records, model_id)
223
  log.append(summary)
 
224
 
225
  df = pd.DataFrame(all_records)
226
  return "".join(log), df
@@ -233,8 +329,9 @@ def run_analysis(
233
  def build_tab_analyze():
234
  with gr.Tab("๐Ÿ“Š ๅˆ†ๆž"):
235
  gr.Markdown("""
236
- **็ฌฌไบŒๆญฅ๏ผš้€‰ๆ‹ฉๅฑ‚่Œƒๅ›ด๏ผŒ่ฎก็ฎ—็Ž‹ๆฐไบ”ๅฎšๅพ‹ๅ…จๆŒ‡ๆ ‡**
237
- ๅฑ‚ๅท = safetensors key ไธญ `layers.{N}` ็š„ๅŽŸๅง‹ N๏ผŒK=V ๅ…ฑไบซๅฑ‚่‡ชๅŠจๅค„็†ใ€‚
 
238
  """)
239
 
240
  with gr.Row():
 
4
  - ไฝฟ็”จ LayerProfile ่‡ชๅŠจๆŽจๆ–ญ็ป“ๆž„
5
  - start_layer / end_layer ๆŒ‰ๅŽŸๅง‹ๅฑ‚ๅท่ฟ‡ๆปค
6
  - ้€ๅคด่ฎก็ฎ—ไบ”ๅฎšๅพ‹ๅ…จๆŒ‡ๆ ‡
7
+ - ็ป“ๆžœๅ†™ๅ…ฅ SQLite๏ผˆๆ–ญ็‚น็ปญไผ ๏ผŒไปฅ prefix+layer ไธบ็ฒ’ๅบฆ๏ผ‰
8
  """
9
 
10
  import gradio as gr
11
  import requests
12
  import pandas as pd
13
  import numpy as np
14
+ from datetime import datetime
15
 
16
+ from core.debug import dlog
17
  from core.fetcher import (
18
  load_all_shard_headers,
19
  load_tensor_remote,
 
27
  )
28
  from core.metrics import analyze_layer, summarize_records
29
 
30
+ from db.schema import init_db
31
+ from db.writer import (
32
+ upsert_model,
33
+ upsert_component,
34
+ write_layer_records,
35
+ update_model_summary,
36
+ get_analyzed_layers,
37
+ is_layer_complete,
38
+ infer_layer_type,
39
+ )
40
 
41
  SIDEBAR_MD = """
42
  ### โœ… ๆŽจ่ๆจกๅž‹
 
47
  deepseek-ai/DeepSeek-R1-Distill-Qwen-14B
48
  meta-llama/Meta-Llama-3-8B
49
 
 
50
  ### ๅฑ‚ๅท่ฏดๆ˜Ž
51
  - ๅฑ‚ๅท = safetensors key ไธญ `layers.{N}` ็š„ **N**
52
  - **ไธๆŒ‰็ป„ไปถ้‡ๆŽ’**๏ผŒๅŽŸๅง‹ๅ€ผ็›ดๆŽฅ่พ“ๅ‡บ
 
84
  token = hf_token.strip() or None
85
  start_l = int(start_layer)
86
  end_l = int(end_layer)
87
+ t_start = datetime.utcnow()
88
+
89
+ log = [
90
  f"๐Ÿ” ๅˆ†ๆž๏ผš{model_id} ๅฑ‚ {start_l}~{end_l}\n"
91
  f"{'โ•'*80}\n"
92
  ]
93
  all_records: list[dict] = []
94
 
95
+ # โ”€โ”€ ๅˆๅง‹ๅŒ–ๆ•ฐๆฎๅบ“่ฟžๆŽฅ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
96
+ conn = init_db()
97
+
98
  # โ”€โ”€ ้‡ๅŒ–ๆฃ€ๆต‹ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
99
  progress(0.02, desc="้‡ๅŒ–ๆฃ€ๆต‹...")
100
  blocked, qmsg = check_quantization(model_id, token)
 
105
  # โ”€โ”€ config.json โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
106
  progress(0.05, desc="่ฏปๅ– config...")
107
  config_params = {}
108
+ config_raw = {}
109
  try:
110
  r = requests.get(
111
  f"https://huggingface.co/{model_id}/resolve/main/config.json",
 
113
  timeout=15
114
  )
115
  if r.status_code == 200:
116
+ config_raw = r.json()
117
+ config_params = extract_config_params(config_raw)
118
  log.append(
119
  f"๐Ÿ“‹ config๏ผšmodel_type={config_params.get('model_type')} "
120
  f"head_dim={config_params.get('head_dim')}\n"
 
123
  except Exception:
124
  log.append("โš ๏ธ ๆ— ๆณ•่ฏปๅ– config.json\n")
125
 
126
+ # โ”€โ”€ ๅ†™ๅ…ฅๆจกๅž‹ๅ…ƒๆ•ฐๆฎ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
127
+ model_type = config_params.get("model_type", "unknown")
128
+ upsert_model(conn, model_id, model_type=model_type)
129
+
130
  # โ”€โ”€ ่ฏปๅ–ๆ‰€ๆœ‰ shard headers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
131
  progress(0.08, desc="่ฏปๅ– shard headers...")
132
  try:
 
148
  if not profiles:
149
  return "".join(log) + "โš ๏ธ ๆœชๅ‘็Žฐไปปไฝ• Q/K/V ๅฑ‚\n", None
150
 
151
+ # โ”€โ”€ ๆŒ‰็ป„ไปถๅ†™ๅ…ฅ components ่กจ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
152
+ # ๆŒ‰ prefix ๅˆ†็ป„๏ผŒ็ปŸ่ฎก็ป„ไปถไฟกๆฏ
153
+ by_prefix: dict[str, list] = {}
154
+ for (pfx, idx), prof in profiles.items():
155
+ by_prefix.setdefault(pfx, []).append(prof)
156
+
157
+ for pfx, profs in by_prefix.items():
158
+ complete_profs = [p for p in profs if p.complete]
159
+ if not complete_profs:
160
+ continue
161
+
162
+ head_dims = [p.head_dim for p in complete_profs]
163
+ has_shared = any(p.kv_shared for p in complete_profs)
164
+ has_global = has_shared # kv_shared=True โ†’ global ๅฑ‚
165
+ d_models = [p.d_model for p in complete_profs if p.d_model > 0]
166
+
167
+ upsert_component(
168
+ conn = conn,
169
+ model_id = model_id,
170
+ prefix = pfx,
171
+ n_layers = len(complete_profs),
172
+ head_dim_min = min(head_dims),
173
+ head_dim_max = max(head_dims),
174
+ has_kv_shared= has_shared,
175
+ has_global = has_global,
176
+ d_model = d_models[0] if d_models else 0,
177
+ )
178
+
179
  # โ”€โ”€ ๆŒ‰ๅŽŸๅง‹ๅฑ‚ๅท่ฟ‡ๆปค โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
180
  filtered = {
181
  (pfx, idx): prof
 
184
  }
185
 
186
  if not filtered:
187
+ by_pfx_all: dict[str, list] = {}
 
188
  for (pfx, idx) in profiles:
189
+ by_pfx_all.setdefault(pfx, []).append(idx)
190
  info = "\n".join(
191
  f" '{p}': {sorted(v)}"
192
+ for p, v in sorted(by_pfx_all.items())
193
  )
194
  return (
195
  "".join(log) +
 
197
  f"ๅฎž้™…ๅฑ‚ๅท๏ผš\n{info}\n", None
198
  )
199
 
200
+ # โ”€โ”€ ๆ–ญ็‚น็ปญไผ ๏ผšๆŸฅ่ฏขๅทฒๅฎŒๆˆๅฑ‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
201
+ # ๆŒ‰ prefix ๅˆ†ๅˆซๆŸฅ่ฏข
202
+ done_layers: dict[str, set] = {}
203
+ for pfx in set(pfx for pfx, _ in filtered):
204
+ done_layers[pfx] = get_analyzed_layers(conn, model_id, pfx)
205
+
206
+ # ๆ‰“ๅฐๅฐ†ๅˆ†ๆž็š„ๅฑ‚๏ผˆๅซๆ–ญ็‚น็ปญไผ ็Šถๆ€๏ผ‰
207
  by_pfx2: dict[str, list] = {}
208
  for (pfx, idx) in filtered:
209
  by_pfx2.setdefault(pfx, []).append(idx)
210
+
211
+ log.append("๐Ÿ“ ๅฐ†ๅˆ†ๆž๏ผš\n")
212
+ skipped_total = 0
213
  for pfx, idxs in sorted(by_pfx2.items()):
214
+ done = done_layers.get(pfx, set())
215
+ todo = [i for i in sorted(idxs) if i not in done]
216
+ skip = [i for i in sorted(idxs) if i in done]
217
+ skipped_total += len(skip)
218
+ log.append(f" '{pfx}'\n")
219
+ log.append(f" ๅพ…ๅˆ†ๆž๏ผš{todo}\n")
220
+ if skip:
221
+ log.append(f" ๅทฒ่ทณ่ฟ‡๏ผˆๆ–ญ็‚น็ปญไผ ๏ผ‰๏ผš{skip}\n")
222
  log.append(f"{'โ•'*80}\n")
223
 
224
+ if skipped_total > 0:
225
+ log.append(f"โšก ๆ–ญ็‚น็ปญไผ ๏ผš่ทณ่ฟ‡ {skipped_total} ๅฑ‚๏ผˆๅทฒๆœ‰ๆ•ฐๆฎ๏ผ‰\n")
226
+
227
  # โ”€โ”€ ้€ๅฑ‚ๅˆ†ๆž โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
228
  sorted_items = sorted(filtered.items(), key=lambda x: (x[0][0], x[0][1]))
229
  total = len(sorted_items)
230
 
231
  for i, ((pfx, idx), prof) in enumerate(sorted_items):
232
+
233
+ # ๆ–ญ็‚น็ปญไผ ๏ผš่ฏฅๅฑ‚ๅทฒๅฎŒๆˆๅˆ™่ทณ่ฟ‡
234
+ if idx in done_layers.get(pfx, set()):
235
+ # ไปŽๆ•ฐๆฎๅบ“่ฏปๅ–ๅทฒๆœ‰่ฎฐๅฝ•ๅŠ ๅ…ฅ all_records๏ผˆ็”จไบŽๆœ€็ปˆๅฑ•็คบ๏ผ‰
236
+ continue
237
+
238
  progress(
239
  0.15 + 0.80 * i / max(total, 1),
240
  desc=f"{pfx.split('.')[-2] if '.' in pfx else pfx} L{idx}..."
241
  )
242
 
243
+ # โ”€โ”€ ๅŠ ่ฝฝ Q/K/V โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
244
  try:
245
  q_url = get_file_url(model_id, prof.q.shard)
246
  k_url = get_file_url(model_id, prof.k.shard)
 
262
  W_k = load_tensor_remote(k_url, prof.k.key, k_hdr, k_hs, token)
263
 
264
  if prof.kv_shared:
 
265
  W_v = W_k.clone()
266
  else:
267
  v_url = get_file_url(model_id, prof.v.shard)
 
276
  log.append(f"[{pfx}] Layer {idx}: โš ๏ธ tensor ไธบ None\n")
277
  continue
278
 
279
+ # โ”€โ”€ ่ฎก็ฎ—ไบ”ๅฎšๅพ‹ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
280
  try:
281
  records, layer_log = analyze_layer(W_q, W_k, W_v, prof)
282
  all_records.extend(records)
283
  log.append(layer_log)
284
+
285
+ # โ”€โ”€ ๅ†™ๅ…ฅๆ•ฐๆฎๅบ“ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
286
+ if records:
287
+ write_layer_records(conn, model_id, records)
288
+ # ๆฏๅฑ‚ๅ†™ๅฎŒ็ซ‹ๅˆปๆ›ดๆ–ฐ summary๏ผˆๆ”ฏๆŒไธญ้€”ๆŸฅ็œ‹ๆŽ’่กŒๆฆœ๏ผ‰
289
+ update_model_summary(conn, model_id, pfx)
290
+ log.append(
291
+ f" โœ… ๅทฒๅ†™ๅบ“๏ผš{len(records)} ๆก่ฎฐๅฝ• "
292
+ f"[{pfx}] Layer {idx}\n"
293
+ )
294
+
295
  except Exception as e:
296
  log.append(f"[{pfx}] Layer {idx}: โŒ ่ฎก็ฎ—ๅคฑ่ดฅ๏ผš{e}\n")
297
  finally:
298
  del W_q, W_k, W_v
299
 
300
+ # โ”€โ”€ ๆ›ดๆ–ฐๅˆ†ๆž่€—ๆ—ถ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
301
+ elapsed = (datetime.utcnow() - t_start).total_seconds()
302
+ conn.execute(
303
+ "UPDATE models SET analyze_sec = ? WHERE model_id = ?",
304
+ (elapsed, model_id)
305
+ )
306
+ conn.commit()
307
+
308
  # โ”€โ”€ ๆฑ‡ๆ€ป โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
309
  if not all_records:
310
+ # ๅฏ่ƒฝๅ…จ้ƒจๆ˜ฏๆ–ญ็‚น็ปญไผ ่ทณ่ฟ‡็š„
311
+ log.append(
312
+ "\nโšก ๆ‰€ๆœ‰ๅฑ‚ๅ‡ๅทฒๅฎŒๆˆ๏ผˆๆ–ญ็‚น็ปญไผ ๏ผ‰๏ผŒ"
313
+ "่ฏทๅˆฐใ€ŒๆŽ’่กŒๆฆœใ€ๆˆ–ใ€Œๆ•ฐๆฎๅบ“ใ€Tab ๆŸฅ็œ‹็ป“ๆžœ\n"
314
+ )
315
+ return "".join(log), None
316
 
317
  summary = summarize_records(all_records, model_id)
318
  log.append(summary)
319
+ log.append(f"\nโฑ๏ธ ๆœฌๆฌก่€—ๆ—ถ๏ผš{elapsed:.1f} ็ง’\n")
320
 
321
  df = pd.DataFrame(all_records)
322
  return "".join(log), df
 
329
  def build_tab_analyze():
330
  with gr.Tab("๐Ÿ“Š ๅˆ†ๆž"):
331
  gr.Markdown("""
332
+ **็ฌฌไบŒๆญฅ๏ผš้€‰ๆ‹ฉๅฑ‚่Œƒๅ›ด๏ผŒ่ฎก็ฎ—็Ž‹ๆฐไบ”ๅฎšๅพ‹ๅ…จๆŒ‡ๆ ‡**
333
+ ๅฑ‚ๅท = safetensors key ไธญ `layers.{N}` ็š„ๅŽŸๅง‹ N๏ผŒK=V ๅ…ฑไบซๅฑ‚่‡ชๅŠจๅค„็†ใ€‚
334
+ โšก **ๆ”ฏๆŒๆ–ญ็‚น็ปญไผ **๏ผšๅทฒๅˆ†ๆž็š„ๅฑ‚่‡ชๅŠจ่ทณ่ฟ‡๏ผŒ้šๆ—ถไธญๆ–ญ้šๆ—ถ็ปง็ปญใ€‚
335
  """)
336
 
337
  with gr.Row():