inputs-and-layer-wise-states

inputs-and-layer-wise-states is a skill for Claude Code from zjunlp/Mechanist. It costs 41 tokens per session (5,086 once invoked), scanned A, original, MIT.

A set of tools for measuring and visualizing how gradients differ across the layers of a language model during fine-tuning. It compares patterns for fast-answer and step-by-step reasoning tasks.

In plain words
What is it for?
Loading training data and models, calculating layer-level gradient statistics, and examining fine-tuning behavior across model layers.
Why use it?
It helps show which model layers receive stronger or weaker training signals and how those patterns vary by task type.

Skill for Claude Code

Written for Claude Code: shipped in a Claude Code plugin.

Part of the mechanist plugin — 54 skills, 4 agents shipped together

Good fit Loading training data and models, calculating layer-level gradient statistics, and examining fine-tuning behavior across model layers.

Compare 6 skills from other repositories ↓
Install with agentmods
npx agentmods add skills/zjunlp/mechanist/inputs-and-layer-wise-states
Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

Any agent
npx skills add zjunlp/Mechanist --skill inputs-and-layer-wise-states
Clone the repo
git clone --depth 1 https://github.com/zjunlp/Mechanist

Made for: Claude Code.

Or install mechanist, the plugin that ships this one along with the rest of its 54 skills, 4 agents.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for inputs-and-layer-wise-states

