Concepts / Creating a Custom Dataset for Instruction Data

Creating a Custom Dataset for Instruction Data

Each split is loaded by creating an InstructionDataset for it and then wrapping that Dataset in a DataLoader.

  • Programming

Three Splits, One Repeated Pattern

Instruction fine-tuning works with three separate splits of data: training data, validation data, and test data. Each split has to reach the model in batches, and the code that does this follows one repeated pattern. For each split, you first wrap the raw data in a custom Dataset object, then pass that Dataset to PyTorch's DataLoader along with the settings that control how batches are formed.

The goal of this article is not to memorize a setup listing line by line. The goal is to learn to read such a listing so that, for any loader, you can tell which data it reads, how it groups that data into batches, and how its ordering and parallelism are set.

What do you think happens?

Suppose a split has 7 examples, batch_size is 3, and shuffle=False with drop_last=False. How many examples are in the final batch, and does shuffling change that count?

  • The final batch has 3 examples, and shuffling changes it

  • The final batch has 1 example, and shuffling does not change the count

  • The final batch is dropped, because 7 is not divisible by 3

Reveal answer
Answer:

The final batch has 1 example, and shuffling does not change the count.

Seven examples split into batches of 3 gives two full batches of 3 (6 examples) and one leftover example. With drop_last=False, that leftover example is kept as a smaller final batch. Shuffling only changes which examples land in each batch, not how many examples there are, so the final batch still holds 1 example.

Tracing One Split from Raw Data to Batches

Each split follows the same two steps. First, a dataset is created from the split. In the listing this article is based on, that Dataset is an InstructionDataset, a custom Dataset class built for instruction data. Its constructor takes the raw split and a tokenizer, as in InstructionDataset(train_data, tokenizer). Second, that dataset is wrapped in a DataLoader, which produces the batches the model consumes.

The DataLoader does not know how instruction data is stored. It relies on the Dataset to supply individual examples. The Dataset answers the question where do the examples come from, while the DataLoader answers how many examples go together and in what order they are handed out.

python
Notes on the code
  • InstructionDataset wraps the raw training split and the tokenizer
  • DataLoader receives the dataset as its first argument
  • batch_size sets how many examples form one batch
  • collate_fn names the function that assembles a list of examples into a batch
  • shuffle, drop_last, and num_workers control ordering, batch completeness, and parallel loading

Reading a DataLoader Call Argument by Argument

A DataLoader needs two inputs: a Dataset instance and a batch_size. The Dataset tells the loader where the examples come from, and batch_size tells it how many examples to group together. The other keyword arguments adjust how batches are formed and loaded. In the listing this article follows, every DataLoader call passes the same set of keyword arguments after the dataset, and each one changes a different part of the loading behavior.

ArgumentWhat it controlsRole in this listing
datasetThe Dataset instance the loader reads examples fromEach split's InstructionDataset
batch_sizeHow many examples are grouped into one batchShared across the three loaders
collate_fnHow a list of individual examples is assembled into a batchShared across the three loaders
shuffleWhether the order of examples is randomizedTrue for training, False for validation and test
drop_lastWhether an incomplete final batch is discardedTrue for training, False for validation and test
num_workersHow many worker processes load data in parallel; 0 means no parallel processingControls parallel loading

The arguments in a DataLoader call and the role each one plays

To read a call, start with the first argument to find the dataset, then check batch_size for the group size. Next, look at shuffle and drop_last, which decide the order and the completeness of the batches. Finally, look at num_workers to see whether loading happens in parallel. Reading the call in this order lets you answer for any loader which data it reads and how that data is grouped.

Following Indices Through shuffle and drop_last

Consider a training split with 7 examples, numbered by their dataset index from 0 to 6, and a loader with batch_size=3, shuffle=True, and drop_last=True. Shuffling changes the order in which indices are visited, so the same examples may be grouped differently on a different pass. The grouping below is one possible result for a single pass.

Worked example

One shuffled pass with drop_last=True

Seven examples (indices 0 through 6), batch_size=3, shuffle=True, drop_last=True. Which indices form each batch, and which are discarded?

  1. 1
    Count the full batches

    Seven examples divided into groups of 3 gives two full batches, which hold 6 examples, and 1 leftover example.

  2. 2
    Shuffle the visiting order

    With shuffle=True the indices are visited in a randomized order. For this pass the order is 4, 0, 6, 2, 5, 1, 3.

  3. 3
    Fill batch 1

    The first three indices in the shuffled order are 4, 0, and 6, so batch 1 contains examples 4, 0, and 6.

  4. 4
    Fill batch 2

    The next three indices are 2, 5, and 1, so batch 2 contains examples 2, 5, and 1.

  5. 5
    Apply drop_last

    The leftover index 3 does not fill a complete batch. With drop_last=True it is discarded for this pass.

Result

Batch 1 holds indices 4, 0, 6. Batch 2 holds indices 2, 5, 1. Index 3 is dropped for this pass.

