Batching and Training Loops in PyTorch
The DataLoader class from torch.utils.data produces batches from a dataset for training, validation, and testing.
Why Training Reads Data in Batches
Training a model on a dataset rarely means handing the model every sample at once. Instead, the samples are fed in groups called batches, and each pass of the training loop works on one batch at a time. A data loader is the object that produces these batches from a dataset. In PyTorch, the DataLoader class from torch.utils.data does this job. The source for this lesson shows it being configured for three separate datasets: training, validation, and testing.
This article starts from a working configuration and asks what each argument does. You will form a prediction about the batches a loader produces, then check that prediction against the rules that govern the DataLoader class. The goal is not to memorize a template. The goal is to be able to read any DataLoader call and say what batches it will produce.
What do you think happens?
A dataset has 10 samples and batch_size is 3. If drop_last is True, how many batches does one pass of the loop receive?
Reveal answer
3 batches
With batch_size 3, the first three batches hold 3 samples each, which is 9 samples. The 10th sample forms a final partial batch of size 1. Because drop_last is True, that smaller final batch is never yielded, so only 3 batches come out. Without drop_last, the same loader would yield 4 batches.
The Five Arguments of a DataLoader
The DataLoader class is defined by a set of arguments. The general form given in the source is DataLoader(dataset, batch_size, shuffle, num_workers, drop_last). Each argument controls one aspect of the batches the loop receives. The dataset is the source of samples. The other four arguments are the levers: batch_size sets how many samples go into each batch, shuffle controls whether the samples are reordered, num_workers sets how many data-loading subprocesses run, and drop_last controls whether a smaller final batch is discarded.
Because each argument affects a different part of what the loop eventually receives, the parameters are best learned as a set of separate levers rather than as one combined rule. When a batch looks wrong, you do not need to change everything. You need to find the one lever whose effect matches the symptom.
How batch_size Splits Samples into Groups
The batch_size argument sets the number of samples in each batch. Think of the loader as walking through the dataset in order and cutting it into consecutive slices of that size. The diagram below shows a dataset of 10 samples, indexed 0 through 9, with batch_size set to 3.
Splitting 10 samples with batch_size 3
A dataset has 10 samples, indexed 0 through 9. A loader is created with batch_size=3 and drop_last=False. Which samples are in each batch, and how many batches does one pass yield?
- 1Start with the first batch
The loader takes the first
batch_sizesamples in order: indices 0, 1, and 2. - 2Continue in slices of 3
The next slices are indices 3, 4, 5 and then 6, 7, 8.
- 3Handle the leftover
Only index 9 remains. It is smaller than
batch_size, so it forms a final partial batch of one sample. - 4Apply drop_last
drop_lastis False, so the partial batch is yielded like any other batch.
Four batches are yielded: [0, 1, 2], [3, 4, 5], [6, 7, 8], and [9]. The batch sizes are 3, 3, 3, and 1.
Notice that the batch sizes are not always equal. The last batch can be smaller than batch_size whenever the dataset size is not an exact multiple of batch_size. This is the situation that drop_last is designed to handle.
What drop_last Removes from a Pass
The drop_last argument is the one most likely to surprise a learner, because it changes the amount of data a single pass uses without changing the dataset itself. When drop_last is True, a final batch smaller than batch_size is never yielded, so the samples in that batch are skipped for that pass. When it is False, the smaller batch is yielded like any other.
How shuffle Changes Sample Order
The shuffle argument controls whether data is shuffled. When shuffle is enabled, the samples are reordered before they are grouped into batches, so the same samples can land in different batches from one pass to the next. Without shuffling, the loader keeps the dataset's original order, and the same grouping appears each time.
The sample orders shown in the diagram are illustrative values chosen for this lesson, not output from a real run. What matters is the pattern: with shuffle enabled, consecutive passes can group the same samples differently, while the set of samples in the dataset stays the same.
How num_workers Loads Batches
The num_workers argument sets the number of data-loading subprocesses. These subprocesses are separate from the main process that runs the training loop. Their job is to prepare the data, so the loop has batches available to consume. The data flows from the dataset to the worker subprocesses, which produce batches, and then the training loop consumes those batches one at a time.
The source describes num_workers only as the number of data-loading subprocesses. It does not walk through the details of queueing. So when reasoning about a loader, treat num_workers as the setting that controls how many subprocesses load data, and keep it separate from batch_size and drop_last, which decide the content and count of the batches themselves.
Comparing the Training, Validation, and Test Loaders
Placing the three calls side by side makes the configuration choices easier to see. Most arguments are shared, and the differences are deliberate. The table below lists what each loader receives from the source listing.
| Loader | batch_size | num_workers | shuffle | drop_last |
|---|---|---|---|---|
| Training | shared setting | shared setting | True (passed explicitly) | True |
| Validation | shared setting | shared setting | not passed | not passed |
| Test | shared setting | shared setting | not passed | not passed |
Arguments passed to each DataLoader in the source listing. Shared settings are batch_size and num_workers, defined once for all three loaders.
The pattern is that only the training loader is shuffled and only the training loader drops its final partial batch. The source shows these settings without giving the reasoning behind them, so treat the table as a record of this configuration rather than a rule for every project. For the validation and test loaders, shuffle is simply not passed, so their order follows whatever default the DataLoader class uses when that argument is omitted. The source does not state that default, so check the DataLoader documentation before relying on it.
Trading Off Batch Size Against Batch Count
Changing batch_size changes how many batches a pass contains. Because each pass of the training loop works on one batch at a time, the number of batches per pass also determines how many times the loop steps through the data. The table below compares a dataset of 12 samples at two batch sizes, with drop_last set to False.
| Setting | Batch size | Batches per pass | Samples in each full batch |
|---|---|---|---|
| Smaller batches | 3 | 4 | 3 |
| Doubled batches | 6 | 2 | 6 |
Doubling batch_size on 12 samples with drop_last=False halves the number of batches per pass, because each batch now holds twice as many samples.
The source does not discuss how batch size affects training outcomes, so this article limits itself to the counting consequence. If the loop takes one step per batch, then doubling batch_size roughly halves the number of steps per pass, and each step handles twice the samples.
Tracing an Unexpected Batch Count
When batches are unexpected, the source suggests checking each argument against its effect, starting from the one whose behavior matches the symptom. A wrong sample order points to the shuffle step. A batch with an unexpected number of samples points to batch_size. A missing final batch points to drop_last. Use the lookup below as a quick trace.
Common mistake Assuming the last batch is always full
What it looks likeA dataset of 10 samples with batch_size 3 ends with a batch of 1, not 3.
Why it failsThe final batch holds whatever samples remain, which is smaller than
batch_sizewhen the dataset size is not an exact multiple of it.Do this insteadCheck whether the leftover is yielded or dropped by looking at drop_last, and count the partial batch when predicting batch sizes.
Common mistake Expecting a missing batch to mean the data was deleted
What it looks likeWith drop_last=True, sample 9 never appears in a pass, but it is still in the dataset.
Why it failsdrop_lastonly controls what the loop receives from a pass. It does not remove samples from the dataset.Do this insteadLook at drop_last as the reason a short final group disappeared from the batch stream.
Common mistake Changing several arguments at once to fix a batch problem
Why it failsWhen several settings change together, you cannot tell which one caused the difference.
Do this insteadIdentify the argument whose effect matches the symptom and change only that one.
Common mistake Reading shuffle as a setting that applies to all three loaders in the listing
A common surprise is a batch count that is one lower than expected. Before suspecting the dataset, check whether drop_last is set on that loader. The training loader in the source is the one with drop_last set, so a shortfall there has a different cause than the same shortfall in the validation or test loader.
Predicting Batches for a New Configuration
A dataset has 17 samples. A loader is created with batch_size=5 and drop_last=True. How many batches does one pass yield, and what is the size of each batch? Then say what would change if drop_last were False.
Hints
- Divide 17 by 5 to find how many full batches fit, then find the number left over.
- The leftover samples form a final batch smaller than
batch_size. drop_lastdecides whether that smaller final batch is yielded.
Key Takeaways
- The DataLoader class from torch.utils.data produces batches from a dataset, so each pass of the training loop works on one batch at a time.
batch_sizesets the number of samples in each batch, shuffle controls whether samples are reordered,num_workerssets the number of data-loading subprocesses, anddrop_lastcontrols whether a smaller final batch is dropped.- With
drop_lastTrue, a final batch smaller thanbatch_sizeis never yielded, so its samples are skipped for that pass, but they remain in the dataset. - When batches look wrong, change one argument at a time: wrong order points to shuffle, unexpected batch size points to
batch_size, and a missing final batch points todrop_last.