## 2 Materials and Methods
### Training Loop  
Once the previous steps are finished, the training loop is designed. The script which runs this loop, written in Python 3.11, takes the name of a DNN model as an input parameter. Based on the name, an instance of this model is created, and its associated YAML configuration file, which contains the model hyperparameters, is loaded. This file additionally contains the path to the desired preprocessed dataset, and therefore its associated statistics file. The statistics file, as mentioned before, contains the number of curriculums generated, the number of samples in each curriculum, the normalization technique used, the percentage of samples used for testing, and the statistical markers for each column of the dataset. The path can be manually set by changing the configuration YAML.  
For the training and validation data, generator functions are used. These receive the batch size and are informed of the current curriculum via a global variable. They load the corresponding data from.npy files and choose random elements from them until they fill the batch which is then returned.  
The models are compiled using mean squared error as the loss function and Adam as the optimizer. Metrics include mean squared error, position error, and orientation error. These last two metrics follow a custom implementation and require activating run_eagerly on the training to allow access to the ground truth and predicted values for each epoch. The custom metrics can be added to the training as metrics or as callbacks. The results are more precise in the first case as they are incorporated within each iteration of the internal loop, however, they are more time and resource consuming.  
The learning rate (LR) for every model is initially set to 0.1 and decreases progressively according to a modified version of the Keras callback ReduceLROnPlateau. This callback monitors one of the metrics and if no improvement is seen for a provided number of epochs, the learning rate is reduced by a factor. In this case, the callback has been modified to update the curriculum number if no improvement is found for the validation loss metric and the LR is at its minimum. When the curriculum number is changed, the LR goes back to its original value and starts decreasing again after a cooldown number of epochs. If the total number of curriculums is reached, the training stops. The pseudocode for this method can be seen in Algorithm 1.  
Figure 8: SimpleRnn: Recurrent Neural Network for learning Inverse Kinematics. It contains one hidden recurrent layer.  
The number of training iterations is set to 500 as a maximum. However, the training will stop following the logic of Algorithm 1 when no improvement is detected and the LR is at its minimum.  
Figure 9: LSTM: Recurrent Deep Neural Network for learning Inverse Kinematics. It contains LSTM layers, dense layers, and dropout layers in between.  
```
if\(\mathit{coddown\_counter}>0\)then \(\mathit{coddown\_counter}--1\) \(\mathit{wait}=0\) endif if\(\mathit{current\_validation\_loss}<\mathit{best\_validation\_loss}-\mathit{delta}\)then best_validation_loss \(\mathit{current\_validation\_loss}\) \(\mathit{wait}=0\) else if\(\mathit{coddown\_counter}\leq 0\)then \(\mathit{wait}+=1\) if\(\mathit{wait}\geq\mathit{patience}\)then if\(\mathit{current\_lr}>\mathit{min\_lr}\)then \(\mathit{new\_lr}=\mathit{current\_lr}*\mathit{factor}\) \(\mathit{new\_lr}=\mathit{max}(\mathit{new\_lr},\mathit{min\_lr})\) \(\mathit{wait}=0\) \(\mathit{coddown\_counter}=\mathit{coddown}\) else if\(\mathit{current\_curriculum}<\mathit{total\_curriculum}\)then \(\mathit{current\_curriculum}+=1\) \(\mathit{new\_lr}=\mathit{max\_lr}\) \(\mathit{wait}=0\) \(\mathit{coddown\_counter}=\mathit{coddown}\) else if\(\mathit{current\_lr}==\mathit{min\_lr}\)then stop training endif endif endif endif endif
```  
**Algorithm 1** method on_epoch_end for callback class UpdateLRCurriculumOnPlateau