index 4batch 1index 0batch 1index 6batch 1index 2batch 2index 5batch 2index 1batch 2index 3droppednext in ordernext in ordernext batchnext in ordernext in order
When shuffle=True and drop_last=True are set, which dataset indices end up in each batch, and which leftover sample is discarded?

The diagram shows the key point of this section. Shuffling decides which indices share a batch, and drop_last decides what happens to the remainder. Index 3 is not lost because of the shuffle itself; it is lost because the number of examples did not divide evenly into full batches and drop_last discarded the incomplete group.

What num_workers Changes in the Loading Flow

num_workers controls parallel data loading. A value of 0 means there is no parallel processing: examples are loaded in the main process. Higher values allow loading to be spread across worker processes, and whether those higher values work depends on operating system support.

The path a batch takes is the same regardless of num_workers. Examples come from the Dataset, pass through the collate function that assembles them into one batch, and the resulting batch is handed to the training loop. What num_workers changes is where the reading of examples happens: with 0 it happens in one process, and with more workers the reading can proceed in parallel before the batches reach the training loop.

Datasetsupplies single examplesLoading workersnum_workers controls howmanyCollate functionassembles examples into onebatchBatchbatch_size examplesTraining loopreceives the batchexamples readexamples passedone batch builtbatch delivered
How do worker processes move samples from the Dataset through the collate function to the training loop, and how does num_workers change that flow?

The diagram is a simplified model. The source confirms only that num_workers controls parallel loading and that 0 means no parallel processing. It does not describe the internal mechanics of worker processes, so treat the middle node as the place where num_workers acts, not as a full description of how it is implemented.

Mistakes When Setting Loader Options

  • Common mistake

    Treating shuffle as a setting that changes how many examples there are

    What it looks like

    Expecting a 7-example split with batch_size=3 to produce three full batches after shuffling

    Why it fails

    Shuffle only changes the order of visiting examples. The count of examples and the count of full batches are determined by the dataset size and batch_size.

    Do this instead

    Count the batches from the dataset size and batch_size, then use shuffle to decide which examples fill them.

  • Common mistake

    Leaving shuffle=True on validation or test loaders

    What it looks like

    Copying the training loader's arguments into the test loader unchanged

    Why it fails

    The source's settings for these loaders are shuffle=False and drop_last=False. Keeping the training values changes the ordering and drops examples from the evaluation data.

    Do this instead

    Set shuffle=False and drop_last=False for validation and test loaders, as the source does.

  • Common mistake

    Assuming a higher num_workers is always better

    Why it fails

    The source says higher values depend on operating system support, and 0 is the setting that means no parallel processing.

    Do this instead

    Start from num_workers=0 and only raise it when the environment supports it.

  • Common mistake

    Forgetting that the Dataset supplies the examples

    Why it fails

    The DataLoader does not know how instruction data is stored. If the Dataset is not built correctly, the loader has nothing correct to batch.

    Do this instead

    Check that each split's InstructionDataset is created from the right split before wrapping it in a loader.

Building the Train, Validation, and Test Loaders

The three loaders share a batch size and a collate function, so the differences between them come down to the dataset each one wraps and the two flags that change ordering and batch completeness. The training loader shuffles and drops incomplete batches, while the validation and test loaders keep a fixed order and keep every example.

python
Output (expected)
No output is printed; the three loaders are created and ready to iterate.
Notes on the code
  • Each split gets its own Dataset and its own loader
  • batch_size and collate_fn are identical across all three loaders
  • Only shuffle and drop_last differ between the training loader and the other two
train_loadershuffle=True,drop_last=Trueval_loadershuffle=False,drop_last=Falsetest_loadershuffle=False,drop_last=False
How do the train, validation, and test loaders differ in their shuffle and drop_last settings while sharing the same batch size and collate function?

The comparison shows that only the training column differs in its loading flags. A reader who understands this pattern can look at any new loader call and check first whether it matches the training pattern or the evaluation pattern.

Practice Reading a Loader Call

MEDIUM

A loader is created as DataLoader(test_dataset, batch_size=8, collate_fn=my_collate_fn, shuffle=True, drop_last=True, num_workers=0). Identify the dataset it wraps, the batch size, and whether its ordering and completeness match the source's pattern for a test loader. Explain what you would change and why.

Hints
  • The first positional argument is the dataset, so look for the name passed right after DataLoader(
  • Compare the shuffle and drop_last values with the source's settings for validation and test loaders
  • Think about whether shuffling a test split changes the examples it contains or only the order they are visited in

Key Takeaways

  • Each split is loaded by creating an InstructionDataset for it and then wrapping that Dataset in a DataLoader.
  • A DataLoader requires a Dataset and a batch_size; collate_fn, shuffle, drop_last, and num_workers adjust how batches are formed and loaded.
  • shuffle changes the order in which examples are visited and drop_last decides whether an incomplete final batch is discarded.
  • num_workers controls parallel loading, with 0 meaning no parallel processing and higher values depending on operating system support.
  • The training loader uses shuffle=True and drop_last=True, while validation and test loaders use shuffle=False and drop_last=False, sharing batch size and collate function.

Related concepts

More concepts starting with C