Spaces:
Running on Zero
Running on Zero
Download layer_data.py from liaoweiduo/SAE-explorer-dev: direct link, hf CLI and curl.
- Browser
- Download file 7.89 kB
-
https://huggingface.co/spaces/liaoweiduo/SAE-explorer-dev/resolve/main/layer_data.py
- Command line
-
hf download hf://spaces/liaoweiduo/SAE-explorer-dev/layer_data.py
-
curl -L -o layer_data.py https://huggingface.co/spaces/liaoweiduo/SAE-explorer-dev/resolve/main/layer_data.py
7.89 kB
| """Layer metadata and neuron detail loading with on-demand caching.""" | |
| import json | |
| import os | |
| from typing import Any, Dict, List, Optional, Tuple | |
| from datasets import get_dataset_split_names, load_dataset | |
| from config import QWEN25_DATASET_ROOT, REPO_ID, qwen25_dataset_path | |
| # Config names and directories in the HF dataset | |
| CONFIG_META = f"{QWEN25_DATASET_ROOT}_meta_data" | |
| CONFIG_DETAILS = f"{QWEN25_DATASET_ROOT}_neuron_details" | |
| # Global cache for per-layer meta dict (lightweight) | |
| layer_meta_cache: Dict[int, Dict[int, Dict]] = {} | |
| # Cache for per-layer, per-chunk neuron detail datasets (non-streaming) | |
| # Keyed by layer_id -> chunk_start (every 1000 neurons) -> dataset split object | |
| layer_datasets: Dict[int, Dict[int, Any]] = {} | |
| # Cache for per-neuron detailed rows (only selected neuron) | |
| neuron_detail_cache: Dict[Tuple[int, int], Dict] = {} | |
| def _summarize_splits(split_names: List[str], head: int = 5, tail: int = 5) -> str: | |
| if not split_names: | |
| return "[]" | |
| if len(split_names) <= head + tail: | |
| return str(split_names) | |
| return str(split_names[:head] + ["..."] + split_names[-tail:]) | |
| def load_layer_options() -> List[int]: | |
| """Fetch available layer IDs, prefer local JSON, fallback to default.""" | |
| try: | |
| if os.path.exists("resources/layer_list.json"): | |
| with open("resources/layer_list.json", "r", encoding="utf-8") as f: | |
| layer_options = json.load(f) | |
| layer_options = sorted(int(x) for x in layer_options) | |
| else: | |
| layer_options = [20] | |
| print(f"[info] Available layer IDs: {layer_options}") | |
| return layer_options | |
| except Exception as e: # pragma: no cover - small utility | |
| print(f"[error] Failed to load layer options: {e}") | |
| return [20] | |
| def load_layer_data(layer_id: int) -> Dict[int, Dict]: | |
| """Load lightweight meta data for a specific layer from HF dataset. | |
| Uses a single-file data_files load for layer meta parquet. | |
| Only minimal fields are stored; heavy refs are not loaded here. | |
| """ | |
| if layer_id in layer_meta_cache: | |
| cached = layer_meta_cache[layer_id] | |
| print(f"[info] Using cached meta_data for layer {layer_id} (size={len(cached)})") | |
| return cached | |
| try: | |
| data_file = qwen25_dataset_path( | |
| f"meta_data/layer_{layer_id}-00000-of-00001.parquet" | |
| ) | |
| print(f"[info] Loading meta_data via data_files: layer={layer_id} file={data_file}") | |
| ds = load_dataset( | |
| REPO_ID, | |
| data_files={"train": [data_file]}, | |
| split="train", | |
| streaming=False, | |
| ) | |
| print(f"[info] meta_data loaded: file={data_file} rows={len(ds)}") | |
| meta_fields = { | |
| "neuron_id", | |
| "modality", | |
| "vision_summary", | |
| "language_summary", | |
| "consistency_score", | |
| "miou", | |
| } | |
| meta_dict: Dict[int, Dict] = {} | |
| for item in ds: | |
| nid = item.get("neuron_id") | |
| if nid is None: | |
| continue | |
| try: | |
| meta = {k: item.get(k) for k in meta_fields} | |
| meta_dict[int(nid)] = meta | |
| except Exception as row_err: # pragma: no cover | |
| print(f"[warn] Skipping meta row for layer {layer_id}: {row_err}") | |
| layer_meta_cache[layer_id] = meta_dict | |
| print(f"[info] Loaded meta_data for {len(meta_dict)} neurons for layer {layer_id}") | |
| return meta_dict | |
| except Exception as e: # pragma: no cover - network/cache dependent | |
| print(f"[error] Failed to load meta_data for layer {layer_id}: {e}") | |
| return {} | |
| def _details_split_name(layer_id: int, neuron_id: int, chunk: int = 1000) -> str: | |
| start = (int(neuron_id) // chunk) * chunk | |
| end = start + (chunk - 1) | |
| return f"layer_{layer_id}_neuron_{start:06d}_{end:06d}" | |
| def load_neuron_detail(layer_id: int, neuron_id: int) -> Optional[Dict]: | |
| """Load detailed refs (vision/text) for the selected neuron only. | |
| The dataset index now aligns with the neuron index, including empty neurons, | |
| so we can directly index into the split without an extra scan on `neuron_id`. | |
| """ | |
| cache_key = (int(layer_id), int(neuron_id)) | |
| if cache_key in neuron_detail_cache: | |
| print(f"[info] Using cached neuron_details for neuron {neuron_id} layer {layer_id}") | |
| return neuron_detail_cache[cache_key] | |
| # Ensure meta exists (for sanity), but don't depend on its split info | |
| meta_dict = load_layer_data(int(layer_id)) | |
| if int(neuron_id) not in meta_dict: | |
| return None | |
| chunk_size = 1000 | |
| split_name = _details_split_name(int(layer_id), int(neuron_id), chunk=chunk_size) | |
| print(f"[info] Loading neuron_details: layer={layer_id} neuron={neuron_id} split={split_name}") | |
| split_names = None | |
| try: | |
| split_names = get_dataset_split_names(path=REPO_ID, config_name=CONFIG_DETAILS) | |
| print( | |
| f"[info] neuron_details splits via config='{CONFIG_DETAILS}': count={len(split_names)} " | |
| f"sample={_summarize_splits(split_names)}" | |
| ) | |
| except Exception as e: | |
| print( | |
| f"[warn] Failed to list neuron_details splits via config: {e}; " | |
| "trying the expected file directly..." | |
| ) | |
| if split_names is not None and split_name not in split_names: | |
| print(f"[warn] neuron_details split '{split_name}' not found for layer {layer_id}") | |
| return None | |
| try: | |
| chunk_start = (int(neuron_id) // chunk_size) * chunk_size | |
| layer_cache = layer_datasets.setdefault(int(layer_id), {}) | |
| if chunk_start in layer_cache: | |
| ds = layer_cache[chunk_start] | |
| print( | |
| f"[info] Using cached neuron_details split='{split_name}' for layer {layer_id} " | |
| f"chunk_start={chunk_start}" | |
| ) | |
| else: | |
| data_file = qwen25_dataset_path( | |
| f"neuron_details/layer_{layer_id}/{split_name}-00000-of-00001.parquet" | |
| ) | |
| print( | |
| f"[info] Loading neuron_details via data_files: layer={layer_id} split={split_name} " | |
| f"file={data_file}" | |
| ) | |
| ds = load_dataset( | |
| REPO_ID, | |
| data_files={"train": [data_file]}, | |
| split="train", | |
| streaming=False, | |
| ) | |
| layer_cache[chunk_start] = ds | |
| print(f"[info] Cached split='{split_name}' rows={len(ds)} for layer {layer_id}") | |
| # Dataset index matches neuron index; empty neurons yield empty rows. | |
| local_index = int(neuron_id) - chunk_start | |
| if local_index < 0 or local_index >= len(ds): | |
| print( | |
| f"[warn] Neuron {neuron_id} maps to local index {local_index}, " | |
| f"but split '{split_name}' has length {len(ds)}" | |
| ) | |
| return None | |
| row = ds[int(local_index)] | |
| neuron_detail_cache[cache_key] = row | |
| print(f"[info] Loaded neuron_details for neuron {neuron_id} layer {layer_id} via direct index") | |
| return row | |
| except Exception as e: # pragma: no cover - network/cache dependent | |
| print(f"[error] Failed to load neuron_details for neuron {neuron_id} layer {layer_id}: {e}") | |
| return None | |
| def get_neuron_ids(layer_id: int) -> List[int]: | |
| """Return all neuron IDs for the given layer from meta_data.""" | |
| data = load_layer_data(layer_id) | |
| if data: | |
| return sorted(data.keys()) | |
| return [] | |
| def get_consistency_neurons(layer_id: int, max_examples: int = 25) -> List[int]: | |
| """Return up to max_examples neurons with consistency_score == 1 from meta_data.""" | |
| data = load_layer_data(layer_id) | |
| if not data: | |
| return [] | |
| matches = [nid for nid, meta in data.items() if meta.get("consistency_score") == 1.0] | |
| return sorted(matches)[:max_examples] | |