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
| """ | |
| Train a binary classifier expert for smart contract vulnerability detection. | |
| Instead of generating text analysis, this approach adds a classification head | |
| on top of Qwen2.5-Coder-3B-Instruct to predict: "Does this contract have | |
| this specific vulnerability type?" β 0 (safe) or 1 (vulnerable). | |
| Advantages over SFT: | |
| - Much faster inference (single forward pass vs autoregressive generation) | |
| - More efficient training (one label per sample vs hundreds of tokens) | |
| - Directly optimizes the binary decision | |
| Usage: | |
| python train_expert_classifier.py --expert Reentrancy | |
| python train_expert_classifier.py --expert "Access Control" | |
| python train_expert_classifier.py --expert "Integer Overflow/Underflow" | |
| python train_expert_classifier.py --expert "Timestamp Dependence" | |
| python train_expert_classifier.py --expert "Unchecked Low-Level Calls" | |
| """ | |
| import argparse | |
| import os | |
| import numpy as np | |
| import torch | |
| from datasets import load_dataset | |
| from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training, TaskType | |
| from transformers import ( | |
| AutoModelForSequenceClassification, | |
| AutoTokenizer, | |
| BitsAndBytesConfig, | |
| DataCollatorWithPadding, | |
| Trainer, | |
| TrainingArguments, | |
| ) | |
| from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score, roc_auc_score | |
| from scipy.special import softmax | |
| from huggingface_hub import HfApi | |
| import trackio | |
| BASE_MODEL = "Qwen/Qwen2.5-Coder-3B-Instruct" | |
| # Expert β dataset mapping | |
| 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", | |
| } | |
| def parse_args(): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--expert", type=str, required=True, | |
| choices=list(EXPERT_DATASETS.keys()), | |
| help="Vulnerability type to train expert for") | |
| parser.add_argument("--output_dir", type=str, default=None) | |
| parser.add_argument("--lora_r", type=int, default=16) | |
| parser.add_argument("--epochs", type=int, default=5) | |
| parser.add_argument("--batch_size", type=int, default=8) | |
| parser.add_argument("--grad_accum", type=int, default=4) | |
| parser.add_argument("--lr", type=float, default=2e-4) | |
| parser.add_argument("--max_seq_len", type=int, default=1536) | |
| parser.add_argument("--push_to_hub", action="store_true", default=True) | |
| return parser.parse_args() | |
| def compute_metrics(eval_pred): | |
| """Compute classification metrics.""" | |
| logits, labels = eval_pred | |
| preds = np.argmax(logits, axis=-1) | |
| probs = softmax(logits, axis=-1)[:, 1] | |
| metrics = { | |
| "accuracy": accuracy_score(labels, preds), | |
| "f1": f1_score(labels, preds, average="binary"), | |
| "precision": precision_score(labels, preds, average="binary", zero_division=0), | |
| "recall": recall_score(labels, preds, average="binary", zero_division=0), | |
| } | |
| # AUC requires both classes present | |
| if len(set(labels)) > 1: | |
| metrics["auc"] = roc_auc_score(labels, probs) | |
| return metrics | |
| def main(): | |
| args = parse_args() | |
| expert_name = args.expert | |
| dataset_id = EXPERT_DATASETS[expert_name] | |
| slug = expert_name.lower().replace(" ", "-").replace("/", "-") | |
| hub_model_id = f"jhsu12/solidity-vuln-cls-{slug}-v1" | |
| output_dir = args.output_dir or f"./cls-expert-{slug}" | |
| print("=" * 60) | |
| print(f" Classification Expert: {expert_name}") | |
| print(f" Base Model: {BASE_MODEL}") | |
| print(f" Dataset: {dataset_id}") | |
| print(f" Hub Model: {hub_model_id}") | |
| print("=" * 60) | |
| # GPU config | |
| HAS_BF16 = torch.cuda.is_bf16_supported() if torch.cuda.is_available() else False | |
| GPU_MEM = torch.cuda.get_device_properties(0).total_memory / 1e9 if torch.cuda.is_available() else 0 | |
| print(f"\nπ₯οΈ GPU: {torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU'}") | |
| print(f"πΎ VRAM: {GPU_MEM:.1f} GB") | |
| print(f"π’ BF16: {HAS_BF16}") | |
| compute_dtype = torch.bfloat16 if HAS_BF16 else torch.float16 | |
| # Trackio monitoring | |
| trackio.init( | |
| project=f"solidity-cls-{slug}", | |
| name=f"{slug}-cls-3b-v1", | |
| ) | |
| # ββ Load & preprocess dataset ββββββββββββββββββββββββββββββββββββββββββ | |
| print("\nπ¦ Loading dataset...") | |
| dataset = load_dataset(dataset_id) | |
| tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True) | |
| # Qwen2.5 already has pad_token=<|endoftext|> (151643) β keep defaults | |
| def preprocess(examples): | |
| """Extract Solidity code from user message and create classification input.""" | |
| texts = [] | |
| for msgs in examples["messages"]: | |
| # Extract the user message containing the Solidity code | |
| user_content = "" | |
| for msg in msgs: | |
| if msg["role"] == "user": | |
| user_content = msg["content"] | |
| break | |
| texts.append(user_content) | |
| tokenized = tokenizer( | |
| texts, | |
| truncation=True, | |
| max_length=args.max_seq_len, | |
| padding=False, # Dynamic padding via DataCollatorWithPadding | |
| ) | |
| tokenized["labels"] = [int(x) for x in examples["is_expert_type"]] | |
| return tokenized | |
| print(" Tokenizing...") | |
| train_dataset = dataset["train"].map( | |
| preprocess, | |
| batched=True, | |
| remove_columns=dataset["train"].column_names, | |
| desc="Tokenizing train", | |
| ) | |
| eval_dataset = dataset["test"].map( | |
| preprocess, | |
| batched=True, | |
| remove_columns=dataset["test"].column_names, | |
| desc="Tokenizing eval", | |
| ) | |
| # Class distribution | |
| train_labels = train_dataset["labels"] | |
| pos = sum(train_labels) | |
| neg = len(train_labels) - pos | |
| print(f" Train: {len(train_dataset)} (pos={pos}, neg={neg}, ratio={pos/len(train_labels):.1%})") | |
| print(f" Eval: {len(eval_dataset)}") | |
| # ββ Load model with classification head ββββββββββββββββββββββββββββββββ | |
| bnb_config = BitsAndBytesConfig( | |
| load_in_4bit=True, | |
| bnb_4bit_quant_type="nf4", | |
| bnb_4bit_compute_dtype=compute_dtype, | |
| bnb_4bit_use_double_quant=True, | |
| ) | |
| print(f"\nπ€ Loading {BASE_MODEL} with classification head...") | |
| model = AutoModelForSequenceClassification.from_pretrained( | |
| BASE_MODEL, | |
| num_labels=2, | |
| id2label={0: "safe", 1: "vulnerable"}, | |
| label2id={"safe": 0, "vulnerable": 1}, | |
| quantization_config=bnb_config, | |
| device_map="auto", | |
| dtype=compute_dtype, | |
| trust_remote_code=True, | |
| attn_implementation="sdpa", | |
| ignore_mismatched_sizes=True, # score head is new, not in checkpoint | |
| ) | |
| # Required for batch_size > 1 β model needs to know which token is padding | |
| model.config.pad_token_id = tokenizer.pad_token_id | |
| model.config.use_cache = False # Required for gradient checkpointing | |
| print(" β Model loaded with score head") | |
| # ββ LoRA config ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| model = prepare_model_for_kbit_training(model, use_gradient_checkpointing=True) | |
| peft_config = LoraConfig( | |
| task_type=TaskType.SEQ_CLS, | |
| r=args.lora_r, | |
| lora_alpha=args.lora_r * 2, # alpha = 2 * r (standard for classification) | |
| lora_dropout=0.05, | |
| bias="none", | |
| target_modules=["q_proj", "k_proj", "v_proj", "o_proj"], | |
| modules_to_save=["score"], # Unfreeze the classification head | |
| ) | |
| model = get_peft_model(model, peft_config) | |
| model.print_trainable_parameters() | |
| # ββ Training config ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| training_args = TrainingArguments( | |
| output_dir=output_dir, | |
| num_train_epochs=args.epochs, | |
| per_device_train_batch_size=args.batch_size, | |
| per_device_eval_batch_size=args.batch_size * 2, | |
| gradient_accumulation_steps=args.grad_accum, | |
| learning_rate=args.lr, | |
| bf16=HAS_BF16, | |
| fp16=not HAS_BF16, | |
| gradient_checkpointing=True, | |
| gradient_checkpointing_kwargs={"use_reentrant": False}, | |
| optim="paged_adamw_8bit", | |
| warmup_ratio=0.05, | |
| lr_scheduler_type="cosine", | |
| weight_decay=0.01, | |
| max_grad_norm=0.3, | |
| logging_steps=10, | |
| logging_first_step=True, | |
| logging_strategy="steps", | |
| disable_tqdm=True, | |
| report_to=["trackio"], | |
| save_strategy="epoch", | |
| eval_strategy="epoch", | |
| load_best_model_at_end=True, | |
| metric_for_best_model="f1", | |
| greater_is_better=True, | |
| push_to_hub=False, | |
| seed=42, | |
| ) | |
| # ββ Trainer ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print("\nποΈ Initializing trainer...") | |
| trainer = Trainer( | |
| model=model, | |
| args=training_args, | |
| train_dataset=train_dataset, | |
| eval_dataset=eval_dataset, | |
| processing_class=tokenizer, | |
| data_collator=DataCollatorWithPadding(tokenizer), | |
| compute_metrics=compute_metrics, | |
| ) | |
| trainable = sum(p.numel() for p in model.parameters() if p.requires_grad) | |
| total = sum(p.numel() for p in model.parameters()) | |
| print(f" Trainable: {trainable:,} ({100 * trainable / total:.2f}%)") | |
| # ββ Train ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\nπ Starting classification training for {expert_name} expert...") | |
| train_result = trainer.train() | |
| print(f"\nβ Training complete!") | |
| print(f" Train loss: {train_result.training_loss:.4f}") | |
| # ββ Final evaluation βββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print("\nπ Final evaluation...") | |
| eval_results = trainer.evaluate() | |
| print(f" Eval loss: {eval_results['eval_loss']:.4f}") | |
| print(f" Accuracy: {eval_results['eval_accuracy']:.4f}") | |
| print(f" F1: {eval_results['eval_f1']:.4f}") | |
| print(f" Precision: {eval_results['eval_precision']:.4f}") | |
| print(f" Recall: {eval_results['eval_recall']:.4f}") | |
| if "eval_auc" in eval_results: | |
| print(f" AUC: {eval_results['eval_auc']:.4f}") | |
| # ββ Save βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| save_dir = os.path.join(output_dir, "best_model") | |
| print(f"\nπΎ Saving to {save_dir}...") | |
| trainer.save_model(save_dir) | |
| tokenizer.save_pretrained(save_dir) | |
| # ββ Push to hub ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| if args.push_to_hub: | |
| print(f"\nπ Pushing to {hub_model_id}...") | |
| api = HfApi() | |
| api.upload_folder( | |
| folder_path=save_dir, | |
| repo_id=hub_model_id, | |
| ignore_patterns=[ | |
| "optimizer*", "scheduler*", "training_args*", | |
| "trainer_state*", "rng_state*", | |
| ], | |
| commit_message=f"Classification expert for {expert_name} vulnerability detection (3B base)", | |
| ) | |
| print(f" β Pushed to https://hf.co/{hub_model_id}") | |
| print(f"\n{'=' * 60}") | |
| print(f" Classification Expert {expert_name} Complete!") | |
| print(f" Base Model: {BASE_MODEL}") | |
| print(f" Train loss: {train_result.training_loss:.4f}") | |
| print(f" Eval F1: {eval_results['eval_f1']:.4f}") | |
| print(f" Eval Acc: {eval_results['eval_accuracy']:.4f}") | |
| print(f"{'=' * 60}") | |
| if __name__ == "__main__": | |
| main() | |