Thinc
Thinc is a lightweight deep learning library from the makers of spaCy and Prodigy, offering a type-checked, functional-programming API for composing models. It emphasizes composition over inheritance and supports wrapping layers from other frameworks like PyTorch, TensorFlow, and MXNet, allowing for flexible model development. Thinc is actively maintained with frequent releases to support new Python versions and address bug fixes.
Warnings
- breaking Thinc dropped support for Python 3.9 in recent versions (e.g., v8.3.7). Ensure your Python environment is 3.10 or newer.
- breaking `Model.from_disk` (and deserialization in general) requires the model architecture to match exactly what it was serialized from. Side-effects within the `init` function of a `Model` will not be replicated during deserialization if they modify the layer's node structure.
- breaking The `Loss.get_grad` method computes the gradient with respect to *logits* (pre-softmax outputs), not the post-softmax probabilities. While this design is for numerical stability, it can be a source of confusion if not explicitly understood.
- breaking Thinc's migration to Pydantic v2 (required for Python 3.13+) introduced breaking changes due to how Thinc's internal configuration system used Pydantic v1. While Thinc has adapted, direct interactions with Pydantic in custom Thinc components might require updates if migrating from older Thinc/Pydantic versions.
- gotcha There have been intermittent crashes related to the `blis` package on Windows, leading to specific version pinning in Thinc releases. Users on Windows may encounter stability issues if `blis` versions are mismatched or not well-tested for their environment.
- gotcha Thinc's built-in layers and constructors often define output dimension (`nO`) as the first argument, followed by input dimension (`nI`), which is opposite to the `in_features`, `out_features` convention in PyTorch layers.
- gotcha A float64 dtype mismatch in BLIS gemm operations can lead to errors. This usually indicates an incompatibility in the array types being passed to Thinc's underlying numerical backend.
Install
-
pip install thinc
Imports
- Model
from thinc.api import Model
- chain
from thinc.api import chain
- Relu
from thinc.api import Relu
- Softmax
from thinc.api import Softmax
- Config
from thinc.api import Config
- registry
from thinc.api import registry
Quickstart
import thinc.api as api
# Define a simple feed-forward model using combinators
n_hidden = 128
with api.Model.define_operators({ ">>" : api.chain }):
model = api.Relu(nO=n_hidden) >> api.Relu(nO=n_hidden) >> api.Softmax()
# Initialize the model (e.g., with dummy data for shape inference)
# In a real scenario, this would be done with actual data or explicit nI/nO.
# For demonstration, we'll manually set nI if it's not inferred.
if model.init_no_grad is None:
model.init_no_grad = lambda X, Y: (X, Y)
# Example: If your model requires an input dimension, set it manually or via dummy data
# For this simple model, `nI` must be set if not inferred from `X` during init.
# Let's assume an input dimension of 784 (e.g., for MNIST flattened images)
model.set_dim("nI", 784)
model.initialize() # Initialize parameters
print(f"Model: {model.name}")
print(f"Input dimension (nI): {model.get_dim('nI')}")
print(f"Output dimension (nO): {model.get_dim('nO')}")
print(f"Number of parameters: {model.to_bytes().nbytes} bytes")
# Simulate a forward pass (requires numpy for dummy data)
import numpy
X_dummy = numpy.random.rand(10, model.get_dim('nI')).astype('f')
Y_dummy, callback = model(X_dummy, is_train=False)
print(f"Output shape: {Y_dummy.shape}")