{ "cells": [ { "cell_type": "markdown", "id": "cell-0", "metadata": {}, "source": [ "# Fine-tune a BERT sentence classifier\n", "\n", "Install the checkout's `[notebooks]` extra and run `data.ipynb` first.\n", "The default is an offline CPU demonstration: a tiny randomly initialised\n", "BERT with a local vocabulary, trained for one epoch. It verifies the\n", "pipeline and does **not** reproduce SciBERT or its historical scores.\n", "\n", "Set `GREAT_AI_NOTEBOOK_FULL=1` before starting Jupyter to fine-tune\n", "`allenai/scibert_scivocab_uncased` instead. This downloads pretrained weights\n", "and takes substantially more memory and time; a GPU is recommended.\n", "Run the data and deployment notebooks in the same mode." ] }, { "cell_type": "markdown", "id": "2346798f", "metadata": {}, "source": [ "## Local setup\n", "\n", "Use Python 3.12 or 3.13 and install this checkout with `uv pip install --editable '.[notebooks]'`.\n", "See **Run notebooks locally** in the repository README for the kernel, execution order,\n", "and full-data options. Generated artifacts stay under `.cache/notebooks/`.\n" ] }, { "cell_type": "code", "execution_count": 1, "id": "824837fa", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\u001b[38;5;226mEnvironment variable ENVIRONMENT is not set, defaulting to development mode ‼️\u001b[0m\n", "\u001b[38;5;226mThe selected tracing database (ParallelTinyDbDriver) is not recommended for production\u001b[0m\n", "\u001b[38;5;39mGreatAI (v0.1.11): configured ✅\u001b[0m\n", "\u001b[38;5;39m 🔩 tracing_database: ParallelTinyDbDriver\u001b[0m\n", "\u001b[38;5;39m 🔩 large_file_implementation: LargeFileLocal\u001b[0m\n", "\u001b[38;5;39m 🔩 is_production: False\u001b[0m\n", "\u001b[38;5;39m 🔩 should_log_exception_stack: True\u001b[0m\n", "\u001b[38;5;39m 🔩 prediction_cache_size: 512\u001b[0m\n", "\u001b[38;5;39m 🔩 dashboard_table_size: 50\u001b[0m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Notebook artifacts: /Users/schmelczer/Projects/great-ai/.cache/notebooks/scibert\n" ] } ], "source": [ "import os\n", "import sys\n", "from pathlib import Path\n", "\n", "# Works when opened from the repository root or any notebook directory.\n", "_start = Path(globals().get(\"__file__\", Path.cwd())).resolve()\n", "ROOT = next(\n", " p\n", " for p in [_start, *_start.parents]\n", " if (p / \"pyproject.toml\").is_file() and (p / \"great_ai\").is_dir()\n", ")\n", "sys.path.insert(0, str(ROOT / \"docs\"))\n", "from notebook_support import setup_notebook, mag_lines\n", "\n", "FULL_RUN = os.environ.get(\"GREAT_AI_NOTEBOOK_FULL\") == \"1\"\n", "WORK_DIR = setup_notebook(ROOT, \"scibert\")\n", "DATA_DIR = ROOT / \"docs/tutorial/data\"" ] }, { "cell_type": "code", "execution_count": 2, "id": "cell-3", "metadata": {}, "outputs": [], "source": [ "# Dependencies are installed once with uv pip install --editable \".[notebooks]\"." ] }, { "cell_type": "markdown", "id": "cell-4", "metadata": {}, "source": [ "Load the dataset saved locally by `data.ipynb`." ] }, { "cell_type": "code", "execution_count": 3, "id": "cell-5", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "\u001b[38;5;39mFetching cached versions of summary-train-dataset-small\u001b[0m\n", "\u001b[38;5;39mLatest version of summary-train-dataset-small is 0 (from versions: 0)\u001b[0m\n", "\u001b[38;5;39mFile summary-train-dataset-small-0 found in cache\u001b[0m\n" ] } ], "source": [ "from great_ai.large_file import LargeFileLocal\n", "import json\n", "\n", "with LargeFileLocal(\"summary-train-dataset-small\", encoding=\"utf-8\") as f:\n", " X, y = json.load(f)" ] }, { "cell_type": "markdown", "id": "cell-6", "metadata": {}, "source": [ "Finetune SciBERT, for more info about this step, check out [HuggingFace](https://huggingface.co/docs/transformers/training).\n", "If you're only here for `great-ai`, feel free to skip the next cell.\n", "\n", "We use an 80/20 training/validation split. Early stopping and checkpoint selection both use validation binary F1 for positive label `1`. There is no independent test split in this example. The split and training seed is fixed for future runs, and the selected checkpoint's evaluation and run metadata are saved under `models/`.\n" ] }, { "cell_type": "code", "execution_count": 4, "id": "cell-7", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "W1028 12:48:58.270000 53390 torch/distributed/elastic/multiprocessing/redirects.py:35] NOTE: Redirects are currently not supported in MacOs.\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "2c74823d6364447a96609229fbbc5512", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Map: 0%| | 0/60 [00:00