Okay, so I put a forward hook on the first layer (conv2d) and the inputs and outputs were the same. So I tried it on the second layer (batchnorm2d) and the inputs were the same, but the outputs were different. However, I have checked that all the parameters in the state dict are the same, which I think are the weights and biases. I have no idea why the batch norm outputs are different; what else could be causing this difference? Or perhaps my code for checking the parameters is incorrect. My code is here:
#################

import torch
import torch.nn as nn
import torch.backends.cudnn as cudnn
from torch.autograd import Variable
import torchvision
import matplotlib.pyplot as plt
import numpy as np
from torch.utils.data import DataLoader

from config import Config # pylint: disable=no-name-in-module
import utils
from myclasses import CIFAR10Noise

from IPython import embed
from pynvml import *
from random import randrange
from copy import deepcopy
from collections import OrderedDict

def compare_models(model_1, model_2):
    models_differ = 0
    for key_item_1, key_item_2 in zip(model_1.state_dict().items(), model_2.state_dict().items()):
        if torch.equal(key_item_1[1], key_item_2[1]):
            pass
        else:
            models_differ += 1
            if (key_item_1[0] == key_item_2[0]):
                print('Mismatch found at', key_item_1[0])
            else:
                raise Exception
    if models_differ == 0:
        print('Models match perfectly! :)')

# A simple hook class that returns the input and output of a layer during forward/backward pass
class Hook():
    def __init__(self, module, backward=False):
        if backward==False:
            self.hook = module.register_forward_hook(self.hook_fn)
        
    def hook_fn(self, module, input, output):
        self.input = input
        self.output = output
    def close(self):
        self.hook.remove()


classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

####################

conf = Config(run_number=1)
net, device, handle = utils.prepare_net(conf.net(), conf.use_gpu)
model = (torch.load('/model_path', map_location=torch.device('cpu')))

# if running on CPU
if (device == 'cpu'):
    new_state_dict = OrderedDict()
    for k, v in model.items():
        name = k[7:] # remove 'module.' of dataparallel
        new_state_dict[name]=v
    net.load_state_dict(new_state_dict) # load model

    # turn off tracking running means in batch norm layers
    for child in net.children():
        if type(child) is (torch.nn.modules.container.Sequential):
            for layer in child:
                if isinstance(layer, nn.BatchNorm2d):
                    layer.track_running_stats = False
                    layer.momentum = 0
# if running on GPU
else:
    net.load_state_dict(model)# load model

    # turn off tracking running means in batch norm layer
    for child in net.module.children():
        if type(child) is (torch.nn.modules.container.Sequential):
            for layer in child:
                if isinstance(layer, nn.BatchNorm2d):
                    layer.track_running_stats = False
                    layer.momentum = 0

# small data set (subset of larger set)
train_set = torchvision.datasets.CIFAR10()
# large data set
train_set2 = CIFAR10Noise()


train_loader = DataLoader(train_set, batch_size=1500, shuffle=False, num_workers=conf.test_provider_count)
train_loader2 = DataLoader(train_set2, batch_size=1500, shuffle=False, num_workers=conf.test_provider_count)

# turn model to evaluation mode
net.eval()

# set hook on first batchnorm layer: features[1]
if (device == 'cpu'):
    hookF = Hook(net.features[1])
else:
    hookF = Hook(net.module.features[1])


"""
With both Dataloaders in nonshuffle mode, the matching images are in fixed locations.

Train loader 1 batch number : 0
i =  0

Train loader 2 batch number:  37
j =  166
"""

# copy net before evaluation so I can compare parameters after forward passes, 
# to see if any parameters changed
net2 = deepcopy(net)

# find matching images and save the hook inputs and outputs of their 
# respective batches
with torch.no_grad():
    
    # get batch with desired image from first dataset
    for batchNum1, data in enumerate(train_loader):
        if (batchNum1 == 0):
            images, labels = data
            outputs = net(images)
            _, predicted = torch.max(outputs.data, 1)

            # forward hook on batchnorm layer
            hookInput1 = hookF.input[0]
            hookOutput1 = hookF.output
            break

    print('See if model changed after train loader 1 forward pass')
    compare_models(net, net2)

    # get batch with desired image from second dataset
    for batchNum2, data2 in enumerate(train_loader2):
        if (batchNum2 == 37):
            images2, labels2 = data2
            outputs2 = net(images2)
            _, predicted2 = torch.max(outputs2.data, 1)

            # forward hook on batchnorm layer
            hookInput2 = hookF.input[0]
            hookOutput2 = hookF.output
            break
    
    print('See if model changed after train loader 2 forward passes')
    compare_models(net, net2)
    
    # indices of the desired matching image
    i = 0
    j = 166

    # store batch norm layer inputs and outputs from first dataset batch
    in1 = hookInput1[i]
    out1 = hookOutput1[i]

    # store batch norm layer inputs outputs from second dataset batch
    in2 = hookInput2[j]
    out2 = hookOutput2[j]

    if torch.equal(in1, in2):
        print('batch norm inputs are equal')
    else:
        print('batch norm inputs not equal')

    if torch.equal(out1, out2):
        print('batch norm outputs are equal')
    else:
        print('batch norm outputs not equal')

And the output from this is:
See if model changed after train loader 1 forward pass
Models match perfectly! :)
See if model changed after train loader 2 forward passes
Models match perfectly! :)
batch norm inputs are equal
batch norm outputs not equal

By the way, I checked and the running mean and variance are the same before and after the forward passes.