Neural Networks
Logistic regression model has an important limitation. It is a linear model. Each feature is multiplied by some constant parameter and the results are just summed up into the logit.
z=w0+w1⋅x1+w2⋅x2+...+wn⋅xnThat means a couple of things:
- The effect of a feature on the logit is always strictly proportional to its value. If one character adds
2to the logit, ten characters add20. However, more characters don't always mean the message is more likely spam. - The effect of a feature on the logit is isolated. If we have 2 occurrences of
free, it always adds the same value to the logit. However,freein isolation might not be that spammy compared to having bothfreeandmoneyin the same message.
Decision boundary
To make it easier to illustrate the non-linearity problem, let's look at a model with one feature (number of characters) and a small number of training examples.
In this training set, the messages are spam when they are too short or too long, and not spam when they have a medium length.
We can't fit this training set with our model, because the decision boundary is always a single point, regardless of how we change the parameters.
So the maximum accuracy we can reach on this dataset is only 67%. This is another cause of underfitting.
We could make the model more flexible by manually changing the logit formula. E.g. square some features (x12) or multiply together (x1⋅x2). This technique is called feature engineering.
However, it does not scale well, with more features the number of combinations explodes, especially for large models like LLMs. Instead, we will use neural networks to address these issues.
Neural network model
The core idea is to stack many simple functions on top of each other.
For example, we can take our current model and make three different logistic regression functions instead of one:
a1[1]a2[1]a3[1]=σ(w1,0[1]+x1w1,1[1]+x2w1,2[1]+⋯+x30w1,30[1])=σ(w2,0[1]+x1w2,1[1]+x2w2,2[1]+⋯+x30w2,30[1])=σ(w3,0[1]+x1w3,1[1]+x2w3,2[1]+⋯+x30w3,30[1])And then combine the results into another final function:
y=σ(w1,0[2]+a1[1]w1,1[2]+a2[1]w1,2[2]+a3[1]w1,3[2])This is a neural network with four neurons and two layers.
The number of inputs and outputs is the same, but we have more parameters now. So we use wjk[l] notation to describe different parameters on different neurons:
- l is the layer of the neuron
- j is the neuron's index in the current layer
- k is the feature's index or the index of the input neuron from the previous layer
With the neural network the function graph is more flexible, we have two decision boundaries now and can reach 100% accuracy on the same dataset.
Training the neural network
The training algorithm is the same, but we have more derivatives to calculate now. The loss function is bigger as well, since it consists of multiple functions stacked across neurons.
We should apply the same chain rule to calculate the derivatives with respect to each parameter. For example for our small neural network with two layers:
- The output neuron derivatives over each parameter will be:
- The hidden layer neurons derivatives over each parameter will have a longer chain:
Testing the model
Our simple neural network is called a Multilayer Perceptron (MLP) where every neuron is connected to every neuron in the next layer.
Using the neural network the accuracy increased to 96%.
Here is how the model behaves for any text message:
There are still a lot of potential improvements we could make. For example: using more data, using more features, presenting inputs differently, scaling the neural network. But these are just implementation details that do not change the core idea.
So we will leave the spam filtering model as it is and return to our original problem in the next section: building an LLM.