7-level sentiment classifier on gemma-3-270m
Browse files- .gitattributes +1 -0
- NOTICE +1 -0
- README.md +96 -0
- config.json +80 -0
- model.safetensors +3 -0
- tokenizer.json +3 -0
- tokenizer_config.json +24 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
NOTICE
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
Gemma is provided under and subject to the Gemma Terms of Use found at ai.google.dev/gemma/terms
|
README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: gemma
|
| 3 |
+
base_model: google/gemma-3-270m
|
| 4 |
+
pipeline_tag: text-classification
|
| 5 |
+
language:
|
| 6 |
+
- en
|
| 7 |
+
tags:
|
| 8 |
+
- sentiment-analysis
|
| 9 |
+
- text-classification
|
| 10 |
+
- gemma3
|
| 11 |
+
- synthetic-data
|
| 12 |
+
metrics:
|
| 13 |
+
- accuracy
|
| 14 |
+
- f1
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
# Gemma 3 270M: 7-level sentiment classifier
|
| 18 |
+
|
| 19 |
+
A fine-tune of [google/gemma-3-270m](https://huggingface.co/google/gemma-3-270m) (the base model, not the instruct version) with a classification head. It sorts a short piece of text (a sentence, heading, bullet point, or table row) into one of seven sentiment levels:
|
| 20 |
+
|
| 21 |
+
| id | label |
|
| 22 |
+
|---|---|
|
| 23 |
+
| 0 | very positive |
|
| 24 |
+
| 1 | positive |
|
| 25 |
+
| 2 | somewhat positive |
|
| 26 |
+
| 3 | neutral |
|
| 27 |
+
| 4 | somewhat negative |
|
| 28 |
+
| 5 | negative |
|
| 29 |
+
| 6 | very negative |
|
| 30 |
+
|
| 31 |
+
## Results
|
| 32 |
+
|
| 33 |
+
On a held-out test set of 8,749 segments (from documents never seen in training):
|
| 34 |
+
|
| 35 |
+
| Metric | Score |
|
| 36 |
+
|---|---|
|
| 37 |
+
| Exact label | **84.0%** |
|
| 38 |
+
| Exact or one level off | **95.2%** |
|
| 39 |
+
| Macro-F1 | 0.833 |
|
| 40 |
+
|
| 41 |
+
| Label | F1 |
|
| 42 |
+
|---|---|
|
| 43 |
+
| very positive | 0.88 |
|
| 44 |
+
| positive | 0.80 |
|
| 45 |
+
| somewhat positive | 0.88 |
|
| 46 |
+
| neutral | 0.90 |
|
| 47 |
+
| somewhat negative | 0.70 |
|
| 48 |
+
| negative | 0.79 |
|
| 49 |
+
| very negative | 0.89 |
|
| 50 |
+
|
| 51 |
+
Most errors are one level off. The hardest boundary is "somewhat negative" versus "negative".
|
| 52 |
+
|
| 53 |
+
**Important:** the test set is synthetic and was labelled by the same process as the training data (see below). These scores measure agreement with that labelling. The model has not yet been evaluated on human-labelled, real-world text.
|
| 54 |
+
|
| 55 |
+
## Usage
|
| 56 |
+
|
| 57 |
+
```python
|
| 58 |
+
from transformers import pipeline
|
| 59 |
+
|
| 60 |
+
clf = pipeline("text-classification", model="dejanai/sentiment-classifier")
|
| 61 |
+
clf("Delivery took three weeks and nobody answered my emails.")
|
| 62 |
+
# [{'label': 'negative', 'score': 0.88}]
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
Classify one sentence or short segment at a time. For a whole document, split it into sentences, headings, bullet points, and table rows first, and classify each. Inputs are truncated at 128 tokens.
|
| 66 |
+
|
| 67 |
+
## Training data
|
| 68 |
+
|
| 69 |
+
About 83,000 labelled segments from 2,782 synthetic documents, made in three steps:
|
| 70 |
+
|
| 71 |
+
1. **Writer:** Gemini 3.8 Flash wrote complete documents in 26 content formats (blog posts, product reviews, tweet threads, meeting notes, technical papers, press releases, support chats, YouTube and podcast transcripts, FAQ pages, and more). Topics were seeded mainly from products, services, brands, and invented people, with some general topics (parenting, politics, health, everyday life). People in the documents are fictional.
|
| 72 |
+
2. **Segmenter:** a Python script split each document into its natural units, keeping structure: headings, bullet points, table rows, metadata lines (bylines, dates), code lines, and sentences.
|
| 73 |
+
3. **Labeller:** a separate Gemini 3.8 Flash call labelled every segment, reading it in the context of the whole document.
|
| 74 |
+
|
| 75 |
+
Most documents mix tones; a further set was written with one dominant tone, to bring every non-neutral label up to about 10,900 segments. Neutral has about 17,800. Overused names and phrases were replaced with varied alternatives.
|
| 76 |
+
|
| 77 |
+
Splits are by document (80/10/10), so no document has segments in both training and test.
|
| 78 |
+
|
| 79 |
+
## Training procedure
|
| 80 |
+
|
| 81 |
+
- Base: `google/gemma-3-270m`, `Gemma3TextForSequenceClassification` head, 7 labels
|
| 82 |
+
- Input embedding frozen; all other weights trained
|
| 83 |
+
- AdamW, learning rate 2e-5 with one-cycle schedule over 1.5 epochs, batch size 32, max length 128, bf16 autocast
|
| 84 |
+
- Cross-entropy weighted by inverse label frequency
|
| 85 |
+
- Validation every 100 steps; early stopping with patience 5. Stopped at step 2,600; the released checkpoint (lowest validation loss) is from step 2,100.
|
| 86 |
+
|
| 87 |
+
## Limitations
|
| 88 |
+
|
| 89 |
+
- Trained and tested only on synthetic, model-written English text. Real reviews, social posts, and informal writing may score lower.
|
| 90 |
+
- Labels come from one model (Gemini 3.8 Flash), so its judgement and biases about sentiment strength are built in.
|
| 91 |
+
- Each segment is classified on its own. A sentence whose tone depends on what came before (for example "And yet…") may be misread.
|
| 92 |
+
- Neighbouring levels, especially "somewhat negative" and "negative", are often confused.
|
| 93 |
+
|
| 94 |
+
## License
|
| 95 |
+
|
| 96 |
+
This model is a derivative of Gemma and is provided under and subject to the [Gemma Terms of Use](https://ai.google.dev/gemma/terms). Use must also follow the [Gemma Prohibited Use Policy](https://ai.google.dev/gemma/prohibited_use_policy).
|
config.json
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_sliding_window_pattern": 6,
|
| 3 |
+
"architectures": [
|
| 4 |
+
"Gemma3TextForSequenceClassification"
|
| 5 |
+
],
|
| 6 |
+
"attention_bias": false,
|
| 7 |
+
"attention_dropout": 0.0,
|
| 8 |
+
"attn_logit_softcapping": null,
|
| 9 |
+
"bos_token_id": 2,
|
| 10 |
+
"dtype": "bfloat16",
|
| 11 |
+
"eos_token_id": 1,
|
| 12 |
+
"final_logit_softcapping": null,
|
| 13 |
+
"head_dim": 256,
|
| 14 |
+
"hidden_activation": "gelu_pytorch_tanh",
|
| 15 |
+
"hidden_size": 640,
|
| 16 |
+
"id2label": {
|
| 17 |
+
"0": "very positive",
|
| 18 |
+
"1": "positive",
|
| 19 |
+
"2": "somewhat positive",
|
| 20 |
+
"3": "neutral",
|
| 21 |
+
"4": "somewhat negative",
|
| 22 |
+
"5": "negative",
|
| 23 |
+
"6": "very negative"
|
| 24 |
+
},
|
| 25 |
+
"initializer_range": 0.02,
|
| 26 |
+
"intermediate_size": 2048,
|
| 27 |
+
"label2id": {
|
| 28 |
+
"very positive": 0,
|
| 29 |
+
"positive": 1,
|
| 30 |
+
"somewhat positive": 2,
|
| 31 |
+
"neutral": 3,
|
| 32 |
+
"somewhat negative": 4,
|
| 33 |
+
"negative": 5,
|
| 34 |
+
"very negative": 6
|
| 35 |
+
},
|
| 36 |
+
"layer_types": [
|
| 37 |
+
"sliding_attention",
|
| 38 |
+
"sliding_attention",
|
| 39 |
+
"sliding_attention",
|
| 40 |
+
"sliding_attention",
|
| 41 |
+
"sliding_attention",
|
| 42 |
+
"full_attention",
|
| 43 |
+
"sliding_attention",
|
| 44 |
+
"sliding_attention",
|
| 45 |
+
"sliding_attention",
|
| 46 |
+
"sliding_attention",
|
| 47 |
+
"sliding_attention",
|
| 48 |
+
"full_attention",
|
| 49 |
+
"sliding_attention",
|
| 50 |
+
"sliding_attention",
|
| 51 |
+
"sliding_attention",
|
| 52 |
+
"sliding_attention",
|
| 53 |
+
"sliding_attention",
|
| 54 |
+
"full_attention"
|
| 55 |
+
],
|
| 56 |
+
"max_position_embeddings": 32768,
|
| 57 |
+
"model_type": "gemma3_text",
|
| 58 |
+
"num_attention_heads": 4,
|
| 59 |
+
"num_hidden_layers": 18,
|
| 60 |
+
"num_key_value_heads": 1,
|
| 61 |
+
"pad_token_id": 0,
|
| 62 |
+
"query_pre_attn_scalar": 256,
|
| 63 |
+
"rms_norm_eps": 1e-06,
|
| 64 |
+
"rope_parameters": {
|
| 65 |
+
"full_attention": {
|
| 66 |
+
"rope_theta": 1000000.0,
|
| 67 |
+
"rope_type": "default"
|
| 68 |
+
},
|
| 69 |
+
"sliding_attention": {
|
| 70 |
+
"rope_theta": 10000.0,
|
| 71 |
+
"rope_type": "default"
|
| 72 |
+
}
|
| 73 |
+
},
|
| 74 |
+
"sliding_window": 512,
|
| 75 |
+
"tie_word_embeddings": true,
|
| 76 |
+
"transformers_version": "5.5.0",
|
| 77 |
+
"use_bidirectional_attention": false,
|
| 78 |
+
"use_cache": true,
|
| 79 |
+
"vocab_size": 262144
|
| 80 |
+
}
|
model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f78047aff96b53e4675d97f3a0def8482a4ce7fb3d15df04cd7340a6a76c8ac4
|
| 3 |
+
size 536232096
|
tokenizer.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ea32934d51349dfadb7bd02697c64fb740160bcc7a472c2aaca1f9d2df4768f7
|
| 3 |
+
size 33384819
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"backend": "tokenizers",
|
| 3 |
+
"boi_token": "<start_of_image>",
|
| 4 |
+
"bos_token": "<bos>",
|
| 5 |
+
"clean_up_tokenization_spaces": false,
|
| 6 |
+
"eoi_token": "<end_of_image>",
|
| 7 |
+
"eos_token": "<eos>",
|
| 8 |
+
"image_token": "<image_soft_token>",
|
| 9 |
+
"is_local": false,
|
| 10 |
+
"mask_token": "<mask>",
|
| 11 |
+
"model_max_length": 1000000000000000019884624838656,
|
| 12 |
+
"model_specific_special_tokens": {
|
| 13 |
+
"boi_token": "<start_of_image>",
|
| 14 |
+
"eoi_token": "<end_of_image>",
|
| 15 |
+
"image_token": "<image_soft_token>"
|
| 16 |
+
},
|
| 17 |
+
"pad_token": "<pad>",
|
| 18 |
+
"padding_side": "left",
|
| 19 |
+
"sp_model_kwargs": null,
|
| 20 |
+
"spaces_between_special_tokens": false,
|
| 21 |
+
"tokenizer_class": "GemmaTokenizer",
|
| 22 |
+
"unk_token": "<unk>",
|
| 23 |
+
"use_default_system_prompt": false
|
| 24 |
+
}
|