Sorry for such a long post.  I tried to provide all the relevant information.  This is my first attempt at neural networks so I’ve done a few things the long way to allow for some debugging.  It mostly works so I haven’t gone through and done any cleanup.
I’m using four 7 channel images in an attempt to classify wetlands from upland and water.  Training, validation, and testing is showing very promising results with accuracy around 90% in all classes.  When I save the model, load it, and classify one of the training images I’m getting around 60% accuracy.
I break up the original files into 128x128 images and do some data augmentation which includes flipping, rotating, and transposing.  The paths are all saved in a csv file.  There are around 35k tiny images.
I’m using:
python 3.6.6
pytorch 0.4.1
UNet model 6
CrossEntropyLoss
Adam optimizer
Setting up the environment to get reproducible results
np.random.seed(0)
torch.manual_seed(0)
torch.cuda.manual_seed_all(0)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
model = unet.UNet(num_classes, in_channels=in_channels+extra_indices, depth=6, start_filts=64)
if torch.cuda.is_available:
    model.cuda()

I get population mean and stdev as well as class weights based off of a shuffled sample of my training data.  I have some areas of nodata which I ignore.
dataset_train = data_utils.SatIn(data_path, csvfile, 'train', transform=transforms.Compose([aug.RemoveZeros(), aug.RemoveNoData(), aug.WetlandOnly(), aug.SpecificBands(usebands), aug.NDVI(bands=[1,2])]))
train_dataloader = DataLoader(dataset_train, batch_size=2000, num_workers=1, shuffle=True)
if normalize or weighting:
    for i, data in enumerate(train_dataloader):
        if i == 0:
            if normalize:
                numpy_image = data['sat_img'].numpy()
                popmean = torch.from_numpy(np.mean(np.multiply(numpy_image, (numpy_image < -3.5028235e+4) | (numpy_image > -3.3028235e+4)), axis=(0,2,3))).float()
                popstd = torch.from_numpy(np.std(np.multiply(numpy_image, (numpy_image < -3.5028235e+4) | (numpy_image > -3.3028235e+4)), axis=(0,2,3))).float()
            if weighting:
                unique, counts = np.unique(data['map_img'].numpy(), return_counts=True)
                mapunique = unique
                mapcount = counts
                print('Unique:', unique)
                print('Counts:', counts)
                if weighting:
                    weights = 1 - (counts/sum(counts))
            break

Setup loss and optimizer
#criterion
if weighting:
    criterion = nn.CrossEntropyLoss(weight = weight)
else:
    criterion = nn.CrossEntropyLoss()

# optimizer
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

# decay LR
lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)

Load data
dataset_train = data_utils.SatIn(data_path, csvfile, 'train', transform=transforms.Compose([aug.RemoveZeros(), aug.RemoveNoData(), aug.WetlandOnly(), aug.SpecificBands(usebands), aug.NDVI(bands=[1,2]), aug.ToTensorTarget(), aug.NormalizeTarget(mean=popmean, std=popstd)]))
dataset_val = data_utils.SatIn(data_path, csvfile, 'valid',  transform=transforms.Compose([aug.RemoveZeros(), aug.RemoveNoData(), aug.WetlandOnly(), aug.SpecificBands(usebands), aug.NDVI(bands=[1,2]), aug.ToTensorTarget(), aug.NormalizeTarget(mean=popmean, std=popstd)]))
dataset_test = data_utils.SatIn(data_path, csvfile, 'test',  transform=transforms.Compose([aug.RemoveZeros(), aug.RemoveNoData(), aug.WetlandOnly(), aug.SpecificBands(usebands), aug.NDVI(bands=[1,2]), aug.ToTensorTarget(), aug.NormalizeTarget(mean=popmean, std=popstd)]))
train_dataloader = DataLoader(dataset_train, batch_size=batch_size, num_workers=4, shuffle=True)
val_dataloader = DataLoader(dataset_val, batch_size=3, num_workers=4, shuffle=False)
test_dataloader = DataLoader(dataset_test, batch_size=3, num_workers=4, shuffle=False)

