Imported from turdalievargen32/BERT_NLP_proj (
AGENTS.md). Install upstream withnpx skills add turdalievargen32/BERT_NLP_proj. Copyright stays with the author.
AGENTS.md
Entry point for AI coding agents and for humans arriving without context. Vendor-neutral: nothing here assumes a particular assistant or tool.
What this project is
A binary sentiment classifier — Negative (0) / Positive (1) — fine-tuned
from bert-base-uncased on the IMDB movie-review dataset, plus scripts for
evaluation, error analysis, and per-token explainability.
It is a small, single-purpose repository. There is no service, no API, no database, and no deployment target. The deliverable is a reproducible pipeline that runs from a clean clone.
Canonical documents
Read in this order. Where they disagree, the one higher in this list wins.
| Document | What it is authoritative for |
|---|---|
AGENTS.md (this file) |
Invariants, safe commands, change boundaries |
DECISIONS.md |
Why the code is shaped the way it is; every PR's rationale and rejected alternatives |
README.md |
User-facing usage, configuration table, quickstart |
src/config.py |
The actual runtime values — paths, model id, hyperparameters |
If code and documentation disagree, that is a bug. Fix it in the same change rather than working around it.
Invariants
Breaking any of these is a behaviour change, not a refactor. If a task requires it, say so explicitly rather than doing it silently.
- The task is binary.
config.NUM_LABELS == 2andconfig.CLASS_NAMES == ["Negative", "Positive"].config._validate()enforces that these two agree. An earlier README claimed a third "neutral" class; it never existed in the code. src/config.pyis the single source of truth. Model id, dataset name,MAX_LENGTH,BATCH_SIZE,NUM_EPOCHS, and every path live there. Do not reintroduce a literal"bert-base-uncased",128, or16into a script — readconfig.*instead.- No absolute paths. Every default is derived from
config.REPO_ROOT. A path beginning/content/,/Users/, or/home/insrc/is a regression — that was the defect that made the original repository unrunnable outside its author's Colab session. - Training saves where consumers load.
run_trainerwrites toconfig.MODEL_DIR;evaluate.py,analyze.py,predict.py, and the explainability scripts all read from it. These must never diverge.tests/test_training_smoke.pyguards this. - Local weights load with
use_safetensors=True. Loading a local pickle-format checkpoint can execute code. Hub downloads (config.BASE_MODEL) deliberately do not force it — see PR 4 inDECISIONS.md. - Artifacts stay out of the repo. Models go to
best_model/, plots and Trainer output tooutputs/; both are git-ignored. Nothing should write intosrc/.
Commands
Safe to run at any time, no network or GPU needed:
python -m ruff check src tests # lint gate
python -m pytest -q -m "not slow" # fast tests (~3s, no torch needed)
Needs the full dependency set:
python -m pytest -q -m slow # training round-trip (~10s, small download)
python -m pytest -q # everything
Expensive — do not run these to "check whether it works", they download datasets and train for a long time:
python src/train.py # full IMDB fine-tune (hours on CPU)
python src/evaluate.py # needs a trained model, downloads IMDB test split
To exercise the pipeline cheaply, prefer the smoke test — it does exactly this against a tiny model and asserts the result. If you need to drive the real script, override the config rather than editing it:
BERT_BASE_MODEL=hf-internal-testing/tiny-random-BertForSequenceClassification \
BERT_NUM_EPOCHS=1 BERT_MAX_LENGTH=32 python src/train.py
That still downloads the full IMDB dataset, so the smoke test remains the cheap option.
Where things live
src/config.py single source of truth (invariants 2-4)
src/train.py fine-tuning entry point
src/predict.py inference CLI
src/models/bert_classifier.py the only model factory — build_model()
src/training/train_with_trainer.py HF Trainer wrapper
src/training/metrics.py compute_metrics, torch-free by design
src/utils/text_cleaning.py clean_text — used by training AND inference
src/utils/prediction.py label/confidence formatting, torch-free by design
src/data/dataset.py torch Dataset wrapper; renames label -> labels
metrics.py and prediction.py are torch-free on purpose so they can be
unit-tested without the full stack. Do not move heavy imports into them.
Entry scripts start with a three-line sys.path shim so
python src/train.py works from the repo root without a package install.
A full package refactor is a known follow-up (see DECISIONS.md); until
then, keep the shim when adding a new entry script.
Change boundaries
Safe to change freely: tests, docstrings, README.md, adding new
BERT_* config options, adding new scripts under src/.
Change with care, and say why in DECISIONS.md: anything in
src/config.py, the ruff rule set in pyproject.toml, dependency bounds in
requirements.txt, the CI workflow.
Do not change without being asked: the modelling approach itself. The architecture, the dataset, the loss, and the metric choices are deliberate and out of scope for engineering cleanups. Improve the code around the model.
Watch out for:
requirements.txtneedsaccelerateeven though nothing imports it — it is a runtime requirement oftransformers'Trainer. A dependency being absent from everyimportline does not mean it is unused.- Never hand-edit
requirements.lockorrequirements-dev.lock. Changerequirements.txt,requirements-dev.txt, orconstraints.txtand regenerate — the exact command is inCONTRIBUTING.md, and CI fails if the committed lockfiles do not match a fresh regeneration.
Definition of done
Before considering a change complete:
python -m ruff check src testspasses.python -m pytest -qpasses (or-m "not slow"if torch is unavailable — say which you ran).- New behaviour has a test. New decisions have a
DECISIONS.mdentry stating the problem, the choice, and what was rejected. - Documentation matches the code. If you changed a command, a path, or a config default, the README says the new thing.
Handoff
Work is done one concern per branch. When handing off mid-task, state:
- which branch, and what the last commit does;
- which of the two gates you ran and their result — including failures, and including "I could not run this" with the reason;
- what is deliberately left undone, and why.
Do not report a check as passing unless you ran it and saw it pass.