Current maintained release: 0.3.0
This repository provides a hierarchical job ads classifier with two backends:
- a
LinearJobOffersClassifierbased on TF-IDF plusnapkinxc - a
TransformerJobOffersClassifierbased on Hugging Face encoder models
The current 0.3.x line focuses on:
- modern packaging and installation
- compatibility with existing saved models
- CPU and GPU-safe runtime handling
- a faster transformer data path with batched tokenization and dynamic padding
If you use this repository, please cite:
Beręsewicz, M., Wydmuch, M., Cherniaiev, H., and Pater, R. (2026). Multilingual Hierarchical Classification of Job Advertisements for Job Vacancy Statistics. Journal of Official Statistics, 42(1), 23-61. https://doi.org/10.1177/0282423X251395400
GitHub citation metadata is also available in CITATION.cff.
- Python:
3.11or3.12 - CPU: supported
- GPU: supported for the transformer backend when a matching PyTorch build is installed first
The package uses optional dependency groups:
linear: dependencies for the TF-IDF plusnapkinxcbackendtransformer: dependencies for the Hugging Face plus Lightning backendtest: pytest and test helpers
Typical full development install:
pip install -e ".[linear,transformer,test]"CPU-oriented full install:
git clone https://github.com/OJALAB/job-ads-classifier.git
cd job-ads-classifier
python -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -e ".[linear,transformer,test]"If you prefer the fully pinned release files instead of extras:
pip install torch
pip install -r requirements-0.3.0.txt
pip install -e .Until a dedicated PyPI release is published, install from GitHub or from a built wheel.
python -m pip install --upgrade pip
pip install "job-ads-classifier[linear,transformer] @ git+https://github.com/OJALAB/job-ads-classifier.git@main"Local editable install:
uv venv
source .venv/bin/activate
uv pip install -e ".[linear,transformer,test]"Install from GitHub:
uv venv
source .venv/bin/activate
uv pip install "job-ads-classifier[linear,transformer] @ git+https://github.com/OJALAB/job-ads-classifier.git@main"For GPU work, install the matching PyTorch build first and then install the package extras:
pip install torch # replace with the correct CUDA build from pytorch.org
pip install -e ".[transformer]"Use the selector at pytorch.org for the exact CUDA build.
With pip tooling:
python -m pip install build
python -m build
pip install dist/job_ads_classifier-0.3.0-py3-none-any.whlWith uv:
uv build
uv pip install dist/job_ads_classifier-0.3.0-py3-none-any.whlThe repository keeps the main.py entry point and also exposes the installable console script:
job-ads-classifier --help
python main.py --helppython main.py fit LinearJobOffersClassifier \
-x tests/data/x_train.txt \
-y tests/data/y_train.txt \
--hierarchy-data tests/data/classes.tsv \
-m models/linear-demo \
--tfidf-vectorizer-min-df 1 \
-T 1python main.py predict LinearJobOffersClassifier \
-x tests/data/x_test.txt \
-m models/linear-demo \
-p predictions-linear.txt \
-T 1python main.py fit TransformerJobOffersClassifier \
-x tests/data/x_train.txt \
-y tests/data/y_train.txt \
--hierarchy-data tests/data/classes.tsv \
-m models/transformer-demo \
-t google/bert_uncased_L-2_H-128_A-2 \
-mm bottom-up \
-e 1 \
-b 2 \
-s 32 \
--pooling cls \
--tokenization-mode batched \
-A cpu \
-P 32 \
-T 1python main.py predict TransformerJobOffersClassifier \
-x tests/data/x_test.txt \
-m models/transformer-demo \
-p predictions-transformer.txt \
--tokenization-mode batched \
-A cpu \
-P 32 \
-T 1--pooling {cls,mean}--gradient-checkpointing--tokenization-mode {batched,lazy}
Defaults:
pooling=clsgradient_checkpointing=Falsetokenization_mode=batched
- transformer tokenization can now run in a batched pre-encoded mode
- batch collation now uses dynamic padding instead of always padding every sample to
max_sequence_length - transformer pooling is now configurable with
clsormean - gradient checkpointing is exposed for larger transformer runs
- prediction now goes through the Lightning datamodule path with less logging overhead
- a benchmark helper was added to measure lazy vs batched tokenization paths
- the main README now documents
pipanduvinstallation flows
Release 0.3.0 includes a benchmark helper:
python scripts/benchmark_0_3_0.py --helpThis benchmark does not require a saved model. It compares the legacy lazy per-sample path with the new batched path using the current dataset and collator implementations.
python scripts/benchmark_0_3_0.py transformer-data \
--text-count 5000 \
--batch-size 32 \
--repeats 3 \
--max-seq-length 128Use an extracted RepOD transformer model and compare lazy vs batched on the same predict path:
python scripts/benchmark_0_3_0.py existing-model-compare \
--classifier TransformerJobOffersClassifier \
--model-dir /path/to/transformer-bottom-base-2024/transformer-bottom-base-2024 \
--input-file tests/data/x_test.txt \
--pred-path-prefix /tmp/job-ads-bench \
--accelerator cpu \
--precision 32 \
--threads 1 \
--batch-size 64 \
--repeats 3The benchmark report for this release is tracked in BENCHMARK-0.3.0.md.
To compare the old release tag with the current checkout on the same extracted model, use:
bash scripts/compare_server_0_2_0_vs_0_3_0.sh \
--classifier TransformerJobOffersClassifier \
--model-dir /path/to/transformer-bottom-base-2024/transformer-bottom-base-2024The script:
- creates temporary git worktrees for
v0.2.0and the currentHEAD - runs repeated
predicttimings on the same input data - measures
0.3.0inbatchedmode and, for transformers, also inlazymode - compares the prediction files and
.mapfiles - writes both
summary.jsonandsummary.md
Current measured offline benchmark result for 0.3.0:
transformer-data,10000texts,batch_size=32,repeats=3,tokenizer_model=local-fast- repeated local runs landed between
5.33xand5.89x - representative measured speedup: about
5.4x
Measured end-to-end results on an existing public RepOD transformer were more conservative:
- CPU server predict with
transformer-bottom-base-2024:lazyandbatchedwere effectively tied, with no meaningful steady-state speedup - Colab GPU predict on a larger replicated input:
batchedlooked better on the full average because of a very slow firstlazyrun, but steady-state runs were again very close - practical conclusion:
0.3.0gives a clearly faster transformer data path in isolation, while full inference on an existing HerBERT-based model remains dominated by model execution rather than tokenization
Public pretrained classifiers are available in RepOD:
- DOI landing page: https://doi.org/10.18150/OCUTSI
- dataset page: https://repod.icm.edu.pl/dataset.xhtml?persistentId=doi:10.18150/OCUTSI
Important artifacts include:
linear-bottom-2024.ziplinear-top-2024.ziptransformer-bottom-base-2024.ziptransformer-top-base-2024.ziptransformer-bottom-base-rob-2024.ziptransformer-top-base-rob-2024.zip- multilingual
xlm-RoBERTavariants - split large-model archives stored as
.tar.gz.partaaand.partab
Practical starting points:
- first CPU compatibility check:
linear-bottom-2024.ziplinear-top-2024.ziptransformer-bottom-base-2024.ziptransformer-top-base-2024.zip
- first GPU compatibility check:
transformer-bottom-base-2024.zip
If you use one of the split large-model archives, merge the parts first:
cat transformer-bottom-large-2024.tar.gz.partaa transformer-bottom-large-2024.tar.gz.partab > transformer-bottom-large-2024.tar.gz
tar -xzf transformer-bottom-large-2024.tar.gzTransformer model:
EXISTING_MODEL_DIR=/path/to/existing-model \
EXISTING_MODEL_INPUT=/path/to/input.txt \
EXISTING_MODEL_CLASSIFIER=TransformerJobOffersClassifier \
pytest tests/test_existing_model_cpu.py -qLinear model:
EXISTING_MODEL_DIR=/path/to/existing-model \
EXISTING_MODEL_INPUT=/path/to/input.txt \
EXISTING_MODEL_CLASSIFIER=LinearJobOffersClassifier \
pytest tests/test_existing_model_cpu.py -qTransformer example:
bash scripts/validate_existing_model_cpu.sh \
TransformerJobOffersClassifier \
/path/to/extracted-model \
tests/data/x_test.txt \
/tmp/job-ads-checkLinear example:
bash scripts/validate_existing_model_cpu.sh \
LinearJobOffersClassifier \
/path/to/extracted-model \
tests/data/x_test.txt \
/tmp/job-ads-checkThe current compatibility path has been validated against old RepOD models, including:
linear-bottom-2024.ziptransformer-bottom-base-2024.zip
The transformer backend expects Hugging Face encoder-style models through:
AutoTokenizer.from_pretrained(...)AutoModel.from_pretrained(...)
Recommended starting points:
- Polish-focused:
allegro/herbert-base-cased - multilingual:
FacebookAI/xlm-roberta-base - modern general-purpose baseline:
answerdotai/ModernBERT-base - smallest smoke-test model:
google/bert_uncased_L-2_H-128_A-2
Models that are not a drop-in fit for the current pipeline:
- decoder-only LLMs such as Gemma, Llama, Mistral, Qwen, GPT-style models
- sentence-transformers style pipelines that expect dedicated pooling heads
Why Gemma is not a recommended default here:
- the current code is built around encoder-style tokenization and
AutoModel - the classifier pools encoder hidden states and feeds them into a classification head
- decoder-only LLMs do not match that interface as cleanly as encoder backbones do
Fast suite:
pytest -m "not integration"Linear smoke test:
pytest tests/test_smoke_linear.py -qTransformer smoke test:
RUN_TRANSFORMER_SMOKE=1 pytest tests/test_smoke_transformer.py -qOptional model override:
RUN_TRANSFORMER_SMOKE=1 \
TRANSFORMER_SMOKE_MODEL=google/bert_uncased_L-2_H-128_A-2 \
pytest tests/test_smoke_transformer.py -qThe colab/ folder contains notebooks for the maintained release line:
colab/colab-smoke-test-0.2.0.ipynbcolab/colab-repod-pretrained-models-0.2.0.ipynbcolab/colab-existing-model-gpu-predict-0.2.0.ipynbcolab/colab-short-transformer-training-gpu-0.2.0.ipynb
The GPU-specific notebooks currently track main so they include the latest Colab fixes.
For a one-cell Colab benchmark from install to GPU timing, you can also run:
bash scripts/run_colab_transformer_benchmark_0_3_0.shThis script:
- clones the repository
- installs the
0.3.0Colab dependencies - downloads
transformer-bottom-base-2024.zipfrom RepOD - extracts the model
- builds a larger benchmark input file from
tests/data/x_test.txt - runs
lazyvsbatchedbenchmark on GPU
Historical and versioned READMEs remain in the repository:
README-0.1.0.mdREADME-0.2.0.mdREADME-0.3.0.md
Default dependency pointers now target the maintained line:
requirements.txt->requirements-0.3.0.txtrequirements-colab.txt->requirements-colab-0.3.0.txt