Downloads · 30 days
4
8% of all-time downloads
nyxhuang/ednoda-grade-cefr-mapping
ednoda-grade-cefr-mapping is a text classification model from nyxhuang. Use it when you need a label for a piece of text. It is set up for text-to-grade. The card lists the license as mit.
End-to-end English text → US K-6 grade level predictor.
Downloads · 30 days
4
8% of all-time downloads
All-time downloads
48
Public
Repo size
183 MB
Likes
0
Public
Click a slice to open those files.
.bin183 MB · 100%
From the Hugging Face model README
End-to-end English text → US K-6 grade level predictor.
Given an English sentence, it returns:
[1.0, 6.0] (1 = A1 … 6 = C2),A1–C2),[0.0, 6.0] (0 = preschool, 1–6 = grades 1–6),preschool, one, … six).It is a two-stage model:
bert-base-uncased with a single-linear
regression head. This stage is loaded verbatim from
SNALYF/CEFR_Bert_Fine-tuned
(Ace-CEFR baseline, arXiv:2506.14046 §4.5.1).The model uses a custom modeling.py, so loading needs trust_remote_code or
a local download of the repo. Either form works:
# Option A: clone or hf_hub_download then load locally
from modeling import TextToGradePredictor
model = TextToGradePredictor.from_pretrained("YourUser/text-to-grade")
model.eval()
results = model.predict([
"I'm from Canada.",
"The committee unanimously ratified the long-debated treaty.",
])
for r in results:
print(r)
# {'text': "I'm from Canada.", 'cefr_score': 2.313, 'cefr_level': 'A2',
# 'grade_num': 4.05, 'grade_word': 'four'}
predict() batches under the hood (batch_size=32 by default). For raw
forward access you can call model(input_ids, attention_mask, token_type_ids)
or model.cefr_score(list_of_texts) to skip the grade head.
| CEFR score | CEFR level |
|---|---|
| 1 | A1 |
| 2 | A2 |
| 3 | B1 |
| 4 | B2 |
| 5 | C1 |
| 6 | C2 |
| grade num | grade word |
|---|---|
| 0 | preschool |
| 1 | one |
| 2 | two |
| 3 | three |
| 4 | four |
| 5 | five |
| 6 | six |
The grade head was fit on the ednoda snapshot — a 2,448-row corpus of K-6
English-learner expressions, vocabulary, and question prompts, each labelled
with one or more grade words. Multi-grade rows were exploded so each
(text, grade) becomes its own row (~2,989 pairs).
Per-grade CEFR distribution from the calibration set:
| grade | n | mean CEFR | mean level |
|---|---|---|---|
| preschool (0) | 5 | 1.34 | A1 |
| one (1) | 2 | 1.39 | A1 |
| three (3) | 717 | 1.69 | A2 |
| four (4) | 757 | 1.68 | A2 |
| five (5) | 860 | 1.88 | A2 |
| six (6) | 648 | 2.00 | A2 |
The fit was an sklearn.IsotonicRegression(increasing=True) from CEFR score
to grade number, serialised as a 51-point piecewise-linear table inside
config.json. At inference the model interpolates with np.interp — no scikit
dependency is required to load.
These are training-set fit metrics; they are an upper bound on the calibrator's ceiling, not a held-out estimate. The CEFR head's own held-out metrics (445-row ACE-CEFR test) are MSE 0.567, 51.5 % exact level, 93.9 % within ±1 level — see the source repo.
grade_word = "six".
When the upstream CEFR score is ≥ ~3, treat the grade as "≥ six" rather than
a literal value.[0, 1] are unreliable.bert-base-uncased.modeling.py # TextToGradePredictor — defines model + load/save
config.json # bert hyperparams + isotonic table + grade-word map
pytorch_model.bin # 45.7M params (3-layer BERT + regressor)
SNALYF/CEFR_Bert_Fine-tunedMIT (same as the upstream CEFR head). Re-uploading the upstream weights here is done with credit to the original author; if you are not the same author, please obtain their consent before publishing this repo.