Can you fix my code

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import MinMaxScaler
from numba import cuda, float32
import math

# Part 1: CPU-side Setup (Data Preparation and Basic Function Definitions)

# Load the dataset
data = pd.read_excel('/content/drive/MyDrive/Data.ods', sheet_name=None)
full_data = pd.concat(data.values())

# Preprocess the data
X = full_data.iloc[:, :-1].values
y = full_data.iloc[:, -1].values

# Normalize the data
scaler_x = MinMaxScaler(feature_range=(-1, 1))
scaler_y = MinMaxScaler(feature_range=(-1, 1))
X_normalized = scaler_x.fit_transform(X)
y_normalized = scaler_y.fit_transform(y.reshape(-1, 1)).flatten()

# Split the data
X_train, X_temp, y_train, y_temp = train_test_split(X_normalized, y_normalized, test_size=0.28, random_state=42)
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=(10/28), random_state=42)

# Define ANN architecture parameters
n_input = X_train.shape[1]
n_hidden = 10
n_output = 1
learning_rate = 0.001
num_epochs = 100
threadsperblock = 32

# Part 2: GPU-accelerated Computation Logic with Numba CUDA

# CUDA Kernel for Forward Propagation
@cuda.jit
def forward_propagation_cuda(X, W1, b1, W2, b2, A1, A2):
    row = cuda.grid(1)
    if row < X.shape[0]:
        for j in range(W1.shape[1]):
            Z1_val = 0.0
            for k in range(W1.shape[0]):
                Z1_val += X[row, k] * W1[k, j]
            A1[row, j] = math.tanh(Z1_val + b1[j])

        for j in range(W2.shape[1]):
            Z2_val = 0.0
            for k in range(W2.shape[0]):
                Z2_val += A1[row, k] * W2[k, j]
            A2[row, j] = 1 / (1 + math.exp(-(Z2_val + b2[j])))

# CUDA Kernel for Backward Propagation
@cuda.jit
def backward_propagation_cuda(X, Y, W1, W2, A1, A2, dW1, dW2, db1, db2, learning_rate):
    row = cuda.grid(1)
    if row < X.shape[0]:
        # Initialize dZ1 array with zeros
        dZ1_size = W1.shape[1]  # Calculate the size based on the dimensions of W1
        dZ1 = cuda.local.array(shape=W1.shape[1], dtype=float32)
        for j in range(dZ1_size):
            dZ1[j] = 0.0

        # Calculate gradients for W2 and b2
        dZ2 = A2[row, 0] - Y[row]
        for j in range(W2.shape[1]):
            db2[j] += dZ2
            for k in range(W2.shape[0]):
                dW2[k, j] += A1[row, k] * dZ2

        # Backpropagate through hidden layer
        for j in range(W1.shape[1]):
            for k in range(W2.shape[0]):
                dZ1[j] += dZ2 * W2[k, j]

        # Update gradients for W1 and b1
        for j in range(W1.shape[1]):
            db1[j] += dZ1[j] * (1 - A1[row, j]**2)
            for k in range(W1.shape[0]):
                dW1[k, j] += X[row, k] * dZ1[j]

# Initialize GPU-focused parts
# Allocate and copy forward propagation variables
W1_device = cuda.to_device(np.random.randn(n_input, n_hidden).astype(np.float32))
b1_device = cuda.to_device(np.random.randn(n_hidden).astype(np.float32))
W2_device = cuda.to_device(np.random.randn(n_hidden, n_output).astype(np.float32))
b2_device = cuda.to_device(np.random.randn(n_output).astype(np.float32))

# Output arrays for hidden and output layers
A1_device = cuda.device_array((X_train.shape[0], n_hidden), dtype=np.float32)
A2_device = cuda.device_array((X_train.shape[0], n_output), dtype=np.float32)

# Initializing arrays for gradients and parameter updates
dW1_device = cuda.device_array_like(W1_device)
dW2_device = cuda.device_array_like(W2_device)
db1_device = cuda.device_array_like(b1_device)
db2_device = cuda.device_array_like(b2_device)

# Transfer training data to GPU
X_train_device = cuda.to_device(X_train.astype(np.float32))
y_train_device = cuda.to_device(y_train.astype(np.float32))

# Validation data
X_val_device = cuda.to_device(X_val.astype(np.float32))
y_val_device = cuda.to_device(y_val.astype(np.float32))


# Training loop execution on GPU
train_losses = []
val_losses = []

# GPU execution function setup
def execute_forward_propagation(X_device, W1_device, b1_device, W2_device, b2_device, A1_device, A2_device):
    blockspergrid = (X_device.shape[0] + (threadsperblock - 1)) // threadsperblock
    forward_propagation_cuda[blockspergrid, threadsperblock](X_device, W1_device, b1_device, W2_device, b2_device, A1_device, A2_device)

# Adjusted and corrected train loop
for epoch in range(num_epochs):
    # Forward Propagation on Training Data
    execute_forward_propagation(X_train_device, W1_device, b1_device, W2_device, b2_device, A1_device, A2_device)

    # Backward Propagation and Parameter Update
    blockspergrid = (X_train.shape[0] + (threadsperblock - 1)) // threadsperblock
    backward_propagation_cuda[blockspergrid, threadsperblock](X_train_device, y_train_device, W1_device, W2_device, A1_device, A2_device, dW1_device, dW2_device, db1_device, db2_device, learning_rate)

    cuda.synchronize()

    # Validation
    execute_forward_propagation(X_val_device, W1_device, b1_device, W2_device, b2_device, A1_device, A2_device)

    # Calculate and Log Validation Loss
    if epoch % 10 == 0:
        A2_val = A2_device.copy_to_host()
        val_loss = np.mean((A2_val.flatten() - y_val) ** 2)
        val_losses.append(val_loss)
        print(f"Epoch {epoch}: Validation Loss = {val_loss}")

    # Compute Training Loss for Monitoring
    train_loss = np.mean((A2_device.copy_to_host().flatten() - y_train) ** 2)
    train_losses.append(train_loss)
    print(f"Epoch {epoch}: Training Loss = {train_loss}")

# Plotting Training and Validation Losses
epochs = range(0, num_epochs, 10)
plt.plot(epochs, train_losses, label='Training Loss')
plt.plot(epochs, val_losses, label='Validation Loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.title('Training and Validation Losses')
plt.legend()
plt.show()

# Copy final trained parameters back to host
W1_final = W1_device.copy_to_host()
b1_final = b1_device.copy_to_host()
W2_final = W2_device.copy_to_host()
b2_final = b2_device.copy_to_host()

# Optionally, you can perform inference or further analysis using the trained parameters