santh-cpu commited on
Commit
eca8b6c
·
verified ·
1 Parent(s): ce50f5c

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +76 -151
README.md CHANGED
@@ -15,165 +15,90 @@ metrics:
15
 
16
  # ai_code_detect
17
 
18
- ### Architecture
19
- - **Semantic Engine:** `Salesforce/codet5-base`
20
- - **Statistical Extraction:** `microsoft/codebert-base-mlm` (Calculates Entropy and Log-Rank across 256 tokens)
21
- - **Fusion Network:** 1D CNN for temporal feature extraction + Dense Feed-Forward Classifier
22
 
23
- ### Performance Metrics
24
- Trained on a polyglot dataset (Python, Java, C++) to prevent single-language overfitting.
25
- - **Training Validation F1:** 0.9861
26
- - **Unseen SemEval-2026 Audit (F1):** 0.9921
27
- - **Overall Accuracy:** 99.20%
28
 
29
- ### Requires:
30
- transformers==4.35.2
31
 
32
- ### How to use
33
- To use this model in your own application, download the weights directly from this hub and load them into the custom `TemporalFusionClassifier` architecture.
34
 
35
- ```python
36
- from huggingface_hub import hf_hub_download
37
- import torch
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
- weights_path = hf_hub_download(repo_id="santh-cpu/ai_code_detect", filename="pytorch_model.bin")
40
 
41
- model = TemporalFusionClassifier(base_model)
42
- model.load_state_dict(torch.load(weights_path))
43
- model.eval()
44
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
 
46
- ### Example
47
  ```python
48
- import torch
49
- import torch.nn as nn
50
- import torch.nn.functional as F
51
- from transformers import T5EncoderModel, AutoTokenizer, AutoModelForMaskedLM
52
  from huggingface_hub import hf_hub_download
53
 
