hul0 commited on
Commit
afdaf2d
·
verified ·
1 Parent(s): 6591d08

Upload folder using huggingface_hub

Browse files
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rupam Ghosh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md CHANGED
@@ -1,3 +1,197 @@
1
  ---
 
 
 
 
2
  license: mit
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ pipeline_tag: text-classification
3
+ library_name: transformers
4
+ language:
5
+ - en
6
  license: mit
7
+ datasets:
8
+ - thesofakillers/jigsaw-toxic-comment-classification-challenge
9
+ base_model: bert-base-uncased
10
+ tags:
11
+ - toxic
12
+ - moderation
13
+ - safety
14
+ - content-moderation
15
+ - onnx
16
+ - quantized
17
  ---
18
+
19
+ # 🌟 Shuddhi v1: BERT-Base Toxicity Checker
20
+
21
+
22
+ [![Model Type: BERT-Base](https://img.shields.io/badge/Model_Type-BERT--Base-blue.svg?style=flat-square)](https://huggingface.co/bert-base-uncased)
23
+ [![Dataset: JIGSAW](https://img.shields.io/badge/Dataset-JIGSAW-orange.svg?style=flat-square)](https://www.kaggle.com/c/jigsaw-toxic-comment-classification-challenge)
24
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg?style=flat-square)](./LICENSE)
25
+ [![Framework: PyTorch / ONNX](https://img.shields.io/badge/Framework-PyTorch%20%2F%20ONNX-blueviolet.svg?style=flat-square)](#quick-start)
26
+ [![Task: Multi-label Classification](https://img.shields.io/badge/Task-Multi--label%20Classification-yellowgreen.svg?style=flat-square)](#model-card)
27
+
28
+ **Shuddhi** is a high-performance, production-ready moderation model based on the `bert-base-uncased` architecture. It is fine-tuned on the JIGSAW Toxic Comment Classification dataset to detect and classify toxic text into six distinct labels.
29
+
30
+ The repository includes both the standard PyTorch model configuration and a **quantized ONNX version** (`model_quantized.onnx`) optimized for low-latency CPU and edge deployments.
31
+
32
+ ---
33
+
34
+ ## 🚀 Model Details
35
+
36
+ - **Developed by:** Shuddhi Project Authors
37
+ - **Model Type:** Transformer (`bert`)
38
+ - **Base Model:** `bert-base-uncased`
39
+ - **Language(s) (NLP):** English
40
+ - **License:** MIT
41
+ - **Task:** Multi-Label Text Classification (Toxicity Moderation)
42
+ - **Input Limit:** 512 tokens
43
+
44
+ ### Detected Categories & Optimal Thresholds
45
+
46
+ The model classifies text across the 6 JIGSAW standard categories. To optimize moderation accuracy and balance precision/recall, use the pre-calculated classification thresholds from [`thresholds.json`](./thresholds.json):
47
+
48
+ | Category | Description | Optimal Threshold |
49
+ | :-------------- | :----------------------------------------------- | :---------------- |
50
+ | `toxic` | General toxic, rude, or disrespectful comment | `0.7800` |
51
+ | `severe_toxic` | Extremely aggressive or highly offensive comment | `0.8539` |
52
+ | `obscene` | Obscene, vulgar, or profane language | `0.9070` |
53
+ | `threat` | Threats of violence, physical harm, or death | `0.3861` |
54
+ | `insult` | Insults or derogatory remarks | `0.8832` |
55
+ | `identity_hate` | Hate speech targeting identity groups | `0.7942` |
56
+
57
+ ---
58
+
59
+ ## ⚡ Quick Start
60
+
61
+ You can load and perform inference with this model using either Python's `transformers` library or using the optimized ONNX runtime.
62
+
63
+ ### Option 1: Standard PyTorch Inference (via Hugging Face Transformers)
64
+
65
+ ```python
66
+ import torch
67
+ import json
68
+ from transformers import AutoTokenizer, AutoModelForSequenceClassification
69
+
70
+ # Load model, tokenizer, and thresholds
71
+ model_path = "./" # Path to the shuddhi_v1 directory
72
+ tokenizer = AutoTokenizer.from_pretrained(model_path)
73
+ model = AutoModelForSequenceClassification.from_pretrained(model_path)
74
+
75
+ with open(f"{model_path}/thresholds.json") as f:
76
+ thresholds = json.load(f)
77
+
78
+ # Prepare inputs
79
+ text = "Go play in traffic!"
80
+ inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
81
+
82
+ # Run prediction
83
+ with torch.no_grad():
84
+ outputs = model(**inputs)
85
+ logits = outputs.logits
86
+ # Apply sigmoid since it is multi-label classification
87
+ probabilities = torch.sigmoid(logits).cpu().numpy()[0]
88
+
89
+ # Class mapping and threshold application
90
+ results = {}
91
+ for i in range(len(probabilities)):
92
+ label = model.config.id2label[i]
93
+ score = float(probabilities[i])
94
+ results[label] = {
95
+ "score": score,
96
+ "flagged": score >= thresholds.get(label, 0.5)
97
+ }
98
+
99
+ print("Moderation Scores:")
100
+ for label, res in results.items():
101
+ status = "🚨 FLAGGED" if res["flagged"] else "✅ CLEAN"
102
+ print(f" - {label:<15}: {res['score']:.4f} [{status}]")
103
+ ```
104
+
105
+ ### Option 2: High-Performance ONNX Runtime Inference
106
+
107
+ For low-latency production applications, load the pre-quantized ONNX model (`model_quantized.onnx`):
108
+
109
+ ```python
110
+ import numpy as np
111
+ import json
112
+ from transformers import AutoTokenizer
113
+ import onnxruntime as ort
114
+
115
+ # Load tokenizer, ONNX session, and thresholds
116
+ model_path = "./"
117
+ tokenizer = AutoTokenizer.from_pretrained(model_path)
118
+ ort_session = ort.InferenceSession(f"{model_path}/model_quantized.onnx")
119
+
120
+ with open(f"{model_path}/thresholds.json") as f:
121
+ thresholds = json.load(f)
122
+
123
+ # Prepare inputs
124
+ text = "This is a clean, helpful, and respectful comment."
125
+ inputs = tokenizer(text, return_tensors="np", truncation=True, max_length=512)
126
+
127
+ # Cast token inputs to INT64 for ONNX compatibility
128
+ onnx_inputs = {
129
+ "input_ids": inputs["input_ids"].astype(np.int64),
130
+ "attention_mask": inputs["attention_mask"].astype(np.int64),
131
+ }
132
+ if "token_type_ids" in inputs:
133
+ onnx_inputs["token_type_ids"] = inputs["token_type_ids"].astype(np.int64)
134
+
135
+ # Run ONNX inference
136
+ logits = ort_session.run(None, onnx_inputs)[0]
137
+
138
+ # Compute probabilities (Sigmoid)
139
+ probabilities = 1 / (1 + np.exp(-logits))[0]
140
+
141
+ # Output results using thresholds
142
+ labels = ["toxic", "severe_toxic", "obscene", "threat", "insult", "identity_hate"]
143
+ results = {}
144
+ for label, score in zip(labels, probabilities):
145
+ results[label] = {
146
+ "score": float(score),
147
+ "flagged": float(score) >= thresholds.get(label, 0.5)
148
+ }
149
+
150
+ print("ONNX Moderation Scores:")
151
+ for label, res in results.items():
152
+ status = "🚨 FLAGGED" if res["flagged"] else "✅ CLEAN"
153
+ print(f" - {label:<15}: {res['score']:.4f} [{status}]")
154
+ ```
155
+
156
+ ---
157
+
158
+ ## 📈 Performance & Benchmark
159
+
160
+ The quantization of Shuddhi to ONNX format yields significant latency reductions with minimal loss in classification accuracy.
161
+
162
+ | Runtime / Format | Precision | Avg. Latency (CPU) | Storage Size |
163
+ | :----------------- | :-------- | :---------------------- | :----------- |
164
+ | **PyTorch (Base)** | FP32 | ~120ms | ~438 MB |
165
+ | **ONNX Quantized** | INT8 | **~25ms** (4.8x faster) | **105 MB** |
166
+
167
+ _Note: Benchmarks conducted on a typical AMD Ryzen 5 5500U CPU with sequence lengths of 128 tokens._
168
+
169
+ ---
170
+
171
+ ## 📊 Dataset: JIGSAW Toxicity
172
+
173
+ The model was trained on the dataset from the **JIGSAW Toxic Comment Classification Challenge** on Kaggle. The dataset contains comments from Wikipedia talk pages labeled by human raters for toxic behavior.
174
+
175
+ - **Total Samples:** 465,899 comments (source: [`thesofakillers/jigsaw-toxic-comment-classification-challenge`](https://huggingface.co/datasets/thesofakillers/jigsaw-toxic-comment-classification-challenge))
176
+ - **Toxicity Rate:** ~10% of the comments in the training set are labeled as toxic or hostile.
177
+
178
+ ---
179
+
180
+ ## ⚠️ Intended Use & Limitations
181
+
182
+ ### Intended Use
183
+
184
+ - Moderation engines for chat applications, comment threads, and online communities.
185
+ - Real-time safety filters for collaborative platforms.
186
+ - Analysis tools for historical community sentiment or behavior metrics.
187
+
188
+ ### Limitations & Biases
189
+
190
+ - **Nuance and Context:** The model is trained at the comment/sentence level and may struggle with subtle sarcasm, irony, or highly contextual toxicity.
191
+ - **Bias in Training Data:** Because the model is trained on JIGSAW data sourced from Wikipedia talk pages, it may reflect historical biases present in the labeling process (e.g., higher false-positive rates for text containing certain demographic keywords). We advise monitoring predictions and using a confidence threshold suited to your application needs.
192
+
193
+ ---
194
+
195
+ ## 📄 License
196
+
197
+ This model card and the Shuddhi model are distributed under the **MIT License**. See the accompanying [LICENSE](./LICENSE) file for details.
config.json ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "architectures": [
3
+ "BertForSequenceClassification"
4
+ ],
5
+ "attention_probs_dropout_prob": 0.1,
6
+ "classifier_dropout": null,
7
+ "dtype": "float32",
8
+ "gradient_checkpointing": false,
9
+ "hidden_act": "gelu",
10
+ "hidden_dropout_prob": 0.1,
11
+ "hidden_size": 768,
12
+ "id2label": {
13
+ "0": "toxic",
14
+ "1": "severe_toxic",
15
+ "2": "obscene",
16
+ "3": "threat",
17
+ "4": "insult",
18
+ "5": "identity_hate"
19
+ },
20
+ "initializer_range": 0.02,
21
+ "intermediate_size": 3072,
22
+ "label2id": {
23
+ "identity_hate": 5,
24
+ "insult": 4,
25
+ "obscene": 2,
26
+ "severe_toxic": 1,
27
+ "threat": 3,
28
+ "toxic": 0
29
+ },
30
+ "layer_norm_eps": 1e-12,
31
+ "max_position_embeddings": 512,
32
+ "model_type": "bert",
33
+ "num_attention_heads": 12,
34
+ "num_hidden_layers": 12,
35
+ "pad_token_id": 0,
36
+ "position_embedding_type": "absolute",
37
+ "problem_type": "multi_label_classification",
38
+ "transformers_version": "4.57.6",
39
+ "type_vocab_size": 2,
40
+ "use_cache": true,
41
+ "vocab_size": 30522
42
+ }
model_quantized.onnx ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8c5614458e16096ce40729565f89784b04932448e576c6397b4bd9a07ea0c5ff
3
+ size 110283961
ort_config.json ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "one_external_file": true,
3
+ "opset": null,
4
+ "optimization": {},
5
+ "quantization": {
6
+ "activations_dtype": "QUInt8",
7
+ "activations_symmetric": false,
8
+ "format": "QOperator",
9
+ "is_static": false,
10
+ "mode": "IntegerOps",
11
+ "nodes_to_exclude": [],
12
+ "nodes_to_quantize": [],
13
+ "operators_to_quantize": [
14
+ "Conv",
15
+ "MatMul",
16
+ "Attention",
17
+ "LSTM",
18
+ "Gather",
19
+ "Transpose",
20
+ "EmbedLayerNormalization"
21
+ ],
22
+ "per_channel": false,
23
+ "qdq_add_pair_to_weight": false,
24
+ "qdq_dedicated_pair": false,
25
+ "qdq_op_type_per_channel_support_to_axis": {
26
+ "MatMul": 1
27
+ },
28
+ "reduce_range": false,
29
+ "weights_dtype": "QUInt8",
30
+ "weights_symmetric": true
31
+ },
32
+ "use_external_data_format": false
33
+ }
special_tokens_map.json ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "mask_token": "[MASK]",
4
+ "pad_token": "[PAD]",
5
+ "sep_token": "[SEP]",
6
+ "unk_token": "[UNK]"
7
+ }
thresholds.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "toxic": 0.7799928784370422,
3
+ "severe_toxic": 0.8539127111434937,
4
+ "obscene": 0.9069831967353821,
5
+ "threat": 0.38606879115104675,
6
+ "insult": 0.8832359910011292,
7
+ "identity_hate": 0.7942253947257996
8
+ }
tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
tokenizer_config.json ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "100": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "101": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "102": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "103": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "clean_up_tokenization_spaces": false,
45
+ "cls_token": "[CLS]",
46
+ "do_lower_case": true,
47
+ "extra_special_tokens": {},
48
+ "mask_token": "[MASK]",
49
+ "model_max_length": 512,
50
+ "pad_token": "[PAD]",
51
+ "sep_token": "[SEP]",
52
+ "strip_accents": null,
53
+ "tokenize_chinese_chars": true,
54
+ "tokenizer_class": "BertTokenizer",
55
+ "unk_token": "[UNK]"
56
+ }
vocab.txt ADDED
The diff for this file is too large to render. See raw diff