Downloads · 30 days
12
12% of all-time downloads
fpianz/sentiment-webnovel-comments-xlmr-en-zh
sentiment-webnovel-comments-xlmr-en-zh is a text classification model from fpianz. Use it when you need a label for a piece of text. It is set up for transformers. The card lists the license as apache-2.0.
A bilingual (English + Chinese) sentiment classifier for webnovel reader comments (sourced from Qidian and WebNovel and manually annotated), finetuned from cardiffnlp/twitter-xlm-roberta-base-sentiment.
Downloads · 30 days
12
12% of all-time downloads
All-time downloads
101
Public
Parameters
278M
2.2 GB on disk
Likes
0
Public
Click a slice to open those files.
.safetensors1.1 GB · 100%
From the Hugging Face model README
A bilingual (English + Chinese) sentiment classifier for webnovel reader comments (sourced from Qidian and WebNovel and manually annotated), finetuned from cardiffnlp/twitter-xlm-roberta-base-sentiment.
Classifies comments into three categories (negative, neutral, positive) and produces continuous valence scores via softmax probabilities: valence = p(positive) - p(negative), yielding a score in [-1, +1].
This model was developed for a computational literary studies project investigating emotional links between story content and reader responses in bilingual (EN-ZH) webnovel corpora. It is designed to score millions of reader comments with a continuous sentiment valence, which serves as a dependent variable in a Generalized Additive Mixed Model (GAMM) predicting comment sentiment from story paragraph sentiment (see the article https://doi.org/10.26083/tuda-7994).
Primary use case: Batch inference on informal reader comments from platforms like Goodreads, Qidian, and Webnovel.com.
Why a single bilingual model? Using the same model for both languages ensures measurement invariance, i.e. systematic differences in valence scores reflect genuine cross-lingual sentiment differences rather than model-specific biases. This is critical for the downstream GAMM, where language is a factor.
1,580 manually annotated bilingual webnovel comments (779 EN, 801 ZH) sampled from Qidian and Webnovel.com. Comments were independently annotated by two annotators into three sentiment categories, who later discussed to reach a final curated version of the annotations.
| Class | EN | ZH | Total |
|---|---|---|---|
| Negative | 373 | 395 | 768 |
| Neutral | 216 | 241 | 457 |
| Positive | 190 | 165 | 355 |
| Total | 779 | 801 | 1,580 |
Preprocessing: stripped [fn=N] footnote markers, removed 4 duplicate texts.
Source: Yu, Z., Pianzola, F., & Tatar, E. (2024). Qidian-Webnovel Corpus 110 (Version V2) [dataset]. DataverseNL. https://doi.org/10.34894/GQXX3K
cardiffnlp/twitter-xlm-roberta-base-sentiment -- an XLM-RoBERTa model pretrained on ~198M multilingual tweets with sentiment labels. Selected because it won a multi-model comparison on both paragraph-level and comment-level sentiment tasks (see Model Selection below).language x label to preserve proportions). Each fold trains on 1,264 comments and evaluates on 316.eval_macro_f1, with load_best_model_at_end=True. Best epochs per fold: [4, 4, 3, 3, 4]; median = 4.sklearn.utils.class_weight.compute_class_weight("balanced")), compensating for class imbalance.| Parameter | Value |
|---|---|
| Learning rate | 3e-5 |
| Batch size | 32 |
| Max sequence length | 256 tokens |
| Weight decay | 0.01 |
| Warmup ratio | 0.1 |
| Precision | fp16 |
| Optimizer | AdamW |
| Seed | 42 |
| Training epochs (final) | 4 |
Trained on the Habrok HPC cluster at the University of Groningen (1x NVIDIA A100 GPU). Total training time for the final model: ~17 seconds.
p(pos) - p(neg) and ordinal gold labels (negative = -1, neutral = 0, positive = +1). This is the primary evaluation metric for the downstream GAMM, where continuous valence (not discrete class) is used as the dependent variable.Three XLM-RoBERTa base models were compared, each with human-only training data and with synthetic data augmentation (+1,580 resampled LLM-generated comments added to training folds; evaluation always on held-out human annotations). All used the same CV protocol. These selection runs used lr=2e-5, maxlen=128, and checkpoint selection by eval_loss; the final published model uses tuned hyperparameters (see Hyperparameter Tuning below).
| Model | Base | Data | Acc | F1m | kappa_q | rho |
|---|---|---|---|---|---|---|
| xlmr_multi | twitter-xlm-roberta-base-sentiment-multilingual | human | .710 | .700 | .588 | .631 |
| xlmr_multi | +synth | .690 | .684 | .584 | .637 | |
| xlmr_en | twitter-xlm-roberta-base-sentiment | human | .723 | .714 | .603 | .646 |
| xlmr_en | +synth | .694 | .687 | .582 | .655 | |
| xlmr_base | xlm-roberta-base | human | .702 | .691 | .552 | .577 |
| xlmr_base | +synth | .692 | .682 | .565 | .590 |
| Model | Data | Acc | F1m | kappa_q | rho |
|---|---|---|---|---|---|
| xlmr_multi | human | .732 | .726 | .668 | .692 |
| xlmr_multi | +synth | .702 | .702 | .642 | .696 |
| xlmr_en | human | .745 | .739 | .675 | .706 |
| xlmr_en | +synth | .716 | .714 | .646 | .717 |
| xlmr_base | human | .692 | .686 | .562 | .578 |
| xlmr_base | +synth | .693 | .689 | .584 | .602 |
| Model | Data | Acc | F1m | kappa_q | rho |
|---|---|---|---|---|---|
| xlmr_multi | human | .689 | .670 | .502 | .562 |
| xlmr_multi | +synth | .678 | .654 | .514 | .574 |
| xlmr_en | human | .702 | .686 | .526 | .579 |
| xlmr_en | +synth | .672 | .651 | .506 | .590 |
| xlmr_base | human | .712 | .693 | .541 | .577 |
| xlmr_base | +synth | .690 | .669 | .541 | .582 |
xlmr_en (human only) was selected as the base model. It leads on accuracy, F1, and kappa_q overall and for both languages, and on rho overall. Synthetic data augmentation yielded marginal rho improvements (+.006 to +.013) at the cost of consistent accuracy and F1 losses (-.010 to -.029). These rho gains fall within fold-level SD, making them statistically indistinguishable from noise. The human-only model was therefore preferred.
After model selection, hyperparameters were tuned by comparing the original configuration (lr=2e-5, maxlen=128, checkpoint selection by eval_loss) against an alternative (lr=3e-5, maxlen=256, checkpoint selection by eval_macro_f1). Both configurations used the same 5-fold CV protocol on the 1,580 cleaned comments.
| Config | lr | maxlen | Selection | F1m | kappa_q | rho | EN rho | ZH rho |
|---|---|---|---|---|---|---|---|---|
| Initial | 2e-5 | 128 | eval_loss | .714 | .603 | .646 | .706 | .579 |
| Tuned | 3e-5 | 256 | macro_f1 | .733 | .634 | .665 | .723 | .603 |
| Delta | +.019 | +.031 | +.019 | +.017 | +.024 |
The improvement is consistent across all metrics and both languages. The maxlen increase from 128 to 256 tokens likely accounts for most of the gain: some webnovel comments exceed 128 tokens and were being truncated. Note that the checkpoint selection metric also changed (eval_loss -> macro_f1), so the gain is not attributable to lr/maxlen alone. Dropout was kept at the model default (~0.1); increasing it to 0.2 was tested but yielded no meaningful improvement.
Metrics computed on concatenated held-out predictions across all folds (i.e., every sample is scored exactly once by a model that never saw it during training).
| Subset | N | Acc | F1m | kappa_q | rho |
|---|---|---|---|---|---|
| Overall | 1,580 | .748 | .733 | .634 | .665 |
| English | 779 | .775 | .767 | .715 | .723 |
| Chinese | 801 | .722 | .691 | .541 | .603 |
| Zero-shot baseline | 1,580 | .679 | .646 | .541 | .614 |
| * English* | 779 | .675 | .653 | .602 | .664 |
| * Chinese* | 801 | .683 | .633 | .473 | .565 |
| Majority baseline | 1,580 | .486 | -- | -- | -- |
Per-class F1:
| Class | N | F1 | EN F1 | ZH F1 |
|---|---|---|---|---|
| Negative | 768 | .800 | .815 | .787 |
| Neutral | 457 | .689 | .690 | .688 |
| Positive | 355 | .710 | .796 | .597 |
Fold-level means +- SD:
| Metric | Mean +- SD |
|---|---|
| Accuracy | .748 +- .023 |
| F1 macro | .732 +- .024 |
| F1 weighted | .747 +- .023 |
| Cohen kappa_q | .633 +- .041 |
| Spearman rho | .670 +- .029 |
Improvement over zero-shot: Delta Acc = +.069, Delta F1m = +.087, Delta kappa_q = +.093, Delta rho = +.051.
To test whether additional training data could improve performance, 1,580 synthetic comments were generated by an LLM and resampled to match the human annotation class distribution (negative: 768, neutral: 457, positive: 355). Neutral was oversampled with replacement (385 available synthetic neutrals -> 457); negative and positive were downsampled. Synthetic data was added to training folds only; evaluation was always on held-out human annotations.
Result: synthetic augmentation consistently improved rho by small margins (+.006 to +.013) but degraded accuracy (-.010 to -.029) and F1 macro (-.009 to -.027) across all three base models. The rho gains fall within fold-level variability and are not statistically significant. The classification degradation suggests the synthetic data introduces noise into the decision boundary.
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
model_name = "fpianz/sentiment-webnovel-comments-xlmr-en-zh"
tokenizer = AutoTokenizer.from_pretrained(model_name, use_fast=False)
model = AutoModelForSequenceClassification.from_pretrained(model_name)
model.eval()
texts = [
"This chapter was absolutely incredible, I cried at the end",
"meh, nothing really happened",
"This was a decent chapter but I expected more from the protagonist",
]
inputs = tokenizer(texts, return_tensors="pt", padding=True, truncation=True, max_length=256)
with torch.no_grad():
outputs = model(**inputs)
probs = torch.softmax(outputs.logits, dim=-1)
# Discrete labels
labels = ["negative", "neutral", "positive"]
predictions = [labels[p] for p in probs.argmax(dim=-1)]
# Continuous valence: p(positive) - p(negative), range [-1, +1]
valence = (probs[:, 2] - probs[:, 0]).tolist()
for text, pred, val in zip(texts, predictions, valence):
print(f"{pred:>8s} (valence={val:+.3f}) {text[:60]}")
Note: Use use_fast=False for the tokenizer to avoid potential tiktoken conversion issues with XLM-RoBERTa.
| ID | Label |
|---|---|
| 0 | negative |
| 1 | neutral |
| 2 | positive |
The training script (finetune_comments_cv.py) and SLURM runner (run_finetune_comments.sh) are available in the project repository. Key implementation details:
WeightedTrainer extending HuggingFace Trainer with class-weighted cross-entropy losslanguage x label stratification keyEarlyStoppingCallback(patience=3) monitoring eval_macro_f1If you use this model, please cite:
@misc{pianzla2026webnovel-comments,
title={sentiment-webnovel-comments-xlmr-en-zh: A Bilingual Sentiment Classifier for Webnovel Reader Comments},
author={Pianzola, Federico, and Yu, Ze},
year={2026},
url={https://huggingface.co/fpianz/sentiment-webnovel-comments-xlmr-en-zh}
}
Computational resources provided by the Center for Information Technology of the University of Groningen (Habrok HPC cluster).