 So here we can go back and see the blocks that we referred to that are new with this version We haven't made a big deal out of them because they're not super complex But I do like showing how straightforward it is to create a new block It's a class. It doesn't subclass anything other than just the Python object and It has a forward pass and a backward pass and if you're doing it right it has a dunder string method That's all it really needs So here for our one-hot class it has a number of categories So we can specify that it's going to expect four categories for each pass we initialize the result so our zeros of length four and then we can look at our dictionary of categories we can pull out the keys and we can say hey if our label is in our list of category keys already then great we find out what position is associated with that and Put a one in that position But if it's not we can look at how many categories we have so far and If that's less than our number of categories we still have room to add more categories then we can go into our categories add that label Add the position that goes with it, which is the number of categories so far that's the next free position and Then we can set that position equal to one in the result and then pass that on so that's a way to create a one-hot array out of a sequence of labels and The only thing you need to know is the number of labels that you expect beforehand and If you don't know the number of labels that you expect then you can choose a number that's larger than what you expect to ever see and Fill in as many of those as you need On the backward pass this doesn't do anything This is something we might want to change in the future for making predictions So if we pass it a one-hot array, it'll return the label associated with it But for now, we're just gonna leave it leave it blank We also have here our flatten block Again, the structure is a class with the forward pass and a backward pass and a dunder string method What it does is it keeps track of the shape So if it gets an input it notes the shape of that input and then it uses the NumPy's Ravel function to spin that out into a one-dimensional array and Then it does take and make it a two-dimensional array with one row and spread it all out across columns This suits it for use in a linear block and a dense block and this is the default representation for the structure the way I've built it Then on the backward pass it can invert this flattening operation. So if it gets an array of The same size that it passed out It'll take it and reshape it according to the input shape and then pass it back the other direction So in reverse, it's a nice reshape command based on the shape of the original array The other piece that we're introducing for the first time here is the logger for logging values in this instance There's a number of arguments that we can pass it most of these control how the graph is created that summarizes it But the core function here is that when it's passed a new value it logs it It appends it to a list it adds one to the number of iterations that it counts on and then Periodically it takes and will generate a report. So it'll update the plot and save that plot out Also, it'll write the complete history to a CSV file the function for creating the plot report takes the values and Does some smoothing? It interprets the options It interprets the arguments for whether to make it a log scale For how to set the minimum and maximum value of the plot and then it creates that plot and saves it out and Then the write function takes that list and generates a CSV and writes it And we'll look at examples of those outputs when we run our example