Skip to content

Commit 0174591

Browse files
authored
Merge pull request #25 from plantcad/update-docs
Updated documentation and reworked the command-line interface for the prediction pipeline.
2 parents 7029fc3 + c0232f6 commit 0174591

29 files changed

Lines changed: 6745 additions & 2592 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ logs/train*
1010
.specstory/
1111
data/
1212
genecad_result/
13+
/.idea

README.md

Lines changed: 379 additions & 1042 deletions
Large diffs are not rendered by default.
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# Installing GeneCAD
2+
3+
## Installing from a pre-built wheel (recommended)
4+
5+
The recommended method uses a pre-built wheel to reduce installation time.
6+
7+
```bash
8+
# Download the GeneCAD repository
9+
git clone https://github.com/plantcad/genecad.git
10+
cd genecad
11+
12+
# Create a virtual environment and install GeneCAD
13+
uv venv
14+
source .venv/bin/activate
15+
bash scripts/install_release.sh
16+
```
17+
18+
## Install from Source (Using uv)
19+
20+
If you are a developer and want to install GeneCAD from the source code instead of using the pre-built wheel, use [uv](https://docs.astral.sh/uv/):
21+
22+
```bash
23+
# Clone the repository
24+
git clone https://github.com/plantcad/genecad && cd genecad
25+
26+
# Install all dependencies
27+
# mamba and causal-conv1d build from source — this can take 3–30 minutes
28+
uv sync --extra torch --extra mamba
29+
30+
# Activate the virtual environment
31+
source .venv/bin/activate
32+
```
33+
34+
PyTorch is pinned to 2.7.1 (CUDA 12.8) to ensure compatibility with `mamba` (2.2.4) and `causal-conv1d` (1.5.0.post8). Newer combinations may work but are not officially tested.
35+
36+
`mamba` and `causal-conv1d` build from source without build isolation for reliability. To cache the built wheels and speed up future installs, add these entries to `pyproject.toml`:
37+
38+
```toml
39+
[tool.uv.sources]
40+
mamba-ssm = { path = "path/to/mamba_ssm-2.2.4-*.whl" }
41+
causal-conv1d = { path = "path/to/causal_conv1d-1.5.0.post8-*.whl" }
42+
# Or use a remote URL:
43+
# mamba-ssm = { url = "https://.../mamba_ssm-2.2.4-*.whl" }
44+
```
45+
46+
## Containers (Singularity/Apptainer or Docker)
47+
48+
The Docker image at `ghcr.io/plantcad/genecad_v1` bundles the complete runtime.
49+
Source code is **mounted at run time**, so changes you make to the cloned repository
50+
take effect immediately — no rebuild needed.
51+
52+
> [!TIP]
53+
> **Understanding File Paths in Containers**
54+
> The argument `-v $(pwd):/workspace` connects your current folder on the host machine
55+
> to the `/workspace` folder inside the container. Always place your input FASTA
56+
> files inside your current directory so the container can see them!
57+
58+
> [!IMPORTANT]
59+
> If your environment requires a specific Docker alias (e.g., `docker1`), replace
60+
> `docker` with your local command in the examples below.
61+
62+
```bash
63+
# Clone the repository
64+
git clone https://github.com/plantcad/genecad && cd genecad
65+
66+
# Pull the image
67+
docker pull ghcr.io/plantcad/genecad_v1:latest
68+
69+
# Run GeneCAD in your Docker container
70+
docker run --rm --gpus all \
71+
-v $(pwd):/workspace -w /workspace \
72+
ghcr.io/plantcad/genecad_v1:latest \
73+
bash predict.sh \
74+
-i /workspace/data/my_plant.fa \
75+
-o /workspace/output \
76+
-s Zmays \
77+
-m plant
78+
```
79+
80+
For HPC environments where Docker is not available, you can use Singularity
81+
(or Apptainer) to pull and run the Docker image directly. The `--nv` flag is
82+
required to enable GPU support.
83+
84+
```bash
85+
# Clone the repository
86+
git clone https://github.com/plantcad/genecad && cd genecad
87+
88+
# Pull the Docker image and convert it to a Singularity image
89+
singularity pull genecad.sif docker://ghcr.io/plantcad/genecad_v1:latest
90+
91+
# Run on the bundled Arabidopsis example (auto-downloads FASTA)
92+
singularity exec --nv \
93+
--bind $(pwd):/workspace \
94+
--pwd /workspace \
95+
genecad.sif \
96+
/usr/local/bin/genecad bash predict.sh
97+
98+
# Run GeneCAD in your Singularity container
99+
singularity exec --nv \
100+
--bind $(pwd):/workspace \
101+
--pwd /workspace \
102+
genecad.sif \
103+
/usr/local/bin/genecad bash predict.sh \
104+
-i /workspace/data/my_plant.fa \
105+
-o /workspace/output \
106+
-s Zmays \
107+
-m plant
108+
```
109+
110+
## Working with SLURM on HPC Clusters
111+
112+
When installing GeneCAD [from source](#install-from-source-using-uv) or using
113+
the [quick-start installation script](#download-and-install) on an HPC, make sure
114+
you are performing installation on a node that has access to GPU resources. This is
115+
essential for the package manager to identify the correct version of `pytorch` with
116+
`CUDA` for your system. Alternatively, use the [container-based installation](#containers-singularityapptainer-or-docker).
117+
118+
You may need to load specific modules, such as your system's `cuda-toolkit`, to
119+
successfully install the GeneCAD environment. Remember to activate your environment
120+
with `source .venv/bin/activate` in your SLURM batch script before calling GeneCAD.
121+
122+
> [!TIP]
123+
> **Multi-GPU on a Single Node:** To use all GPUs on a node, request them with `--gres=gpu:4` and pass `--gpus all` to
124+
> `genecad predict`. If there are many chromosomes, they will be distributed across GPUs.
125+
> If there are fewer chromosomes than GPUs, GeneCAD will automatically split the longest
126+
> sequences into parallel windows across the GPUs.
127+
128+
> [!TIP]
129+
> **Multi-Node Distributed Inference (e.g., TACC):** GeneCAD natively detects multi-node
130+
> SLURM topologies. If you allocate multiple nodes (e.g., `#SBATCH --nodes=4`), you can
131+
> use `srun` to seamlessly process enormous single contigs across the entire
132+
> cluster. `genecad predict` will automatically bypass local launchers and
133+
> allow PyTorch Lightning to route the distributed process windows.
134+
135+
> [!TIP]
136+
> **Custom launcher:** If your cluster requires a non-standard Python entrypoint
137+
> (e.g. `srun python` instead of `torchrun`), use `--launcher` or the `LAUNCHER`
138+
> environment variable to override automatic detection.
139+
140+
## Cloud Provisioning (SkyPilot)
141+
142+
[SkyPilot](https://docs.skypilot.co/en/latest/docs/index.html) lets you provision on-demand cloud GPUs across many providers (AWS, GCP, Lambda, RunPod, etc.) without managing infrastructure manually. This is useful if you do not have access to a local GPU or HPC cluster.
143+
144+
> [!IMPORTANT]
145+
> Run these commands from your **local machine or a login node with internet access** — not from an HPC compute node, which typically has no outbound internet and cannot reach cloud provider APIs.
146+
147+
**Step 1 — Install SkyPilot** (in a dedicated environment, separate from the GeneCAD venv to avoid dependency conflicts):
148+
149+
```bash
150+
python3 -m venv ~/skypilot-env
151+
source ~/skypilot-env/bin/activate
152+
pip install "skypilot[lambda]>=0.10.3"
153+
```
154+
155+
**Step 2 — Start the API server and configure credentials:**
156+
157+
```bash
158+
# Start the SkyPilot API server (runs as a background process)
159+
sky api start
160+
161+
# Verify credentials for your cloud provider
162+
sky check lambda
163+
```
164+
165+
If `sky check lambda` shows `Lambda: disabled`, configure your API key:
166+
1. Generate a key at [https://cloud.lambdalabs.com/api-keys](https://cloud.lambdalabs.com/api-keys)
167+
2. Add it to `~/.lambda_cloud/lambda_keys`:
168+
169+
```bash
170+
mkdir -p ~/.lambda_cloud
171+
echo "api_key = YOUR_API_KEY_HERE" > ~/.lambda_cloud/lambda_keys
172+
sky check lambda # should now show: Lambda: enabled ✓
173+
```
174+
175+
**Step 3 — Launch a GPU node and run:**
176+
177+
*(Make sure your terminal is currently in the root of the cloned `genecad` repository)*
178+
179+
> [!NOTE]
180+
> **Annotating your own genome:** When you are ready to annotate your own data, place your FASTA file inside the `genecad` directory (e.g., `genecad/my_genome.fa`) before running `sky launch`. This ensures SkyPilot automatically uploads it to the cloud. You would then append `-i my_genome.fa -s MySpecies` to the `bash predict.sh` command below.
181+
182+
```bash
183+
# 1. Deploy the GPU node (--no-setup: Docker replaces uv sync)
184+
sky launch --num-nodes 1 --yes --no-setup \
185+
--cluster genecad examples/configs/cluster.sky.yaml
186+
187+
# 2. Run the workload (this example runs the built-in Arabidopsis test)
188+
sky exec genecad 'docker pull ghcr.io/plantcad/genecad_v1:latest && \
189+
docker run --rm --gpus all \
190+
-v $(pwd):/workspace -w /workspace \
191+
ghcr.io/plantcad/genecad_v1:latest \
192+
bash predict.sh'
193+
194+
# 3. Download the results back to your local machine
195+
rsync -avz genecad:~/sky_workdir/genecad_result/ ./genecad_result/
196+
197+
# 4. Terminate the node to stop billing
198+
sky down genecad --yes
199+
```
200+
201+
> [!IMPORTANT]
202+
> **Why Docker instead of `uv sync`?**
203+
> `flash-attn`, `mamba-ssm`, and `causal-conv1d` must all compile from source, which can
204+
> take **30–60 minutes** on a fresh cloud node and may fail if the CUDA/GCC versions mismatch.
205+
> The pre-built Docker image includes all compiled packages, making cluster setup take seconds
206+
> instead of hours.
207+
208+
See the [Throughput](../README.md#prerequisites) section for GPU cost comparisons across providers.
209+
210+
<details><summary>SkyPilot GPU rates</summary>
211+
212+
```
213+
> sky show-gpus L4:1 # low-end development GPU
214+
GPU CLOUD INSTANCE_TYPE DEVICE_MEM HOURLY_PRICE REGION
215+
L4 RunPod 1x_L4_SECURE 24GB $ 0.440 CA
216+
L4 GCP g2-standard-4 24GB $ 0.705 us-east4
217+
L4 AWS g6.xlarge 22GB $ 0.805 us-east-2
218+
219+
> sky show-gpus H100:1 # high-end production GPU
220+
GPU CLOUD INSTANCE_TYPE DEVICE_MEM HOURLY_PRICE REGION
221+
H100 Hyperbolic 1x-H100-75-722 80GB $ 1.290 default
222+
H100 Lambda gpu_1x_h100_pcie 80GB $ 2.490 europe-central-1
223+
H100 GCP a3-highgpu-1g 80GB $ 5.383 us-central1
224+
```
225+
226+
</details>

docs/create_manifest.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Detailed documentation for create_manifest.py
2+
3+
Optional step between [1/7] and [2/7] of the prediction pipeline creates a keyfile that
4+
coordinates processing multiple contigs at the same time.
5+
6+
```
7+
python create_manifest.py \
8+
--input-zarr path/to/output/sequence.zarr \
9+
--output-json path/to/output/manifest.json \
10+
--species-id species_name \
11+
--intermediate-dir path/to/output
12+
```
13+
14+
### Parameters
15+
16+
* `--input-zarr` `-i-` - sequences.zarr file from `extract_fasta.py`
17+
* `--output-json` `-o` - output manifest.json file
18+
* `--species-id` - The name of the species or sample
19+
* `--intermediate-dir`- Path to a directory which will store intermediate GeneCAD files.
20+
By default, this is the parent directory of `input-zarr`
21+
22+
23+
### Manifest Format
24+
GeneCAD manifest files use human-readable JSON format to list the parameters
25+
specific to each chromosome while using the prediction pipeline. The following
26+
parameters are required:
27+
* `chromosome_id` - name of the chromosome
28+
* `sequence_zarr` - sequences.zarr file from `extract_fasta.py`
29+
* `predictions_dir` - predictions directory from `predict.py`
30+
* `intervals_zarr` - intervals.zarr file from `detect_intervals.py`
31+
* `raw_gff` - unfiltered gff file from `export_gff.py`
32+
* `filtered_gff` - post-filter gff file from `filter_raw_gff.py`
33+
34+
An example of the formatting for the `manifest` file
35+
```
36+
[{"chromosome_id": "Chr1", "sequence_zarr": "sequence.zarr", "predictions_dir": "predictions_Chr1/", "intervals_zarr": "intervals_Chr1.zarr", "raw_gff": "predictions_raw_Chr1.gff", "filtered_gff": "predictions_filtered_Chr1.gff"},
37+
{"chromosome_id": "Chr2", "sequence_zarr": "sequence.zarr", "predictions_dir":"predictions_Chr2/", "intervals_zarr": "intervals_Chr2.zarr", "raw_gff": "predictions_raw_Chr2.gff", "filtered_gff": "predictions_filtered_Chr2.gff"},
38+
{"chromosome_id": "Chr3", "sequence_zarr": "sequence.zarr", "predictions_dir":"predictions_Chr3/", "intervals_zarr": "intervals_Chr3.zarr", "raw_gff": "predictions_raw_Chr3.gff", "filtered_gff": "predictions_filtered_Chr3.gff"}]
39+
40+
```
41+
42+
### Next Step
43+
44+
`python predict.py` [Predict Documentation](predict.md)

docs/detect_intervals.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Detailed documentation for detect_intervals.py
2+
3+
Step [3/7] of the prediction pipeline converts base-level classifications to genomic regions,
4+
such as CDS and UTR exons using the viterbi algorithm and domain-specific
5+
transition probabilities.
6+
7+
```
8+
python detect_intervals.py \
9+
--input-dir predictions_Chr1/
10+
--output-zarr intervals_Chr1.zarr
11+
```
12+
13+
### Parameters
14+
15+
* `--input-dir`, `-i` - The base-level predictions, output from `predict.py`
16+
* `--output-zarr`, `-o` - Output zarr file containing interval/region data.
17+
* `--manifest` - Json file containing input and output paths for a set of chromosomes/samples.
18+
This can be used in place of specifying `--input-dir` and `--output-zarr`. Required key for each
19+
sample are: chromosome_id, predictions_dir, and intervals_zarr.
20+
* `--viterbi-alpha` - Float between 0 and 1. Increases the transition probability for all state transitions.
21+
Higher transition probabilities are more sensitive to detecting genes, but also increase the likelihood of
22+
finding pseudogenes and/or creating ill-formed gene models. Default None.
23+
* `--decode-direct` - Flag. By default, this script uses the viterbi algorithm and a
24+
preset transition matrix to adhere to valid gene structure (e.g. introns must be bounded by exons, 3'
25+
UTR must follow CDS, etc.). The direct method creates intervals directly from the base-level predictions,
26+
with no enforcement of gene model structure.
27+
* `--intergenic-bias` - Float. Penalizes predictions of intergenic bases, increasing the model's sensitivity towards
28+
predicting genic regions (CDS, 3' UTR, 5' UTR, or intron). Note that this value is applied before
29+
softmax, and so can be greater than 1.
30+
* `--keep-incomplete-features` - Flag. If set, gene models missing UTRs are allowed.
31+
* `--domain` - Domain sets the transition probabilities between states based on empirical observation from
32+
different types of organisms. Default: plant. Options: plant, animal.
33+
34+
### Next Step
35+
36+
`python export_gff.py` [Export GFF Documentation](export_gff.md)

docs/export_gff.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Detailed documentation for export_gff.py
2+
3+
Step [4/7] of the prediction pipeline converts predicted intervals into a GFF3 formatted file.
4+
5+
```
6+
python export_gff.py \
7+
--input-zarr intervals_Chr1.zarr \
8+
--output-gff Chr1_raw.gff
9+
```
10+
11+
### Parameters
12+
13+
* `--input-zarr`, `-i` - Input intervals zarr file. This is the output from
14+
`detect_intervals.py`.
15+
* `--output-gff`, `-o` - Output gff file name.
16+
* `--manifest` - Json file containing input and output paths for a set of chromosomes/samples.
17+
This can be used in place of specifying `--input-zarr` and `--output-gff`. Required key for each
18+
sample are: chromosome_id, intervals_zarr, and raw_gff.
19+
* `--min-transcript-length` - Remove any transcripts that are shorter than this (including introns).
20+
Default 0
21+
* `--tqdm-position` - Index of the tqdm row to use for export when multiple jobs are run in one terminal.
22+
Optional, default: None
23+
* `--cpu-workers` - Number of CPU worker processes for transcript grouping. Default: 1
24+
25+
### Next Step
26+
27+
`python filter_raw_gff.py` [Filter Raw GFF Documentation](filter_raw_gff.md)

docs/extract_fasta.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Detailed documentation for extract_fasta.py
2+
3+
Step [1/7] of the prediction pipeline prepares fasta sequences for inference.
4+
5+
```
6+
python extract_fasta.py \
7+
--species-id species_name \
8+
--input-fasta path/to/fasta.fa \
9+
--model-path emarro/pcad2-200M-cnet-baseline \
10+
--output-zarr path/to/output/sequence.zarr
11+
```
12+
13+
### Parameters
14+
15+
* `--species-id` - The name of the species or sample.
16+
This is used primarily in file names and metadata tags.
17+
* `--input-fasta`, `-i` - Path to the fasta file to be processed.
18+
* `--model-path` - Path to the base PlantCAD model being used.
19+
Both absolute local paths and HuggingFace repository paths are supported.
20+
For help determining which model to use, see [Available GeneCAD Models]
21+
> [!NOTE]
22+
> Use the same GeneCAD and PlantCAD models through all steps in the pipeline.
23+
* `--output-zarr`, `-o` - path to the output sequence dataset file. The output
24+
is in .zarr format and will appear as a directory.
25+
* `--chrom-map` - (Optional) Map to rename chromosomes and/or select a
26+
subset of chromosomes. If set, chromosomes will be renamed according to the map,
27+
and chromosome names that do not appear in the map will be skipped. If not set,
28+
all chromosomes will be prepared and will retain their original names. The map should
29+
be formatted as a comma-separated list of key-value pairs, e.g.
30+
`oldChr1:newChr1,oldChr2:newChr2,oldChr3:newChr3...`
31+
32+
### Next Step
33+
34+
Optional: If your fasta file has multiple contigs, use `create_manifest.py` to
35+
process all contigs at once. Otherwise, you will have to run through the pipeline steps
36+
independently for each contig. [Create Manifest Documentation](create_manifest.md)
37+
38+
If you are only processing one contig or would like to process contigs independently, move
39+
on to `python predict.py` [Predict Documentation](predict.md)

0 commit comments

Comments
 (0)