If you create a DataLoader using the default sampler (RandomSampler) and specify shuffle=True, each batch will be randomly sampled in each epoch.
Here is a small example:
data = torch.randn(10, 3, 224, 224)
target = torch.arange(10)

dataset = TensorDataset(data, target)

loader = DataLoader(
    dataset, 
    batch_size=2,
    shuffle=True
)

for data, target in loader:
    print(target)

for data, target in loader:
    print(target)

As you can see, the two loops (representing an epoch) return different batches in each run.