## Tinker engine


## train.engine.TrainOp


One optimization step: a forward-backward and its optim step as a single value.


Usage

``` python
train.engine.TrainOp(
    datums,
    loss,
    lr,
)
```


Binding the pair into one op means the inefficient shape -- awaiting the forward-backward before submitting the optim -- has no representation for a consumer to write.


#### Attributes


`datums: tuple[tinker.Datum, …]`  
The step's training batch.

`loss: Loss`  
The loss to train against, which also carries its billing multiplier.

`lr: float`  
The learning rate for this step's fresh optimizer params, so a schedule falls out free.


## train.engine.ScoreOp


A batched forward pass scoring `datums`, billed as prefill.


Usage

``` python
train.engine.ScoreOp(datums)
```


#### Parameter Attributes


`datums: tuple[tinker.Datum, …]`  


## train.engine.SnapshotOp


Save the current weights for sampling, optionally scoring eval datums against them.


Usage

``` python
train.engine.SnapshotOp(name, ttl_seconds, eval=())
```


The eval datums live on the snapshot, so which weights they were scored against is carried by the op rather than inferred from adjacency.


#### Attributes


`name: str`  
The sampler checkpoint name.

`ttl_seconds: int | None`  
How long the saved weights live, or None to keep them forever.

`eval: tuple[tinker.Datum, …]`  
The datums to score against these exact weights, or empty for a bare save.


## train.engine.CrossEntropy


Tinker's named `cross_entropy` loss: one forward-backward pass per step.


Usage

``` python
train.engine.CrossEntropy()
```


## train.engine.Custom


A client-side loss (DPO): a forward pass and a surrogate backward, so two passes per step.


Usage

``` python
train.engine.Custom(fn)
```


Both passes are priced at the train rate. If Tinker bills the preliminary forward at the cheaper prefill rate, the projection overstates -- deliberately conservative for a spend cap, which must over-reserve rather than under.


#### Parameter Attributes


`fn: LossFn`  


## train.engine.TrainDone


The result of a [TrainOp](tinker-engine.md#athome.train.engine.TrainOp): its op and the forward-backward output for the fold.


Usage

``` python
train.engine.TrainDone(op, output)
```


#### Parameter Attributes


`op: `<a href="tinker-engine.html#athome.train.engine.TrainOp" class="gdls-link gdls-code"><code>TrainOp</code></a>  

`output: tinker.ForwardBackwardOutput`  


## train.engine.ScoreDone


The result of a [ScoreOp](tinker-engine.md#athome.train.engine.ScoreOp): its op and one logprob output per scored datum.


Usage

``` python
train.engine.ScoreDone(op, outputs)
```


#### Parameter Attributes


`op: `<a href="tinker-engine.html#athome.train.engine.ScoreOp" class="gdls-link gdls-code"><code>ScoreOp</code></a>  

`outputs: Sequence[dict[str, tinker.TensorData]]`  


## train.engine.SnapshotDone


The result of a [SnapshotOp](tinker-engine.md#athome.train.engine.SnapshotOp): both saved paths and eval outputs, or None outputs when bare.


Usage

``` python
train.engine.SnapshotDone(op, sampler_path, state_path, outputs)
```


Both paths always land -- a sampler save without its training-state twin has no representation.


#### Attributes


`op: `<a href="tinker-engine.html#athome.train.engine.SnapshotOp" class="gdls-link gdls-code"><code>SnapshotOp</code></a>  
The snapshot op that produced this result.

`sampler_path: str`  
The `tinker://` address the sampler (inference) weights were saved to.

`state_path: str`  
The `tinker://` address the training state (weights+optimizer) was saved to.

`outputs: Sequence[dict[str, tinker.TensorData]] | None`  
One logprob output per scored eval datum, or None for a bare snapshot.


## train.engine.execute()


Submit `schedule`'s ops to [client](serve.md#athome.serve.ManagedServer.client) and yield their results in submission order.


Usage

``` python
train.engine.execute(client, schedule)
```


This is the only code that holds an `APIFuture`. It keeps the server's queue non-empty by submitting up to `MAX_PENDING` compute-bearing ops ahead of the one it is draining -- every [TrainOp](tinker-engine.md#athome.train.engine.TrainOp) submits its forward-backward and optim together before either result is awaited, so a step costs one clock cycle instead of three. Snapshots and scores ride the same queue between steps without stalling it. Results drain strictly in order; a failed op raises from its own yield, with every earlier result already delivered -- and an op whose *submission* fails raises only after every already-submitted op has drained, so no billable work goes unobserved.


#### Parameters


`client: tinker.TrainingClient`  
The Tinker training client whose turnstile executes the ops.

`schedule: Sequence[Op]`  
The ops to run, in order.


#### Yields


`One: AsyncIterator[OpResult]`  
data:`OpResult` per op, in submission order.


## train.engine.projection()


The dollar cost `schedule` will bill at `price` -- a pure fold over the same value [execute](tinker-engine.md#athome.train.engine.execute) runs.


Usage

``` python
train.engine.projection(schedule, price)
```


A [TrainOp](tinker-engine.md#athome.train.engine.TrainOp) bills its tokens at the train rate times the loss's pass count; a [ScoreOp](tinker-engine.md#athome.train.engine.ScoreOp) and a snapshot's eval datums bill at the prefill rate; a bare snapshot is free. Folding the exact schedule that runs is what makes projected and billed cost the same.


## train.engine.token_count()


The total input-token count across `datums` -- what the metered classes bill against.


Usage

``` python
train.engine.token_count(datums)
```
