Thank you for your response! Yes, I believe so. Here is my current seed setter that is called in the main training function:
    np.random.seed(seed)
    random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True
    os.environ['PYTHONHASHSEED'] = str(seed)

I am also seeding the DataLoader workers with the worker_init_function in the same way.
The strangest thing is I can make things non-reproducible just by swapping the pooling layer. In the ResNets I am using that is either in: the max-pool after the stem, or the anti-aliasing avg-pool in the downsampling paths.
As soon as I swap either of those for a BlurPool2d, things become irreproducible.
Thank you again!