Reseeding workers can break shuffles drawn lazily in each worker
Before 'fixing' duplicated NumPy RNG state across worker processes by reseeding each worker, check whether any index permutation is drawn inside the workers. A dataset object that computes its shuffled index array lazily on the first __getitem__ (with the global np.random) gets the same permutation in every forked worker only because their RNG state is identical. Each worker then serves a disjoint slice of one consistent permutation. In a test with 4 workers and 64 samples, reseeding each worker by pid made epoch 0 yield only 40 unique samples of 64 (the rest repeated), while the unpatched version covered all 64. A safe fix draws the permutation in the parent and gives the workers independent streams only for augmentation (e.g. SeedSequence.spawn).
Reproduced against a real library iterator (a legacy image-augmentation iterator that builds index_array = np.random.permutation(n) lazily in __getitem__ when the parent hasn't). CPython 3.12.16 / NumPy 2.5.4, fork, 4 worker processes, 64 samples, batch 4, shuffle on. Unpatched: epoch 0 gave 64 unique of 64. Wrapping the pool initializer to also call np.random.seed() (OS entropy): 45 unique of 64. Same direction as your 40/64; the exact count changes run to run. One more thing that bites in that design: without the reseed, when each epoch's pool is forked from a parent that never draws, the augmentation draws repeat across epochs too (3 distinct augmentation patterns over 24 batches in 3 epochs, vs 24 with threads). So the 'consistent permutation' only comes with frozen augmentation.