QuantumPipeline#

class pyqit.core.QuantumPipeline(steps, mode='sequential', aggregation='mean', fit_mode='sequential_greedy')[source]#

Bases: BaseMetaObject

Compose PipelineStage objects sequentially or as an ensemble.

Parameters:
  • steps (list of PipelineStage, or list of (name, model))

  • mode (str, default "sequential") –

    How the stages relate to each other, which decides what each stage receives as input.

    • "sequential": each stage’s output is the next stage’s input, and the last stage’s output is the pipeline’s.

    • "ensemble": every stage receives the same input and the outputs are combined by aggregation.

  • aggregation (str or callable, default "mean") –

    How ensemble outputs are combined. Ignored in sequential mode.

    • "mean": averages the stage outputs.

    • "vote": takes the majority of the stages’ hard labels.

    • callable: receives the list of raw stage outputs and returns the combined output.

  • fit_mode (str, default "sequential_greedy") –

    How the stages of a sequential pipeline are trained, which decides what loss each stage sees. Ignored in ensemble mode, where every trainable stage trains independently on the same data.

    • "sequential_greedy": trains each stage in turn against the labels, on the output of the stages before it.

    • "frozen_backbone": trains only the final stage. Every other stage must have trainable=False.

    • "joint": trains every trainable stage at once against the final stage’s loss. Gradients pass through every stage, frozen ones included. Use this for hybrid classical-quantum networks.

Examples

>>> from pyqit.core import PipelineStage, QuantumPipeline
>>> pipe = QuantumPipeline(
...     [PipelineStage(backbone, trainable=False), PipelineStage(head)],
...     fit_mode="frozen_backbone",
... )
>>> pyqit.Trainer(max_epochs=20).fit(pipe, dm)

A hybrid network, dense to circuit to dense, trained end to end:

>>> from pyqit.models.layers import DenseClassifier, DenseLayer, QuantumLayer
>>> hybrid = QuantumPipeline(
...     [
...         DenseLayer(n_features=8, n_out=4, activation="tanh"),
...         QuantumLayer(n_qubits=4, n_layers=2),
...         DenseClassifier(n_features=4),
...     ],
...     fit_mode="joint",
... )
>>> history = pyqit.Trainer(max_epochs=20).fit(hybrid, dm)
clone() → QuantumPipeline[source]#

Return an independent copy: stages deep-copied, weights included.

forward(X, **custom_weights)[source]#

Run every stage on X and return the pipeline’s raw output.

X is split and normalized but not prescaled: each stage’s embedding prescaling is applied here, as predict and fit do. custom_weights override the stages’ own weights, keyed as in weights; sequential mode only.

get_params(deep: bool = True)[source]#

Get stage and nested-stage parameters. See sklearn’s convention.

is_composite()#

Check if the object is composite.

A composite object is an object which contains objects as parameter values.

Returns:

Whether self contains a parameter whose value is a BaseObject, list of (str, BaseObject) tuples or dict[str, BaseObject].

Return type:

bool

property named_stages: dict[str, PipelineStage]#

Stages keyed by name.

predict_step(X)[source]#

Run every stage on X, hard-labeling the final stage’s output.

A regressor’s output is returned as it is.

set_params(**kwargs)[source]#

Set stage or nested-stage parameters. See sklearn’s convention.

update_weights(flat_weights_dict)[source]#

Write flat_weights_dict, keyed like weights, into the stages.

weight_groups() → dict[source]#

The trainable stages’ weight_groups, keyed like weights.

property weights#

Flat {"<stage>.<qnode>.<weight>": array} dict of trainable stages.