Implementing a Regression Neural Network with PyTorch: From Setup to Deployment

Import Dependencies

import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader, random_split

Training Configuration Setup

Customize these hyperparameters to tune model performance and ensure reproducibility.

device = "cuda" if torch.cuda.is_available() else "cpu"
training_config = {
    "random_seed": 999123,  # Custom random seed for consistent results
    "use_full_features": True,  # Toggle to utilize all input features
    "val_split": 0.15,  # Fraction of training data allocated for validation
    "total_epochs": 4000,  # Number of complete training cycles
    "batch_size": 128,
    "learning_rate": 5e-6,
    "patience": 500,  # Early stopping threshold for stalled validation loss
    "checkpoint_path": "./checkpoints/best_model.ckpt"  # Path to save the optimal model
}

Define the Regression Neural Network

This feedforward network maps input features to continuous output values using fully connected layers and ReLU activations.

class RegressionModel(nn.Module):
    def __init__(self, input_features):
        super().__init__()
        # Stack of fully connected layers with non-linear activations
        self.fc_stack = nn.Sequential(
            nn.Linear(input_features, 32),
            nn.ReLU(),
            nn.Linear(32, 16),
            nn.ReLU(),
            nn.Linear(16, 1)
        )
    
    def forward(self, x):
        output = self.fc_stack(x)
        return output.squeeze(dim=1)  # Reduce tensor dimension from (batch_size, 1) to (batch_size)

Model Training Loop

This function handles training, validation, early stopping, and model checkpointing.

def train_model(train_dataloader, val_dataloader, model, config, compute_device):
    loss_function = nn.MSELoss(reduction="mean")  # Mean Squared Loss for regression tasks
    # Stochastic Gradient Descent optimizer with momentum
    optimizer = torch.optim.SGD(model.parameters(), lr=config["learning_rate"], momentum=0.95)
    
    total_epochs = config["total_epochs"]
    best_val_loss = float("inf")
    step_count = 0
    stop_tracker = 0

    for epoch in range(total_epochs):
        model.train()  # Enable training mode (activates dropout/batch norm updates)
        training_losses = []

        for batch_x, batch_y in train_dataloader:
            optimizer.zero_grad()  # Reset gradients to prevent accumulation
            batch_x, batch_y = batch_x.to(compute_device), batch_y.to(compute_device)
            
            pred = model(batch_x)
            loss = loss_function(pred, batch_y)
            
            loss.backward()  # Compute gradients via backpropagation
            optimizer.step()  # Update model parameters
            
            step_count += 1
            training_losses.append(loss.detach().item())
            
            # Update progress bar with current training status
            train_pbar.set_description(f"Epoch [{epoch+1}/{total_epochs}]")
            train_pbar.set_postfix({"Loss": loss.detach().item()})
        
        avg_train_loss = sum(training_losses) / len(training_losses)
        writer.add_scalar("Loss/Train", avg_train_loss, step_count)

        model.eval()  # Switch to evaluation mode (disables training-specific layers)
        validation_losses = []
        with torch.no_grad():  # Disable gradient computation to save memory
            for batch_x, batch_y in val_dataloader:
                batch_x, batch_y = batch_x.to(compute_device), batch_y.to(compute_device)
                pred = model(batch_x)
                val_loss = loss_function(pred, batch_y)
                validation_losses.append(val_loss.item())
        
        avg_val_loss = sum(validation_losses) / len(validation_losses)
        print(f"Epoch [{epoch+1}/{total_epochs}]: Avg Train Loss: {avg_train_loss:.4f}, Avg Val Loss: {avg_val_loss:.4f}")
        writer.add_scalar("Loss/Validation", avg_val_loss, step_count)

        # Save the model if it achieves the lowest validation loss so far
        if avg_val_loss < best_val_loss:
            best_val_loss = avg_val_loss
            torch.save(model.state_dict(), config["checkpoint_path"])
            print(f"Best model saved with validation loss: {best_val_loss:.3f}")
            stop_tracker = 0
        else:
            stop_tracker += 1
        
        # Early stopping if no improvement for specified number of epochs
        if stop_tracker >= config["patience"]:
            print("\nTraining halted early due to no validation loss improvement.")
            return

Initialize and Launch Training

# Determine input feature count from training dataset
input_feature_count = x_train.shape[1]
model = RegressionModel(input_feature_count).to(device)

# Begin training process
train_model(train_loader, val_loader, model, training_config, device)

Inference Function for Test Data

def run_inference(test_dataloader, model, compute_device):
    model.eval()
    predictions = []
    
    for batch in tqdm(test_dataloader):
        batch = batch.to(compute_device)
        with torch.no_grad():
            batch_preds = model(batch)
            predictions.append(batch_preds.detach().cpu())
    
    return torch.cat(predictions, dim=0).numpy()

Generate and Export Test Predictions

def export_predictions(predictions, output_file_path):
    """Save prediction results to a CSV file in the required format"""
    import csv
    with open(output_file_path, "w", newline="") as file:
        writer = csv.writer(file)
        writer.writerow(["id", "predicted_value"])
        for index, pred in enumerate(predictions):
            writer.writerow([index, pred])

# Load the pre-trained best model
inference_model = RegressionModel(input_feature_count).to(device)
inference_model.load_state_dict(torch.load(training_config["checkpoint_path"]))

# Generate predictions on test dataset
test_results = run_inference(test_loader, inference_model, device)

# Export results to CSV
export_predictions(test_results, "test_predictions.csv")

Tags: pytorch Regression Neural Network Machine Learning model training Hyperparameter Tuning

Posted on Sun, 06 Sep 2026 16:37:09 +0000 by nelsons