thinc review
Thinc 9.1.1 is Explosion's typed, functional neural-network toolkit and a model layer used in the spaCy family. Networks are `Model` objects assembled with functions such as `chain`, `clone`, `residual`, and `with_array`; training exposes the forward output and its backprop callback instead of hiding them behind a trainer. It also has NumPy and CuPy backends, optimizers, schedules, config registries, serialization, and wrappers for external frameworks. The 9.1 line moved to NumPy 2 and Blis 1, while 9.1.1 expanded the wheel targets. PyPI's highest version and the repository's actively released 8.3 line now disagree, so choosing the largest version number is unsafe.
Thinc fits the Explosion stack and developers who deliberately want typed functional composition with visible backprop callbacks. For a new general-purpose ML platform, choose a larger framework and avoid Thinc's split 9.1-versus-8.3 release story.
We installed it
| Install | ✓ · 2.4s | 17 packages on disk · 118 MB |
| Import | ✓ | import thinc in 0.81s · compiled extensions · py.typed · requires Python >=3.9 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does thinc install cleanly?
Yes. In a fresh container with an empty cache, pip install thinc finished in 2 seconds, leaving 17 packages and 118 MB on disk. pip-audit reported no known vulnerabilities.
What does thinc need to run?
Python >=3.9, and a platform wheel with compiled extensions. In our run import thinc succeeded in 0.81s, and the package ships py.typed for type checkers.
thinc or torch: which should you use?
torch: Use it for a broad model, accelerator, distributed-training, serving, and third-party extension ecosystem. Thinc fits the Explosion stack and developers who deliberately want typed functional composition with visible backprop callbacks.
When should you not use thinc?
This is a greenfield deep-learning platform with no Explosion dependency. PyTorch, JAX, and TensorFlow have far larger catalogs of models, deployment targets, accelerator tooling, and training examples.
Use it if
- You are extending spaCy or another Explosion project that already passes Thinc `Model` objects and array types through its pipeline.
- A research model benefits from explicit forward functions and callbacks that make gradient routing visible in ordinary Python.
- Ragged, padded, list, and dense array shapes need typed combinators with initialization-time dimension checks.
- Model factories and hyperparameters should be reconstructed from versioned registry names in a configuration file.
- This is a greenfield deep-learning platform with no Explosion dependency. PyTorch, JAX, and TensorFlow have far larger catalogs of models, deployment targets, accelerator tooling, and training examples.
- Native-layer speed is the main requirement. Thinc's model guide says its own models can be slower because it does not perform the graph optimizations used by larger frameworks, and recommends wrappers for expensive components.
- The team wants a finished training loop. `begin_update` returns a backprop callback, and callers still own batching, loss gradients, optimizer steps, metrics, checkpoints, and stopping policy.
- The project needs current TensorFlow or MXNet through Thinc's extras. PyPI metadata for 9.1.1 caps TensorFlow below 2.6 and MXNet below 1.6, limits that do not fit modern framework stacks.
- Your installer assumes the highest PyPI version is the maintained release line. PyPI selects 9.1.1 from 2024, while GitHub's default branch is `v8.3.x` and its latest release is 8.3.13 from 2026.
Setup reality
We installed Thinc 9.1.1 in a fresh Python 3.12 Bookworm container. pip completed in 2.4 seconds, leaving 17 packages and 118 MB. The distribution declares 35 direct dependencies, requires Python 3.9 or newer, includes compiled .so extensions, and ships py.typed. import thinc worked in 0.81 seconds. pip-audit found zero known vulnerabilities in the resolved environment.
Binary wheels avoid a local compiler on covered platforms. A source install needs the build requirements and a C compiler because Thinc includes Cython extensions. PyPI's 9.1.1 files cover CPython 3.9 through 3.12 across several operating-system targets; newer Python versions may fall outside that wheel set. GPU use adds CuPy or supported MPS/PyTorch plumbing. Match the CUDA-specific CuPy package to the machine, and avoid letting CuPy and another framework reserve competing GPU memory pools.
Models often lack final dimensions until initialize(X=..., Y=...) sees representative samples. Inference calls predict. Training calls begin_update, feeds the loss gradient into the returned callback, then applies an optimizer with finish_update. A custom layer must return both its output and a correct gradient callback. Serialization stores model state, so rebuild the matching architecture before from_disk; a newer 8.3 release explicitly documents that requirement.
Configuration uses Confection syntax and versioned registry entries. Import any module that registers project factories before registry.resolve, or the config cannot find them. Static checking also needs the documented thinc.mypy plugin. Pin the line required by the parent application: the highest PyPI version is 9.1.1 from 2024, but repository development and releases moved back to 8.3.x, where 8.3.13 shipped in 2026.
Patterns
Build a sequential classifier compose-dense-network
from thinc.api import Relu, Softmax, chain
model = chain(
Relu(nO=64, dropout=0.2),
Relu(nO=32, dropout=0.1),
Softmax(nO=3),
)`chain` passes each layer's output to the next. Missing input widths can be inferred during initialization.
Infer dimensions before inference initialize-and-predict
import numpy as np
X = np.zeros((4, 20), dtype='float32')
Y = np.zeros((4, 3), dtype='float32')
model.initialize(X=X, Y=Y)
predictions = model.predict(X)Use samples with the real rank and output width. Initialization performs shape inference and can expose incompatible layer annotations.
Run the explicit update sequence train-single-batch
from thinc.api import Adam, CategoricalCrossentropy
optimizer = Adam(learn_rate=0.001)
loss_fn = CategoricalCrossentropy()
guesses, backprop = model.begin_update(X)
d_guesses, loss = loss_fn(guesses, truths)
backprop(d_guesses)
model.finish_update(optimizer)The loss object returns the output gradient first and the scalar loss second. Apply that gradient before calling the optimizer step.
Own the minibatch training loop iterate-shuffled-batches
for X_batch, Y_batch in model.ops.multibatch(
32, train_X, train_Y, shuffle=True
):
guesses, backprop = model.begin_update(X_batch)
d_guesses, loss = loss_fn(guesses, Y_batch)
backprop(d_guesses)
model.finish_update(optimizer)Thinc supplies batching, but the application still tracks epochs, evaluation metrics, checkpoints, logs, and early stopping.
Increase batch size over time schedule-growing-batches
from thinc.api import compounding
batch_sizes = compounding(1.0, 32.0, 1.001)
for X_batch, Y_batch in model.ops.multibatch(
batch_sizes, train_X, train_Y, shuffle=True
):
train_batch(model, X_batch, Y_batch)The schedule is a stateful iterator. Construct a new one for an independent training run.
Define local infix composition scope-composition-operator
from thinc.api import Model, Relu, Softmax, chain
with Model.define_operators({'>>': chain}):
model = Relu(64) >> Relu(32) >> Softmax(3)Keep the context small. Named combinator calls are easier to search when custom operators make a model harder to review.
Return a matching gradient callback write-custom-layer
from thinc.api import Model
def scale_forward(model, X, is_train):
factor = model.attrs['factor']
Y = X * factor
def backprop(dY):
return dY * factor
return Y, backprop
def Scale(factor: float):
return Model('scale', scale_forward, attrs={'factor': factor})The forward function receives the model, input, and training flag. Its callback must map output gradients back to the input shape.
Construct registered objects from config resolve-config-tree
from thinc.api import Config, registry
config = Config().from_disk('training.cfg')
resolved = registry.resolve(config)
model = resolved['model']
optimizer = resolved['optimizer']Import project modules that register factories before resolution, or their names will be absent from the registry.
Expose an optimizer to config register-versioned-factory
import thinc
from thinc.api import Adam
@thinc.registry.optimizers('project.adam.v1')
def make_optimizer(learn_rate: float, beta1: float):
return Adam(learn_rate=learn_rate, beta1=beta1)Annotations feed config validation. Publish changed behavior under a new versioned name so old config files keep their meaning.
Reload into the same architecture persist-model-state
model.to_disk('model.bin')
restored = build_model()
restored.initialize(X=sample_X, Y=sample_Y)
restored.from_disk('model.bin')Serialization contains parameters and model state, not a substitute for constructing compatible code. The architecture must match before loading.
Apply one array layer to ragged data adapt-ragged-input
from thinc.api import Linear, with_array
model = with_array(Linear(nO=64))
model.initialize(X=ragged_batch)
outputs = model.predict(ragged_batch)`with_array` converts supported ragged, padded, list, or dense structures around an inner array-to-array layer. Initialize with the actual container type.
Select a GPU backend when present prefer-available-gpu
from thinc.api import prefer_gpu
using_gpu = prefer_gpu(0)
print({'gpu': using_gpu})CUDA requires a compatible CuPy install; Apple GPU use depends on supported PyTorch MPS. Call this before allocating model parameters.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| torch | PyPI | Use it for a broad model, accelerator, distributed-training, serving, and third-party extension ecosystem. |
| jax | PyPI | Use it when functional array programs need automatic differentiation, compilation, vectorization, and accelerator transforms. |
| tensorflow | PyPI | Use it when Keras, TensorFlow serving formats, mobile tooling, or an existing TensorFlow production stack decides the choice. |
More ai / ml guides
openai · mcp · huggingface-hub · scikit-learn · tiktoken · @modelcontextprotocol/sdk · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

