I have been given a task to approximate the function 5x^3 - 10x^2 - 5x - 9 using a neural network in pytorch. The training data is the set of integers in the range [-100,100] and I have to test the trained model against a non-integer value.
For the same, I have used a neural network with some layers and activation functions and I have also used Batch Normalization. However, the approximated function is far off from the actual function and gives extremely poor results.
Given below is the code
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
Define the polynomial function f(x) = 5x^3 - 10x^2 - 5x + 9
def polynomial_function(x):
return 5x3 - 10x*2 - 5x + 9
Generate training data for integers in the range [-100, 100]
x_train = np.arange(-100, 101, dtype=np.float32)
y_train = polynomial_function(x_train)
Define an improved neural network
class PolynomialApproximator(nn.Module):
def init(self):
super(PolynomialApproximator, self).init()
self.fc1 = nn.Linear(1, 128)
self.relu1 = nn.ReLU()
self.fc2 = nn.Linear(128, 64)
self.relu2 = nn.ReLU()
self.fc3 = nn.Linear(64, 1)
self.bn1 = nn.BatchNorm1d(128)
self.bn2 = nn.BatchNorm1d(64)
self.dropout1 = nn.Dropout(0.2)
self.dropout2 = nn.Dropout(0.2)
def forward(self, x):
x = self.fc1(x)
x = self.bn1(x)
x = self.relu1(x)
x = self.dropout1(x)
x = self.fc2(x)
x = self.bn2(x)
x = self.relu2(x)
x = self.dropout2(x)
x = self.fc3(x)
return x
Instantiate the improved model, MAE loss function, and optimizer
model = PolynomialApproximator()
criterion = nn.L1Loss() # Mean Absolute Error (MAE) loss
optimizer = optim.Adam(model.parameters(), lr=0.001) # Use Adam optimizer for better convergence
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=500, gamma=0.5) # Learning rate scheduler
Training loop
num_epochs = 10000
for epoch in range(num_epochs):
model.train()
inputs = torch.from_numpy(x_train.reshape(-1, 1))
targets = torch.from_numpy(y_train.reshape(-1, 1))
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
scheduler.step()
if (epoch + 1) % 100 == 0:
model.eval()
with torch.no_grad():
# Calculate MAE for printing accuracy
mae = torch.mean(torch.abs(outputs - targets))
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}, MAE: {mae.item():.4f}')
Evaluate the trained model on a non-integer input
x_test = torch.tensor([[90.5]])
y_test_pred = model(x_test).item()
Compare the function output vs. the NN output
print(f"Polynomial function output at x=78.6: {polynomial_function(90.5)}")
print(f"NN output at x=78.6: {y_test_pred}")
Plot the original function and the trained neural network
x_plot = np.linspace(-100, 100, 1000)
y_plot_original = polynomial_function(x_plot)
y_plot_approximated = model(torch.from_numpy(x_plot.reshape(-1, 1)).float()).detach().numpy()
y_plot_approximated = y_plot_approximated-min(y_plot_approximated)/(max(y_plot_approximated)- min(y_plot_approximated))
y_plot_original = y_plot_original-min(y_plot_original)/(max(y_plot_original)- min(y_plot_original))
x_mean, x_std = y_plot_original.mean(), y_plot_original.std()
y_mean, y_std = y_plot_approximated.mean(), y_plot_approximated.std()
y_plot_original = (y_plot_original - x_mean) / x_std
y_plot_approximated = (y_plot_approximated - y_mean) / y_std
plt.figure(figsize=(10, 6))
plt.plot(x_plot, y_plot_original, color='pink', label='Original Function', linewidth=2)
plt.plot(x_plot, y_plot_approximated, label='NN Approximation', linewidth=2)
plt.scatter(x_test.item(), y_test_pred, color='blue', marker='x', label='Test Point (x=78.6)')
plt.legend()
plt.title('Improved Function Approximation using Neural Network')
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)
plt.show()
What am I doing wrong ?
