finetune and the case for scikit-learn shaped NLP finetuning
Scikit-learn style model finetuning for NLP
At a glance
- What is it?
- finetune wraps BERT, RoBERTa, GPT, GPT2, TextCNN, TCN and DistilBERT behind a fit, predict and save API borrowed from scikit-learn, so text classification looks like any other model. The cost is a heavy TensorFlow dependency and a project whose last tagged release predates the recent work.
- Who is it for?
- finetune suits a team that wants to prototype a text classifier with the API muscle memory of scikit-learn and the option to swap the base model by changing one import, since that is what the library is for.
- Can I use it commercially?
- Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 171 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The whole pitch is one line of scikit-learn
finetune is a library that lets users use state-of-the-art pretrained NLP models for a wide variety of downstream tasks, and it is described in a single line as scikit-learn style model finetuning for NLP.
That API tour in the guide is the whole idea:
model = Classifier() # Load base model
model.fit(trainX, trainY) # Finetune base model on custom data
model.save(path) # Serialize the model to disk
...
model = Classifier.load(path) # Reload models from disk at any time
predictions = model.predict(testX) # [{'class_1': 0.23, 'class_2': 0.54, ..}, ..]Fit, predict, save, load. For anyone who has trained a text classifier with scikit-learn, this removes the entire category of confusion that normally comes with neural models, which is that the training loop is not yours to write. Here you hand over two arrays and get a fitted object back.
The predict output is worth pausing on, because it is a list of dictionaries with a score per class rather than a hard label. That is what a multi-class problem needs, and it is a detail that quietly makes the interface more useful than a bare argmax would be.
The project is MPL-2.0 licensed, written in Python, and its home page is finetune.indico.io, with a full API reference and a configuration document hosted there.
Swapping the base model is an import change
The base model is chosen from the finetune.base_models module, and the mechanism is deliberately plain:
from finetune.base_models import BERT, RoBERTa, GPT, GPT2, TextCNN, TCN
model = Classifier(base_model=BERT)The supported set covers a wide spread of architectures and vintages. The listed models are BERT, from the pre-training of deep bidirectional transformers paper, RoBERTa, from the paper on a more carefully optimised BERT pretraining approach, GPT, from the generative pre-training paper, GPT2, from the unsupervised multitask learners paper, TextCNN, from the convolutional networks for sentence classification paper, the Temporal Convolution Network from the empirical evaluation of generic convolutional and recurrent networks paper, and DistilBERT, the distilled version of BERT.
That list is a good summary of the library's era. TextCNN and TCN are pre-transformer sequence models that remain useful for short text, and including them alongside GPT and DistilBERT means the library spans the whole history of the last decade of NLP modelling rather than only the newest architecture.
The one detail that changes the shape of the code is the base model being a constructor argument rather than a class. You pass BERT to Classifier and the same classifier, the same fit call and the same predict call work for all of them, so a comparison across architectures becomes a change in one line of the script.
Tuning is done through configurables passed to the constructor, with the guide giving an example that combines several:
model = Classifier(low_memory_mode=True, lr_schedule="warmup_linear", max_length=512, l2_reg=0.01, oversample=True, ...)The complete list of configuration items is in the finetune docs.
Twelve target types, and the one that decides your architecture
The library covers a lot more than classification, and the target type list in the guide is worth reading as a design map.
The classification and regression group runs from Classifier and MultiLabelClassifier through MultiFieldClassifier and MultipleChoice, then Regressor, OrdinalRegressor and MultifieldRegressor. The extraction group has SequenceLabeler and Association, described as extracting tokens from a given class or inferring relationships between them. The comparison group is Comparison, ComparisonRegressor and ComparisonOrdinalRegressor, for comparing two documents for a given task. And then LanguageModel and MultiTask, for further pretraining the base models.
The last entry in the list is the one that changes how you deploy. DeploymentModel is described as a wrapper to optimize your serialized models for a production environment, so the model you trained and the model you serve are not the same object.
Two of the names are less obvious. MultiFieldClassifier implies a field-aware problem, where the model sees a structured input rather than one string, and MultipleChoice is the case where a single input maps to one of several labelled alternatives. Both are problems where a plain text classifier would need a custom wrapper around the model, and here they are target types in the same family.
Example usage for each target type is in the finetune/datasets directory, and the guide notes that for simplicity and runtime those examples use smaller versions of the published datasets.
Two-step finetuning when the labels are the scarce resource
There is one workflow in the guide that is worth pulling out on its own, because it addresses a common real situation.
If you have large amounts of unlabeled training data and only a small amount of labeled training data, you can finetune in two steps for best performance:
model = Classifier() # Load base model
model.fit(unlabeledX) # Finetune base model on unlabeled training data
model.fit(trainX, trainY) # Continue finetuning with a smaller amount of labeled data
predictions = model.predict(testX) # [{'class_1': 0.23, 'class_2': 0.54, ..}, ..]
model.save(path) # Serialize the model to diskThe mechanism is that the first fit call trains on the unlabeled set with no targets, and the second call continues from that state with the small labeled set. The same model object is reused, so the continuation is not a fresh start.
This is a well-known approach in applied NLP, and having it expressed as two calls on one object rather than as a separate pretraining phase keeps the whole workflow inside the scikit-learn mental model. The alternative shape, a separate base model preparation step followed by a classifier fit, would break exactly the consistency the library is selling.
Note also that predict comes before save in the example, which is a small but useful reminder that the fitted object is what you query, and save is just the serialization of it.
Installation drags in TensorFlow, spaCy and a GPU driver
The installation section is where the library's cost becomes concrete, and it is worth reading before the API tour.
From PyPI it is one command:
pip3 install finetuneFrom source it is four:
git clone -b master https://github.com/IndicoDataSolutions/finetune && cd finetune
python3 setup.py develop # symlinks the git directory to your python path
pip3 install tensorflow-gpu --upgrade # or tensorflow-cpu
python3 -m spacy download en # download spacy tokenizerThree things stand out. The clone uses the master branch explicitly, even though the default branch for the repository is development. The TensorFlow install is separate, because the library treats it as an optional extra rather than a hard dependency: pyproject.toml lists tensorflow at 2.20.0 and tensorflow-gpu at 2.20.0 under optional dependency groups named tf and tf_gpu.
And the spaCy tokenizer has to be downloaded separately, with the model name given on the command line. That is a step that catches people out, because the package installs but the tokenizer is not there until you fetch it.
The guide also states the runtime requirement plainly: to run finetune on your host you will need a working copy of tensorflow-gpu at 1.14.0 or newer and up to date nvidia-driver versions. The remaining dependencies in pyproject.toml are substantial too, including numpy, scikit-learn, spacy, nltk, keras, tokenizers, ftfy, joblib, pynvml and psutil, which is a heavy install for a text classifier.
The Docker path assumes NVIDIA and a container that never exits
For running the library in a container, the guide offers GPU and CPU routes through shell scripts, with a stated assumption that you have a functional install of docker and nvidia-docker.
The GPU sequence builds an image and starts a container in the background, forwarding the current directory into the container, and then opens a shell inside it:
git clone https://github.com/IndicoDataSolutions/finetune && cd finetune
# For usage with NVIDIA GPUs
./docker/build_gpu_docker.sh # builds a docker image
./docker/start_gpu_docker.sh # starts a docker container in the background, forwards $PWD to /finetune
docker exec -it finetune bash # starts a bash session in the docker containerThe CPU-only route is two scripts:
./docker/build_cpu_docker.sh
./docker/start_cpu_docker.shThe Dockerfile explains what the image is. It starts from python:3.12-slim, installs tensorflow with the and-cuda extra at version 2.20.0, installs cmake and g++, exposes port 6006 for tensorboard, and sets the command to sleep infinity, which is why the workflow is to exec into the container rather than to run a service in it.
The docker-compose.yml at the repository root is configured for GPU use, with the LD_LIBRARY_PATH pointing at the CUPTI library and a device reservation requesting the nvidia driver with GPU capabilities.
So this is a development container rather than a service image, and the compose file is a convenience for a machine with a specific GPU configuration rather than something general.
Release history, licence and the gap that concerns adopters
The maintenance record is the part that needs attention.
The listed releases are 0.8.5 from 2019-11-06, 0.8.6 from 2020-01-10 and 0.10.0 from 2023-09-29, and the last push to the repository was on 2026-05-05. The version in pyproject.toml is 0.10.1, which does not correspond to any of those tags, so the published package and the tagged releases are not the same sequence.
The gap between the newest tag and the last commit is more than a year, and a gap of that length in a library that depends on a fast-moving framework is worth thinking about. The dependency list pins TensorFlow to an exact version in the optional extras, and the manifest requires numpy 2.0.0 or newer, scikit-learn 1.0.2 or newer and spacy 3.0.0 or newer, so the current tree is being kept in step with a modern stack even though the release tags have not moved.
The licence is MPL-2.0, which is a file-level copyleft licence. For a library consumed by applications, that is a middle position: modifications to the library's own files carry the obligation, while a larger application that merely imports it is not forced to adopt the licence.
The repository layout is a conventional Python package layout with a finetune/ package directory, a tests/ directory, a docs/ directory, a speed_benchmarks/ directory and a Data/ directory, plus a pyproject.toml, a pytest.ini, a MANIFEST.in, a CHANGES.txt and a pre-commit configuration. The existence of pytest.ini and a pre-commit config is a good sign for the internal quality of the project even where the release cadence is slow.
Editorial conclusion
finetune suits a team that wants to prototype a text classifier with the API muscle memory of scikit-learn and the option to swap the base model by changing one import, since that is what the library is for. It does not suit a project that has standardised on the transformers ecosystem, because finetune carries its own TensorFlow and spaCy stack, and it does not suit someone who needs a supported release train, since the newest listed tag is 0.10.0 from 2023-09-29 while the project version in pyproject.toml is 0.10.1 and the last push was on 2026-05-05. Before you build on it, check the TensorFlow version your environment already has, since the optional extras pin tensorflow at 2.20.0, and read the docs directory rather than assuming the API matches the published examples.
Frequently asked questions
What is the finetune Python library?
finetune is a library for finetuning pretrained NLP models with a scikit-learn style API. You call fit with your training data, predict to get class scores, and save or load the fitted model, without writing a training loop.
Which base models does finetune support?
It supports TensorFlow implementations of BERT, RoBERTa, GPT, GPT2, TextCNN, the Temporal Convolution Network and DistilBERT. The base model is imported from finetune.base_models and passed to the constructor, so switching architectures is a one line change.
How do I install finetune and its TensorFlow dependency?
pip3 install finetune installs the package from PyPI, and TensorFlow is an optional extra pinned at 2.20.0. From source you run python3 setup.py develop, install tensorflow-gpu or tensorflow-cpu separately, and download the spaCy tokenizer with python3 -m spacy download en.
Can finetune use unlabeled data before the labeled data?
Yes. Fit the model on the unlabeled set first, then call fit again with the smaller labeled set, and the second call continues from the state the first one produced. The guide describes this as finetuning in two steps for best performance.
What is the newest release of finetune?
The listed releases are 0.10.0 from 2023-09-29, 0.8.6 from 2020-01-10 and 0.8.5 from 2019-11-06, while the version in pyproject.toml is 0.10.1. The last push to the repository was on 2026-05-05.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/indicodatasolutions-finetune)Was this useful?