Skip to main content

Hybrid Workflow Tutorial: Nawal + Kinich

Level: Intermediate · Time: 30–45 minutes · Prerequisites: Basic ML knowledge, Python

This tutorial builds a sentiment classifier that pairs a classical transformer (Nawal) with a quantum layer (Kinich) for enhanced feature discrimination.

Architecture

Text ──▶ Nawal transformer ──▶ classical embeddings
                                      │
                                      ▼
                          Kinich quantum layer (VQC/VQNN)
                                      │
                                      ▼
                          Hybrid prediction head

Step 1 — Setup

import torch
import torch.nn as nn

from nawal.models import BelizeChainLLM
from nawal.models.hybrid_llm import HybridQuantumClassicalLLM
from nawal.quantum.kinich_connector import KinichQuantumConnector

from kinich.qml.classifiers import VQC
from kinich.qml.hybrid import TorchQuantumNeuralNetwork

Step 2 — Classical Baseline

Always establish a classical baseline first so the quantum contribution can be measured:

class ClassicalSentimentModel(nn.Module):
    def __init__(self, encoder):
        super().__init__()
        self.encoder = encoder
        self.head = nn.Linear(encoder.hidden_size, 2)

    def forward(self, input_ids, attention_mask):
        features = self.encoder(input_ids, attention_mask).last_hidden_state[:, 0]
        return self.head(features)

Train it, record accuracy and loss — this is the yardstick.

Step 3 — Add the Quantum Layer

Replace the linear head with a quantum-enhanced layer via the Torch interop:

quantum_layer = TorchQuantumNeuralNetwork(
    n_qubits=8,
    feature_map="zz",
    ansatz_depth=3,
)

class HybridSentimentModel(nn.Module):
    def __init__(self, encoder):
        super().__init__()
        self.encoder = encoder
        self.quantum = quantum_layer
        self.head = nn.Linear(8, 2)

    def forward(self, input_ids, attention_mask):
        features = self.encoder(input_ids, attention_mask).last_hidden_state[:, 0, :8]
        q_features = self.quantum(features)
        return self.head(q_features)

Step 4 — Train End-to-End

model = HybridSentimentModel(encoder)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)

for batch in loader:
    logits = model(batch["input_ids"], batch["attention_mask"])
    loss = nn.functional.cross_entropy(logits, batch["labels"])
    loss.backward()
    optimizer.step()

Step 5 — Compare

Evaluate the hybrid model against the classical baseline on the same held-out set. Keep the quantum path only if it earns its cost — the classical fallback exists for exactly this reason.

Notes

  • Keep qubit counts small (4–12) for current hardware fidelities
  • Batch embedding vectors before quantum encoding to amortize dispatch cost
  • Use SPSA or COBYLA when training directly on noisy hardware

Related