54
- class TemporalFusionClassifier(nn.Module):
55
- def __init__(self, base, metric_dim=7):
56
- super().__init__()
57
- self.base = base
58
- h = base.config.hidden_size
59
-
60
- self.metric_cnn = nn.Sequential(
61
- nn.Conv1d(metric_dim, 32, 3, padding=1),
62
- nn.BatchNorm1d(32),
63
- nn.ReLU(),
64
- nn.MaxPool1d(2),
65
- nn.Conv1d(32, 64, 3, padding=1),
66
- nn.BatchNorm1d(64),
67
- nn.ReLU(),
68
- nn.AdaptiveAvgPool1d(1)
69
- )
70
-
71
- self.classifier = nn.Sequential(
72
- nn.Linear(h + 64, 1024),
73
- nn.ReLU(),
74
- nn.Dropout(0.1),
75
- nn.Linear(1024, 1)
76
- )
77
-
78
- def forward(self, input_ids, attention_mask, metric_vector):
79
- out = self.base(input_ids=input_ids, attention_mask=attention_mask)
80
- hidden = out.last_hidden_state
81
- mask = attention_mask.unsqueeze(-1).float()
82
- pooled = (hidden * mask).sum(dim=1) / mask.sum(dim=1).clamp(min=1e-4)
83
-
84
- cnn_features = self.metric_cnn(metric_vector.transpose(1, 2)).squeeze(-1)
85
- return self.classifier(torch.cat([pooled, cnn_features], dim=1))
86
-
87
- class AICodeDetector:
88
- def __init__(self, repo_id="santh-cpu/ai_code_detect"):
89
- self.device = "cuda" if torch.cuda.is_available() else "cpu"
90
- self.max_len = 256
91
-
92
- self.cb_tokenizer = AutoTokenizer.from_pretrained("microsoft/codebert-base-mlm")
93
- self.cb_model = AutoModelForMaskedLM.from_pretrained("microsoft/codebert-base-mlm").to(self.device).eval()
94
-
95
- self.t5_tokenizer = AutoTokenizer.from_pretrained("Salesforce/codet5-base")
96
- base_t5 = T5EncoderModel.from_pretrained("Salesforce/codet5-base")
97
-
98
- weights_path = hf_hub_download(repo_id=repo_id, filename="pytorch_model.bin")
99
- self.detector = TemporalFusionClassifier(base_t5).to(self.device)
100
- self.detector.load_state_dict(torch.load(weights_path, map_location=self.device))
101
- self.detector.eval()
102
-
103
- def analyze(self, code_snippet):
104
- with torch.no_grad():
105
- cb_in = self.cb_tokenizer(code_snippet, return_tensors="pt", padding="max_length", truncation=True, max_length=self.max_len).to(self.device)
106
- logits = self.cb_model(**cb_in).logits
107
-
108
- seq_len = cb_in["attention_mask"][0].sum().item()
109
- metrics = torch.zeros((1, self.max_len, 7), device=self.device)
110
-
111
- if seq_len > 1:
112
- seq_logits = logits[0:1, :seq_len-1, :]
113
- seq_labels = cb_in["input_ids"][0:1, 1:seq_len]
114
- probs = F.softmax(seq_logits, dim=-1)
115
-
116
- entropy = -torch.sum(probs * torch.log(probs + 1e-9), dim=-1)
117
- ranks = (torch.argsort(seq_logits, dim=-1, descending=True) == seq_labels.unsqueeze(-1)).nonzero(as_tuple=True)[2].view(1, -1) + 1
118
-
119
- token_metrics = torch.stack([
120
- torch.log(probs.gather(2, seq_labels.unsqueeze(-1)).squeeze(-1) + 1e-9),
121
- torch.log(ranks.float()),
122
- entropy,
123
- (ranks <= 10).float(),
124
- ((ranks > 10) & (ranks <= 100)).float(),
125
- ((ranks > 100) & (ranks <= 1000)).float(),
126
- (ranks > 1000).float()
127
- ], dim=-1)
128
- metrics[0, :token_metrics.size(1), :] = token_metrics[0]
129
-
130
- clean_metrics = torch.nan_to_num(metrics, nan=0.0, posinf=10.0, neginf=-100.0)
131
- t5_in = self.t5_tokenizer(code_snippet, return_tensors="pt", padding="max_length", truncation=True, max_length=self.max_len).to(self.device)
132
- prob = torch.sigmoid(self.detector(t5_in["input_ids"], t5_in["attention_mask"], clean_metrics)).item()
133
-
134
- return {"prediction": "AI Generated" if prob > 0.5 else "Human Written", "ai_probability": round(prob * 100, 2)}
135
-
136
- sample = """
137
- #include <bits/stdc++.h>
138
- using namespace std;
139
-
140
- int main() {
141
- ios::sync_with_stdio(0);
142
- cin.tie(0);
143
-
144
- int n, k, w;
145
- string s;
146
- cin >> n >> k >> w >> s;
147
-
148
- vector<vector<long long>> pre(k, vector<long long>(n));
149
-
150
- for (int i = 0; i < k; ++i) {
151
- for (int j = 0; j < n; ++j) {
152
- if (j % k == i && s[j] == '0')
153
- pre[i][j]++;
154
-
155
- if (j % k != i && s[j] == '1')
156
- pre[i][j]++;
157
-
158
- if (j > 0)
159
- pre[i][j] += pre[i][j - 1];
160
- }
161
- }
162
-
163
- for (int i = 0; i < w; ++i) {
164
- int l, r;
165
- cin >> l >> r;
166
- l--, r--;
167
-
168
- int m = (l + k - 1) % k;
169
-
170
- cout << pre[m][r] - (l > 0 ? pre[m][l - 1] : 0) << "\n";
171
- }
172
-
173
- return 0;
174
- }"""
175
-
176
- if __name__ == "__main__":
177
- detector = AICodeDetector()
178
- print("\n",detector.analyze(sample))
179
  ```
 
15
 
16
  # ai_code_detect
17
 
18
+ Binary classifier: human-written vs. AI-generated code. Trained on 500k samples (Python, Java, C++). Macro F1: **0.9813**.
 
 
 
19
 
20
+ ---
 
 
 
 
21
 
22
+ ## Architecture
 
23
 
24
+ Two input streams fused into a single MLP classifier.
 
25
 
26
+ **Stream 1 — Probabilistic**
27
+
28
+ Code is passed through `Salesforce/codegen-350M-mono`. Per-token surprisal signals are extracted across a 256-token window:
29
+
30
+ | # | Feature | Description |
31
+ |---|---------|-------------|
32
+ | 0 | `log_prob` | Log-probability of the actual token |
33
+ | 1 | `log_rank` | Log-rank within the distribution |
34
+ | 2 | `entropy` | Shannon entropy of the token distribution |
35
+ | 3 | `varentropy` | Variance of entropy |
36
+ | 4 | `top10_mass` | Probability mass in top-10 tokens |
37
+ | 5 | `gap_1_2` | Log-prob gap between rank-1 and rank-2 |
38
+ | 6 | `surprisal_z` | Per-token surprisal z-score |
39
+ | 7 | `entropy_delta` | Entropy change from previous position |
40
+ | 8 | `cum_rank` | Cumulative mean log-rank |
41
+ | 9 | `is_special` | Special token flag |
42
+ | 10 | `r10_flag` | Rank ≤ 10 |
43
+ | 11 | `r100_flag` | 10 < rank ≤ 100 |
44
+
45
+ These 12 per-token features aggregate into 32 sequence-level statistics (moments, autocorrelations, burstiness, etc.) passed downstream.
46
+
47
+ **Stream 2 — Semantic**
48
+
49
+ `Salesforce/codet5-base` mean-pools hidden states into a 768-dim embedding capturing style, structure, naming, and comment density.
50
+
51
+ **Classifier**
52
+
53
+ Token (256-dim) + sequence (64-dim) + semantic (768-dim) representations are concatenated → 1088-dim → 3-layer MLP with LayerNorm, GELU, dropout → sigmoid.
54
+
55
+ ---
56
 
57
+ ## Performance
58
 
59
+ Evaluated on 3,000 balanced validation samples (1,000/language):
60
+
61
+ | Metric | Score |
62
+ |--------|-------|
63
+ | Macro F1 | **0.9813** |
64
+ | Accuracy | **98.13%** |
65
+ | Threshold | 0.475 |
66
+
67
+ | Language | Accuracy | Human p̄ | AI p̄ | Gap |
68
+ |----------|----------|---------|-------|-----|
69
+ | Python | 99.50% | 0.001 | 0.992 | 0.991 |
70
+ | Java | 98.00% | 0.043 | 0.968 | 0.926 |
71
+ | C++ | 96.90% | 0.063 | 0.966 | 0.903 |
72
+
73
+ ---
74
+
75
+ ## Training
76
+
77
+ | Setting | Value |
78
+ |---------|-------|
79
+ | Optimizer | AdamW (encoder lr 8e-6, head lr 3e-5) |
80
+ | Scheduler | OneCycleLR + cosine annealing |
81
+ | Loss | BCEWithLogitsLoss |
82
+ | Regularization | EMA (decay=0.998), dropout, LayerNorm |
83
+ | Precision | fp16 via HuggingFace Accelerate |
84
+ | Hardware | 2× GPU |
85
+ | Epochs | 4 (500k samples) |
86
+
87
+
88
+ from SemEval-2026 Task 13
89
+ ---
90
+
91
+ ## Usage
92
 
 
93
  ```python
94
+ import os
95
+ import sys
 
 
96
  from huggingface_hub import hf_hub_download
97
 
98
+ REPO_ID = "santh-cpu/ai_code_detect"
99
+ script_path = hf_hub_download(repo_id=REPO_ID, filename="model.py")
100
+ sys.path.append(os.path.dirname(script_path))
101
+ from model import predict
102
+
103
+ print(predict("your code here"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  ```