modify the code so that the resulting neural network works with all image sizes: import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms
from PIL import Image
import numpy as np
import os
import time

# Define a simple CNN model using PyTorch
class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, padding=1)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, padding=1)
        self.conv3 = nn.Conv2d(64, 1, kernel_size=3, padding=1)

    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = torch.relu(self.conv2(x))
        x = torch.sigmoid(self.conv3(x))
        return x

def load_images_from_directory(directory, transform, image_size=(64, 64)):
    images = []
    for root, _, files in os.walk(directory):
        for filename in sorted(files):
            if filename.endswith('.png') or filename.endswith('.jpg'):
                filepath = os.path.join(root, filename)
                with Image.open(filepath) as img:
                    img = img.convert('L')  # Convert to grayscale
                    img = img.resize(image_size)
                    images.append(transform(img))
    return torch.stack(images)

# Image transformation and normalization
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

# Load training data
input_train_dir = "D:\\Bilder\\Python\\1. Input"
output_train_dir = "D:\\Bilder\\Python\\2. Output"

input_train_images = load_images_from_directory(input_train_dir, transform)
output_train_images = load_images_from_directory(output_train_dir, transform)

# Load testing data
input_test_dir = "D:\\Bilder\\Python\\Test\\Input"
output_test_dir = "D:\\Bilder\\Python\\Test\\Output"

input_test_images = load_images_from_directory(input_test_dir, transform)
output_test_images = load_images_from_directory(output_test_dir, transform)

# Initialize the model, loss function, and optimizer
model = SimpleCNN()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# Training loop
epochs = 1
batch_size = 8

# Measure time for tracking the duration
start_time = time.time()

for epoch in range(epochs):
    epoch_start_time = time.time()  # Start time for the current epoch

    permutation = torch.randperm(input_train_images.size()[0])
    for i in range(0, input_train_images.size()[0], batch_size):
        indices = permutation[i:i+batch_size]
        batch_inputs, batch_outputs = input_train_images[indices], output_train_images[indices]

        optimizer.zero_grad()
        outputs = model(batch_inputs)
        loss = criterion(outputs, batch_outputs)
        loss.backward()
        optimizer.step()
    
    epoch_end_time = time.time()  # End time for the current epoch
    elapsed = epoch_end_time - epoch_start_time
    remaining_time = elapsed * (epochs - epoch - 1)

    print(f'Epoch {epoch+1}, Loss: {loss.item()}, Time elapsed: {elapsed:.2f}s, Estimated time remaining: {remaining_time:.2f}s')

# Total training time
total_time = time.time() - start_time
print(f'Total training time: {total_time:.2f}s')

# Evaluate the model
with torch.no_grad():
    test_outputs = model(input_test_images)
    test_loss = criterion(test_outputs, output_test_images)
    print(f'Evaluation Loss: {test_loss.item()}')

# Save the model
save_path = "D:\\Bilder\\Python\\grayscale_adjustment_model.pth"
torch.save(model.state_dict(), save_path)
print(f'Model saved to {save_path}')