Trainer#

Trainer orchestrates a run but trains nothing itself. It seeds the RNG, calls setup() on the datamodule, prints the model table, optionally runs the barren-plateau pre-flight, assembles the callback list, then hands off to a training loop chosen by the active backend.

import pyqit

trainer = pyqit.Trainer(max_epochs=30, learning_rate=0.05)
history = trainer.fit(model, dm)

print(history.best_epoch, history.best_score)
trainer.validate(model, dm)             # {"val_loss": ..., "val_acc": ...}
trainer.test(model, dm)                 # {"test_loss": ..., "test_acc": ...}
preds = trainer.predict(model, dm)      # runs on the test split

Trainer.fit() returns a TrainingHistory holding train_loss, val_loss, train_acc, val_acc and epoch_times, one entry per epoch.

learning_rate is one float for every weight, or one per weight group. A model sorts its weights into "quantum" (the QNodes’) and "classical" (dense layers’), listed by model.weight_groups(), and each group gets its own optimizer, so a hybrid can move its circuit angles slower than its dense layers. A mapping must name exactly the groups the model has.

trainer = pyqit.Trainer(learning_rate={"quantum": 0.01, "classical": 0.1})

Seeding happens too late for weights#

Trainer(seed=...) covers training and the diagnostics, not weight initialisation. Models draw their weights in __init__, so seed before you build one:

pyqit.set_seed(42)                      # first
model = VQCClassifier(n_qubits=4)       # then

The same ordering applies to set_backend(), which each object reads once in its own __init__.

Settings a backend cannot honour#

Each loop declares what it cannot do, and Trainer validates that when the loop is built, before any data is split. The PennyLane loop rejects backend_kwargs, because it has no Lightning trainer to forward them to, and warns on logger, because metrics still come back in the history. A rejected setting raises. A warned one trains correctly.

Both checks measure against the signature defaults, so a Trainer built with defaults never complains.

Passing Lightning settings#

On the torch backend, backend_kwargs goes straight to lightning.pytorch.Trainer:

pyqit.Trainer(
    max_epochs=50,
    backend_kwargs={"accelerator": "gpu", "devices": 1, "gradient_clip_val": 0.5},
)

Lightning’s constructor is not mirrored onto Trainer. It carries roughly forty parameters, most of which a PennyLane optimizer loop cannot honour, and it holds none of learning_rate, optimizer, loss_fn or batch_size anyway. The accelerator defaults to "cpu", so a GPU runs only when you ask for one.