klue-review-star-4class

Predicts a 1.0โ€“5.0 star rating from Korean restaurant review text, and rejects input that is not a restaurant review.

Successor to likeyellow/klue-review-star, which had no way to decline.

Why a fourth class

The 3-class predecessor was forced to pick one of negative / positive / neutral for any input. Unrelated text still produced a rating:

Input 3-class output
์—„๋งˆ ๋ณด๊ณ  ์‹ถ์–ด์š” ("I miss my mom") 4.04 stars, confidence 0.21
ใ…‡ใ„ดใ…‡ใ…Žใ„ดใ„ทใ…Ž (keyboard mash) 3.57 stars, confidence 0.08

Low confidence flagged these, but a threshold could not separate them from genuinely mixed reviews โ€” both sat in the same 0.15โ€“0.35 band. Measured over 25 hand-labelled sentences:

Category Mean confidence
Clear negative 0.904
Clear positive 0.615
Informational 0.400
Unrelated 0.269
Mixed review 0.256

A fourth class was added instead.

Labels

id Meaning Star anchor
0 negative 1.0
1 positive 5.0
2 neutral 3.0
3 not a review โ€” (no rating produced)

For classes 0โ€“2, the rating is the expected value over anchors after renormalising the first three probabilities. Confidence is the normalised, inverted entropy of that renormalised distribution, so it stays comparable to the 3-class model.

Usage

import numpy as np, torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer

MODEL  = "likeyellow/klue-review-star-4class"
ANCHOR = np.array([1.0, 5.0, 3.0])
LABEL  = ["negative", "positive", "neutral", "not_a_review"]

tok = AutoTokenizer.from_pretrained(MODEL)
model = AutoModelForSequenceClassification.from_pretrained(MODEL).eval()

def predict(text):
    enc = tok(text, truncation=True, max_length=256, return_tensors="pt")
    with torch.no_grad():
        p = torch.softmax(model(**enc).logits, dim=-1)[0].numpy()
    if int(p.argmax()) == 3:
        return {"label": "not_a_review", "star": None, "confidence": None}
    q = p[:3] / p[:3].sum()
    ent = float(-(q * np.log(q + 1e-9)).sum())
    return {"label": LABEL[int(p.argmax())],
            "star": round(float((q * ANCHOR).sum()), 2),
            "confidence": round(1 - ent / np.log(3), 3)}

predict("์กด๋ง›ํƒฑ")            # {'label': 'positive', 'star': 4.94, ...}
predict("์—„๋งˆ ๋ณด๊ณ  ์‹ถ์–ด์š”")   # {'label': 'not_a_review', 'star': None, ...}

Results

Test set: 17,494 held-out examples.

Class Precision Recall F1 Support
negative 0.712 0.883 0.789 1,719
positive 0.868 0.777 0.820 9,106
neutral 0.582 0.655 0.616 4,215
not a review 0.994 0.998 0.996 2,454
accuracy 0.789

Star MAE on review classes only: 0.668 (3-class predecessor: 0.640).

Rejection costs almost nothing in rating accuracy: only 16 of 15,040 genuine reviews were misrouted to class 3, and recall on negative and neutral actually improved (0.846 โ†’ 0.883, 0.626 โ†’ 0.655).

Note that the 0.996 F1 on class 3 reflects an easy test distribution โ€” news headlines differ sharply in register from reviews. Real borderline input is harder; see below.

Training

  • 150,000 KR3 reviews (classes 0โ€“2), stratified
  • 20,000 klue/ynat news headlines (class 3)
  • ~480 hand-built out-of-domain sentences, repeated ร—10 (class 3)
  • Class weights to correct imbalance; 1 epoch, lr 2e-5, batch 32, max_len 256, T4
  • Validation loss rose at epoch 2 (0.4035 โ†’ 0.4155), so epoch 1 was kept

Why the hand-built set mattered

A first attempt used news headlines alone. It caught keyboard mash and everyday chat, but food-related non-reviews still passed:

Input v1 (news only) v2 (+ hand-built)
๋–ก๋ณถ์ด ๋จน๊ณ  ์‹ถ๋‹ค ("I want tteokbokki") neutral 0.977 not a review 0.999
์ด ์ฑ… ์ •๋ง ์žฌ๋ฐŒ์–ด์š” ("this book is fun") neutral 0.841 not a review 1.000
์˜ค๋Š˜ ์ ์‹ฌ ๋ญ ๋จน์ง€ ("what's for lunch") neutral 0.894 not a review 0.709

The model had learned a shallow rule โ€” food word present โ‡’ review โ€” because no food vocabulary appeared in the negative examples. Adding food-related non-review sentences fixed it, and the fix generalised: ๋งŒ๋‘ ("dumpling") and ์†Œ์„ค ("novel") were held out of training entirely, yet both are rejected at 0.999+.

Limitations

  • Borderline input is weaker than the metrics suggest. ์˜ค๋Š˜ ์ ์‹ฌ ๋ญ ๋จน์ง€ scores 0.709 for class 3 while other rejections score 0.999+.
  • Neutral remains noisy. Precision 0.582, with 1,826 positiveโ†’neutral and 1,035 neutralโ†’positive errors. This is inherited from KR3's ambiguous label and is unchanged from the 3-class model.
  • Korean only. Korean tokenizer, Korean training data.
  • Confidence is not accuracy. It measures how concentrated the distribution is, not how often the model is right. No calibration performed.
  • Understated complaints skew neutral. ์•„์‰ฌ์› ์–ด์š” phrasing lands around 3 stars rather than lower.

Observed behaviour

Probing with crafted sentence pairs revealed that the model weights revisit-intent phrasing above sentiment adjectives:

Input Star
๊ฐ€๊ฒฉ์ด ๋„ˆ๋ฌด ๋น„์‹ธ์„œ ์•„์‰ฌ์› ์–ด์š” ํ•˜์ง€๋งŒ ๋˜ ๊ฐˆ ๊ฒƒ ๊ฐ™์•„์š” 4.16
๊ฐ€๊ฒฉ์ด ๋„ˆ๋ฌด ๋น„์‹ธ์„œ ์•„์‰ฌ์› ์–ด์š” ๋‹ค์‹œ๋Š” ์•ˆ ๊ฐˆ ๊ฒƒ ๊ฐ™์•„์š” 1.05
๋ง›์žˆ์—ˆ์–ด์š” ๊ทผ๋ฐ ๋‹ค์‹œ๋Š” ์•ˆ ๊ฐˆ ๊ฒƒ ๊ฐ™์•„์š” 1.92 (negative)

The last row carries an explicit positive adjective yet is classified negative. This matches how people assign stars in practice.

It is also more confident on colloquial phrasing than formal phrasing: ์กด๋ง›ํƒฑ (slang for "delicious") scores 4.94 at confidence 0.87, while ๋งค์šฐ ํ›Œ๋ฅญํ•œ ๋ง›์ด์—ˆ์Šต๋‹ˆ๋‹ค (formal, same meaning) scores 4.59 at 0.51.

License

CC BY-NC-SA 4.0, inherited from KR3. Non-commercial use only.

Links

Downloads last month
-
Safetensors
Model size
0.1B params
Tensor type
F32
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for likeyellow/klue-review-star-4class

Base model

klue/bert-base
Finetuned
(175)
this model

Datasets used to train likeyellow/klue-review-star-4class