rishini commited on
Commit
f238825
·
verified ·
1 Parent(s): d6059f5

Add training and evaluation scripts

Browse files
scripts/README.md ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Finetune + Eval Scripts
2
+
3
+ Scripts used to train and evaluate the adapters in this repo.
4
+
5
+ ## Environment
6
+ ```bash
7
+ python3 -m venv /home/ai/llama-finetune-env
8
+ /home/ai/llama-finetune-env/bin/pip install torch transformers accelerate peft bitsandbytes trl datasets huggingface_hub
9
+ ```
10
+
11
+ GPU note: GPU 0 is occupied by vLLM; both scripts pin `CUDA_VISIBLE_DEVICES=1`.
12
+
13
+ ## Programming model (this repo)
14
+ - `programming_finetune_aggressive.py` — trains `rishini/qwen2.5-coder-7b-programming-lora`
15
+ - Base: `Qwen/Qwen2.5-Coder-7B-Instruct`, LoRA r=64 alpha=128, 6k filtered CodeAlpaca examples, 3 epochs, completion-only masking.
16
+ - Output dir: `/home/ai/qwen-coder-programming-best`
17
+ - `eval_best_model.py` — held-out evaluation prompts, loads the adapter from `/home/ai/qwen-coder-programming-best`.
18
+
19
+ ## Security model (other work)
20
+ - `security_finetune.py` — CodeLlama-7B-Instruct + LoRA for vulnerability analysis.
21
+ - Base: `codellama/CodeLlama-7b-Instruct-hf`, output dir: `/home/ai/codellama-security-finetuned`
22
+ - `test_security_model.py` — runs the security adapter on sample vulnerable snippets.
23
+
24
+ ## Run
25
+ ```bash
26
+ cd /home/ai
27
+ /home/ai/llama-finetune-env/bin/python programming_finetune_aggressive.py # train
28
+ /home/ai/llama-finetune-env/bin/python eval_best_model.py # eval
29
+ ```
scripts/eval_best_model.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ os.environ["CUDA_VISIBLE_DEVICES"] = "1"
3
+ import torch
4
+ from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
5
+ from peft import PeftModel
6
+
7
+ BASE_MODEL = "Qwen/Qwen2.5-Coder-7B-Instruct"
8
+ ADAPTER_PATH = "/home/ai/qwen-coder-programming-best"
9
+
10
+ def load_model():
11
+ bnb_config = BitsAndBytesConfig(
12
+ load_in_4bit=True, bnb_4bit_quant_type="nf4",
13
+ bnb_4bit_compute_dtype=torch.bfloat16, bnb_4bit_use_double_quant=True,
14
+ )
15
+ model = AutoModelForCausalLM.from_pretrained(
16
+ BASE_MODEL, quantization_config=bnb_config, device_map="auto",
17
+ trust_remote_code=True, torch_dtype=torch.bfloat16,
18
+ )
19
+ model = PeftModel.from_pretrained(model, ADAPTER_PATH)
20
+ tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True, use_fast=True)
21
+ tokenizer.pad_token = tokenizer.eos_token
22
+ return model, tokenizer
23
+
24
+ def generate(model, tokenizer, prompt):
25
+ messages = [{"role": "user", "content": prompt}]
26
+ text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
27
+ inputs = tokenizer(text, return_tensors="pt").to(model.device)
28
+ with torch.no_grad():
29
+ outputs = model.generate(
30
+ **inputs, max_new_tokens=512, temperature=0.2, top_p=0.9,
31
+ do_sample=True, repetition_penalty=1.05, pad_token_id=tokenizer.pad_token_id,
32
+ )
33
+ return tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
34
+
35
+ HELD_OUT = [
36
+ "Write a Python function to find the longest common prefix among a list of strings.",
37
+ "Implement a min-heap in Python from scratch without using the heapq module.",
38
+ "Write a Python function that performs topological sort on a directed acyclic graph represented as an adjacency list.",
39
+ "Write a Python function to serialize and deserialize a binary tree using a queue-based BFS approach.",
40
+ "Implement a Python function that finds all palindromic substrings of a given string.",
41
+ "Write Python code using the sliding window technique to find the longest substring without repeating characters.",
42
+ ]
43
+
44
+ def main():
45
+ model, tokenizer = load_model()
46
+ for t in HELD_OUT:
47
+ print("=" * 64)
48
+ print("PROMPT:", t)
49
+ print("-" * 64)
50
+ print(generate(model, tokenizer, t))
51
+ print()
52
+
53
+ if __name__ == "__main__":
54
+ main()
scripts/programming_finetune.py ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ os.environ["CUDA_VISIBLE_DEVICES"] = "1"
3
+
4
+ import torch
5
+ from datasets import Dataset
6
+ from transformers import (
7
+ AutoModelForCausalLM,
8
+ AutoTokenizer,
9
+ TrainingArguments,
10
+ Trainer,
11
+ DataCollatorForLanguageModeling,
12
+ BitsAndBytesConfig,
13
+ )
14
+ from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training, TaskType
15
+
16
+ MODEL_NAME = "Qwen/Qwen2.5-Coder-7B-Instruct"
17
+ OUTPUT_DIR = "/home/ai/qwen-coder-programming-finetuned"
18
+
19
+ PROG_DATA = [
20
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function to check if a string is a valid palindrome ignoring case and non-alphanumeric characters.", "output": "```python\ndef is_palindrome(s: str) -> bool:\n cleaned = ''.join(c.lower() for c in s if c.isalnum())\n return cleaned == cleaned[::-1]\n```\n\nTime: O(n), Space: O(n). Returns True for 'A man, a plan, a canal: Panama'."},
21
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function using a binary search to find the index of a target in a sorted list, or -1 if not present.", "output": "```python\ndef binary_search(arr, target):\n low, high = 0, len(arr) - 1\n while low <= high:\n mid = (low + high) // 2\n if arr[mid] == target:\n return mid\n elif arr[mid] < target:\n low = mid + 1\n else:\n high = mid - 1\n return -1\n```\n\nTime: O(log n), Space: O(1)." },
22
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function that returns the nth Fibonacci number using dynamic programming with memoization.", "output": "```python\nfrom functools import lru_cache\n\ndef fib(n: int) -> int:\n @lru_cache(maxsize=None)\n def _fib(n: int) -> int:\n if n < 2:\n return n\n return _fib(n - 1) + _fib(n - 2)\n return _fib(n)\n```\n\nTime: O(n), Space: O(n). Using lru_cache avoids exponential recomputation."},
23
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python class implementing a simple LRU cache with get and put operations in O(1).", "output": "```python\nfrom collections import OrderedDict\n\nclass LRUCache:\n def __init__(self, capacity: int):\n self.capacity = capacity\n self.cache = OrderedDict()\n\n def get(self, key: int) -> int:\n if key not in self.cache:\n return -1\n self.cache.move_to_end(key)\n return self.cache[key]\n\n def put(self, key: int, value: int) -> None:\n if key in self.cache:\n self.cache.move_to_end(key)\n self.cache[key] = value\n if len(self.cache) > self.capacity:\n self.cache.popitem(last=False)\n```\n\nBoth operations are O(1) using OrderedDict."},
24
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function to merge two sorted lists into one sorted list.", "output": "```python\ndef merge_sorted(a, b):\n result = []\n i = j = 0\n while i < len(a) and j < len(b):\n if a[i] <= b[j]:\n result.append(a[i]); i += 1\n else:\n result.append(b[j]); j += 1\n result.extend(a[i:])\n result.extend(b[j:])\n return result\n```\n\nTime: O(n + m), Space: O(n + m)." },
25
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function using a trie to find if a word exists in a set of words.", "output": "```python\nclass TrieNode:\n def __init__(self):\n self.children = {}\n self.is_word = False\n\ndef build_trie(words):\n root = TrieNode()\n for w in words:\n node = root\n for ch in w:\n node = node.children.setdefault(ch, TrieNode())\n node.is_word = True\n return root\n\ndef exists(trie, word):\n node = trie\n for ch in word:\n if ch not in node.children:\n return False\n node = node.children[ch]\n return node.is_word\n```\n\nInsert and search are O(len(word))."},
26
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function that reverses a linked list in place.", "output": "```python\ndef reverse_linked_list(head):\n prev = None\n curr = head\n while curr:\n nxt = curr.next\n curr.next = prev\n prev = curr\n curr = nxt\n return prev\n```\n\nIterative approach, O(n) time, O(1) space."},
27
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function using a heap to return the k largest elements of a list.", "output": "```python\nimport heapq\n\ndef k_largest(nums, k):\n if k <= 0:\n return []\n heap = nums[:k]\n heapq.heapify(heap)\n for x in nums[k:]:\n if x > heap[0]:\n heapq.heapreplace(heap, x)\n return sorted(heap, reverse=True)\n```\n\nUses a min-heap of size k. Time: O(n log k)."},
28
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function that returns all permutations of a given list of distinct integers.", "output": "```python\ndef permutations(nums):\n result = []\n def backtrack(path, remaining):\n if not remaining:\n result.append(path[:])\n return\n for i in range(len(remaining)):\n backtrack(path + [remaining[i]], remaining[:i] + remaining[i+1:])\n backtrack([], nums)\n return result\n```\n\nBacktracking, O(n!) permutations."},
29
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write Python code using dynamic programming to compute the length of the longest increasing subsequence in an array.", "output": "```python\ndef lis_length(nums):\n import bisect\n tails = []\n for x in nums:\n i = bisect.bisect_left(tails, x)\n if i == len(tails):\n tails.append(x)\n else:\n tails[i] = x\n return len(tails)\n```\n\nPatience sorting: O(n log n) time, O(n) space."},
30
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function that checks whether a binary tree is balanced (heights differ by at most 1).", "output": "```python\ndef is_balanced(root):\n def height(node):\n if not node:\n return 0\n left = height(node.left)\n right = height(node.right)\n if left == -1 or right == -1 or abs(left - right) > 1:\n return -1\n return 1 + max(left, right)\n return height(root) != -1\n```\n\nDFS returns -1 for unbalanced subtree. O(n) time."},
31
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write Python code using a queue (BFS) to find the shortest path length in a grid from (0,0) to (n-1,m-1) avoiding walls.", "output": "```python\nfrom collections import deque\n\ndef shortest_path(grid):\n n, m = len(grid), len(grid[0])\n if grid[0][0] == 1 or grid[n-1][m-1] == 1:\n return -1\n q = deque([(0, 0, 1)])\n grid[0][0] = 1\n while q:\n r, c, d = q.popleft()\n if (r, c) == (n-1, m-1):\n return d\n for dr, dc in ((1,0),(-1,0),(0,1),(0,-1)):\n nr, nc = r+dr, c+dc\n if 0 <= nr < n and 0 <= nc < m and grid[nr][nc] == 0:\n grid[nr][nc] = 1\n q.append((nr, nc, d+1))\n return -1\n```\n\nBFS on grid: O(n*m)."},
32
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write Python code using a hash map to find two numbers in a list that sum to a target.", "output": "```python\ndef two_sum(nums, target):\n seen = {}\n for i, x in enumerate(nums):\n complement = target - x\n if complement in seen:\n return [seen[complement], i]\n seen[x] = i\n return []\n```\n\nSingle pass, O(n) time, O(n) space."},
33
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function that converts an integer to its binary string representation without using bin().", "output": "```python\ndef to_binary(n: int) -> str:\n if n == 0:\n return \"0\"\n bits = []\n while n:\n bits.append(str(n & 1))\n n >>= 1\n return ''.join(reversed(bits))\n```\n\nRepeatedly takes least significant bit. O(log n) time."},
34
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write Python code using Dijkstra's algorithm to find the shortest path in a weighted graph.", "output": "```python\nimport heapq\n\ndef dijkstra(graph, start):\n dist = {node: float('inf') for node in graph}\n dist[start] = 0\n pq = [(0, start)]\n while pq:\n d, u = heapq.heappop(pq)\n if d > dist[u]:\n continue\n for v, w in graph[u]:\n nd = d + w\n if nd < dist[v]:\n dist[v] = nd\n heapq.heappush(pq, (nd, v))\n return dist\n```\n\nPriority-queue Dijkstra: O((V+E) log V)."},
35
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write a Python function to determine if two strings are anagrams.", "output": "```python\nfrom collections import Counter\n\ndef is_anagram(s: str, t: str) -> bool:\n if len(s) != len(t):\n return False\n return Counter(s) == Counter(t)\n```\n\nCounter comparison is O(n). Works for any character set."},
36
+ {"system": "You are an expert software engineer. Write clean, correct, efficient code.", "prompt": "Write Python code with a DFS to find all paths from a source to a target in an undirected graph.", "output": "```python\ndef all_paths(graph, src, dst):\n result = []\n def dfs(node, path):\n path.append(node)\n if node == dst:\n result.append(path[:])\n else:\n for nei in graph[node]:\n if nei not in path:\n dfs(nei, path)\n path.pop()\n dfs(src, [])\n return result\n```\n\nBacktracking DFS enumerates all paths."},
37
+ ]
38
+
39
+ def format_example(ex):
40
+ return f"""<|im_start|>system
41
+ {ex['system']}<|im_end|>
42
+ <|im_start|>user
43
+ {ex['prompt']}<|im_end|>
44
+ <|im_start|>assistant
45
+ {ex['output']}<|im_end|>"""
46
+
47
+ def main():
48
+ print("Loading tokenizer...")
49
+ tokenizer = AutoTokenizer.from_pretrained(
50
+ MODEL_NAME, trust_remote_code=True, use_fast=True
51
+ )
52
+ tokenizer.pad_token = tokenizer.eos_token
53
+ tokenizer.padding_side = "right"
54
+
55
+ print("Loading model with 4-bit quantization...")
56
+ bnb_config = BitsAndBytesConfig(
57
+ load_in_4bit=True,
58
+ bnb_4bit_quant_type="nf4",
59
+ bnb_4bit_compute_dtype=torch.bfloat16,
60
+ bnb_4bit_use_double_quant=True,
61
+ )
62
+
63
+ model = AutoModelForCausalLM.from_pretrained(
64
+ MODEL_NAME,
65
+ quantization_config=bnb_config,
66
+ device_map="auto",
67
+ trust_remote_code=True,
68
+ torch_dtype=torch.bfloat16,
69
+ )
70
+
71
+ model = prepare_model_for_kbit_training(model)
72
+ model.gradient_checkpointing_enable()
73
+
74
+ lora_config = LoraConfig(
75
+ r=32,
76
+ lora_alpha=64,
77
+ target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
78
+ lora_dropout=0.05,
79
+ bias="none",
80
+ task_type=TaskType.CAUSAL_LM,
81
+ )
82
+
83
+ model = get_peft_model(model, lora_config)
84
+ model.print_trainable_parameters()
85
+
86
+ print("Preparing dataset...")
87
+ formatted_data = [{"text": format_example(ex)} for ex in PROG_DATA]
88
+ dataset = Dataset.from_list(formatted_data)
89
+
90
+ def tokenize_function(examples):
91
+ result = tokenizer(
92
+ examples["text"],
93
+ truncation=True,
94
+ max_length=1024,
95
+ padding="max_length",
96
+ return_tensors="pt",
97
+ )
98
+ result["labels"] = result["input_ids"].clone()
99
+ return result
100
+
101
+ tokenized_dataset = dataset.map(
102
+ tokenize_function, batched=True, remove_columns=["text"]
103
+ )
104
+ tokenized_dataset.set_format(
105
+ type="torch", columns=["input_ids", "attention_mask", "labels"]
106
+ )
107
+
108
+ training_args = TrainingArguments(
109
+ output_dir=OUTPUT_DIR,
110
+ num_train_epochs=2,
111
+ per_device_train_batch_size=2,
112
+ gradient_accumulation_steps=4,
113
+ warmup_steps=5,
114
+ learning_rate=2e-4,
115
+ fp16=False,
116
+ bf16=True,
117
+ logging_steps=5,
118
+ save_steps=500,
119
+ save_total_limit=2,
120
+ optim="paged_adamw_8bit",
121
+ lr_scheduler_type="cosine",
122
+ report_to="none",
123
+ remove_unused_columns=False,
124
+ dataloader_pin_memory=False,
125
+ max_grad_norm=0.3,
126
+ )
127
+
128
+ data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
129
+
130
+ trainer = Trainer(
131
+ model=model,
132
+ train_dataset=tokenized_dataset,
133
+ args=training_args,
134
+ data_collator=data_collator,
135
+ )
136
+
137
+ print("Starting training...")
138
+ trainer.train()
139
+
140
+ print("Saving model...")
141
+ trainer.save_model()
142
+ tokenizer.save_pretrained(OUTPUT_DIR)
143
+ print(f"Model saved to {OUTPUT_DIR}")
144
+
145
+ if __name__ == "__main__":
146
+ main()
scripts/programming_finetune_aggressive.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ os.environ["CUDA_VISIBLE_DEVICES"] = "1"
3
+ os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
4
+
5
+ import torch
6
+ from datasets import load_dataset, Dataset
7
+ from transformers import (
8
+ AutoModelForCausalLM,
9
+ AutoTokenizer,
10
+ TrainingArguments,
11
+ Trainer,
12
+ BitsAndBytesConfig,
13
+ )
14
+ from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training, TaskType
15
+ from dataclasses import dataclass
16
+ from transformers import DataCollatorWithPadding
17
+
18
+ MODEL_NAME = "Qwen/Qwen2.5-Coder-7B-Instruct"
19
+ OUTPUT_DIR = "/home/ai/qwen-coder-programming-best"
20
+ SYSTEM = "You are an expert software engineer. Write clean, correct, efficient, well-structured code with brief explanations."
21
+
22
+ EXPERT_EXAMPLES = [
23
+ {"instruction": "Write a Python function to check if a string is a valid palindrome ignoring case and non-alphanumeric characters.", "input": "", "output": "```python\ndef is_palindrome(s: str) -> bool:\n cleaned = ''.join(c.lower() for c in s if c.isalnum())\n return cleaned == cleaned[::-1]\n```\n\nTime: O(n), Space: O(n). Returns True for 'A man, a plan, a canal: Panama'."},
24
+ {"instruction": "Write a Python function using a binary search to find the index of a target in a sorted list, or -1 if not present.", "input": "", "output": "```python\ndef binary_search(arr, target):\n low, high = 0, len(arr) - 1\n while low <= high:\n mid = (low + high) // 2\n if arr[mid] == target:\n return mid\n elif arr[mid] < target:\n low = mid + 1\n else:\n high = mid - 1\n return -1\n```\n\nTime: O(log n), Space: O(1)."},
25
+ {"instruction": "Write a Python class implementing a simple LRU cache with get and put operations in O(1).", "input": "", "output": "```python\nfrom collections import OrderedDict\n\nclass LRUCache:\n def __init__(self, capacity: int):\n self.capacity = capacity\n self.cache = OrderedDict()\n\n def get(self, key: int) -> int:\n if key not in self.cache:\n return -1\n self.cache.move_to_end(key)\n return self.cache[key]\n\n def put(self, key: int, value: int) -> None:\n if key in self.cache:\n self.cache.move_to_end(key)\n self.cache[key] = value\n if len(self.cache) > self.capacity:\n self.cache.popitem(last=False)\n```\n\nBoth operations are O(1) using OrderedDict."},
26
+ {"instruction": "Write Python code using a queue (BFS) to find the shortest path length in a grid from (0,0) to (n-1,m-1) avoiding walls.", "input": "", "output": "```python\nfrom collections import deque\n\ndef shortest_path(grid):\n n, m = len(grid), len(grid[0])\n if grid[0][0] == 1 or grid[n-1][m-1] == 1:\n return -1\n q = deque([(0, 0, 1)])\n grid[0][0] = 1\n while q:\n r, c, d = q.popleft()\n if (r, c) == (n-1, m-1):\n return d\n for dr, dc in ((1,0),(-1,0),(0,1),(0,-1)):\n nr, nc = r+dr, c+dc\n if 0 <= nr < n and 0 <= nc < m and grid[nr][nc] == 0:\n grid[nr][nc] = 1\n q.append((nr, nc, d+1))\n return -1\n```\n\nBFS on grid: O(n*m)."},
27
+ {"instruction": "Write Python code using Dijkstra's algorithm to find the shortest path in a weighted graph.", "input": "", "output": "```python\nimport heapq\n\ndef dijkstra(graph, start):\n dist = {node: float('inf') for node in graph}\n dist[start] = 0\n pq = [(0, start)]\n while pq:\n d, u = heapq.heappop(pq)\n if d > dist[u]:\n continue\n for v, w in graph[u]:\n nd = d + w\n if nd < dist[v]:\n dist[v] = nd\n heapq.heappush(pq, (nd, v))\n return dist\n```\n\nPriority-queue Dijkstra: O((E+V) log V)."},
28
+ {"instruction": "Write a Python function using dynamic programming to compute the length of the longest increasing subsequence in an array.", "input": "", "output": "```python\ndef lis_length(nums):\n import bisect\n tails = []\n for x in nums:\n i = bisect.bisect_left(tails, x)\n if i == len(tails):\n tails.append(x)\n else:\n tails[i] = x\n return len(tails)\n```\n\nPatience sorting: O(n log n) time, O(n) space."},
29
+ ]
30
+
31
+ # ----------------------------------------------------------------
32
+ # Load and filter CodeAlpaca-18k
33
+ ds = load_dataset("iamtarun/python_code_instructions_18k_alpaca", split="train")
34
+
35
+ def filter_quality(ex):
36
+ out = ex["output"] or ""
37
+ ins = ex["instruction"] or ""
38
+ if not ins.strip() or len(ins) > 2000:
39
+ return False
40
+ if len(out) < 10 or len(out) > 2000:
41
+ return False
42
+ if "def " not in out and "import " not in out and "class " not in out and "{" not in out and "function" not in out.lower():
43
+ return False
44
+ return True
45
+
46
+ ds = ds.filter(filter_quality, num_proc=4)
47
+ ds = ds.shuffle(seed=42)
48
+ N = 6000
49
+ ds = ds.select(range(min(N, len(ds))))
50
+
51
+ expert_ds = Dataset.from_list(EXPERT_EXAMPLES)
52
+
53
+ def normalize(ex):
54
+ return {"instruction": ex["instruction"], "input_text": str(ex.get("input") or ""), "output": ex["output"]}
55
+
56
+ ds = ds.map(normalize, remove_columns=ds.column_names)
57
+ expert_ds = expert_ds.map(lambda e: {"instruction": e["instruction"], "input_text": str(e.get("input") or ""), "output": e["output"]})
58
+ ds = Dataset.from_list(expert_ds.to_list() + ds.to_list())
59
+ print(f"Final train examples: {len(ds)}")
60
+
61
+ # ----------------------------------------------------------------
62
+ def main():
63
+ print("Loading tokenizer...")
64
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True, use_fast=True)
65
+ tokenizer.pad_token = tokenizer.eos_token
66
+ tokenizer.padding_side = "right"
67
+
68
+ bnb_config = BitsAndBytesConfig(
69
+ load_in_4bit=True,
70
+ bnb_4bit_quant_type="nf4",
71
+ bnb_4bit_compute_dtype=torch.bfloat16,
72
+ bnb_4bit_use_double_quant=True,
73
+ )
74
+ model = AutoModelForCausalLM.from_pretrained(
75
+ MODEL_NAME, quantization_config=bnb_config, device_map="auto",
76
+ trust_remote_code=True, torch_dtype=torch.bfloat16,
77
+ )
78
+ model = prepare_model_for_kbit_training(model)
79
+ model.gradient_checkpointing_enable()
80
+ model.enable_input_require_grads()
81
+
82
+ lora_config = LoraConfig(
83
+ r=64,
84
+ lora_alpha=128,
85
+ target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
86
+ lora_dropout=0.05,
87
+ bias="none",
88
+ task_type=TaskType.CAUSAL_LM,
89
+ use_rslora=True,
90
+ )
91
+ model = get_peft_model(model, lora_config)
92
+ model.print_trainable_parameters()
93
+
94
+ def format_chat(ex):
95
+ user_content = ex["instruction"] + (f"\n\nInput:\n{ex['input_text']}" if ex["input_text"] else "")
96
+ prefix = f"<|im_start|>system\n{SYSTEM}<|im_end|>\n<|im_start|>user\n{user_content}<|im_end|>\n"
97
+ suffix = f"<|im_start|>assistant\n{ex['output']}<|im_end|>"
98
+ return {"prefix": prefix, "suffix": suffix}
99
+
100
+ def tokenize_with_masks(ex, max_length=2048):
101
+ p = tokenizer(ex["prefix"], add_special_tokens=False)
102
+ s = tokenizer(ex["suffix"], add_special_tokens=False)
103
+ input_ids = (p["input_ids"] + s["input_ids"])[:max_length]
104
+ labels = ([-100] * len(p["input_ids"]) + s["input_ids"])[:max_length]
105
+ attention_mask = [1] * len(input_ids)
106
+ return {"input_ids": input_ids, "labels": labels, "attention_mask": attention_mask}
107
+
108
+ ds_map = ds.map(format_chat, remove_columns=ds.column_names)
109
+ ds_map = ds_map.map(
110
+ lambda e: tokenize_with_masks(e),
111
+ remove_columns=ds_map.column_names,
112
+ batched=False,
113
+ )
114
+ print("Sample input ids len:", len(ds_map[0]["input_ids"]))
115
+
116
+ class CompletionOnlyDataCollator:
117
+ def __init__(self, tokenizer):
118
+ self.tokenizer = tokenizer
119
+ def __call__(self, features):
120
+ pad_id = self.tokenizer.pad_token_id
121
+ max_len = max(len(f["input_ids"]) for f in features)
122
+ input_ids, attention_mask, labels = [], [], []
123
+ for f in features:
124
+ ids, mask, lab = f["input_ids"], f["attention_mask"], f["labels"]
125
+ pad = max_len - len(ids)
126
+ input_ids.append(ids + [pad_id] * pad)
127
+ attention_mask.append(mask + [0] * pad)
128
+ labels.append(lab + [-100] * pad)
129
+ return {
130
+ "input_ids": torch.tensor(input_ids, dtype=torch.long),
131
+ "attention_mask": torch.tensor(attention_mask, dtype=torch.long),
132
+ "labels": torch.tensor(labels, dtype=torch.long),
133
+ }
134
+
135
+ training_args = TrainingArguments(
136
+ output_dir=OUTPUT_DIR,
137
+ num_train_epochs=3,
138
+ per_device_train_batch_size=8,
139
+ gradient_accumulation_steps=4,
140
+ warmup_steps=80,
141
+ learning_rate=2e-4,
142
+ lr_scheduler_type="cosine",
143
+ weight_decay=0.0,
144
+ fp16=False,
145
+ bf16=True,
146
+ max_grad_norm=1.0,
147
+ logging_steps=20,
148
+ save_steps=250,
149
+ save_total_limit=2,
150
+ optim="adamw_8bit",
151
+ report_to="none",
152
+ remove_unused_columns=False,
153
+ dataloader_pin_memory=False,
154
+ gradient_checkpointing_kwargs={"use_reentrant": False},
155
+ )
156
+
157
+ collator = CompletionOnlyDataCollator(tokenizer=tokenizer)
158
+
159
+ trainer = Trainer(
160
+ model=model,
161
+ train_dataset=ds_map,
162
+ args=training_args,
163
+ data_collator=collator,
164
+ )
165
+
166
+ print("Starting aggressive training...")
167
+ trainer.train()
168
+
169
+ trainer.save_model()
170
+ tokenizer.save_pretrained(OUTPUT_DIR)
171
+ print(f"Model saved to {OUTPUT_DIR}")
172
+
173
+ if __name__ == "__main__":
174
+ main()
scripts/security_finetune.py ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import os
3
+ os.environ["CUDA_VISIBLE_DEVICES"] = "1"
4
+
5
+ import json
6
+ import torch
7
+ from datasets import Dataset
8
+ from transformers import (
9
+ AutoModelForCausalLM,
10
+ AutoTokenizer,
11
+ TrainingArguments,
12
+ Trainer,
13
+ DataCollatorForLanguageModeling,
14
+ BitsAndBytesConfig
15
+ )
16
+ from peft import LoraConfig, get_peft_model, prepare_model_for_kbit_training, TaskType
17
+
18
+ MODEL_NAME = "codellama/CodeLlama-7b-Instruct-hf"
19
+ OUTPUT_DIR = "/home/ai/codellama-security-finetuned"
20
+
21
+ SECURITY_DATA = [
22
+ {"instruction": "Identify the vulnerability in this code", "input": "```python\nimport sqlite3\nconn = sqlite3.connect('users.db')\ncursor = conn.cursor()\nusername = input('Enter username: ')\nquery = f\"SELECT * FROM users WHERE username = '{username}'\"\ncursor.execute(query)\n```", "output": "SQL Injection vulnerability. The query uses string interpolation directly with user input. Fix: Use parameterized queries: `cursor.execute(\"SELECT * FROM users WHERE username = ?\", (username,))`"},
23
+
24
+ {"instruction": "Find the security flaw", "input": "```python\nimport subprocess\nfilename = input('Enter filename: ')\nsubprocess.run(f'cat {filename}', shell=True)\n```", "output": "Command Injection via shell=True and unsanitized user input. Fix: Use `subprocess.run(['cat', filename], shell=False)` with input validation."},
25
+
26
+ {"instruction": "What vulnerability exists here?", "input": "```python\nimport pickle\ndata = pickle.loads(request.data)\n```", "output": "Insecure Deserialization. Pickle can execute arbitrary code during deserialization. Fix: Use JSON or safe serialization formats, validate input."},
27
+
28
+ {"instruction": "Identify the XSS vulnerability", "input": "```javascript\napp.get('/search', (req, res) => {\n res.send(`<h1>Results for: ${req.query.q}</h1>`);\n});\n```", "output": "Reflected XSS. User input directly rendered in HTML without escaping. Fix: Use template engines with auto-escaping or sanitize input with DOMPurify."},
29
+
30
+ {"instruction": "Find the authentication bypass", "input": "```python\n@app.route('/admin')\ndef admin():\n if request.headers.get('X-User-Role') == 'admin':\n return 'Admin panel'\n return 'Forbidden', 403\n```", "output": "Client-side authorization check. Header can be spoofed. Fix: Use server-side session validation with proper authentication tokens."},
31
+
32
+ {"instruction": "What's wrong with this crypto implementation?", "input": "```python\nfrom Crypto.Cipher import AES\nkey = b'mysecretkey12345'\ncipher = AES.new(key, AES.MODE_ECB)\nciphertext = cipher.encrypt(pad(data, 16))\n```", "output": "AES-ECB mode is insecure (deterministic, reveals patterns). Hardcoded key. Fix: Use AES-GCM with random IV, derive key via PBKDF2/Argon2."},
33
+
34
+ {"instruction": "Identify the path traversal", "input": "```python\n@app.route('/download')\ndef download():\n filename = request.args.get('file')\n return send_file(f'/var/www/files/{filename}')\n```", "output": "Path Traversal. No validation on filename allows `../../etc/passwd`. Fix: Use `secure_filename`, validate against allowlist, use `os.path.basename`."},
35
+
36
+ {"instruction": "Find the SSRF vulnerability", "input": "```python\nimport requests\nurl = request.args.get('url')\nresponse = requests.get(url)\nreturn response.text\n```", "output": "Server-Side Request Forgery (SSRF). User controls URL parameter, can access internal services. Fix: Validate URL against allowlist, block private IPs, use allowlist of domains."},
37
+
38
+ {"instruction": "What's the race condition here?", "input": "```python\ndef transfer(from_acc, to_acc, amount):\n if get_balance(from_acc) >= amount:\n debit(from_acc, amount)\n credit(to_acc, amount)\n```", "output": "TOCTOU Race Condition. Balance check and transfer aren't atomic. Fix: Use database transactions with SELECT FOR UPDATE or atomic operations."},
39
+
40
+ {"instruction": "Identify the JWT vulnerability", "input": "```python\nimport jwt\ntoken = request.headers.get('Authorization')\npayload = jwt.decode(token, 'secret', algorithms=['HS256'])\n```", "output": "Hardcoded secret, no algorithm validation (allows 'none' alg), no expiration check. Fix: Use strong secret from env, specify algorithms=['HS256'], verify exp claim."},
41
+
42
+ {"instruction": "Find the XXE vulnerability", "input": "```python\nimport xml.etree.ElementTree as ET\ndef parse_xml(xml_data):\n return ET.fromstring(xml_data)\n```", "output": "XML External Entity (XXE) injection. Parser processes external entities. Fix: Disable DTD processing: `ET.XMLParser(resolve_entities=False)` or use defusedxml."},
43
+
44
+ {"instruction": "What's the issue with this CORS config?", "input": "```python\napp.add_middleware(CORSMiddleware,\n allow_origins=['*'],\n allow_credentials=True,\n allow_methods=['*'],\n allow_headers=['*']\n)\n```", "output": "Wildcard origin with credentials enabled - violates CORS spec, allows credential theft. Fix: Specify exact origins, don't use '*' with credentials."},
45
+
46
+ {"instruction": "Identify the insecure direct object reference", "input": "```python\n@app.route('/api/user/<int:user_id>/profile')\ndef get_profile(user_id):\n return jsonify(db.query(User).filter_by(id=user_id).first())\n```", "output": "IDOR - No authorization check. Users can access any profile by changing user_id. Fix: Verify current user owns the resource or has permission."},
47
+
48
+ {"instruction": "Find the weak randomness", "input": "```python\nimport random\nsession_token = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=32))\n```", "output": "Using random (Mersenne Twister) for cryptographic purposes - predictable. Fix: Use `secrets.token_urlsafe(32)` or `os.urandom()` for crypto-safe randomness."},
49
+
50
+ {"instruction": "What's the container escape risk?", "input": "```dockerfile\nFROM ubuntu:latest\nRUN apt-get update && apt-get install -y docker.io\nVOLUME /var/run/docker.sock\n```", "output": "Mounting docker.sock gives container root access to host. Fix: Don't mount docker.sock; use socket proxies like docker-socket-proxy with limited permissions."},
51
+
52
+ {"instruction": "Identify the supply chain attack vector", "input": "```json\n{\n \"dependencies\": {\n \"left-pad\": \"^1.0.0\",\n \"event-stream\": \"^3.3.4\"\n }\n}\n```", "output": "Unpinned dependencies allow malicious updates. event-stream was compromised. Fix: Pin exact versions, use lockfiles, enable Dependabot, verify package integrity with npm audit/signatures."},
53
+
54
+ {"instruction": "Find the timing attack vulnerability", "input": "```python\ndef verify_token(token, expected):\n return token == expected\n```", "output": "String comparison short-circuits - timing attack reveals token character by character. Fix: Use `hmac.compare_digest(token, expected)` for constant-time comparison."},
55
+
56
+ {"instruction": "What's the log injection issue?", "input": "```python\nimport logging\nlogging.info(f'User {username} logged in from {ip}')\n```", "output": "Log Injection - username/ip can contain newlines to forge log entries. Fix: Sanitize input, use structured logging (JSON), escape newlines."},
57
+
58
+ {"instruction": "Identify the broken access control", "input": "```python\n@app.route('/api/admin/delete-user/<int:id>')\ndef delete_user(id):\n User.query.filter_by(id=id).delete()\n return 'OK'\n```", "output": "Missing authorization - any authenticated user can delete users. Fix: Add @require_admin decorator, check user permissions before action."},
59
+
60
+ {"instruction": "Find the prototype pollution", "input": "```javascript\nfunction merge(target, source) {\n for (let key in source) {\n target[key] = source[key];\n }\n}\nmerge({}, JSON.parse(userInput));\n```", "output": "Prototype Pollution - `__proto__` or `constructor.prototype` in input pollutes Object.prototype. Fix: Validate keys, use `Object.create(null)`, freeze prototype, use lodash.mergeWith."},
61
+
62
+ {"instruction": "What's the deserialization RCE?", "input": "```java\nObjectInputStream ois = new ObjectInputStream(new FileInputStream(\"data.ser\"));\nObject obj = ois.readObject();\n```", "output": "Java Deserialization RCE - gadget chains (CommonsCollections, etc.) execute code. Fix: Avoid native serialization, use JSON, implement ObjectInputFilter, use SerialKiller/NotSoSerial."}
63
+ ]
64
+
65
+ def format_example(example):
66
+ return f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
67
+ You are a cybersecurity expert specializing in vulnerability assessment, penetration testing, and secure code review. Identify security flaws, explain the impact, and provide remediation.
68
+ <|eot_id|><|start_header_id|>user<|end_header_id|>
69
+ {example['instruction']}
70
+
71
+ {example['input']}
72
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>
73
+ {example['output']}
74
+ <|eot_id|>"""
75
+
76
+ def main():
77
+ print("Loading tokenizer...")
78
+ tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, trust_remote_code=True)
79
+ tokenizer.pad_token = tokenizer.eos_token
80
+ tokenizer.padding_side = "right"
81
+
82
+ print("Loading model with 4-bit quantization...")
83
+ bnb_config = BitsAndBytesConfig(
84
+ load_in_4bit=True,
85
+ bnb_4bit_quant_type="nf4",
86
+ bnb_4bit_compute_dtype=torch.bfloat16,
87
+ bnb_4bit_use_double_quant=True,
88
+ )
89
+
90
+ model = AutoModelForCausalLM.from_pretrained(
91
+ MODEL_NAME,
92
+ quantization_config=bnb_config,
93
+ device_map="auto",
94
+ trust_remote_code=True,
95
+ torch_dtype=torch.bfloat16,
96
+ )
97
+
98
+ model = prepare_model_for_kbit_training(model)
99
+
100
+ lora_config = LoraConfig(
101
+ r=64,
102
+ lora_alpha=128,
103
+ target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
104
+ lora_dropout=0.05,
105
+ bias="none",
106
+ task_type=TaskType.CAUSAL_LM,
107
+ )
108
+
109
+ model = get_peft_model(model, lora_config)
110
+ model.print_trainable_parameters()
111
+
112
+ print("Preparing dataset...")
113
+ formatted_data = [{"text": format_example(ex)} for ex in SECURITY_DATA]
114
+ dataset = Dataset.from_list(formatted_data)
115
+
116
+ def tokenize_function(examples):
117
+ result = tokenizer(
118
+ examples["text"],
119
+ truncation=True,
120
+ max_length=1024,
121
+ padding="max_length",
122
+ return_tensors="pt"
123
+ )
124
+ result["labels"] = result["input_ids"].clone()
125
+ return result
126
+
127
+ tokenized_dataset = dataset.map(tokenize_function, batched=True, remove_columns=["text"])
128
+ tokenized_dataset.set_format(type="torch", columns=["input_ids", "attention_mask", "labels"])
129
+
130
+ training_args = TrainingArguments(
131
+ output_dir=OUTPUT_DIR,
132
+ num_train_epochs=3,
133
+ per_device_train_batch_size=1,
134
+ gradient_accumulation_steps=8,
135
+ warmup_steps=10,
136
+ learning_rate=2e-4,
137
+ fp16=False,
138
+ bf16=True,
139
+ logging_steps=5,
140
+ save_steps=50,
141
+ save_total_limit=2,
142
+ optim="paged_adamw_8bit",
143
+ lr_scheduler_type="cosine",
144
+ report_to="none",
145
+ remove_unused_columns=False,
146
+ dataloader_pin_memory=False,
147
+ max_grad_norm=0.3,
148
+ )
149
+
150
+ data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
151
+
152
+ trainer = Trainer(
153
+ model=model,
154
+ train_dataset=tokenized_dataset,
155
+ args=training_args,
156
+ data_collator=data_collator,
157
+ )
158
+
159
+ print("Starting training...")
160
+ trainer.train()
161
+
162
+ print("Saving model...")
163
+ trainer.save_model()
164
+ tokenizer.save_pretrained(OUTPUT_DIR)
165
+ print(f"Model saved to {OUTPUT_DIR}")
166
+
167
+ if __name__ == "__main__":
168
+ main()
scripts/test_programming_model.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ os.environ["CUDA_VISIBLE_DEVICES"] = "1"
3
+ import torch
4
+ from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
5
+ from peft import PeftModel
6
+
7
+ BASE_MODEL = "Qwen/Qwen2.5-Coder-7B-Instruct"
8
+ ADAPTER_PATH = "/home/ai/qwen-coder-programming-finetuned"
9
+
10
+ def load_model():
11
+ bnb_config = BitsAndBytesConfig(
12
+ load_in_4bit=True,
13
+ bnb_4bit_quant_type="nf4",
14
+ bnb_4bit_compute_dtype=torch.bfloat16,
15
+ bnb_4bit_use_double_quant=True,
16
+ )
17
+ model = AutoModelForCausalLM.from_pretrained(
18
+ BASE_MODEL, quantization_config=bnb_config, device_map="auto",
19
+ trust_remote_code=True, torch_dtype=torch.bfloat16,
20
+ )
21
+ model = PeftModel.from_pretrained(model, ADAPTER_PATH)
22
+ tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True, use_fast=True)
23
+ tokenizer.pad_token = tokenizer.eos_token
24
+ return model, tokenizer
25
+
26
+ def generate(model, tokenizer, prompt):
27
+ messages = [{"role": "user", "content": prompt}]
28
+ text = tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
29
+ inputs = tokenizer(text, return_tensors="pt").to(model.device)
30
+ with torch.no_grad():
31
+ outputs = model.generate(
32
+ **inputs, max_new_tokens=512, temperature=0.3, top_p=0.9,
33
+ do_sample=True, repetition_penalty=1.1, pad_token_id=tokenizer.pad_token_id,
34
+ )
35
+ return tokenizer.decode(outputs[0][inputs["input_ids"].shape[1]:], skip_special_tokens=True)
36
+
37
+ def main():
38
+ model, tokenizer = load_model()
39
+ tests = [
40
+ "Write a Python function to merge two sorted lists into one sorted list.",
41
+ "Write a Python class implementing a simple LRU cache with get and put operations in O(1).",
42
+ "Write a Python function using dynamic programming to compute the length of the longest increasing subsequence in an array.",
43
+ "Write Python code using Dijkstra's algorithm to find the shortest path in a weighted graph.",
44
+ ]
45
+ for t in tests:
46
+ print("=" * 60)
47
+ print("PROMPT:", t)
48
+ print("-" * 60)
49
+ print(generate(model, tokenizer, t))
50
+ print()
51
+
52
+ if __name__ == "__main__":
53
+ main()
scripts/test_security_model.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
3
+ from peft import PeftModel
4
+
5
+ BASE_MODEL = "codellama/CodeLlama-7b-Instruct-hf"
6
+ ADAPTER_PATH = "/home/ai/codellama-security-finetuned"
7
+
8
+ def load_model():
9
+ print("Loading base model...")
10
+ bnb_config = BitsAndBytesConfig(
11
+ load_in_4bit=True,
12
+ bnb_4bit_quant_type="nf4",
13
+ bnb_4bit_compute_dtype=torch.bfloat16,
14
+ bnb_4bit_use_double_quant=True,
15
+ )
16
+
17
+ model = AutoModelForCausalLM.from_pretrained(
18
+ BASE_MODEL,
19
+ quantization_config=bnb_config,
20
+ device_map="auto",
21
+ trust_remote_code=True,
22
+ torch_dtype=torch.bfloat16,
23
+ )
24
+
25
+ print("Loading LoRA adapter...")
26
+ model = PeftModel.from_pretrained(model, ADAPTER_PATH)
27
+ model = model.merge_and_unload()
28
+
29
+ tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True)
30
+ tokenizer.pad_token = tokenizer.eos_token
31
+
32
+ return model, tokenizer
33
+
34
+ def analyze_code(model, tokenizer, code, instruction="Identify all security vulnerabilities in this code"):
35
+ prompt = f"""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
36
+ You are a cybersecurity expert specializing in vulnerability assessment, penetration testing, and secure code review. Identify security flaws, explain the impact, and provide remediation.
37
+ <|eot_id|><|start_header_id|>user<|end_header_id|>
38
+ {instruction}
39
+
40
+ ```python
41
+ {code}
42
+ ```
43
+ <|eot_id|><|start_header_id|>assistant<|end_header_id|>"""
44
+
45
+ inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
46
+
47
+ with torch.no_grad():
48
+ outputs = model.generate(
49
+ **inputs,
50
+ max_new_tokens=1024,
51
+ temperature=0.3,
52
+ top_p=0.9,
53
+ do_sample=True,
54
+ repetition_penalty=1.1,
55
+ pad_token_id=tokenizer.eos_token_id,
56
+ )
57
+
58
+ response = tokenizer.decode(outputs[0], skip_special_tokens=True)
59
+ return response.split("<|start_header_id|>assistant<|end_header_id|>")[-1].strip()
60
+
61
+ def main():
62
+ model, tokenizer = load_model()
63
+
64
+ test_cases = [
65
+ ("SQL Injection", """
66
+ import sqlite3
67
+ def get_user(username):
68
+ conn = sqlite3.connect('app.db')
69
+ cursor = conn.cursor()
70
+ query = f"SELECT * FROM users WHERE name = '{username}'"
71
+ return cursor.execute(query).fetchall()
72
+ """),
73
+ ("Command Injection", """
74
+ import subprocess
75
+ def ping_host(host):
76
+ result = subprocess.run(f"ping -c 4 {host}", shell=True, capture_output=True)
77
+ return result.stdout
78
+ """),
79
+ ("Path Traversal", """
80
+ from flask import request, send_file
81
+ @app.route('/download')
82
+ def download():
83
+ filename = request.args.get('file')
84
+ return send_file(f'/var/www/uploads/{filename}')
85
+ """),
86
+ ("Insecure Deserialization", """
87
+ import pickle
88
+ def load_session(data):
89
+ return pickle.loads(data)
90
+ """),
91
+ ("JWT Issues", """
92
+ import jwt
93
+ def verify_token(token):
94
+ return jwt.decode(token, 'secret123', algorithms=['HS256'])
95
+ """),
96
+ ]
97
+
98
+ for name, code in test_cases:
99
+ print(f"\n{'='*60}")
100
+ print(f"TEST: {name}")
101
+ print(f"{'='*60}")
102
+ result = analyze_code(model, tokenizer, code)
103
+ print(result)
104
+
105
+ if __name__ == "__main__":
106
+ main()