You will need to subclass batchnorm to make that happen.
Here is an example for the 2d version:
Class MyLearntBatchnorm(nn. BatchNorm2d):
  def __init__(self, *args, **kwargs):
    # Initialize the regular batchnorm
    super().__init__(*args, **kwargs)
    # Get the size of the runnning_* buffers
    stats_size = self.running_mean.size()
    # Unregister them as buffer by deleting them
    del self.running_mean
    del self.running_var
    # Make them learnable parameters now
    self.running_mean = nn.Parameter(torch.Tensor(stats_size))
    self.running_var = nn.Parameter(torch.Tensor(stats_size))
    # Initialize them whichever way you want (I don't think uniform is a good idea here but not sure what to use)
    with torch.no_grad():
      self.running_mean.uniform_()
      self.running_var.uniform_()

  def forward(self, *args, **kwargs):
    # Our version behaves the same during train and eval and mimicks the original eval mode
    orig_training = self.training
    self.training = False
    # Use the regular batchnorm forward
    super().forward(*args, **kwargs)
    # Restore the original training flag
    self.training = orig_training

I haven’t tried the code so there might be some typos but that should clearly present the idea.
What can block this approach would be that the gradients for running_mean and running_var are not implemented in the provided batchnorm.
In that case, you will have to reimplement the batchnorm by hand using python functions.