CoolFace
Modelpublic

AbijahKaj/qwen3.5-4b-kicad-netlist

sourceHugging Faceapache-2.0updated 5mo agoView on Hugging Face
1likes17downloads
Model Card

Qwen3.5-4B KiCad Netlist Generator

Fine-tuned Qwen/Qwen3.5-4B to generate valid KiCad s-expression netlists from natural language circuit descriptions — with optional tool-calling to look up real component data at inference time.

Continuation of [AbijahKaj/qwen3-4b-kicad-netlist](https://huggingface.co/AbijahKaj/qwen3-4b-kicad-netlist) on the newer Qwen3.5 architecture (hybrid GatedDeltaNet + FullAttention).
⚠️ Pending retraining on v2 dataset. The current adapter was trained on v1 dataset (137 examples, many without proper nets). The v2 dataset has 28,702 examples with proper (nets sections + 285 tool-augmented examples with both search_component and get_datasheet_info tools. See train.py for the ready-to-run training script.

What It Does

Given a description like "Design an RP2040 flight controller with IMU, barometer, USB-C, and SWD debug", this model:

  1. 1.Identifies all required components (MCU, sensors, regulators, connectors, passives)
  2. 2.(Optional) Calls tools to look up component pinouts, footprints, and reference circuits from real databases
  3. 3.Generates a complete KiCad netlist with all electrical connections, power nets, decoupling caps, and proper pin assignments

Two Modes of Operation

ModeDescriptionWhen to Use
Direct generationModel generates the full netlist from memoryQuick prototyping, common circuits
Tool-augmentedModel calls search_component / get_datasheet_info, then generatesUncommon ICs, production accuracy

Quick Start

Direct Generation (no tools)

python
import torch
from transformers import Qwen3_5ForConditionalGeneration, AutoTokenizer, BitsAndBytesConfig
from peft import PeftModel

BASE_MODEL = "Qwen/Qwen3.5-4B"
ADAPTER = "AbijahKaj/qwen3.5-4b-kicad-netlist"

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.bfloat16,
)

base_model = Qwen3_5ForConditionalGeneration.from_pretrained(BASE_MODEL, quantization_config=bnb_config, device_map="auto")
model = PeftModel.from_pretrained(base_model, ADAPTER)
model.eval()
tokenizer = AutoTokenizer.from_pretrained(ADAPTER)

messages = [
    {"role": "system", "content": "You are an expert electronics engineer and KiCad schematic designer. When given a description of an electronic circuit or system, you generate a complete, valid KiCad netlist in s-expression format."},
    {"role": "user", "content": "Design an RP2040-based flight controller with ICM-42688-P IMU on SPI, BMP388 barometer on I2C, 4 PWM motor outputs, USB-C, QSPI flash, and SWD debug header."}
]

text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True, enable_thinking=False)
inputs = tokenizer(text, return_tensors="pt").to(model.device)

with torch.no_grad():
    outputs = model.generate(**inputs, max_new_tokens=8192, temperature=0.3, top_p=0.9, do_sample=True)

netlist = tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:], skip_special_tokens=True)
print(netlist)

Agentic Mode (with tool calling)

See `inference_agent.py` for a full agent implementation that:

  • —Runs a multi-turn generate → tool call → tool result → generate loop
  • —Connects to real APIs (Nexar/Octopart, LCSC) for component lookup
  • —Falls back to a local KiCad library index for offline use
bash
python inference_agent.py "Design an ESP32-S3 IoT gateway with W5500 Ethernet and CAN bus"
Important: Use Qwen3_5ForConditionalGeneration — not AutoModelForCausalLM. Qwen3.5 is a multimodal model class; using the wrong loader will produce incorrect weight mappings.

Supported Circuit Types

Circuit TypeKey ComponentsComplexity
Flight ControllerRP2040/STM32F405, ICM-42688-P/BMI270 IMU, BMP388/DPS310 baroMedium-High
IoT Sensor NodenRF52840/ESP32-S3, BMP388, SSD1306 OLED, microSDMedium
IoT GatewayESP32-S3, W5500 Ethernet, INA219, ADS1115, TMP102Medium
GPS TrackernRF52840, NEO-M9N GNSS, QMC5883L compass, microSDMedium
Motor ControllerRP2040/SAMD21, DRV8833/TMC2209, current sensingMedium
CNC ControllerRP2040, TMC2209 steppers, ADS1115, DS3231 RTCHigh
USB-to-CAN AdapterSAMD21, SN65HVD230, TXB0104 level shifterMedium
CM4/CM5 Carrier BoardDual Hirose DF40HC, PCIe NVMe, USB 3.0, EthernetHigh
Simple circuitsLED drivers, voltage dividers, power meters, data loggersLow

Architecture: Why Qwen3.5 Is Different

Qwen3.5-4B is a hybrid model — not a standard transformer:

Layer Pattern: [GatedDeltaNet, GatedDeltaNet, GatedDeltaNet, FullAttention] × 8
               \_______________ 24 layers ________________/  \__ 8 layers __/
ComponentTypePurpose
GatedDeltaNet (24 layers)Linear attentionO(n) complexity, long-range dependencies
FullAttention (8 layers)Standard self-attentionPrecise local attention every 4th layer
Vision encoder (model.visual.*)ViTImage understanding (excluded from LoRA)
MTP head (mtp.*)Multi-token predictionSpeculative decoding (excluded from LoRA)

LoRA Target Modules