README.md
[![agentmods](https://agentmods.dev/badge/skills/zjunlp/mechanist/inputs-and-layer-wise-states/github.svg)](https://agentmods.dev/skills/zjunlp/mechanist/inputs-and-layer-wise-states)
Your own site
<a href="https://agentmods.dev/skills/zjunlp/mechanist/inputs-and-layer-wise-states"><img src="https://agentmods.dev/badge/skills/zjunlp/mechanist/inputs-and-layer-wise-states/github.svg" alt="Measured on agentmods" height="20"></a>

Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.

agentmods 80×15 button for inputs-and-layer-wise-states

Your own site · 80×15
<a href="https://agentmods.dev/skills/zjunlp/mechanist/inputs-and-layer-wise-states"><img src="https://agentmods.dev/badge/skills/zjunlp/mechanist/inputs-and-layer-wise-states.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 41 Skills are progressive disclosure: only the name and description are preloaded; the body loads when the skill is used.
When invoked 5,086 The whole file, excluding the scripts and references it only reads on demand.
Security scan A 0 findings. A grade says what 26 rules found in the file — not that it is safe. Third-party audits
  • NVIDIA SkillSpector pass 7 Sept 2026
How audits are shown
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.00041 $0.05086
Opus 5 $0.00020 $0.02543
Sonnet 5 $0.00008 $0.01017
Haiku 4.5 $0.00004 $0.00509

Measured 10d ago against content hash bd5e90c73d4b, method: parsed. Prices are Anthropic first-party input rates as of 2026-09-10, from the pricing page.

Security

Grade A, and why

inputs-and-layer-wise-states scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 10d ago.

The scan reads SKILL.md. This mod also ships 2 executable files (scripts/calculate_gradients.py, scripts/visualize_gradients.py), listed below but not scanned — reading those needs a real analyzer, not pattern matching.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

skills/mechanism-skills/gradient-detection/inputs-and-layer-wise-states/SKILL.md · 756 lines

How it starts

The opening of the file, as written. The whole thing — 756 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Demo Scripts

scripts/calculate_gradients.py

#!/usr/bin/env python3
"""
Calculate Layer-wise Gradient Statistics for LLM Fine-tuning

This script demonstrates how to calculate gradient statistics for each layer
when fine-tuning LLMs on different types of responses (fast vs slow thinking).
"""

import json
import torch
import numpy as np
from typing import Dict, List, Tuple, Optional
from transformers import AutoTokenizer, AutoModelForCausalLM
import argparse
from pathlib import Path


def load_training_data(data_path: str) -> List[Dict]:
    """
    Load training data from JSON file.
    
    Args:
        data_path: Path to the JSON data file
        
    Returns:
        List of training examples
    """
    with open(data_path, 'r') as f:
        data = json.load(f)
    return data


def prepare_model_and_tokenizer(
    model_name_or_path: str,
    device: str = "cuda"
) -> Tuple[AutoModelForCausalLM, AutoTokenizer]:
    """
    Load and prepare model and tokenizer for gradient calculation.
    
    Args:
        model_name_or_path: Hugging Face model identifier or local path
        device: Device to load model on
        
    Returns:
        Tuple of (model, tokenizer)
    """
    tokenizer = AutoTokenizer.from_pretrained(model_name_or_path)
    
    # Add padding token if not present
    if tokenizer.pad_token is None:
        tokenizer.pad_token = tokenizer.eos_token
    
    model = AutoModelForCausalLM.from_pretrained(
        model_name_or_path,
        torch_dtype=torch.float16,
        device_map="auto"
    )
    
    model.eval()
    return model, tokenizer


def calculate_layer_gradients(
    model: AutoModelForCausalLM,
    tokenizer: AutoTokenizer,
    text: str,
    max_length: int = 1024
) -> Dict[str, float]:
    """
    Calculate gradient norms for each layer of the model.
    
    Args:
        model: The language model
        tokenizer: The tokenizer
        text: Input text for gradient calculation
        max_length: Maximum sequence length
        
    Returns:
        Dictionary mapping layer names to gradient norms
    """
    # Tokenize input
    inputs = tokenizer(
        text,
        return_tensors="pt",
        truncation=True,
        max_length=max_length,
        padding=True
    ).to(model.device)
    
    # Enable gradient calculation
    model.zero_grad()
    
    # Forward pass with gradient calculation
    with torch.enable_grad():
        outputs = model(**inputs, labels=inputs["input_ids"])
        loss = outputs.loss
        
        # Backward pass
        loss.backward()
    
    # Collect gradient norms for each layer
    gradient_norms = {}
    
    for name, param in model.named_parameters():
        if param.grad is not None:
            # Calculate L2 norm of gradients
            grad_norm = torch.norm(param.grad, p=2).item()
            gradient_norms[name] = grad_norm
    
    return gradient_norms


def calculate_svd_vectors(
    model: AutoModelForCausalLM,
    tokenizer: AutoTokenizer,
    text: str,
    num_components: int = 10
) -> Dict[str, np.ndarray]:
    """
    Calculate SVD vectors for gradient analysis.
    
    Args:
        model: The language model
        tokenizer: The tokenizer
        text: Input text
        num_components: Number of SVD components to compute
        
    Returns:
        Dictionary mapping layer names to SVD components
    """
    # Get gradients
    inputs = tokenizer(text, return_tensors="pt", truncation=True).to(model.device)
    
    model.zero_grad()
    with torch.enable_grad():
        outputs = model(**inputs, labels=inputs["input_ids"])
        outputs.loss.backward()
    
    svd_results = {}
    
    for name, param in model.named_parameters():
        if param.grad is not None and len(param.grad.shape) >= 2:
            # Flatten gradient tensor for SVD
            grad_flat = param.grad.view(param.grad.shape[0], -1).cpu().numpy()
            
            # Compute SVD
            try:
                U, S, Vt = np.linalg.svd(grad_flat, full_matrices=False)
                # Store top components
                svd_results[name] = {
                    'singular_values': S[:num_components].tolist(),
                    'top_component_variance': (S[0]**2 / np.sum(S**2)).item()
                }
            except:
                svd_results[name] = None
                
    return svd_results


def analyze_gradient_patterns(
    gradient_norms: Dict[str, float],
    layer_groups: Optional[Dict[str, List[str]]] = None
) -> Dict[str, float]:
    """
    Analyze gradient patterns across layers.
    
    Args:
        gradient_norms: Dictionary of layer gradient norms
        layer_groups: Optional grouping of layers (e.g., early, middle, late)
        
    Returns:
        Dictionary of gradient statistics
    """
    norms = list(gradient_norms.values())
    
    stats = {
        'mean_norm': np.mean(norms),
        'std_norm': np.std(norms),
        'max_norm': np.max(norms),
        'min_norm': np.min(norms),
        'coefficient_of_variation': np.std(norms) / np.mean(norms) if np.mean(norms) > 0 else 0
    }
    
    # Calculate layer-wise differences
    if len(norms) > 1:
        differences = [abs(norms[i+1] - norms[i]) for i in range(len(norms)-1)]
        stats['mean_layer_difference'] = np.mean(differences)
        stats['max_layer_difference'] = np.max(differences)
    
    # Analyze by layer groups if provided
    if layer_groups:
        for group_name, layer_names in layer_groups.items():
            group_norms = [gradient_norms[name] for name in layer_names if name in gradient_norms]
            if group_norms:
                stats[f'{group_name}_mean'] = np.mean(group_norms)
                stats[f'{group_name}_std'] = np.std(group_norms)
    
    return stats


def process_dataset(
    model: AutoModelForCausalLM,
    tokenizer: AutoTokenizer,
    data: List[Dict],
    output_path: str,
    max_samples: int = None
):
    """
    Process entire dataset and save gradient statistics.
    
    Args:
        model: The language model
        tokenizer: The tokenizer
        data: List of training examples
        output_path: Path to save results
        max_samples: Maximum number of samples to process
    """
    results = []
    
    if max_samples:
        data = data[:max_samples]
    
    for idx, example in enumerate(data):
        print(f"Processing example {idx+1}/{len(data)}")
        
        # Prepare text (combine instruction and response)
        if 'instruction' in example and 'response' in example:
            text = f"{example['instruction']}\n{example['response']}"
        elif 'text' in example:
            text = example['text']
        else:
            continue
        
        # Calculate gradients
        gradient_norms = calculate_layer_gradients(model, tokenizer, text)
        
        # Calculate statistics
        stats = analyze_gradient_patterns(gradient_norms)
        
        # Store results
        result = {
            'example_id': idx,
            'gradient_norms': gradient_norms,
            'statistics': stats
        }
        
        results.append(result)
        
        # Save incrementally
        if (idx + 1) % 10 == 0:
            with open(output_path, 'w') as f:
                for res in results:
                    f.write(json.dumps(res) + '\n')
    
    # Final save
    with open(output_path, 'w') as f:
        for res in results:
            f.write(json.dumps(res) + '\n')
    
    print(f"Results saved to {output_path}")


def main():
    parser = argparse.ArgumentParser(description="Calculate layer-wise gradient statistics")
    parser.add_argument("--data_path", type=str, required=True, help="Path to training data")
    parser.add_argument("--model_name_or_path", type=str, required=True, help="Model identifier")
    parser.add_argument("--output_path", type=str, required=True, help="Output path for results")
    parser.add_argument("--max_samples", type=int, default=None, help="Maximum samples to process")
    parser.add_argument("--max_length", type=int, default=1024, help="Maximum sequence length")
    
    args = parser.parse_args()
    
    # Load data
    print(f"Loading data from {args.data_path}")
    data = load_training_data(args.data_path)
    
    # Load model and tokenizer
    print(f"Loading model: {args.model_name_or_path}")
    model, tokenizer = prepare_model_and_tokenizer(args.model_name_or_path)
    
    # Process dataset
    process_dataset(
        model=model,
        tokenizer=tokenizer,
        data=data,
        output_path=args.output_path,
        max_samples=args.max_samples
    )


if __name__ == "__main__":
    main()

Read the full file on GitHub · 756 lines

Files

What ships with it

3 files beside SKILL.md in the same directory: the scripts, references and assets a skill reads on demand. Not counted in the per-session cost; read them before you install if any of them is executable.

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 10d ago First seen · 756 lines · 41 tokens per session scan A bd5e90c73d4b

Subscribe to this mod's changes

inputs-and-layer-wise-states is a skill published in the GitHub repository zjunlp/Mechanist (74 stars, last pushed 14d ago), licensed MIT. It adds 41 tokens to every session and 5,086 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.