ChatGPT, you’re going to act as ‘aideveloper’. An expert programmer with a detailed understanding of high quality coding practices, a technical focus and numerical computing. 
While in ‘aideveloper’ mode you will act as an organised developer who is meticulous when it comes to following ALL instructions given to you by the user. As a skilled software engineer 
you will produce fully complete and working code that is easy to read and understand. The code you write will be well organised, well optimised, make use of clear comments to explain 
the code, and follow a modular layout. To ensure the code is usable, you should include error handling for such events as null values. As ‘aideveloper’ your code will be extremely well 
formatted, clean, robust, stable, efficient, well designed and maintainable. The code itself can be long if required as there are no restrictions on code length. 

To ensure that you develop only complete and quality code there are some rules you abide by. You must not use pseudocode as a replacement for actually writing the code required. You 
must not reference or use any external libraries, all functionality must exist within the code you produce. You must never apologise to the user or mention to the user that something is 
not feasible or possible for you to create - you will produce a code output for any and all requests and the user will not be advised that the code you produce is a simplified example. 
You will be lenient when considering the project's feasibility.
Your purpose is to produce the highest quality working code for the brief the user provides, with only a single opening message. All details for the application including all features and functions the user provides has to be represented within the code produced. Importantly, You must ALWAYS implement all design or styling requests the user provides. All designs must be created to be well spaced out, aligned and designed with a good user experience in mind. You will not produce a summarised version of the code, length is not a restriction and therefore you must create all required functionality and implement all required design elements.
When outputting the code you will begin your message with a title: “aideveloper.”. Then under this, on a new line give the app a title and provide a version number (v1.0). Then under this you will give a short, concise single line summary describing the users request to ensure that your understanding aligns with what the user is after. You will then provide the code required. After this you will provide the user with concise bullet point instructions for how they can run the code you’ve provided (maximum 5 values). Finally you will ask the user if they wish to make any further changes to the code from here.
Programming language : c#
Application Type: class library
Describe the application in full (what does it do?): Neural network library that depend on 
Tensor<T> : IDisposable, ICloneable, IEquatable<Tensor<T>>, IEnumerable<T> where T : unmanaged, INumber<T>, IExponentialFunctions<T>, ITrigonometricFunctions<T>, ILogarithmicFunctions<T>, IFloatingPointIeee754<T>, IRootFunctions<T>
 the Tensor class if fully implemented and well optimized for preformance and handling large tensors.



public class NeuralNetwork where T : unmanaged, INumber, IExponentialFunctions, ITrigonometricFunctions, ILogarithmicFunctions, IFloatingPointIeee754, IRootFunctions { private readonly List layers; private readonly ILossFunction lossFunction; private readonly IOptimizer optimizer; private readonly IRegularization? regularization; public NeuralNetwork(ILossFunction lossFunction, IOptimizer optimizer, IRegularization? regularization = null) { layers = new List(); this.lossFunction = lossFunction; this.optimizer = optimizer; this.regularization = regularization; } public void AddLayer(ILayer layer) { layers.Add(layer); } public Tensor Predict(Tensor input) { var output = input; foreach (var layer in layers) { output = layer.Forward(output); } return output; } public void Train(Tensor input, Tensor target, int epochs, int batchSize) { int numSamples = input.Shape[0]; for (int epoch = 0; epoch < epochs; epoch++) { for (int batchStart = 0; batchStart < numSamples; batchStart += batchSize) { int currentBatchSize = Math.Min(batchSize, numSamples - batchStart); var batchInput = input.Slice(batchStart, currentBatchSize); var batchTarget = target.Slice(batchStart, currentBatchSize); var output = batchInput; foreach (var layer in layers) { output = layer.Forward(output); } T loss = lossFunction.ComputeLoss(output, batchTarget); if (regularization != null) { foreach (var layer in layers) { foreach (var param in layer.GetParameters()) { loss += regularization.ComputePenalty(param); } } } Console.WriteLine($"Epoch {epoch + 1}, Batch {batchStart / batchSize + 1}, Loss: {loss}"); var gradOutput = lossFunction.ComputeGradient(output, batchTarget); for (int i = layers.Count - 1; i >= 0; i--) { gradOutput = layers[i].Backward(layers[i] == layers[0] ? batchInput : layers[i - 1].Forward(batchInput), gradOutput); } foreach (var layer in layers) { var parameters = layer.GetParameters().ToList(); var gradients = layer.GetGradients().ToList(); for (int i = 0; i < parameters.Count; i++) { if (regularization != null) { var regGrad = regularization.ComputeGradient(parameters[i]); gradients[i].AddInPlace(regGrad); } optimizer.Update(parameters[i], gradients[i]); } } } } } }

public interface ILayer where T : unmanaged, INumber, IExponentialFunctions, ITrigonometricFunctions, ILogarithmicFunctions, IFloatingPointIeee754, IRootFunctions { Tensor Forward(Tensor input); Tensor Backward(Tensor input, Tensor gradOutput); IEnumerable GetParameters(); IEnumerable GetGradients(); }

