--- title: Physh Classification emoji: πŸ† colorFrom: red colorTo: purple sdk: gradio sdk_version: 6.28.0 python_version: '3.12' app_file: app.py pinned: false license: apache-2.0 models: - LukeFP/physh_topic_supervised_classifier - google/embeddinggemma-300m --- # PhySH Topic Classifier Paste a physics title and abstract; get back its [PhySH](https://physh.org) **disciplines** and **top-level research-area concepts**. ## How it works ``` text ──EmbeddingGemma-300m──> 768-d vector β”‚ β”œβ”€β”€> discipline head 768 β†’ 1024 β†’ 512 β†’ 18 sigmoid β”‚ β”‚ └──> concept head [768 + 18] β†’ 1024 β†’ 512 β†’ 186 sigmoid β–² discipline probabilities ``` Both heads are multi-label MLPs with ReLU and dropout 0.3, trained on EmbeddingGemma vectors. The concept head is *conditioned* on the discipline head's output: its 786-dimensional input is the text embedding concatenated with the 18 discipline probabilities (the checkpoint records `use_logits: False`, so probabilities rather than logits are what it expects). Weights live in [`LukeFP/physh_topic_supervised_classifier`](https://huggingface.co/LukeFP/physh_topic_supervised_classifier) and are downloaded at startup, so retraining only requires a push to that repo β€” no change here. | Head | micro-F1 | macro-F1 | avg labels/sample | |---|---|---|---| | Discipline (18) | 0.799 | 0.683 | 1.41 | | Concept (186) | 0.641 | 0.423 | 2.12 | ## Setup `google/embeddinggemma-300m` is a gated repo. Accept the Gemma license on the model page, then add a read token as a Space secret named `HF_TOKEN` (Settings β†’ Variables and secrets). Without it the Space boots but the first classification fails. This Space runs on **ZeroGPU**: `infer()` carries the `@spaces.GPU` decorator, the models are loaded on CPU in the main process, and device placement happens inside the decorated function. The same code runs unchanged on CPU hardware β€” `spaces` is optional at import and `torch.cuda.is_available()` picks the device. ### Prompt format EmbeddingGemma prepends a task-specific prefix, and the prefix used here must match the one used to build the training embeddings β€” a mismatch degrades accuracy quietly instead of erroring. The default is the document prompt (`title: none | text: …`); the Advanced panel lets you switch and compare. ## Running locally ```bash pip install -r requirements.txt export HF_TOKEN=hf_... python app.py ``` Set `PHYSH_WEIGHTS_DIR=/path/to/physh_topic_supervised_classifier` to load the `.pt` files from a local clone instead of the Hub. ## API Gradio exposes the Space as an API, which is the practical route for batch labelling: ```python from gradio_client import Client client = Client("LukeFP/Physh_Classification") disciplines, concepts, summary = client.predict( "Title and abstract…", 0.5, "document β€” title: none | text: {}", 8, api_name="/classify", ) ```