ThreatIntel / scripts /prepare_dataset.py
Malek98's picture
Deploy FastAPI backend via automated upload
bca5172 verified
Raw
History Blame Contribute Delete
3.31 kB
"""
Prepare dataset for fine-tuning: read cleaned JSONL, optionally apply prompt formatting,
create train/val/test splits (stratified if labels exist), and write HF-compatible JSON/JSONL.
Usage (bash):
python scripts/prepare_dataset.py --cleaned data/cleaned/cleaned_extracted_text.jsonl --out_dir data/prepared_run
"""
import argparse
import json
import os
from collections import Counter
from sklearn.model_selection import train_test_split
# Compact prompt template for training (IDs + short names)
COMPACT_PROMPT = (
"CATEGORIES: 1:MaliciousData 2:Ransomware 3:Marketplace 4:MalwareTools 5:ThreatActor "
"6:VulnIntel 7:InfraOps 8:Credentials 9:SocialEng 10:General\n\nPOST:\n{txt}\n\nCATEGORY_ID:"
)
def format_prompt(text):
return COMPACT_PROMPT.format(txt=text)
def read_jsonl(path):
with open(path, 'r', encoding='utf-8') as f:
for line in f:
yield json.loads(line)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--cleaned', required=True)
parser.add_argument('--out_dir', default='data/prepared_run')
parser.add_argument('--use_prompt', action='store_true')
args = parser.parse_args()
os.makedirs(args.out_dir, exist_ok=True)
samples = list(read_jsonl(args.cleaned))
print(f"Loaded {len(samples)} cleaned samples")
# If labels exist, create stratified splits
labels = [s.get('label') for s in samples]
has_labels = all([l is not None for l in labels])
if has_labels:
# map label names to numeric ids
unique = sorted(list(set(labels)))
label2id = {name: i for i, name in enumerate(unique)}
for s in samples:
s['label_id'] = label2id[s['label']]
# stratified split
train, temp = train_test_split(samples, test_size=0.3, stratify=[s['label_id'] for s in samples], random_state=42)
val, test = train_test_split(temp, test_size=0.5, stratify=[s['label_id'] for s in temp], random_state=42)
else:
# no labels: split randomly
train, val_test = train_test_split(samples, test_size=0.3, random_state=42)
val, test = train_test_split(val_test, test_size=0.5, random_state=42)
label2id = {}
# Optionally apply prompt formatting
def maybe_prompt(s):
txt = s['text']
return format_prompt(txt) if args.use_prompt else txt
def write_jsonl(l, path):
with open(path, 'w', encoding='utf-8') as f:
for s in l:
out = {
'text': maybe_prompt(s),
}
if 'label_id' in s:
out['label'] = s['label_id']
f.write(json.dumps(out, ensure_ascii=False) + '\n')
write_jsonl(train, os.path.join(args.out_dir, 'train.jsonl'))
write_jsonl(val, os.path.join(args.out_dir, 'val.jsonl'))
write_jsonl(test, os.path.join(args.out_dir, 'test.jsonl'))
# Write labels mapping
with open(os.path.join(args.out_dir, 'labels.json'), 'w', encoding='utf-8') as f:
json.dump({'label2id': label2id}, f, ensure_ascii=False, indent=2)
print(f"Prepared splits -> train:{len(train)} val:{len(val)} test:{len(test)}")
if __name__ == '__main__':
main()