2727from clu import parameter_overview
2828from connectomics .jax import training
2929from etils import epath
30+ from ffn .jax import accelerator_utils
3031from ffn .jax import input_pipeline
3132from ffn .jax import tracker
3233from ffn .training import examples
@@ -521,13 +522,27 @@ def train_and_evaluate(
521522 train_iter = checkpointed_state ['train_iter' ]
522523 initial_step = int (state .step ) + 1
523524
524- global_batch_size = config .per_device_batch_size * jax .device_count ()
525- host_batch_size = config .per_device_batch_size * jax .local_device_count ()
525+ # Compute batch sizes based on chip count, not core count. Multi-core
526+ # chips (e.g., tpu7x with 2 cores/chip) expose each core as a
527+ # separate JAX device, which would accidentally double the batch size.
528+ topo_info = accelerator_utils .get_accelerator_topology_info (
529+ config .per_device_batch_size
530+ )
531+
532+ logging .info (
533+ 'cores_per_chip=%d, num_chips=%d (global), local_chips=%d, '
534+ 'global_batch_size=%d, host_batch_size=%d' ,
535+ topo_info .cores_per_chip ,
536+ topo_info .num_chips ,
537+ topo_info .local_chips ,
538+ topo_info .global_batch_size ,
539+ topo_info .host_batch_size ,
540+ )
526541
527542 # Upper bound. The real number will be lower as not all steps are
528543 # taken for every example.
529544 steps_per_epoch = (
530- num_total_examples // global_batch_size * (len (fov_shifts ) + 1 )
545+ num_total_examples // topo_info . global_batch_size * (len (fov_shifts ) + 1 )
531546 )
532547 num_train_steps = steps_per_epoch * config .num_epochs
533548 logging .info (
@@ -593,7 +608,9 @@ def train_fn(state, batch, loss_scale):
593608 logging .info ('Starting training loop at step %d.' , initial_step )
594609 hooks = []
595610 report_progress = training .ReportProgress (
596- global_batch_size , num_train_steps = num_train_steps , writer = writer
611+ topo_info .global_batch_size ,
612+ num_train_steps = num_train_steps ,
613+ writer = writer ,
597614 )
598615 if jax .process_index () == 0 :
599616 hooks .append (report_progress )
@@ -608,7 +625,7 @@ def train_fn(state, batch, loss_scale):
608625 info ,
609626 config ,
610627 seed_shape = tuple (train_canvas_size (info , config ).tolist ()[::- 1 ]),
611- batch_size = host_batch_size ,
628+ batch_size = topo_info . host_batch_size ,
612629 jmp_policy = jmp_policy ,
613630 )
614631
@@ -623,9 +640,9 @@ def _reshape(x):
623640 per_device_data = np .split (x , len (mesh .local_devices ), axis = 0 )
624641
625642 on_dev = jax .device_put (per_device_data , mesh .local_devices )
626- global_shape = (
627- len ( batch_sharding . device_set ) * config . per_device_batch_size ,
628- ) + per_device_data [ 0 ]. shape [ 1 : ]
643+ global_shape = (topo_info . global_batch_size ,) + per_device_data [ 0 ]. shape [
644+ 1 :
645+ ]
629646 return jax .make_array_from_single_device_arrays (
630647 global_shape , batch_sharding , on_dev
631648 )
@@ -672,16 +689,12 @@ def _reshape(x):
672689 )
673690
674691 with training .MeasureTime (timings , 'update_seed' ):
675- host_local_seeds = [] # [b, z, y, x, 1] * num_devices
676- dev_to_slice = batch_sharding .addressable_devices_indices_map (
677- updated_seed .shape
678- )
679-
680692 # Ensure device order is the same as that used to build the
681693 # global array in postprocess_batch().
682- assert list (dev_to_slice .keys ()) == list (mesh .local_devices )
683- for slc in dev_to_slice .values ():
684- host_local_seeds .append (updated_seed [slc ])
694+ shard_by_device = {
695+ s .device : s .data for s in updated_seed .addressable_shards
696+ }
697+ host_local_seeds = [shard_by_device [d ] for d in mesh .local_devices ]
685698
686699 batch_iter .update_seeds (host_local_seeds )
687700
0 commit comments