This repository prepares genomic datasets and trains a contrastive DNA embedding model geared toward variant pathogenicity and mutation robustness. It is tailored for the Dacon DNA sequence learning challenge (see competition description: https://dacon.io/competitions/official/236630/overview/description).
The pipeline:
test.csv via exact window match at the SNV position.torchrun.conda create -n dna-embed python=3.12 -y
conda activate dna-embed
Install packages used in this repo:
cd DNA-embedding
pip install -r requirements.txt
pip install git+https://github.com/songlab-cal/gpn.git
Download hg38 reference FASTA and ClinVar VCF (GRCh38):
cd data
wget https://hgdownload.soe.ucsc.edu/goldenPath/hg38/bigZips/hg38.fa.gz
wget https://ftp.ncbi.nlm.nih.gov/pub/clinvar/vcf_GRCh38/clinvar.vcf.gz
gunzip -k hg38.fa.gz
gunzip -k clinvar.vcf.gz
prepare_clinvar_dataset.py extracts 1024bp windows centered on SNVs, placing the reference base at index 511 (0-based) and records the alternate base and label. Only Benign and Pathogenic (including Likely Pathogenic) entries are kept.
python prepare_clinvar_dataset.py --vcf clinvar.vcf --fasta hg38.fa --out clinvar_compact.csv --window 1024
Outputs:
clinvar_compact.csv with columns: ref_seq, mut_idx, alt, label
mut_idx is typically 511 for window 1024.label is 1 for Benign and -1 for Pathogenic/Likely Pathogenic.sequence_matcher.py performs two tasks:
(ref_seq, alt) match pairs that would leak into test.csv windows.test.csv pairs using precomputed Hamming-distance neighbor pairs.Run it after placing test.csv and clinvar_compact.csv in data/ and precomputing matches into test/results/match_clinvar.csv:
python sequence_matcher.py
Outputs:
clinvar_compact_removed.csv: filtered ClinVar without matched leakage entries.matched_pairs_labeled.csv: pairs from test.csv with labels inferred via ClinVar mapping on the SNV position.test/match.py computes Hamming distances among all unordered pairs in data/test.csv and emits two CSVs:
match_clinvar.csv: pairs at distance 1 with a differing base at position 512 (1-based), used to infer ClinVar labels.match_mut.csv: generic mutation pairs.It uses a compiled _hdist module for speed. To build and run on your machine:
cd ~/DNA-embedding/test
python setup.py build_ext --inplace
python match.py
Training is orchestrated by script/train.sh using torchrun with multi-GPU DDP. The main entry point is train.py, which:
ClinVarRefAltDataset for benign and pathogenic SNVs, and ContrastiveMutateDataset for mutation severity regressionBalancedAlternatingDataset for interleaved multi-task trainingEvaluationCallback, which runs at epoch end and logs cosine distance (cd), pathogenic-benign distance difference (cdd), and Pearson correlation (pcc)cd ~/DNA-embedding
bash script/train.sh
Logs are written to output/<RUN_NAME>/training.log, and checkpoints under output/<RUN_NAME>/joint.
Evaluation is computed in eval_metrics.py after embeddings are generated:
cd (mean cosine distance): Average of cosine distance $\mathrm{cd} = \frac{1-\cos}{2}$ over all ClinVar-matched benign and pathogenic pairs found in data/matched_pairs_labeled.csv. Lower values indicate closer ref/alt pairs overall.cdd (pathogenic minus benign distance): Difference between mean pathogenic and mean benign distances. Higher cdd means pathogenic pairs are farther than benign pairs, which is desired.pcc (Pearson correlation with mutations): Pearson correlation between cosine distance and mutation count (from test/results/match_mut.csv). Higher correlation indicates that embeddings reflect increasing dissimilarity with more mutations.script/generate.shThe generate_embeddings.py script generates embeddings using a fine-tuned model checkpoint. It supports both vanilla GPN (512D) and WrapperModel with projection head (2048D):
python generate_embeddings.py --checkpoint <path_to_checkpoint> --input <input_csv> --output <output_csv>
or
bash script/generate.sh
This runs the model loaded with output/model.safetensors by default.
--use_vanilla_gpn: Use vanilla GPN with mean pooling (512D) instead of projection head (2048D)The base GPN encoder is wrapped with a lightweight projection head that explicitly focuses on the single-nucleotide variant (SNV) position while preserving global context. Together with the datasets and losses below, this yields embeddings where benign SNVs are close to their reference and pathogenic SNVs are farther away.
Projection head (model.py → ProjectionHead):
snv_pos=511) to emphasize the mutation effect on neighboring codons.Training objective (model.py → ContrastiveTrainer), connected to the datasets in the next subsection:
ClinVarRefAltDataset), optimize cosine similarity such that:
ContrastiveMutateDataset), regress the cosine distance cd = (1 - cos) / 2 to the normalized mutation count k/512.These SNV-focused features (local convolution + exact SNV token) strengthen sensitivity at the mutation locus while pooled attention preserves global sequence context.
dataset.py)ClinVarRefAltDataset: Yields (ref, alt) pairs filtered by label (±1). Contrastively encourages benign variants to match reference and pathogenic variants to diverge.ContrastiveMutateDataset: Samples random 1024bp windows from hg38.fa with k point mutations (1 ≤ k ≤ 512). Regresses cosine distance to normalized mutation count (k/512).BalancedAlternatingDataset: Interleaves batches from multiple datasets in round-robin fashion, reshuffling each epoch for balanced multi-task training.ContrastiveDataCollator: Maintains pair structure (ref, alt) by stacking inputs and flattening into batches suitable for contrastive objectives.--cos_loss_margin, e.g., 0.9) for ref/alt embeddings and a regression loss on mutation level (k/512) from ContrastiveMutateDataset.train.sh.This repository prepares genomic datasets and trains a contrastive DNA embedding model geared toward variant pathogenicity and mutation robustness. It is tailored for the Dacon DNA sequence learning challenge (see competition description: https://dacon.io/competitions/official/236630/overview/description).
The pipeline:
test.csv via exact window match at the SNV position.torchrun.conda create -n dna-embed python=3.12 -y
conda activate dna-embed
Install packages used in this repo:
cd DNA-embedding
pip install -r requirements.txt
pip install git+https://github.com/songlab-cal/gpn.git
Download hg38 reference FASTA and ClinVar VCF (GRCh38):
cd data
wget https://hgdownload.soe.ucsc.edu/goldenPath/hg38/bigZips/hg38.fa.gz
wget https://ftp.ncbi.nlm.nih.gov/pub/clinvar/vcf_GRCh38/clinvar.vcf.gz
gunzip -k hg38.fa.gz
gunzip -k clinvar.vcf.gz
prepare_clinvar_dataset.py extracts 1024bp windows centered on SNVs, placing the reference base at index 511 (0-based) and records the alternate base and label. Only Benign and Pathogenic (including Likely Pathogenic) entries are kept.
python prepare_clinvar_dataset.py --vcf clinvar.vcf --fasta hg38.fa --out clinvar_compact.csv --window 1024
Outputs:
clinvar_compact.csv with columns: ref_seq, mut_idx, alt, label
mut_idx is typically 511 for window 1024.label is 1 for Benign and -1 for Pathogenic/Likely Pathogenic.sequence_matcher.py performs two tasks:
(ref_seq, alt) match pairs that would leak into test.csv windows.test.csv pairs using precomputed Hamming-distance neighbor pairs.Run it after placing test.csv and clinvar_compact.csv in data/ and precomputing matches into test/results/match_clinvar.csv:
python sequence_matcher.py
Outputs:
clinvar_compact_removed.csv: filtered ClinVar without matched leakage entries.matched_pairs_labeled.csv: pairs from test.csv with labels inferred via ClinVar mapping on the SNV position.test/match.py computes Hamming distances among all unordered pairs in data/test.csv and emits two CSVs:
match_clinvar.csv: pairs at distance 1 with a differing base at position 512 (1-based), used to infer ClinVar labels.match_mut.csv: generic mutation pairs.It uses a compiled _hdist module for speed. To build and run on your machine:
cd ~/DNA-embedding/test
python setup.py build_ext --inplace
python match.py
Training is orchestrated by script/train.sh using torchrun with multi-GPU DDP. The main entry point is train.py, which:
ClinVarRefAltDataset for benign and pathogenic SNVs, and ContrastiveMutateDataset for mutation severity regressionBalancedAlternatingDataset for interleaved multi-task trainingEvaluationCallback, which runs at epoch end and logs cosine distance (cd), pathogenic-benign distance difference (cdd), and Pearson correlation (pcc)cd ~/DNA-embedding
bash script/train.sh
Logs are written to output/<RUN_NAME>/training.log, and checkpoints under output/<RUN_NAME>/joint.
Evaluation is computed in eval_metrics.py after embeddings are generated:
cd (mean cosine distance): Average of cosine distance $\mathrm{cd} = \frac{1-\cos}{2}$ over all ClinVar-matched benign and pathogenic pairs found in data/matched_pairs_labeled.csv. Lower values indicate closer ref/alt pairs overall.cdd (pathogenic minus benign distance): Difference between mean pathogenic and mean benign distances. Higher cdd means pathogenic pairs are farther than benign pairs, which is desired.pcc (Pearson correlation with mutations): Pearson correlation between cosine distance and mutation count (from test/results/match_mut.csv). Higher correlation indicates that embeddings reflect increasing dissimilarity with more mutations.script/generate.shThe generate_embeddings.py script generates embeddings using a fine-tuned model checkpoint. It supports both vanilla GPN (512D) and WrapperModel with projection head (2048D):
python generate_embeddings.py --checkpoint <path_to_checkpoint> --input <input_csv> --output <output_csv>
or
bash script/generate.sh
This runs the model loaded with output/model.safetensors by default.
--use_vanilla_gpn: Use vanilla GPN with mean pooling (512D) instead of projection head (2048D)The base GPN encoder is wrapped with a lightweight projection head that explicitly focuses on the single-nucleotide variant (SNV) position while preserving global context. Together with the datasets and losses below, this yields embeddings where benign SNVs are close to their reference and pathogenic SNVs are farther away.
Projection head (model.py → ProjectionHead):
snv_pos=511) to emphasize the mutation effect on neighboring codons.Training objective (model.py → ContrastiveTrainer), connected to the datasets in the next subsection:
ClinVarRefAltDataset), optimize cosine similarity such that:
ContrastiveMutateDataset), regress the cosine distance cd = (1 - cos) / 2 to the normalized mutation count k/512.These SNV-focused features (local convolution + exact SNV token) strengthen sensitivity at the mutation locus while pooled attention preserves global sequence context.
dataset.py)ClinVarRefAltDataset: Yields (ref, alt) pairs filtered by label (±1). Contrastively encourages benign variants to match reference and pathogenic variants to diverge.ContrastiveMutateDataset: Samples random 1024bp windows from hg38.fa with k point mutations (1 ≤ k ≤ 512). Regresses cosine distance to normalized mutation count (k/512).BalancedAlternatingDataset: Interleaves batches from multiple datasets in round-robin fashion, reshuffling each epoch for balanced multi-task training.ContrastiveDataCollator: Maintains pair structure (ref, alt) by stacking inputs and flattening into batches suitable for contrastive objectives.--cos_loss_margin, e.g., 0.9) for ref/alt embeddings and a regression loss on mutation level (k/512) from ContrastiveMutateDataset.train.sh.