File size: 11,821 Bytes
56dfd97
 
 
 
d8539db
56dfd97
 
d8539db
56dfd97
d8539db
 
 
 
56dfd97
d8539db
 
 
 
56dfd97
d8539db
 
 
 
56dfd97
 
 
 
d8539db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56dfd97
 
 
d8539db
 
 
 
 
 
56dfd97
d8539db
 
 
 
 
 
 
56dfd97
d8539db
 
 
 
 
56dfd97
 
 
 
d8539db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56dfd97
 
d8539db
56dfd97
 
d8539db
56dfd97
 
 
 
d8539db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56dfd97
 
 
 
 
 
d8539db
56dfd97
 
d8539db
 
 
 
 
 
 
 
 
 
 
56dfd97
 
d8539db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56dfd97
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "f12898a8d61a",
      "metadata": {},
      "source": [
        "# Chandassu: eight-class Telugu poem metre recognition\n",
        "\n",
        "The default model is the new **eight-class ordered poem CNN**. It recognizes\n",
        "ఉత్పలమాల, చంపకమాల, మత్తేభము, శార్దూలం, ఆటవెలది, తేటగీతి, కందము and సీసము.\n",
        "It predicts once from all four ordered pādas; a Seesamu prediction uses its body\n",
        "only. CPU is supported; CUDA is optional. No project checkout or login is required.\n",
        "\n",
        "**Fixed held-out benchmark:** Macro F1 94.84%, accuracy 97.90%. Ataveladi F1 is\n",
        "69.34%, the main weakness. These source-labelled tests include a historically\n",
        "inspected benchmark; they are not independent expert gold or a wholly blind test.\n",
        "Scores are **uncalibrated** and do not verify formal metre rules.\n",
        "\n",
        "Run the setup, loader, and prediction cells in order. The loader resolves `main`\n",
        "once and pins both tokenizer and model to that immutable commit. `trust_remote_code`\n",
        "loads the published, inspectable `hf_poem.py` from this repository. The optional\n",
        "original four-class example remains separate below.\n"
      ]
    },
    {
      "cell_type": "code",
      "id": "2f83c3532128",
      "metadata": {
        "tags": [
          "dependencies"
        ]
      },
      "source": [
        "# Run once in a fresh notebook kernel. Keep Colab's preinstalled PyTorch.\n",
        "%pip install -q \"transformers==4.57.6\" \"safetensors==0.8.0\" \"huggingface-hub==0.36.2\"\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "id": "31ee51cadf3a",
      "metadata": {},
      "source": [
        "import torch\n",
        "from huggingface_hub import HfApi\n",
        "from transformers import AutoTokenizer, AutoModelForSequenceClassification\n",
        "\n",
        "REPO_ID = \"sprx7767/chandassu-recognition\"\n",
        "REVISION = None  # Optional: replace with a complete 40-character release commit.\n",
        "SUBFOLDER = None  # Root defaults to eight classes; \"cnn-eight-class\" is equivalent.\n",
        "\n",
        "resolved_revision = REVISION or HfApi().model_info(REPO_ID, token=False).sha\n",
        "options = {\"revision\": resolved_revision, \"trust_remote_code\": True, \"token\": False}\n",
        "if SUBFOLDER:\n",
        "    options[\"subfolder\"] = SUBFOLDER\n",
        "\n",
        "tokenizer = AutoTokenizer.from_pretrained(REPO_ID, **options)\n",
        "model = AutoModelForSequenceClassification.from_pretrained(REPO_ID, **options).eval()\n",
        "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
        "model = model.to(device)\n",
        "assert model.config.prediction_unit == \"poem\" and len(model.config.labels) == 8\n",
        "print(\"HF commit:\", resolved_revision)\n",
        "print(\"Device:\", device)\n",
        "print(\"Labels:\", model.config.labels)\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "e2dffdfa4464",
      "metadata": {},
      "source": [
        "## Enter a complete poem\n",
        "\n",
        "Use one newline-separated string containing **four full ordered pādas**.\n",
        "For Seesamu, eight body half-lines are paired into four pādas; a 12-line input\n",
        "(eight body half-lines plus four closing geeti lines) also works, and its geeti\n",
        "is excluded. An eight-line input always means eight Seesamu body half-lines,\n",
        "not four full body pādas plus four geeti lines.\n",
        "\n",
        "The limit is 512 Unicode characters per full pāda. Input is never silently\n",
        "truncated. A batch is a list of complete poem strings, not a list of individual\n",
        "pādas. Whole-poem tensors have shape `[batch, 4, tokens]`; logits have shape\n",
        "`[batch, 8]`. There are no independent per-line scores to average.\n"
      ]
    },
    {
      "cell_type": "code",
      "id": "adb382bb6c60",
      "metadata": {},
      "source": [
        "POEM = \"\"\"శ్రీ కైవల్య పదంబుఁ జేరుటకునై చింతించెదన్ లోక ర\n",
        "క్షైకారంభకు, భక్త పాలన కళా సంరంభకున్, దానవో\n",
        "ద్రేకస్తంభకుఁ, గేళి లోల విలసద్దృగ్జాల సంభూత నా\n",
        "నా కంజాత భవాండ కుంభకు, మహానందాంగనాడింభకున్.\"\"\"\n",
        "\n",
        "\n",
        "def predict_poems(poems):\n",
        "    inputs = tokenizer(poems, padding=True, return_tensors=\"pt\").to(device)\n",
        "    with torch.inference_mode():\n",
        "        probabilities = model(**inputs).logits.double().softmax(dim=-1).cpu()\n",
        "    results = []\n",
        "    for scores in probabilities:\n",
        "        winner = int(scores.argmax())\n",
        "        results.append({\n",
        "            \"prediction\": model.config.id2label[winner],\n",
        "            \"uncalibrated_scores\": {\n",
        "                model.config.id2label[i]: float(scores[i])\n",
        "                for i in scores.argsort(descending=True).tolist()\n",
        "            },\n",
        "        })\n",
        "    return results\n",
        "\n",
        "\n",
        "result = predict_poems(POEM)[0]\n",
        "print(\"Prediction:\", result[\"prediction\"])\n",
        "for label, score in result[\"uncalibrated_scores\"].items():\n",
        "    print(f\"{label}: {score:.2%}\")\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "id": "5b00c2754e96",
      "metadata": {},
      "source": [
        "# Optional: paste a Seesamu body as four full pādas or eight half-lines.\n",
        "# A 12-line body-plus-geeti input is supported too; the final geeti is ignored.\n",
        "SEESAMU = None\n",
        "if SEESAMU:\n",
        "    print(predict_poems(SEESAMU)[0])\n",
        "\n",
        "# For a batch, use predict_poems([POEM, ANOTHER_COMPLETE_POEM]).\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "e32c59f04656",
      "metadata": {},
      "source": [
        "## Benchmark and limits\n",
        "\n",
        "| New label | Fit | Validation | Held-out test | Test F1 |\n",
        "|---|---:|---:|---:|---:|\n",
        "| Ataveladi | 289 | 1,092 | 152 | 69.34% |\n",
        "| Tetageeti | 943 | 209 | 640 | 92.27% |\n",
        "| Kandamu | 2,571 | 721 | 1,071 | 99.63% |\n",
        "| Seesamu body | 680 | 250 | 466 | 98.50% |\n",
        "\n",
        "The complete v3 corpus has 23,029 poems: 12,058 fit, 4,131 validation, 5,282 test,\n",
        "and 1,558 reserved calibration poems (unused in this experiment). All original\n",
        "v2 roles stay frozen. Whole poems and work/edition/exact-duplicate groups stay\n",
        "together. Validation poem Macro F1 selected epoch 11; training stopped after 19.\n",
        "The CPU model has 266,056 parameters. No ByT5 retraining was performed.\n",
        "\n",
        "More diverse Ataveladi fitting data is needed. Vemana dominates its validation\n",
        "support; authors can overlap, and the exact-duplicate screen is not proof against\n",
        "fuzzy duplicates. High scores do not validate prosody or reliable rejection of\n",
        "unlisted metres. See [full reports](https://github.com/Pranav-20186017/chandassu_recognition/tree/main/results/v3).\n"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "bdddcacc85bf",
      "metadata": {},
      "source": [
        "## Optional: original four-class line models\n",
        "\n",
        "The original `cnn/` and `byt5/` packages remain available. They classify individual\n",
        "lines into the original four vruttas and average calibrated line probabilities\n",
        "for poems. Keep this calculation separate from the eight-class joint CNN above.\n",
        "ByT5 is a much larger download and is parked by default.\n"
      ]
    },
    {
      "cell_type": "code",
      "id": "7da03b036678",
      "metadata": {},
      "source": [
        "RUN_LEGACY = False\n",
        "LEGACY_MODEL = \"cnn\"  # \"byt5\" is also retained; it downloads a much larger encoder.\n",
        "\n",
        "if RUN_LEGACY:\n",
        "    legacy_options = {\"subfolder\": LEGACY_MODEL, \"revision\": resolved_revision,\n",
        "                      \"trust_remote_code\": True, \"token\": False}\n",
        "    legacy_tokenizer = AutoTokenizer.from_pretrained(REPO_ID, **legacy_options)\n",
        "    legacy_model = AutoModelForSequenceClassification.from_pretrained(\n",
        "        REPO_ID, **legacy_options).to(device).eval()\n",
        "    lines = [line.strip() for line in POEM.splitlines() if line.strip()]\n",
        "    if len(lines) not in (1, 4):\n",
        "        raise ValueError(\"The original model accepts one line or four full pādas\")\n",
        "    legacy_inputs = legacy_tokenizer(lines, padding=True, return_tensors=\"pt\").to(device)\n",
        "    with torch.inference_mode():\n",
        "        logits = legacy_model(**legacy_inputs).logits\n",
        "        scores = (logits.double() / legacy_model.config.calibration_temperature).softmax(-1).mean(0)\n",
        "    print(\"Original four-class prediction:\", legacy_model.config.id2label[int(scores.argmax())])\n",
        "    for i, score in enumerate(scores):\n",
        "        print(f\"{legacy_model.config.id2label[i]}: {float(score):.2%}\")\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "id": "d58d1813824b",
      "metadata": {},
      "source": [
        "import platform\n",
        "import transformers\n",
        "\n",
        "print({\"python\": platform.python_version(), \"torch\": torch.__version__,\n",
        "       \"transformers\": transformers.__version__, \"huggingface_revision\": resolved_revision})\n"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "id": "0208ef2a8279",
      "metadata": {},
      "source": [
        "## Sources and citation\n",
        "\n",
        "[Source and rule references](https://github.com/Pranav-20186017/chandassu_recognition/blob/main/data/SOURCES.md) ·\n",
        "[Work catalogue](https://github.com/Pranav-20186017/chandassu_recognition/blob/main/data/v3/WORKS.md) ·\n",
        "[Model card](https://huggingface.co/sprx7767/chandassu-recognition) ·\n",
        "[Project code](https://github.com/Pranav-20186017/chandassu_recognition)\n",
        "\n",
        "Author: Pranav Surampudi. Project-owned material follows the Chandassu citation\n",
        "license. Poems, editions, transcriptions and annotations retain their source\n",
        "rights. Preserve authors and source links. The examples use a pretrained\n",
        "classifier; they do not implement a formal lakshana verifier or teacher distillation.\n"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "name": "notebook.ipynb",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}