Skip to content

Commit f6032f0

Browse files
Augustin-Zidekcopybara-github
authored andcommitted
Add a flag to compress large output files using zstandard
Inspired by #544 (thank you @ntnn19), but with some differences: 1. Uses zstandard instead of gzip for faster compression times and better compression ratios. 2. Compresses only large files. 3. Doesn't compress already compressed files (distogram and embeddings). 4. Doesn't write large temporary files, compresses directly. PiperOrigin-RevId: 856630504 Change-Id: I4413e26c9d2e8e4592c372dc675dcfa6044fc257
1 parent 8d0a8db commit f6032f0

2 files changed

Lines changed: 36 additions & 7 deletions

File tree

run_alphafold.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,13 @@
369369
' and is non-empty. Useful to set this to True to run the data pipeline and'
370370
' the inference separately, but use the same output directory.',
371371
)
372+
_COMPRESS_LARGE_OUTPUT_FILES = flags.DEFINE_bool(
373+
'compress_large_output_files',
374+
False,
375+
'If True, compresses the output mmCIF and confidences JSON files (the two'
376+
' largest files) using zstandard. Note that embeddings and distogram, if'
377+
' saved, are already stored in a compressed format.',
378+
)
372379

373380

374381
def make_model_config(
@@ -594,6 +601,7 @@ def write_outputs(
594601
all_inference_results: Sequence[ResultsForSeed],
595602
output_dir: os.PathLike[str] | str,
596603
job_name: str,
604+
compress_large_output_files: bool = False,
597605
) -> None:
598606
"""Writes outputs to the specified output directory."""
599607
ranking_scores = []
@@ -614,6 +622,7 @@ def write_outputs(
614622
inference_result=result,
615623
output_dir=sample_dir,
616624
name=f'{job_name}_seed-{seed}_sample-{sample_idx}',
625+
compress=compress_large_output_files,
617626
)
618627
ranking_score = float(result.metadata['ranking_score'])
619628
ranking_scores.append((seed, sample_idx, ranking_score))
@@ -646,6 +655,7 @@ def write_outputs(
646655
# The output terms of use are the same for all seeds/samples.
647656
terms_of_use=output_terms,
648657
name=job_name,
658+
compress=compress_large_output_files,
649659
)
650660
# Save csv of ranking scores with seeds and sample indices, to allow easier
651661
# comparison of ranking scores across different runs.
@@ -689,6 +699,7 @@ def process_fold_input(
689699
conformer_max_iterations: int | None = None,
690700
resolve_msa_overlaps: bool = True,
691701
force_output_dir: bool = False,
702+
compress_large_output_files: bool = False,
692703
) -> folding_input.Input:
693704
...
694705

@@ -705,6 +716,7 @@ def process_fold_input(
705716
conformer_max_iterations: int | None = None,
706717
resolve_msa_overlaps: bool = True,
707718
force_output_dir: bool = False,
719+
compress_large_output_files: bool = False,
708720
) -> Sequence[ResultsForSeed]:
709721
...
710722

@@ -720,6 +732,7 @@ def process_fold_input(
720732
conformer_max_iterations: int | None = None,
721733
resolve_msa_overlaps: bool = True,
722734
force_output_dir: bool = False,
735+
compress_large_output_files: bool = False,
723736
) -> folding_input.Input | Sequence[ResultsForSeed]:
724737
"""Runs data pipeline and/or inference on a single fold input.
725738
@@ -750,6 +763,8 @@ def process_fold_input(
750763
existing one is non-empty. Instead use the existing output directory and
751764
potentially overwrite existing files. If False, create a new timestamped
752765
output directory instead if the existing one is non-empty.
766+
compress_large_output_files: If True, compress large output files (mmCIF and
767+
confidences JSON) using zstandard.
753768
754769
Returns:
755770
The processed fold input, or the inference results for each seed.
@@ -806,6 +821,7 @@ def process_fold_input(
806821
all_inference_results=all_inference_results,
807822
output_dir=output_dir,
808823
job_name=fold_input.sanitised_name(),
824+
compress_large_output_files=compress_large_output_files,
809825
)
810826
output = all_inference_results
811827

@@ -970,6 +986,7 @@ def main(_):
970986
conformer_max_iterations=_CONFORMER_MAX_ITERATIONS.value,
971987
resolve_msa_overlaps=_RESOLVE_MSA_OVERLAPS.value,
972988
force_output_dir=_FORCE_OUTPUT_DIR.value,
989+
compress_large_output_files=_COMPRESS_LARGE_OUTPUT_FILES.value,
973990
)
974991
num_fold_inputs += 1
975992

src/alphafold3/model/post_processing.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from alphafold3.model import mmcif_metadata
2020
from alphafold3.model import model
2121
import numpy as np
22+
import zstandard
2223

2324

2425
@dataclasses.dataclass(frozen=True, slots=True, kw_only=True)
@@ -91,23 +92,34 @@ def write_output(
9192
output_dir: os.PathLike[str] | str,
9293
terms_of_use: str | None = None,
9394
name: str | None = None,
95+
compress: bool = False,
9496
) -> None:
9597
"""Writes processed inference result to a directory."""
9698
processed_result = post_process_inference_result(inference_result)
9799

98100
prefix = f'{name}_' if name is not None else ''
99101

100-
with open(os.path.join(output_dir, f'{prefix}model.cif'), 'wb') as f:
101-
f.write(processed_result.cif)
102+
if compress:
103+
opener = zstandard.open
104+
path_transform = lambda path: f'{path}.zst'
105+
else:
106+
opener = open
107+
path_transform = lambda path: path
102108

103-
with open(
104-
os.path.join(output_dir, f'{prefix}summary_confidences.json'), 'wb'
105-
) as f:
106-
f.write(processed_result.structure_confidence_summary_json)
109+
mmcif_path = os.path.join(output_dir, f'{prefix}model.cif')
110+
with opener(path_transform(mmcif_path), 'wb') as f:
111+
f.write(processed_result.cif)
107112

108-
with open(os.path.join(output_dir, f'{prefix}confidences.json'), 'wb') as f:
113+
full_confidences_path = os.path.join(output_dir, f'{prefix}confidences.json')
114+
with opener(path_transform(full_confidences_path), 'wb') as f:
109115
f.write(processed_result.structure_full_data_json)
110116

117+
summary_confidences_path = os.path.join(
118+
output_dir, f'{prefix}summary_confidences.json'
119+
)
120+
with open(summary_confidences_path, 'wb') as f:
121+
f.write(processed_result.structure_confidence_summary_json)
122+
111123
if terms_of_use is not None:
112124
with open(os.path.join(output_dir, 'TERMS_OF_USE.md'), 'wt') as f:
113125
f.write(terms_of_use)

0 commit comments

Comments
 (0)