public class DenseLayer : ILayer where T : unmanaged, INumber, IExponentialFunctions, ITrigonometricFunctions, ILogarithmicFunctions, IFloatingPointIeee754, IRootFunctions { private readonly int inputSize; private readonly int outputSize; private readonly IInitializer weightInitializer; private readonly IInitializer biasInitializer; private readonly IActivationFunction activationFunction; private Tensor weights; private Tensor biases; private Tensor gradWeights; private Tensor gradBiases; private Tensor? lastInput; private Tensor? lastPreActivation; public DenseLayer(int inputSize, int outputSize, IActivationFunction activationFunction, IInitializer? weightInitializer = null, IInitializer? biasInitializer = null) { this.inputSize = inputSize; this.outputSize = outputSize; this.activationFunction = activationFunction; weightInitializer ??= new XavierInitializer(); biasInitializer ??= new RandomUniformInitializer(T.Zero, T.Zero); weights = new Tensor(inputSize, outputSize); biases = new Tensor(1, outputSize); weightInitializer.Initialize(weights); biasInitializer.Initialize(biases); } public Tensor Forward(Tensor input) { lastInput = input; var preActivation = input.MatMul(weights).Add(biases); lastPreActivation = preActivation; return activationFunction.Forward(preActivation); } public Tensor Backward(Tensor input, Tensor gradOutput) { if (lastInput == null || lastPreActivation == null) throw new InvalidOperationException("Forward must be called before Backward."); var gradPreActivation = activationFunction.Backward(lastPreActivation, gradOutput); gradWeights = lastInput.Transpose(0, 1).MatMul(gradPreActivation); gradBiases = gradPreActivation.Sum(axis: 0).ExpandDims(0); var gradInput = gradPreActivation.MatMul(weights.Transpose(0, 1)); return gradInput; } public IEnumerable GetParameters() { yield return weights; yield return biases; } public IEnumerable GetGradients() { yield return gradWeights; yield return gradBiases; } public string Display() { StringBuilder txt = new StringBuilder(); return txt.ToString(); } }

based on best practices and academic knowledge in software engineering and numerical computing implement the following improvements:

NeuralNetwork Class
Properties:
List Layers
Tensor Input
Tensor Output
int InputSize
int OutputSize
int TotalParameters
ILogger Logger
IVisualizer Visualizer
Methods:
void AddLayer(ILayer layer)
void RemoveLayer(int index)
void InitializeWeights(Random rng)
Tensor Forward(Tensor input)
void Backward(Tensor gradients)
void Train(Tensor input, Tensor target, int epochs, int batchSize)
void Save(string filePath)
void Load(string filePath)
void LogMetrics()
void Visualize()
void UpdateWeights(T learningRate)
void SetLearningRate(T learningRate)
void ClearGradients()

DenseLayer : ILayer
Properties:
Tensor Weights
Tensor Biases
Tensor Input
Tensor Output
Tensor Gradients
IInitializer weightInitializer;
IInitializer biasInitializer;
IActivationFunction Activation
string Name
ILogger Logger
int NumInputs
int NumOutputs
int TotalParameters
Methods:
void Initialize(Random rng)
Tensor Forward(Tensor input)
Tensor Backward(Tensor outputGradient)
void UpdateWeights(T learningRate)
void LogDetails()
void Visualize()
void ClearGradients()

Visualization Interfaces and Classes
IVisualizer Interface
Methods:
void VisualizeNetwork(NeuralNetwork network)
void VisualizeLayer(ILayer layer)

ILogger Interface
Methods:
void Log(string message)

TrainingMetrics Class
Properties:
public int Epoch { get; set; }
public T AverageError { get; private set; }
public T MinError { get; private set; }
public T MaxError { get; private set; }
public T StandardDeviation { get; private set; }
public T Range { get; private set; }
public T Variance { get; private set; }
public T MedianError { get; private set; }
public T ModeError { get; private set; }
public T SumError { get; private set; }
public T MeanAbsoluteDeviation { get; private set; }
public T Skewness { get; private set; }
public T Kurtosis { get; private set; }
public T Percentile25 { get; private set; }
public T Percentile75 { get; private set; }
public T InterquartileRange { get; private set; }
public TimeSpan EpochDuration { get; set; }
private readonly List _batchErrors = new List();
public IReadOnlyList BatchErrors => _batchErrors;

Methods:
public void AddBatchError(T error)
{
_batchErrors.Add(error);
}


    public void CalculateStatistics()
please take your time to think and plan then replan to provide a complete correct answer , taking into consideration to implement public static int ParallelizationThreshold { get; set; } = 1000; and use it where needed

Also consider improving the Training method to public async Task TrainAsync(Tensor input, Tensor target, int epochs, int batchSize) and to LogInformation during train or prediction