Welcome to your first lesson! We're kicking off your journey to mastering Large Language Models by going back to where it all began. Today's goal is to trace the evolution of language models, starting from their simple statistical origins and understanding why the field shifted towards the neural network-based approaches that dominate today.
This foundational knowledge is crucial. Understanding the limitations of early models helps you appreciate why modern architectures like the Transformer were developed and why they are so powerful. This is the first step in building the deep intuition required to become a top-tier AI engineer.
Let's begin by exploring the fundamental idea of language modeling.
What is a Language Model?
At its core, a language model (LM) is a system that calculates the probability of a sequence of words. A primary task for an LM is to predict the next word (or, more technically, token) in a sequence, given the words that came before it. You see a simple version of this every day with your phone's autocomplete feature.
Formally, given a sequence of words , the model aims to compute the probability distribution over the entire vocabulary for the next word, :
This seemingly simple prediction task is the foundation upon which almost all modern Natural Language Processing (NLP) is built. A model that can do this well has implicitly learned the grammar, semantics, and common sense of a language.
The Statistical Era: N-Gram Models
The earliest successful language models were statistical. They didn't "understand" language in a human sense; instead, they relied on counting word frequencies in massive text corpora. The most common approach was the n-gram model.
To get a quick and clear overview of n-grams, from unigrams to bigrams, please watch the first few minutes of the following video.
The Origin of Language Models (like ChatGPT)
This video from CodeEmporium provides a concise, animated explanation of how n-gram models work, starting from Claude Shannon's initial ideas.
Watch from the beginning until the 5:45 mark. Focus on understanding the difference between unigram and bigram models and how moving from characters to words improves the quality of generated text.
As the video explained, an n-gram model makes a simplifying assumption known as the Markov assumption: the probability of the next word depends only on the previous n-1 words.
- A bigram model (
n=2) assumes the probability of a word depends only on the single word that precedes it: . - A trigram model (
n=3) uses the two preceding words: .
These probabilities are calculated using Maximum Likelihood Estimation (MLE), which is just a formal way of saying "count and divide":
For a more detailed summary of n-grams and their critical limitations, please read the first part of the following article.
From N-Grams to Transformers: Tracing the Evolution of ...
This article, 'From N-Grams to Transformers', provides a clear narrative of the evolution we're discussing. We'll start with the section on n-grams.
Read the 'Introduction' and section '1. N-Gram Models'. Pay close attention to the 'Why it fell short' part, as this motivates the entire shift to neural models.
The Downfall of N-grams
As you just read, while n-gram models were simple and effective for certain tasks, they had fundamental flaws that prevented further progress:
- Data Sparsity: If a valid bigram (e.g., "machine learning") never appeared in your training text, the model would assign it a probability of zero. This means the model is incapable of generating novel yet plausible phrases. Techniques like smoothing were developed to mitigate this, but they are essentially patches on a flawed foundation.
- Limited Context: An n-gram model has a fixed and very small context window (typically
n=2or3). It cannot capture long-range dependencies. Consider the sentence: "The man who grew up in France and lived there for 20 years speaks fluent ___." A bigram model only sees "fluent" and has no idea that "France" appeared much earlier. - No Semantic Understanding: The model treats words as discrete, isolated symbols. It has no concept that "dog" and "puppy" are semantically similar. If it learned "the cute dog," it has no way to generalize that knowledge to "the cute puppy."
Test your understanding!
Consider the sentence: "The car is red, but the bike is ___." A human would likely predict a color like "blue" or "green". Why would a simple bigram model struggle to make a sensible prediction here, even if it was trained on a massive corpus?
Show answer
A bigram model only considers the preceding word, which is "is". It would predict the most likely word to follow "is" based on its training data (e.g., "a", "the", "not"). It has no memory of the earlier parts of the sentence, like "car is red" or "bike", which provide the crucial context that another color is expected. This demonstrates the limitation of its fixed, short context window.
These limitations created a ceiling for what was possible with statistical methods, paving the way for a new paradigm: neural language models.
The Shift to Neural Language Models
Instead of just counting co-occurrences, neural networks approach language modeling as a learning problem. The goal is still to predict the next word, but the method is fundamentally different. This new approach directly addresses the shortcomings of n-grams by learning continuous representations of words (known as word embeddings) that capture semantic meaning.
To see this evolution in action, we will now dive into a hands-on example from Andrej Karpathy's "makemore" series. This video is exceptional because it builds a simple character-level bigram model in two ways:
- The "classic" statistical way (counting and normalizing).
- The modern neural network way (gradient-based optimization).
By the end, you will see that both approaches can solve the same simple problem, but the neural approach is infinitely more flexible and scalable, which is why it has taken over the field. Given your experience with PyTorch, you will be able to follow the implementation details closely.
Deep Dive: From Counting to Learning
We will walk through the video in stages. The core idea is to build a character-level model to generate name-like words.
Part 1: The Statistical Bigram Model
First, let's see how to build a bigram model by counting. In this section, Karpathy loads the data, counts character pairs, stores them in a PyTorch tensor, and normalizes the counts to get probability distributions. He then samples from these distributions to generate new names.
The spelled-out intro to language modeling: building makemore
Watch Andrej Karpathy build a statistical bigram model from scratch. This demonstrates the count-and-normalize approach we discussed.
Watch from 03:06 to 36:14. Focus on how the 2D tensor of counts is constructed and then how each row is normalized to create a probability distribution for the next character.
Part 2: The Neural Network Reframing
Now for the crucial shift. Karpathy reframes the exact same problem in a neural network framework. Instead of explicitly counting, we will define a model whose parameters (weights) we can optimize to learn the probabilities.
This section covers:
- Creating a training set of input-output pairs (
(character_1, character_2)). - One-hot encoding the input character to feed it into a network.
- Defining the simplest possible neural network: a single linear layer, which is just a weight matrix
W. - Applying the softmax function to the output of the linear layer (the "logits") to produce a valid probability distribution.
The spelled-out intro to language modeling: building makemore
This is the conceptual heart of the lesson. Watch how the problem is reformulated for a neural network.
Watch from 01:03:08 to 01:28:07. Pay close attention to the role of the weight matrix W and how softmax turns the raw output (logits) into probabilities. The expression logits = x_enc @ W is the fundamental operation.
Notice the key insight here: when you multiply a one-hot encoded vector by a weight matrix W, you are effectively just selecting a specific row from W. This means the weight matrix W is serving a similar role to the count-based table we built earlier, where each row corresponds to a starting character.
Part 3: Optimization and The Big Connection
We now have a model and a way to get probabilities from it. But how do we find the right values for our weight matrix W? We use gradient descent.
This final section shows how to:
- Calculate the negative log-likelihood of the correct next characters. This is our loss function.
- Perform the backward pass to get the gradients of the loss with respect to
W. - Update
Wto minimize the loss. - Finally, Karpathy reveals the beautiful connection: the optimized
Wfrom the neural network is mathematically equivalent to the log-counts from the statistical model. The neural network learned the statistical properties of the data.
The spelled-out intro to language modeling: building makemore
This section ties everything together, showing how gradient descent arrives at the same solution as counting, and explaining why the neural approach is superior.
Watch from 01:28:07 to 01:57:44. Focus on understanding why the negative log-likelihood is a good loss function and the final summary of why the neural network approach is more scalable.
The key takeaway is that while the statistical approach is simple and direct for this bigram case, it's a dead end. We cannot feasibly create a "count table" for a 10-gram model because the number of possible 9-word prefixes is astronomical. The neural network framework, however, is incredibly flexible. We can make the network more complex to handle more context without changing the fundamental process of optimization via gradient descent. This scalability is what enabled the transition to more powerful models.

