Repository navigation
Conversation
shuffle_tfrecords_beam.py runs on Google Cloud Dataflow or on Beam's DirectRunner. DirectRunner holds the whole shuffle in memory, so large training sets need a very large-memory machine, and Beam's Python Spark runner is impractical on EMR (no direct YARN submission, Docker needed on workers, runtime downloads). tools/shuffle_tfrecords_spark.py is a plain PySpark version of the same SHA1-keyed shuffle with the same outputs (sharded tfrecord.gz, dataset_config.pbtxt, example_info.json). Inputs are streamed and Spark's sort-based shuffle spills to disk, so memory does not grow with the dataset. tools/aws_shuffle/ adds a launch script for a transient EMR cluster.
With apache_beam 2.61+, DirectRunner runs pipelines on the Prism runner. The Python client applies --job_server_timeout as a deadline on the whole job-status stream, so any local shuffle that runs longer than the timeout fails with StatusCode.DEADLINE_EXCEEDED while the job is still running. The default is 300 s; it was raised from 60 s in apache/beam#36517, whose description recommends setting --job_server_timeout for longer jobs. The case study's validation-set shuffle finishes in about 2.5 minutes, so it never hits the limit. Shuffling the training set locally takes about 10 minutes: it failed at 5:03 with the default, and completed in 9:52 with --job_server_timeout=86400 (apache_beam 2.71.0, r1.10 script). Add --job_server_timeout=86400 to the DirectRunner example and a note recommending a large value for any local Beam run.
The case study says --direct_num_workers=0 sets the number of threads/subprocesses to the number of cores. With apache_beam 2.71.0, DirectRunner runs the shuffle pipeline on the Prism runner, and only the older FnApiRunner reads this option. A/B test on the validation set (64-core machine, same inputs): --direct_num_workers=1: 2:26.1 wall, 232% CPU, PrismRunner --direct_num_workers=0: 2:26.8 wall, 232% CPU, PrismRunner
Fold the background on why a non-Beam shuffle is needed into the README, and replace the synthetic-only measurements with results from the training case study's examples (HG001; 0.34 GB validation, 1.97 GB training), shuffled with both scripts on the same 64-core server: - Training: Beam DirectRunner 9:52 / 32.6 GB; Spark local[4] 13:09 / 3.9 GB; local[*] 6:33 / 6.1 GB; local[*] with 64 shards 1:45 / 38.9 GB. - All outputs keep exactly the input records and label counts, and their neighbour rate matches random shuffles of the same records. - Spark output is deterministic: repeated runs, and 4- vs 64-core runs, give identical records in identical order. - One validation run on AWS EMR (emr-7.5.0) for about $0.25. Also document the shard-count bottleneck in Tuning and the two Beam DirectRunner pitfalls found (job_server_timeout, direct_num_workers).
The run_emr_ec2.sh header asked for about 3x the compressed input in disk, while the README measures the spill at about 1.5x the gzipped input (plus 1x only when output lands on the same disk). On EMR the output goes to S3, so state 1.5x and point at WORKER_COUNT x WORKER_EBS_GB.
Ran the committed run_emr_ec2.sh end-to-end on the validation set (emr-7.5.0, 2 x m5.2xlarge core nodes), overriding SERVICE_ROLE and INSTANCE_PROFILE with the account's existing EMR roles because the standard EMR_DefaultRole / EMR_EC2_DefaultRole did not exist there. Provisioning took about 3.5 minutes and the step about 5.7 minutes. The output kept all 59,401 records and label counts, and matched the local 64-core Spark run record for record and in order. README changes: - Option 2: name the default roles, note that creating them needs IAM permissions, and point to SERVICE_ROLE / INSTANCE_PROFILE overrides. - AWS EMR test: describe this run of the committed launcher. - Reproducibility: EMR and local outputs are identical.
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
b7be149 to
6155e45
Compare
|
Hi @yinshiyi, thanks for sending out the PR. As you know, we usually accept PRs by incorporating the change internally with the author's consent, and we credit the author. However, since we can't test on AWS, we won't be able to take this PR. I agree it can be useful for other users, though. Would it be OK if we keep it open for reference without incorporating it directly? |
Great to hear from you, @pichuan. Yes, I still remember the g3/CLs. The new Spark shuffler runs on any single machine: a local server, a GCP instance, an AWS instance, and so on. The main problem I wanted to solve is that the current Beam shuffler, when run with DirectRunner, holds the whole dataset in RAM, which isn't feasible for large datasets. The proposed shuffler spills to disk instead, so a patient user can shuffle large dataset with almost any machine that has enough storage. As a bonus, its output is reproducible: the same input produces consistently across platforms. When you have time, I would appreciate it you could test the local Spark shuffler in your setup. If you run into any issues, please let me know. If you think it is useful, I could focus this PR only for local shuffler. I also think two issues I found are worth following up on:
AWS EMR support came along with the Spark work. I'm happy to leave the EMR part as a separate open PR for other users. If you think it's appropriate to mention it in one of the case studies, that could help others as well. |
Add a PySpark shuffle script for users without Google Cloud
DeepVariant training needs the examples shuffled globally before training. The
upstream script,
tools/shuffle_tfrecords_beam.py(v1.10), supports two ways torun it:
a GCP account.
memory grows with the dataset: the case study's 1.97 GB (gzipped) training set
needed 32.6 GB of RAM. Large training sets need a very large-memory machine or
fail with out-of-memory errors.
Running the Beam script on AWS EMR is not a practical alternative: Beam's Python
Spark runner can't submit to EMR's YARN directly and needs Docker on every
worker.
What this PR adds
tools/shuffle_tfrecords_spark.pyis a plain PySpark version of the sameSHA1-keyed shuffle, with the same output files (
*.tfrecord.gz,dataset_config.pbtxt,example_info.json). It runs on a single machine or onAWS EMR (
tools/aws_shuffle/run_emr_ec2.sh). Spark spills the shuffle to disk,so memory depends on the cores used, not on dataset size.
It also adds two notes to the training case study for local Beam users:
DEADLINE_EXCEEDEDunless--job_server_timeoutis raised (Change default timeout and add heartbeat logging apache/beam#36517). The validation shuffle(2.5 min) passes; a local training shuffle (10 min) fails.
--direct_num_workers=0has no effect with Beam 2.71: DirectRunner runs onPrism, and
=0and=1gave the same run time.Results (case study training set, 342,758 examples, same 64-core server)
Beam stays at about 2-4 busy cores whatever the settings; Spark scales with the
cores you give it, and fewer cores means less memory.
Testing
the label counts in
dataset_config.pbtxtmatch.the input matches random shuffles of the same records (0.06% vs 0.06% on
training).
64-core runs, and a run on AWS EMR all gave identical records in identical
order. Beam's order changes on every run.
run_emr_ec2.shshuffled the validation set on a 2-nodeemr-7.5.0 cluster in about 9 minutes end to end, for about $0.25.
Notes
idle on small inputs; set
--num_output_shardsto at least the Spark core count.eg. local[4], set --num_output_shards 4
reproducibility.
SERVICE_ROLEandINSTANCE_PROFILEDetails and setup are in
tools/aws_shuffle/README.md.