I implemented self attention! I will try to explain here, but will do a terrible job: basically, what that is, is it lets the model decide what tokens in the input are more important than the others. The first thing I did was scrap the wavenet model, and switched to a simple bigram model. The second thing I implemented was bag of words, which edits the input tokens so every element is the average of that element and all that came before it. This lets all of the tokens “talk” to eachother. This is all fine and dandy but since all the things are averaged then you don’t know where things came from, and positional data is lost, so we lose a lot of resolution and data, so that sucks. So we have to encode positional data. So instead of just averaging all the elements that came before, we expand each averaged element into a list, which has all the elements in a row instead of averaging them into one number. So the first row could be [1, 0, 0] and the second [1, 2, 0] and the third [1, 2, 3], etc. We do this by masking it with the tril function, from numpy (very cool). But this is problematic, because all of the elements are given the exact same weight. A letter 34 characters back gets the same weight as the last character in the input (which is the letter immediately preceding the predicted letter, the output). To fix this, we add self attention! This is modeled after the groundbreaking paper Attention is All You Need, which started the whole AI hype thing. How it works is each token has a linear layer (that multiplies it by learned weights) called the key, and another called the query. The query is kind of like what that token is looking for, and the key is kind of like what that token has. And these can be multiplied with the keys and queries of all the other tokens, and that lets you know which token has the stuff that the most other tokens are looking for, and is thus more important and can be given more weight. That is a single head of attention, there are multiple heads that can specialize in different things. This, in theory, should increase performance. But it also drastically increases the amount of time it takes to train. The model only has ~56k parameters, which is less than half of the wavenet model, but takes a lot more time to do it’s thing. This is the output from the results of more than 13 hours of training. As you can see from the loss function, the loss was decreasing at a steady rate, so more training could probably improve it. Plus, this was at a highish learning rate the whole time (.1) so decreasing it would probably further improve it. But I can’t do anything on my computer while this is training or it runs out of RAM, and I have to use my computer now, so I will be moving on for now.