Training, validation, and testing have very similar methods.  I call model.eval() and don’t do any of the optimizer of backwards propogation in validation and testing.
def train(train_loader, model, criterion, optimizer, scheduler, epoch_num):
    model.train()
    correct = 0
    totalcount = 0
    scheduler.step()

    # iterate over data
    for idx, data in enumerate(tqdm(train_loader, desc="training")):
        # get the inputs and wrap in Variable
        if torch.cuda.is_available():
            inputs = Variable(data['sat_img'].cuda())
            labels = Variable(data['map_img'].cuda())
        else:
            inputs = Variable(data['sat_img'])
            labels = Variable(data['map_img'])
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels.long())
        loss.backward()
        optimizer.step()
        _, predicted = torch.max(outputs.data, 1)
        test = predicted == labels.long()
        correct += test.sum().item()
        totalcount += test.size()[0] * test.size()[1] * test.size()[2]

    print('Training Loss: {:.4f}, Accuracy: {:.4f}'.format(loss.data[0], correct/totalcount))
    return {'train_loss': loss.data[0], 'train_acc' : correct/totalcount}

def validation(valid_loader, model, criterion, epoch_num):
    correct = 0
    totalcount = 0
    model.eval()

    # Iterate over data.
    for idx, data in enumerate(tqdm(valid_loader, desc='validation')):
        # get the inputs and wrap in Variable
        if torch.cuda.is_available():
            inputs = Variable(data['sat_img'].cuda(), volatile=True)
            labels = Variable(data['map_img'].cuda(), volatile=True)
        else:
            inputs = Variable(data['sat_img'], volatile=True)
            labels = Variable(data['map_img'], volatile=True)
        # forward
        outputs = model(inputs)
        loss = criterion(outputs, labels.long())
        _, predicted = torch.max(outputs.data, 1)
        test = predicted == labels.long()
        correct += test.sum().item()
        totalcount += test.size()[0] * test.size()[1] * test.size()[2]

    print('Validation Loss: {:.4f} Acc: {:.4f}'.format(loss.data[0], correct/totalcount))
    return {'valid_loss': loss.data[0], 'valid_acc': correct/totalcount}

Epoch loop
for epoch in range(start_epoch, num_epochs): 
    lr_scheduler.step()
    training= train(train_dataloader, model, criterion, optimizer, lr_scheduler, epoch)
    vallidating = validation(val_dataloader, model, criterion, epoch)

Save model
torch.save(model.state_dict(),os.path.join(rootdir,'3Image_8bands.pth'))

At this point everything looks great.  Now to load the model
#Set seeds
np.random.seed(0)
torch.manual_seed(0)
torch.cuda.manual_seed_all(0)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.enabled = False
# get model
model = unet.UNet(num_classes, in_channels=in_channels+extra_indices, depth=6, start_filts=64)
if torch.cuda.is_available():
    model.cuda()
model.load_state_dict(torch.load(os.path.join(rootdir, modelName)))
model.eval()

I breakup the image to be classified in the same way I did for training.  The original image is broken down into 128x128 chunks and each of those chunks run through the classifier.
collectpredictions = []
dataset_test = classify.ClassOut(data_path, csvfilename, 'test',  transform=transforms.Compose([aug.RemoveZeros(), aug.RemoveNoData(), aug.WetlandOnly(), aug.SpecificBands(usebands), aug.NDVI(bands=[1,2]), aug.ToTensorTarget(), aug.NormalizeTarget(mean=popmean, std=popstd)]))
test_dataloader = DataLoader(dataset_test, batch_size=1, num_workers=3, shuffle=False)
for idx, data in enumerate(test_dataloader):
    # get the inputs and wrap in Variable
    if torch.cuda.is_available():
        inputs = Variable(data['sat_img'].cuda(), volatile=True)
    else:
        inputs = Variable(data['sat_img'], volatile=True) 
    outputs = model(inputs)
    _, predicted = torch.max(outputs.data, 1)
    collectpredictions.append(predicted[0].cpu().numpy())

Where might I be going wrong?
Thanks!