Single layer precepton vs linear regression

I am doing a stock prediction task.

In theory, when N > p, single-layer perception, and linear regression would give the same results of the model.

However, in my experiments, the results don’t line up. what could be the causes? Is my code buggy?

#fit linear regression model
olsres = sm.OLS(train_y, sm.add_constant(train_X)).fit()
y_pred = olsres.predict(sm.add_constant(trade_X))
y_fit = olsres.predict(sm.add_constant(train_X))
# Single layer precepton
import torch
from torch import nn
from torch.utils.data import DataLoader
from sklearn.datasets import load_boston
from sklearn.preprocessing import StandardScaler

class Dataset(torch.utils.data.Dataset):
  def __init__(self, X, y, scale_data=True):
    if not torch.is_tensor(X) and not torch.is_tensor(y):
      # Apply scaling if necessary
      if scale_data:
          X = StandardScaler(with_mean=True, with_std=True).fit_transform(X)
      self.X = torch.from_numpy(X)
      self.y = torch.from_numpy(y)

  def __len__(self):
      return len(self.X)

  def __getitem__(self, i):
      return self.X[i], self.y[i]
      

class MLP(nn.Module):
  '''
    Multilayer Perceptron for regression.
  '''
  def __init__(self):
    super().__init__()
    self.layers =  nn.Linear(12, 1)

  def forward(self, x):
    '''
      Forward pass
    '''
    return self.layers(x)
  
# Set fixed random number seed
torch.manual_seed(42)

X, y = train_X, train_y.values

# Prepare dataset
dataset = Dataset(X, y)
trainloader = torch.utils.data.DataLoader(dataset, batch_size=len(X), shuffle=True, num_workers=1)

# Initialize the MLP
mlp = MLP()

# Define the loss function and optimizer
loss_function = nn.MSELoss()
optimizer = torch.optim.Adam(mlp.parameters(), lr=1)

# Run the training loop
for epoch in range(0, 1000): 
  
  # Print epoch
  # print(f'Starting epoch {epoch+1}')
  
  # Set current loss value
  current_loss = 0.0
  
  # Iterate over the DataLoader for training data
  for i, data in enumerate(trainloader, 0):
    # Get and prepare inputs
    inputs, targets = data
    inputs, targets = inputs.float(), targets.float()
    targets = targets.reshape((targets.shape[0], 1))

    optimizer.zero_grad()
    outputs = mlp(inputs)
    loss = loss_function(outputs, targets)
    loss.backward()
    optimizer.step()
    
    # Print statistics
    current_loss += loss.item()

  # print('Train Loss:', (current_loss))

with torch.no_grad():

  trainloader = torch.utils.data.DataLoader(dataset, batch_size=len(X), shuffle=False, num_workers=1)
  # Train data
  for i, data in enumerate(trainloader, 0):
    inputs, targets = data
    inputs, targets = inputs.float(), targets.float()
    targets = targets.reshape((targets.shape[0], 1))
    y_fit = mlp(inputs)

  # Test data
  X, y = trade_X, trade_y.values
  dataset = Dataset(X, y)
  testloader = torch.utils.data.DataLoader(dataset, batch_size=len(X), shuffle=False, num_workers=1)

  # Iterate over the DataLoader for test data
  for i, data in enumerate(testloader, 0):
    
    inputs, targets = data
    inputs, targets = inputs.float(), targets.float()
    targets = targets.reshape((targets.shape[0], 1))
    y_pred = mlp(inputs)

y_pred = y_pred.detach().numpy().reshape(-1)
y_fit = y_fit.detach().numpy().reshape(-1)

# Process is complete.
print('Training process has finished.')```