Preparing Text Data for Training
Input-target pairs are the training examples used for LLM training, generated from tokenized data.
From Tokens to Training Examples
Before a language model can learn from text, the text has to be converted into a form the training process can use. Earlier steps in this chapter covered how raw text is broken into tokens. This article picks up at that point. You already have a sequence of tokens, and the question is how to turn that sequence into the examples a model actually trains on.
The chain to keep in mind is this: tokenized data goes in, a sliding window slides across it, and input-target pairs come out. The pairs are what the model is trained on. Each pair ties a piece of input text to the target the model should learn to associate with it.
What do you think happens?
If a text is split into tokens, and a window of fixed length slides across those tokens one position at a time, what do you think the learner's training examples look like?
Reveal answer
Each example is a window of tokens paired with the tokens that follow it
The sliding window produces input-target pairs. The input is a run of tokens, and the target is the matching run of tokens the model should learn to predict from that input.
Why Pairs Matter for Training
An input-target pair is a training example for an LLM. The input is a piece of tokenized text, and the target is the text the model should learn to associate with that input. The source defines these pairs by their purpose: they supply training examples.
Tokenized data is the input to this process, and input-target pairs are its output. The source applies the idea to tokens specifically. The window does not slide over raw characters. It slides over tokens, because tokens are the units the model already treats as discrete pieces. That is why tokenization comes first.
The sliding window approach moves a window across the token sequence to produce these pairs. A single token sequence can yield several pairs, because consecutive window positions overlap. The next section traces exactly how that happens.
Tracing the Sliding Window
Consider a small illustrative token sequence of eight tokens: the, story, was, short, and, clear, to, read. Use a window that holds four tokens and moves forward by one position at each step. The input for each pair is the four tokens inside the window. The target is the four tokens one position later, so that each target position is the token that follows the matching input position.
Step 0 pairs the input the, story, was, short with the target story, was, short, and. Step 1 moves the window one token forward. The input becomes story, was, short, and, and the target becomes was, short, and, clear. Notice that three of the four input tokens in step 1 were also in step 0. That overlap is why one token sequence can produce several pairs.
Producing a pair at one window position
The token sequence is the, story, was, short, and, clear, to, read. The window holds four tokens and starts at position 0. What is the input-target pair at that position?
- 1Identify the input
The window covers positions 0 to 3, which are the, story, was, short.
- 2Identify the target
The target is shifted one position forward, covering positions 1 to 4, which are story, was, short, and.
- 3Check the alignment
Each target token lines up with the input token one position before it. Story in the target follows the in the input, and so on across the window.
Input: the, story, was, short. Target: story, was, short, and.
Choosing a Small Public Text
The text used throughout this part is The Verdict, a short story by Edith Wharton. It was already used in chapter 2. Choosing it solves two problems at once. Because the story is in the public domain, there is no question about usage rights. Because it is small, the code runs on a standard laptop in a matter of minutes, even without a high-end GPU.
Size is the trade-off. A dataset this small cannot train a model that produces useful text on its own. The purpose here is education, so the code runs in minutes instead of weeks. Later in the workflow, pretrained weights from OpenAI are loaded into the model, which is how the small text is made useful in practice.
For scale, the source points to the 7 billion parameter Llama 2 model, a relatively popular openly available LLM. Training it required 184,320 GPU hours on A100 GPUs and processed 2 trillion tokens. A larger corpus is the route toward more extensive training, at a much higher computational cost.
Loading Text and Counting Characters and Tokens
The first code step reads the whole story into a single string. The file is opened in read mode with UTF-8 encoding, and file.read() returns its full contents. Once the text is in memory, it is measured in two different units. The number of characters comes from len(text_data). The number of tokens comes from passing the same text through the tokenizer and measuring the result.
- The file is opened in read mode with UTF-8 encoding.
file.read()returns the full contents as one string.len(text_data)counts characters.- Passing the same text through the tokenizer gives the token count.
The two numbers answer different questions. The character count describes the raw text. The token count describes how the model will actually read it. These are different counts, and the token count is the one that describes what the model reads. In the source's run, the text yields 5,145 tokens. That may look too small to train an LLM, and it is accepted here because the aim is quick educational runs.
Splitting Text with a Train Ratio
Next the text is divided into a training part and a validation part. The validation part is used for model evaluation during training, so it must be kept separate from the training part. The split is set by a train_ratio of 0.90, which means 90 percent of the text goes to training and the remaining 10 percent goes to validation. The source describes this split as a split index computed from train_ratio, and the two parts are never mixed.
- 1N is the total length of the text that is being divided.
- 2Multiply N by
train_ratioto find the training share, for example $0.90 \times N$. - 3Round down to a whole position, which becomes the cut point between the two subsets.
- 4Text before the cut point is the training subset, and text from the cut point onward is the validation subset.
Computing a split index
A text has N = 1000 units. The train_ratio is $0.90$. Where is the cut point, and how many units go to each subset?
- 1Compute the product
$0.90 \times 1000 = 900$.
- 2Set the cut point
The split index is 900, so positions 0 through 899 form the training subset.
- 3Find the validation share
Positions 900 through 999 form the validation subset, which is 100 units, or one tenth of the text.
The training subset has 900 units and the validation subset has 100 units.
From Split Text to Batched Tensors
A split subset is still plain text, and the model needs fixed-size tensors. The source describes the preparation as a chain of operations. The subset is tokenized. The token sequence is divided into chunks of a user-specified length. The chunks are shuffled. The shuffled chunks are organized into batches, where the batch size sets how many chunks are processed together.
The source uses a batch size of 2 because the dataset is small. It notes that training LLMs with batch sizes of 1,024 or larger is not uncommon in practice. Batch size is therefore a resource choice, and the small value here reflects the small dataset rather than a recommended setting for large-scale training.
Training Versus Validation Loader Settings
The loaders are built with the create_dataloader_v1 function from chapter 2. Both calls use the same batch size, max_length, and stride. The settings that differ are drop_last and shuffle, and those differences encode the training-versus-validation distinction. A random seed is also fixed so that the shuffling is repeatable.
| Setting | Training loader | Validation loader |
|---|---|---|
| shuffle | On, so the order of examples varies | Off, so evaluation uses a fixed order |
| drop_last | True, so every batch has the full size | False, so no validation chunk is thrown away |
| batch size | Same value in both | Same value in both |
| max_length and stride | Same value in both | Same value in both |
Loader settings that differ between training and validation, as described in the source
Setting drop_last to True on the training loader discards an incomplete final batch, so every training batch has the full size. The validation loader sets it to False, so no validation chunk is silently discarded. Shuffling is switched on for training, where the order of examples should vary, and switched off for validation, where a fixed order keeps evaluation consistent.
Checking Batch Shapes
The source suggests an optional check. Iterate through each loader and print the shape of every input and target tensor. Each loader yields a pair, an input x and a target y, so the loop unpacks two values per batch. The printed output confirms whether the loaders were built correctly.
In the source's printed output, the training loader yields nine batches, each with two samples of 256 tokens. The validation loader yields one batch of two input examples. This matches what the split and the batch settings predict, since only about a tenth of the text goes to validation.
A text has 5,145 tokens, the context length is 256 tokens per sample, and the batch size is 2. Using the training split of 90 percent, estimate how many full training batches you expect the training loader to yield, and check your estimate against the source's printed output of nine batches. Think about how many tokens the training portion contains and how drop_last affects an incomplete final batch.
Hints
- Start by estimating the training share: 90 percent of 5,145 tokens.
- Divide that training share by the number of tokens in one sample, then by the batch size.
- Remember that
drop_lastdiscards an incomplete final batch.
Mistakes Beginners Make When Preparing Data
Common mistake Treating the character count as the number the model reads
What it looks likeReporting len(text_data) as the size of the training input.
Why it failsThe character count describes the raw text. The token count describes how the model actually reads it.
Do this insteadMeasure the tokens with the tokenizer when you need the size the model sees.
Common mistake Mixing training and validation text
Why it failsThe validation part is used for evaluation during training, so it must stay separate from the training part.
Do this insteadCut the text once at the split index and build each loader from its own subset.
Common mistake Using the same shuffle and drop_last settings for both loaders
Why it failsShuffling for training varies the order of examples, while a fixed order keeps evaluation consistent.
drop_lastdiscards incomplete training batches, but it would also silently drop validation chunks.Do this insteadShuffle and drop the final incomplete batch only on the training loader.
Common mistake Assuming the windows do not overlap, when consecutive window positions share tokens and one sequence can yield several pairs
Practical Notes on Dataset Scale
Dataset choice is a matter of goal and constraints. A small public domain text answers the questions of licensing and speed, which matters when the aim is to learn the mechanics. A larger corpus is the route toward more extensive training, at a much higher computational cost.
Summary of the Preparation Chain
- 1Input-target pairs are the training examples for an LLM, and they are generated from tokenized data.
- 2A sliding window moves across the tokens, and consecutive positions overlap so one sequence yields several pairs.
- 3Characters and tokens are different counts, and the token count describes what the model reads.
- 4A split index computed from
train_ratiodivides the text into training and validation parts that are never mixed. - 5Split text is tokenized, chunked, shuffled, and batched, and the printed shapes confirm the loaders are correct.
At a glance
- Input-target pairs are the training examples for LLM training, generated from tokenized data by a sliding window.
- Consecutive window positions overlap, so a single token sequence can yield several pairs.
- The token count, not the character count, describes what the model reads, and a
train_ratioof 0.90 sends 90 percent of the text to training. - Split text is tokenized, chunked, shuffled, and batched, and the training and validation loaders differ in shuffle and
drop_last.