python
target_modules = [
    # FullAttention layers (8 layers: 3, 7, 11, 15, 19, 23, 27, 31)
    "q_proj", "k_proj", "v_proj", "o_proj",
    # GatedDeltaNet layers (24 layers)
    "in_proj_a", "in_proj_b", "in_proj_qkv", "in_proj_z", "out_proj",
    # MLP (all 32 layers)
    "gate_proj", "up_proj", "down_proj",
]
exclude_modules = r".*\b(visual|mtp)\b.*"
⚠️ GatedDeltaNet modules are in_proj_a, in_proj_b, etc. — NOT in_proj. PEFT uses endswith matching, so "in_proj" would match nothing.

Dataset

The v2 dataset contains:

  • —28,702 direct-generation examples with proper (nets sections — converted from real .kicad_sch schematics from ~6,000 GitHub repos plus synthetic circuits (CM4/CM5 carriers, flight controllers, IoT nodes, CAN bus, etc.)
  • —285 tool-augmented examples with both search_component (1,741 calls) and get_datasheet_info (285 calls) tools
  • —100% have nets, 93% have GND, ~86% have power nets, avg 80 nets per example

Dataset generation scripts are in the dataset repo.

Tool Calling

Two tools available via Qwen-format tool calling:

ToolDescription
search_component(query, category)Look up component by part number/description. Returns MPN, manufacturer, package, footprint, KiCad library, and full pinout.
get_datasheet_info(mpn)Get reference circuit info: decoupling requirements, crystal specs, bus configuration, and design notes.

Connecting Real Backends

BackendAuthCoverageBest For
Local KiCad libraryNone~20K symbolsOffline use, standard parts
LCSC APINone500K+ partsFree, Chinese component market
Nexar/OctopartAPI key1B+ partsProduction use, global supply chain

See `inference_agent.py` for implementation with all three backends.

ERC Validation

The included erc_validator.py (v2) validates generated netlists:

CheckWhat It Validates
SyntaxBalanced parentheses, valid s-expression structure
StructureHas (export), (design), (components), (nets) sections
ComponentsUnique refs, values, footprints, libsource
NetsMulti-node connectivity, no floating pins, pin-type compatibility
Net QualityMulti-node ratio, avg nodes/net, named net ratio
PowerGND net present, power supply net present
DecouplingICs on power nets have bypass capacitors
ConnectivityAll components connected to at least one net
bash
python erc_validator.py output_netlist.kicad_net

Training

Current Adapter (V1 — pre-v2 dataset)

Trained on v1 dataset (137 examples). Small dataset, nets generation limited.

ParameterValue
MethodQLoRA (4-bit NF4, double quant) + SFT
LoRA rankr=64, α=32
Target modulesAll linear in GatedDeltaNet + FullAttention + MLP
ExcludedVision encoder, MTP head
Epochs10 (3 completed in cloud)
Max seq length12,288 tokens
HardwareNVIDIA L40S 48GB

Next: V2 (v2 dataset — ready to train)

train.py is updated for the v2 dataset (28.7K + 285 tool-augmented):

  • —Inline ERC v2 with stricter net quality scoring
  • —3 epochs (dataset is 200× larger now)
  • —Both search_component and get_datasheet_info tools in chat template
  • —Loads both train.jsonl and train_tool_augmented.jsonl

Training Recipe Sources

PaperContribution
CADmium (arXiv:2507.09792)LoRA r=64, all-linear, completion-only loss
OSIRIS (arXiv:2601.19439)QLoRA NF4 on Qwen family for EDA
LoRA Without Regret (Schulman, 2025)High-rank LoRA matches full fine-tuning
PCBSchemaGen (arXiv:2602.00510)ERC validation during training
S0 Tuning (arXiv:2604.01168)Validated LoRA targets for Qwen3.5 hybrid architecture

Repository Contents

FileDescription
adapter_model.safetensorsLoRA adapter weights (248 MB)
adapter_config.jsonPEFT adapter configuration
train.pyV2 training script — v2 dataset, both tools, inline ERC v2
erc_validator.pyERC v2 — stricter net quality checks, validate_netlist() compat
evaluate_model.pyEvaluation suite: 7 prompts, ERC scoring, A/B comparison mode
inference_agent.pyAgentic inference with real tool calling (Nexar, LCSC, local KiCad)
chat_template.jinjaQwen3.5 chat template

Compared to Qwen3-4B Version

Aspect[Qwen3-4B](https://huggingface.co/AbijahKaj/qwen3-4b-kicad-netlist)**Qwen3.5-4B** (this)
ArchitectureStandard transformer (32 layers)Hybrid: 24× GatedDeltaNet + 8× FullAttention
Model classAutoModelForCausalLMQwen3_5ForConditionalGeneration
LoRA targetsall-linear (7 module types)12 module types (+ GatedDeltaNet projections)
Excluded modulesNoneVision encoder + MTP head
Tool calling❌ Direct generation only✅ search_component + get_datasheet_info
Max seq length8,19212,288 (longer tool conversations)

Limitations

  • —Current adapter: Trained on small v1 dataset. Retraining on v2 will significantly improve quality.
  • —Component coverage: Limited to components seen during training. Use tool-calling mode for unseen ICs.
  • —Pin accuracy: Direct generation may hallucinate pin numbers. Tool-augmented mode is more reliable.
  • —Complexity ceiling: Best results on circuits with <100 components.
  • —No PCB layout: Generates netlists only, not physical PCB layouts.

Tips

  1. 1.Be specific: Include IC part numbers, bus types (SPI/I2C/UART), and pin assignments
  2. 2.Use tool-calling mode for uncommon components
  3. 3.Temperature 0.3: Low temperature produces more consistent, valid netlists
  4. 4.Validate output: Always run erc_validator.py on generated netlists
  5. 5.Disable thinking: Use enable_thinking=False for direct output
  6. 6.Use the right model class: Qwen3_5ForConditionalGeneration, NOT AutoModelForCausalLM

License

Apache 2.0 (same as base model Qwen/Qwen3.5-4B)