Case Study 2: The Model That Was Cheap to Train and Ruinous to Run

The business case

A company has a binary classification task in production — roughly a million predictions a month. A research team proposes replacing the classical model with a quantum classifier, and the proposal is unusually careful.

They have read Chapter 32. They compute the training budget explicitly:

   TRAINING = (2n+1) x samples x steps x shots
            = 13 x 201 x 60 x 10,000
            = 1,567,800,000 shots  =  43.6 QPU hours  =  1.8 QPU-days

1.8 QPU-days, once. They price it against a research allocation, note that it is a one-off cost against a model that will run for years, and conclude it is affordable.

The accuracy analysis is honest too. The single-qubit model reaches $0.8343 \pm 0.0407$ against kNN's $0.8970 \pm 0.0377$ — a real deficit, which they flag, arguing the gap may close with more layers.

Everything in the proposal is correct. It is one of the better QML business cases you will see.

The number that is not in it

   INFERENCE, at 1,000 shots per prediction:
     1,000,000 predictions x 1,000 shots = 1,000,000,000 shots
                                         = 27.8 QPU HOURS

Per month. Forever.

The training cost was 43.6 QPU hours once. The inference cost is 27.8 QPU hours every month — so the model spends more on inference in its second month than it ever spent on training, and continues to do so for its entire operational life.

Against the incumbent:

   kNN.predict on 1,000,000 points:     1.1 SECONDS on a laptop
   quantum, at 1,000 shots each:       27.8 QPU HOURS

Roughly ninety thousand times the compute, for a model that is measurably less accurate.

🔬 Honest Assessment: training cost is the number QML papers omit. Inference cost is the number nobody computes at all.

Chapter 32 §32.4 established that total shots decides feasibility, and that it is almost never reported. This is worse, because a training budget is at least a bounded quantity — you pay it and you are done.

A deployed quantum classifier pays a shot budget on every prediction, forever. For any model that reaches production, that recurring cost dominates the lifetime total by orders of magnitude.

Why it was invisible

Three reasons, and they are structural rather than careless.

The research framing is about training. Papers optimize training: better ansätze, better optimizers, fewer iterations. Inference is one forward pass, which feels free — and on a classical model it essentially is. The habit transfers, and it should not.

The shot count is buried in the framework. qml.set_shots(circuit, shots=1000) is a keyword argument, not a line item. Nothing in the API surfaces that the number is multiplied by every future prediction the model will ever make.

And the training cost was computed, which felt like diligence. Having done the harder-looking calculation, the team reasonably assumed they had done the costing. Computing one bill can make you stop looking for the other one.

The shot count is not arbitrary

There is a real question underneath: does inference need 1,000 shots?

Chapter 33 §33.5's answer is that it depends on the margin distribution, and that this is measurable:

   |<Z>| over the 99 test points:
     p0    0.0159      p50   0.6281      p100  0.9891
   points with |<Z>| < 0.05:  1 of 99

Most predictions are far from the decision boundary, so most need very few shots. Measured:

       shots   mean acc      std    worst
         100     0.9051   0.0112   0.8788
       1,000     0.9101   0.0044   0.8990
      10,000     0.9091   0.0000   0.9091
       exact     0.9091   0.0000   0.9091

One hundred shots costs 0.4% accuracy on average — which drops the monthly bill from 27.8 QPU hours to 2.8.

That is a real, defensible optimization, and it is the kind of engineering the proposal should have contained. It also does not change the conclusion: 2.8 QPU hours per month against 1.1 seconds on a laptop is still four orders of magnitude, for a less accurate model.

⚠️ And the shot count is a property of your data, not of the method. One point in 99 sat within 0.05 of the boundary here. A more balanced or harder problem puts more there, and the required shot count rises with them. Measure the margins; do not inherit a number from a tutorial.

What the proposal should have contained

   1. TRAINING COST.  (2n+1) x samples x steps x shots, once.       [they had this]

   2. INFERENCE COST.  shots x predictions, PER PERIOD, forever.    [missing]

   3. THE SHOT COUNT, DERIVED.  From the measured margin distribution,
      not inherited from an example.                                 [missing]

   4. THE INCUMBENT'S COST.  Measured, not assumed.                  [missing]

   5. THE ACCURACY DEFICIT.  With an error bar.                      [they had this]

Items 2 and 4 are each one line of arithmetic, and together they decide the proposal.

The project module refuses to describe a model as deployable without them:

@property
def deployable_claim_supported(self) -> bool:
    """Both bills, and enough replicates to trust the accuracy."""
    return (self.training is not None and self.inference is not None
            and self.n_splits >= MIN_SPLITS)

A report missing the inference cost says so in its summary, rather than presenting an accuracy and a training budget as though they were the whole picture.

When this argument does not apply

Two cases, in fairness.

When predictions are rare and valuable. A model run a hundred times a year on decisions worth millions has a negligible inference bill, and the calculation changes entirely.

When the input is already quantum. Chapter 32 §32.6 noted this and Chapter 35 develops it: if the thing being classified is a quantum state — from an experiment, or from another computation — there is no encoding cost and no classical alternative to compare against. The inference bill is then the cost of doing something classical hardware cannot do at all.

Neither describes a million monthly predictions on a two-dimensional classical dataset.

The lessons

Compute the inference bill. shots × predictions × period. One line, and for a deployed model it dominates everything else.

Derive the shot count from the margin distribution. It is measurable, it is data-specific, and the difference between 100 and 1,000 shots was a factor of ten in the monthly bill here.

Measure the incumbent. kNN.predict on a million points took 1.1 seconds. That number is the denominator of the entire business case and it takes one line to obtain.

A one-time cost and a recurring cost are different kinds of number. Presenting the training budget as "the cost" is the same category error as Chapter 25's team reporting an improvement factor when the decision needed a breakeven.

And having computed one bill carefully can stop you looking for the other. The team's training calculation was more rigorous than most published work. It was also not the number that mattered.


Reproduce it: code/example-03-the-inference-bill.py measures the margin distribution, sweeps the shot count, and prices inference against a measured kNN.predict; inference_cost and ClassifierReport.deployable_claim_supported in code/vqelab/classifiers.py make the omission impossible, and test_a_deployable_claim_needs_the_INFERENCE_bill asserts it.