Test your understanding!
For a simple bigram character model, we saw that both statistical counting and a simple neural network can arrive at the same result. Why is the neural network approach considered vastly more powerful and scalable for language modeling in general?
Show answer
The statistical approach of counting n-grams suffers from the "curse of dimensionality." As the context size n increases, the number of possible n-grams explodes exponentially, making it impossible to store and count them all. The neural network approach, however, doesn't store explicit counts. It learns a compressed representation of the context in its weights. We can scale the model to handle larger contexts by making the network deeper or more complex (e.g., using RNNs or Transformers), which is far more feasible than building an exponentially larger count table.
Conclusion
In this lesson, we traced the critical first step in the evolution of language models.
- We started with statistical n-gram models, which predict the next word by counting occurrences in a text corpus.
- We identified their fundamental limitations: data sparsity, a rigid and short context window, and an inability to understand semantic similarity.
- We then saw how the problem could be reframed in a neural network framework. By representing inputs and learning weights through gradient descent, a neural model can learn the same statistical patterns.
- Most importantly, we established that this neural framework, while equivalent in the simplest case, is far more scalable and flexible, opening the door to the complex architectures that power modern LLMs.
This first step on the staircase of language models is complete.

What's Next?
In the neural network we just explored, we used a simple one-hot vector -> weight matrix lookup. This is a crude way of representing words. The next major breakthrough was the development of word embeddings, which are dense vector representations that capture the rich semantic relationships between words.
In our next lesson, you will implement a simple word embedding layer and explain its role in capturing semantics. This is the next logical step from what we learned today and a core building block for all subsequent models.