File size: 6,667 Bytes
2ef4ea4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
---
license: mit
library_name: transformers
pipeline_tag: text-classification
tags:
  - code
  - clone-detection
  - graphcodebert
  - code-similarity
base_model: microsoft/graphcodebert-base
datasets:
  - PoolC/1-fold-clone-detection-600k-5fold
language:
  - code
metrics:
  - accuracy
  - precision
  - recall
  - f1
model-index:
  - name: graphcodebert-code-clone-detection
    results:
      - task:
          type: text-classification
          name: Binary code clone detection
        dataset:
          type: PoolC/1-fold-clone-detection-600k-5fold
          name: PoolC/1-fold-clone-detection-600k-5fold
          split: test (group-disjoint half of the `val` fold)
        metrics:
          - type: f1
            value: 0.8805
          - type: accuracy
            value: 0.8747
          - type: precision
            value: 0.841
          - type: recall
            value: 0.924
---

# graphcodebert-code-clone-detection

Binary code-clone detection. Full fine-tune of
[`microsoft/graphcodebert-base`](https://huggingface.co/microsoft/graphcodebert-base) on
[`PoolC/1-fold-clone-detection-600k-5fold`](https://huggingface.co/datasets/PoolC/1-fold-clone-detection-600k-5fold),
using GraphCodeBERT's data-flow-aware pairwise architecture.

Output labels: `0 = not clone`, `1 = clone`.

## Architecture

Not a generic sequence-pair classifier. The two snippets are encoded
**separately** by one shared GraphCodeBERT encoder, each with its own
graph-guided masked attention, and the two `<s>` vectors are concatenated for
classification:

```
Linear(2 x 768 -> 768) -> tanh -> Linear(768 -> 2)
```

Per-snippet input layout (length 640):

| segment | length | content | `position_idx` |
|---|---|---|---|
| code tokens | 512 | `<s>` + BPE code tokens + `</s>` | `2 .. n+1` |
| data-flow nodes | 128 | one slot per DFG variable node (`<unk>` id) | `0` |
| padding | remainder | `<pad>` | `1` |

A data-flow node's input embedding is the **average of the embeddings of the
code tokens it was identified from**. Graph-guided attention allows: code to
code; `<s>`/`</s>` to everything; node to the code tokens it comes from (and
back); node to adjacent nodes.

## Preprocessing

The dataset contains **Python** snippets, so data flow is extracted with the
`tree-sitter-python` grammar via a port of GraphCodeBERT's `DFG_python`
extractor (comment/docstring stripping -> AST -> variable states ->
`comesFrom` / `computedFrom` edges).

| | |
|---|---|
| `code_length` | 512 |
| `data_flow_length` | 128 |
| total sequence length | 640 |
| distinct snippets featurised | 44,950 |
| mean data-flow nodes / snippet | 44.22 |
| snippets with empty data flow | 263 |
| total data-flow edges | 2,481,388 |
| extraction status counts | `{"ok": 44930, "comment_strip_failed": 13, "dfg_failed": 7}` |

No example was dropped: a snippet whose data flow could not be extracted is
kept with an empty graph and counted above.

## Data splits

The repository provides one of 5 predefined folds as `train` + `val`; those groups are disjoint and are kept as-is. `val` is partitioned further into validation/test along problem-group boundaries.

`similar` equals `(code1_group == code2_group)` for every row, so the group
columns are a perfect label proxy and are never used as features.

| split | source | pairs | positives | negatives | groups |
|---|---|---:|---:|---:|---:|
| train | `train` fold | 50,000 | 25,000 | 25,000 | 240 |
| validation | half of `val` by group | 20,000 | 10,000 | 10,000 | 29 |
| test | other half of `val` by group | 20,000 | 10,000 | 10,000 | 30 |

Train/validation/test share **no problem group and no code snippet**; this is
asserted at runtime before training starts. 337,398 pairs of the
held-out fold were dropped because their two snippets fell on opposite sides of
the validation/test group boundary.

Class weighting: Measured majority-class share 0.5000 is within the 0.6 threshold, so weighted cross entropy is NOT used.

## Training

| | |
|---|---|
| optimizer | adamw_torch |
| learning rate | 2e-05 |
| scheduler | linear with 0.1 warmup ratio (938 steps) |
| epochs | 3.0 |
| per-device batch size | 16 |
| gradient accumulation | 1 |
| effective batch size | 16 |
| weight decay | 0.01 |
| gradient clipping | 1.0 |
| mixed precision | fp16 |
| gradient checkpointing | False |
| seed | 42 |
| trainable parameters | 125,236,994 |
| training time | 1.923 h |
| GPU | NVIDIA GeForce RTX 5060 Ti (15.9 GB) |
| torch / transformers | 2.11.0+cu128 / 5.17.0 |

Checkpoint selection: best validation **F1** (`load_best_model_at_end=True`,
`metric_for_best_model="f1"`). Best validation F1 = **0.8672**.
The test split was scored once, after selection.

## Results

| split | accuracy | precision | recall | F1 | TP | TN | FP | FN |
|---|---:|---:|---:|---:|---:|---:|---:|---:|
| validation | 0.8557 | 0.8032 | 0.9422 | 0.8672 | 9,422 | 7,692 | 2,308 | 578 |
| test | 0.8747 | 0.8410 | 0.9240 | 0.8805 | 9,240 | 8,253 | 1,747 | 760 |

Test confusion matrix (`[[TN, FP], [FN, TP]]`): `[[8253, 1747], [760, 9240]]`

## Usage

This checkpoint uses a **custom pairwise head and a graph-guided attention
mask**, so `AutoModelForSequenceClassification` will not reproduce these
results. Use the repository's own model class and preprocessing:

```python
import torch
from transformers import AutoTokenizer
from modeling import load_model                      # from this project
from preprocess import build_snippet_features, CloneCollator
from config import Config

cfg = Config()
tokenizer = AutoTokenizer.from_pretrained("thealper2/graphcodebert-code-clone-detection")
model = load_model("thealper2/graphcodebert-code-clone-detection").eval()

features = build_snippet_features(cfg, [code_a, code_b], tokenizer, num_proc=1)
collator = CloneCollator(features)
batch = collator([(0, 1, 0)])                        # (snippet_a, snippet_b, dummy label)
with torch.no_grad():
    logits = model(**{k: v for k, v in batch.items() if k != "labels"}).logits
label = int(logits.argmax(-1))                       # 0 = not clone, 1 = clone
```

## Limitations

- Trained on competitive-programming Python solutions grouped by problem;
  "clone" therefore means *solves the same problem*, which is closer to
  semantic (Type-4) similarity than to syntactic copy-paste detection.
- Data flow is extracted with the Python grammar only. Other languages need the
  matching `tree_sitter_<lang>` grammar and `DFG_<lang>` function.
- Snippets longer than 512 BPE tokens are truncated; 885 of
  44,950 distinct snippets hit that limit.
- Both directions of a pair are not explicitly symmetrised; the head sees
  `concat(<s>_1, <s>_2)` in the given order.