Instructions to use jhsu12/solidity-vulnerability-detector with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use jhsu12/solidity-vulnerability-detector with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-Coder-7B-Instruct") model = PeftModel.from_pretrained(base_model, "jhsu12/solidity-vulnerability-detector") - Transformers
How to use jhsu12/solidity-vulnerability-detector with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="jhsu12/solidity-vulnerability-detector") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("jhsu12/solidity-vulnerability-detector", dtype="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use jhsu12/solidity-vulnerability-detector with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "jhsu12/solidity-vulnerability-detector" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "jhsu12/solidity-vulnerability-detector", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/jhsu12/solidity-vulnerability-detector
- SGLang
How to use jhsu12/solidity-vulnerability-detector with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "jhsu12/solidity-vulnerability-detector" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "jhsu12/solidity-vulnerability-detector", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "jhsu12/solidity-vulnerability-detector" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "jhsu12/solidity-vulnerability-detector", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use jhsu12/solidity-vulnerability-detector with Docker Model Runner:
docker model run hf.co/jhsu12/solidity-vulnerability-detector
| """ | |
| Evaluate classifier expert(s) on the COMBINED training data from ALL expert datasets. | |
| Loads train+test from all 5 expert datasets, merges them into one pool, then | |
| runs each classifier against the full set. For each classifier, its own | |
| expert type = label 1 (vulnerable), everything else = label 0 (safe). | |
| This gives you per-vulnerability-type breakdown using the same data distribution | |
| the models were trained on β no length mismatch issues. | |
| Usage: | |
| # Evaluate one classifier against all combined data: | |
| python evaluate_on_all_train_data.py \ | |
| --checkpoint ./cls-expert-reentrancy/checkpoint-480 \ | |
| --expert reentrancy | |
| # Evaluate ALL classifiers at once: | |
| python evaluate_on_all_train_data.py --all --base_dir . | |
| # Quick test: | |
| python evaluate_on_all_train_data.py --all --base_dir . --max_samples_per_dataset 100 | |
| """ | |
| import argparse | |
| import os | |
| import re | |
| import json | |
| import numpy as np | |
| import torch | |
| from collections import Counter | |
| from datasets import load_dataset, concatenate_datasets | |
| from transformers import AutoTokenizer, AutoModelForSequenceClassification, BitsAndBytesConfig | |
| from peft import PeftModel, PeftConfig | |
| from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, roc_auc_score, confusion_matrix | |
| # ββ Config ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| BASE_MODEL = "Qwen/Qwen2.5-Coder-3B-Instruct" | |
| EXPERT_DATASETS = { | |
| "reentrancy": "jhsu12/solidity-vuln-expert-reentrancy", | |
| "access-control": "jhsu12/solidity-vuln-expert-access-control", | |
| "integer-overflow-underflow": "jhsu12/solidity-vuln-expert-integer-overflow-underflow", | |
| "timestamp-dependence": "jhsu12/solidity-vuln-expert-timestamp-dependence", | |
| "unchecked-low-level-calls": "jhsu12/solidity-vuln-expert-unchecked-low-level-calls", | |
| } | |
| EXPERTS = { | |
| "reentrancy": "Reentrancy", | |
| "access-control": "Access Control", | |
| "integer-overflow-underflow": "Integer Overflow/Underflow", | |
| "timestamp-dependence": "Timestamp Dependence", | |
| "unchecked-low-level-calls": "Unchecked Low-Level Calls", | |
| } | |
| def parse_args(): | |
| parser = argparse.ArgumentParser( | |
| description="Evaluate classifier(s) on combined data from all expert datasets." | |
| ) | |
| # Single expert mode | |
| parser.add_argument("--checkpoint", type=str, default=None) | |
| parser.add_argument("--expert", type=str, default=None, choices=list(EXPERTS.keys())) | |
| # Multi-expert mode | |
| parser.add_argument("--all", action="store_true", default=False) | |
| parser.add_argument("--base_dir", type=str, default=".") | |
| # Options | |
| parser.add_argument("--max_samples_per_dataset", type=int, default=None, | |
| help="Limit samples per expert dataset (for quick testing)") | |
| parser.add_argument("--max_seq_len", type=int, default=1536) | |
| parser.add_argument("--batch_size", type=int, default=16) | |
| parser.add_argument("--threshold", type=float, default=0.5) | |
| parser.add_argument("--preview", type=int, default=5) | |
| return parser.parse_args() | |
| def extract_user_code(messages): | |
| for msg in messages: | |
| if msg["role"] == "user": | |
| return msg["content"] | |
| return "" | |
| def detect_base_model(checkpoint_path): | |
| config_path = os.path.join(checkpoint_path, "adapter_config.json") | |
| if os.path.isfile(config_path): | |
| with open(config_path, "r") as f: | |
| cfg = json.load(f) | |
| return cfg.get("base_model_name_or_path", BASE_MODEL) | |
| try: | |
| peft_config = PeftConfig.from_pretrained(checkpoint_path) | |
| return peft_config.base_model_name_or_path | |
| except Exception: | |
| return BASE_MODEL | |
| def find_best_checkpoint(expert_dir): | |
| if not os.path.isdir(expert_dir): | |
| return None | |
| best_step = -1 | |
| best_path = None | |
| for name in os.listdir(expert_dir): | |
| match = re.match(r"checkpoint-(\d+)$", name) | |
| if match: | |
| step = int(match.group(1)) | |
| if step > best_step: | |
| best_step = step | |
| best_path = os.path.join(expert_dir, name) | |
| best_model_path = os.path.join(expert_dir, "best_model") | |
| if os.path.isdir(best_model_path): | |
| if os.path.isfile(os.path.join(best_model_path, "adapter_config.json")): | |
| return best_model_path | |
| return best_path | |
| def load_classifier(checkpoint_path): | |
| base_model_id = detect_base_model(checkpoint_path) | |
| print(f" Base model: {base_model_id}") | |
| has_bf16 = torch.cuda.is_bf16_supported() if torch.cuda.is_available() else False | |
| compute_dtype = torch.bfloat16 if has_bf16 else torch.float16 | |
| bnb_config = BitsAndBytesConfig( | |
| load_in_4bit=True, bnb_4bit_quant_type="nf4", | |
| bnb_4bit_compute_dtype=compute_dtype, bnb_4bit_use_double_quant=True, | |
| ) | |
| attn_impl = "sdpa" | |
| try: | |
| import flash_attn | |
| attn_impl = "flash_attention_2" | |
| except ImportError: | |
| pass | |
| model = AutoModelForSequenceClassification.from_pretrained( | |
| base_model_id, num_labels=2, | |
| id2label={0: "safe", 1: "vulnerable"}, | |
| label2id={"safe": 0, "vulnerable": 1}, | |
| quantization_config=bnb_config, device_map="auto", | |
| torch_dtype=compute_dtype, trust_remote_code=True, | |
| attn_implementation=attn_impl, ignore_mismatched_sizes=True, | |
| ) | |
| model = PeftModel.from_pretrained(model, checkpoint_path) | |
| model.eval() | |
| try: | |
| tokenizer = AutoTokenizer.from_pretrained(checkpoint_path, trust_remote_code=True) | |
| except Exception: | |
| tokenizer = AutoTokenizer.from_pretrained(base_model_id, trust_remote_code=True) | |
| if tokenizer.pad_token is None: | |
| tokenizer.pad_token = tokenizer.eos_token | |
| model.config.pad_token_id = tokenizer.pad_token_id | |
| return model, tokenizer | |
| def load_all_data(max_samples_per_dataset=None): | |
| """Load train+test from all 5 expert datasets, tag each sample with its source.""" | |
| all_codes = [] | |
| all_source_experts = [] # which expert dataset this sample came from | |
| all_is_expert = [] # is_expert_type from the original dataset | |
| for slug, dataset_id in EXPERT_DATASETS.items(): | |
| print(f" Loading {slug}...", end=" ") | |
| ds = load_dataset(dataset_id) | |
| for split_name in ["train", "test"]: | |
| split = ds[split_name] | |
| if max_samples_per_dataset: | |
| n = min(max_samples_per_dataset, len(split)) | |
| split = split.select(range(n)) | |
| for row in split: | |
| code = extract_user_code(row["messages"]) | |
| all_codes.append(code) | |
| all_source_experts.append(slug) | |
| all_is_expert.append(int(row["is_expert_type"])) | |
| total = len(ds["train"]) + len(ds["test"]) | |
| if max_samples_per_dataset: | |
| total = min(max_samples_per_dataset, len(ds["train"])) + min(max_samples_per_dataset, len(ds["test"])) | |
| print(f"{total} samples") | |
| return all_codes, all_source_experts, all_is_expert | |
| def run_inference(model, tokenizer, codes, batch_size=16, max_seq_len=1536): | |
| all_logits = [] | |
| for i in range(0, len(codes), batch_size): | |
| batch = codes[i:i + batch_size] | |
| inputs = tokenizer(batch, return_tensors="pt", truncation=True, | |
| max_length=max_seq_len, padding=True) | |
| inputs = {k: v.to(model.device) for k, v in inputs.items()} | |
| with torch.no_grad(): | |
| outputs = model(**inputs) | |
| all_logits.append(outputs.logits.cpu().float().numpy()) | |
| done = min(i + batch_size, len(codes)) | |
| if done % (batch_size * 20) == 0 or done == len(codes): | |
| print(f" [{done}/{len(codes)}]") | |
| return np.concatenate(all_logits, axis=0) | |
| def evaluate_one_expert(checkpoint_path, expert_slug, all_codes, all_source_experts, | |
| all_is_expert, args): | |
| """Evaluate one classifier on the full combined dataset.""" | |
| expert_name = EXPERTS[expert_slug] | |
| print(f"\n{'β' * 60}") | |
| print(f" π¬ Evaluating: {expert_name}") | |
| print(f" Checkpoint: {checkpoint_path}") | |
| print(f"{'β' * 60}") | |
| # ββ Ground truth: for THIS expert, label=1 if sample came from this expert's | |
| # dataset AND is_expert_type=True. Everything else is label=0. | |
| labels = [] | |
| for i in range(len(all_codes)): | |
| if all_source_experts[i] == expert_slug and all_is_expert[i] == 1: | |
| labels.append(1) | |
| else: | |
| labels.append(0) | |
| n_pos = sum(labels) | |
| n_neg = len(labels) - n_pos | |
| print(f"\n Total: {len(labels)} samples") | |
| print(f" Positive (this expert's vuln): {n_pos}") | |
| print(f" Negative (everything else): {n_neg}") | |
| # ββ Load model ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n Loading model...") | |
| model, tokenizer = load_classifier(checkpoint_path) | |
| # ββ Inference βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n Running inference on {len(all_codes)} samples...") | |
| logits = run_inference(model, tokenizer, all_codes, | |
| batch_size=args.batch_size, max_seq_len=args.max_seq_len) | |
| probs = torch.softmax(torch.tensor(logits), dim=-1).numpy() | |
| probs_vuln = probs[:, 1].tolist() | |
| preds = [1 if p >= args.threshold else 0 for p in probs_vuln] | |
| # ββ Preview first N samples βββββββββββββββββββββββββββββββββββββββββββββββ | |
| n_preview = min(args.preview, len(all_codes)) | |
| print(f"\n {'β' * 50}") | |
| print(f" FIRST {n_preview} SAMPLES") | |
| print(f" {'β' * 50}") | |
| for idx in range(n_preview): | |
| code_preview = all_codes[idx].replace('\n', ' ')[:80] | |
| gt = "VULNERABLE" if labels[idx] == 1 else "SAFE" | |
| pred = "VULNERABLE" if preds[idx] == 1 else "SAFE" | |
| match = "β " if labels[idx] == preds[idx] else "β" | |
| print(f"\n [{idx+1}] {match}") | |
| print(f" Source: {all_source_experts[idx]} (is_expert={all_is_expert[idx]})") | |
| print(f" Code: {code_preview}...") | |
| print(f" Ground truth: {gt} | Prediction: {pred}") | |
| print(f" P(vuln): {probs_vuln[idx]:.6f} | Logits: safe={logits[idx][0]:.4f} vuln={logits[idx][1]:.4f}") | |
| # ββ Overall metrics βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| acc = accuracy_score(labels, preds) | |
| f1 = f1_score(labels, preds, average="binary", zero_division=0) | |
| prec = precision_score(labels, preds, average="binary", zero_division=0) | |
| rec = recall_score(labels, preds, average="binary", zero_division=0) | |
| try: | |
| auc = roc_auc_score(labels, probs_vuln) if len(set(labels)) > 1 else 0.0 | |
| except ValueError: | |
| auc = 0.0 | |
| cm = confusion_matrix(labels, preds, labels=[0, 1]) | |
| print(f"\n {'β' * 50}") | |
| print(f" OVERALL METRICS") | |
| print(f" {'β' * 50}") | |
| print(f" Accuracy: {acc:.4f}") | |
| print(f" F1: {f1:.4f}") | |
| print(f" Precision: {prec:.4f}") | |
| print(f" Recall: {rec:.4f}") | |
| print(f" AUC: {auc:.4f}") | |
| print(f"\n Confusion Matrix:") | |
| print(f" Pred SAFE Pred VULN") | |
| print(f" Actual SAFE {cm[0][0]:>8} {cm[0][1]:>8}") | |
| print(f" Actual VULN {cm[1][0]:>8} {cm[1][1]:>8}") | |
| # ββ Per source-expert breakdown βββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\n {'β' * 50}") | |
| print(f" PER SOURCE DATASET BREAKDOWN") | |
| print(f" {'β' * 50}") | |
| print(f" {'Source':<35} {'N':>5} {'GT=1':>5} {'Pred=1':>6} {'TP':>4} {'FP':>4} {'TN':>4} {'FN':>4} {'Acc':>6} {'F1':>6} {'MeanP':>6}") | |
| print(f" {'β' * 95}") | |
| per_source = {} | |
| for source_slug in EXPERT_DATASETS.keys(): | |
| mask = [i for i, s in enumerate(all_source_experts) if s == source_slug] | |
| if not mask: | |
| continue | |
| s_labels = [labels[i] for i in mask] | |
| s_preds = [preds[i] for i in mask] | |
| s_probs = [probs_vuln[i] for i in mask] | |
| s_n = len(mask) | |
| s_gt1 = sum(s_labels) | |
| s_pred1 = sum(s_preds) | |
| s_tp = sum(1 for p, l in zip(s_preds, s_labels) if p == 1 and l == 1) | |
| s_fp = sum(1 for p, l in zip(s_preds, s_labels) if p == 1 and l == 0) | |
| s_tn = sum(1 for p, l in zip(s_preds, s_labels) if p == 0 and l == 0) | |
| s_fn = sum(1 for p, l in zip(s_preds, s_labels) if p == 0 and l == 1) | |
| s_acc = accuracy_score(s_labels, s_preds) | |
| s_f1 = f1_score(s_labels, s_preds, average="binary", zero_division=0) | |
| s_mean_p = np.mean(s_probs) | |
| is_self = " β" if source_slug == expert_slug else "" | |
| source_name = EXPERTS.get(source_slug, source_slug)[:33] | |
| print(f" {source_name:<35} {s_n:>5} {s_gt1:>5} {s_pred1:>6} " | |
| f"{s_tp:>4} {s_fp:>4} {s_tn:>4} {s_fn:>4} " | |
| f"{s_acc:>6.3f} {s_f1:>6.3f} {s_mean_p:>6.3f}{is_self}") | |
| per_source[source_slug] = { | |
| "n": s_n, "gt_positive": s_gt1, "pred_positive": s_pred1, | |
| "tp": s_tp, "fp": s_fp, "tn": s_tn, "fn": s_fn, | |
| "accuracy": s_acc, "f1": s_f1, "mean_prob_vuln": float(s_mean_p), | |
| } | |
| # ββ Diagnosis βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| self_data = per_source.get(expert_slug, {}) | |
| print(f"\n {'β' * 50}") | |
| print(f" DIAGNOSIS for {expert_name}") | |
| print(f" {'β' * 50}") | |
| if self_data: | |
| self_recall = self_data["tp"] / (self_data["tp"] + self_data["fn"]) if (self_data["tp"] + self_data["fn"]) > 0 else 0 | |
| print(f" Own type recall: {self_recall:.3f} ({self_data['tp']}/{self_data['tp']+self_data['fn']} detected)") | |
| # False alarms on other types | |
| other_fp_total = sum(per_source[s]["fp"] for s in per_source if s != expert_slug) | |
| other_total = sum(per_source[s]["n"] for s in per_source if s != expert_slug) | |
| if other_total > 0: | |
| fp_rate = other_fp_total / other_total | |
| print(f" False alarm rate on other types: {fp_rate:.3f} ({other_fp_total}/{other_total})") | |
| # Free memory | |
| del model | |
| if torch.cuda.is_available(): | |
| torch.cuda.empty_cache() | |
| return { | |
| "expert_slug": expert_slug, | |
| "expert_name": expert_name, | |
| "checkpoint": checkpoint_path, | |
| "overall": {"accuracy": acc, "f1": f1, "precision": prec, "recall": rec, "auc": auc}, | |
| "per_source": per_source, | |
| } | |
| def main(): | |
| args = parse_args() | |
| print("=" * 60) | |
| print(" Evaluate Classifiers on Combined Training Data") | |
| print("=" * 60) | |
| # ββ Determine which experts to evaluate βββββββββββββββββββββββββββββββββββ | |
| eval_tasks = [] | |
| if args.all: | |
| base_dir = os.path.abspath(args.base_dir) | |
| print(f"\nπ Scanning: {base_dir}") | |
| for slug in EXPERTS: | |
| expert_dir = os.path.join(base_dir, f"cls-expert-{slug}") | |
| ckpt = find_best_checkpoint(expert_dir) | |
| if ckpt: | |
| eval_tasks.append((ckpt, slug)) | |
| print(f" β {slug}: {ckpt}") | |
| else: | |
| print(f" β¬ {slug}: not found") | |
| elif args.checkpoint and args.expert: | |
| eval_tasks.append((args.checkpoint, args.expert)) | |
| else: | |
| print("β Provide --checkpoint + --expert, or use --all") | |
| return | |
| if not eval_tasks: | |
| print("β No checkpoints found!") | |
| return | |
| # ββ Load ALL data βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\nπ¦ Loading all expert datasets (train + test)...") | |
| all_codes, all_source_experts, all_is_expert = load_all_data(args.max_samples_per_dataset) | |
| print(f"\n Combined dataset: {len(all_codes)} total samples") | |
| source_dist = Counter(all_source_experts) | |
| for slug, count in source_dist.most_common(): | |
| n_expert = sum(1 for s, e in zip(all_source_experts, all_is_expert) if s == slug and e == 1) | |
| print(f" {EXPERTS[slug]:<35} {count:>6} samples ({n_expert} positive)") | |
| # ββ Evaluate each classifier ββββββββββββββββββββββββββββββββββββββββββββββ | |
| all_results = [] | |
| for checkpoint_path, expert_slug in eval_tasks: | |
| result = evaluate_one_expert( | |
| checkpoint_path, expert_slug, | |
| all_codes, all_source_experts, all_is_expert, args, | |
| ) | |
| all_results.append(result) | |
| # ββ Final summary βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| if len(all_results) > 1: | |
| print(f"\n{'β' * 60}") | |
| print(f" SUMMARY β ALL EXPERTS") | |
| print(f"{'β' * 60}") | |
| print(f" {'Expert':<30} {'Acc':>6} {'F1':>6} {'Prec':>6} {'Rec':>6} {'AUC':>6}") | |
| print(f" {'β' * 66}") | |
| for r in all_results: | |
| o = r["overall"] | |
| print(f" {r['expert_name']:<30} {o['accuracy']:>6.3f} {o['f1']:>6.3f} " | |
| f"{o['precision']:>6.3f} {o['recall']:>6.3f} {o['auc']:>6.3f}") | |
| print(f"\n{'=' * 60}") | |
| if __name__ == "__main__": | |
| main() | |