Concepts / Loading and Inspecting Instruction Datasets

Loading and Inspecting Instruction Datasets

The format_input function turns one dataset entry into a single prompt string that always includes an Instruction section.

  • Programming

Predicting the Prompt for an Entry

Before a language model can be fine-tuned, its training data has to be read into memory and checked. A dataset can load without any error and still have the wrong shape, the wrong column names, or a lopsided set of labels. Checking first is the difference between a training run you can trust and one you have to repeat.

Instruction datasets store each example as a small record with an instruction, an optional input, and an output. A function called format_input turns one such record into a single prompt string. Many records are instructions that stand alone, with nothing extra to work on, so the first question to settle is whether the formatted prompt should contain an Input section at all.

What do you think happens?

You format an entry whose input field is an empty string. Will the formatted prompt contain an Input section?

  • Yes, with an Input header and nothing under it

  • No, the Input section is left out

Reveal answer
Answer:

No, the Input section is left out.

The Input section is optional. It is added only when the entry's input field contains a non-empty value. A single test on the input field controls the branch, so an empty input means the formatter skips the whole Input half.

Tracing the Input Branch in format_input

The formatter makes one decision, and that decision is the only place where the output can change shape. It tests whether the input field is non-empty. If it is, the formatter adds an Input header and the input text. If it is not, that part of the output is skipped. Nothing else in the function changes between the two cases. This single test is what lets one function handle both kinds of entry without a separate template for each.

Dataset entryinstruction, input, outputInput fieldnon-empty?Add Input header andinput textJoin the halves intothe promptPrompt stringSkip the Inputsectionyesno
For a given dataset entry, the input field decides whether the Input section appears in the prompt. Both branches then join into the same prompt string.

Assembling the Instruction, Input, and Response

The formatter builds its output in two halves and then joins them. The first half always appears. It contains a fixed opening sentence, then an Instruction header, then the text taken from the instruction field. The second half is optional. It begins with a blank line, then an Input header, then the input text, and it exists only when the input field is non-empty.

Because both halves are plain strings, joining them is simply addition. The response is not built inside format_input at all. The caller attaches it after the prompt is returned. This design lets the same function produce prompts for inference, where no response exists yet, as well as complete training text, where the response is attached.

Instruction halfopening sentence,Instruction header,instruction textOptional input halfonly when input isnon-emptyJoinplain string additionAttach responseadded by the callerComplete trainingtextthenthenthen
The instruction half is always built first, the optional input half follows, the two are joined, and the caller attaches the response last.
Worked example

Tracing two entries through format_input

Entry A has an instruction and an empty input field. Entry B has an instruction and a non-empty input field. Trace how each one is assembled, then say which one contains an Input section.

  1. 1
    Build the instruction half for A

    The opening sentence, the Instruction header, and the instruction text are always built, so A's first half is complete.

  2. 2
    Test the input field for A

    The input field is empty, so the optional half is skipped. No Input header is added.

  3. 3
    Join and attach for A

    The first half is joined with nothing else, and the caller then attaches the response.

  4. 4
    Build the instruction half for B

    B's first half is built the same way as A's, with its own instruction text.

  5. 5
    Test the input field for B

    The input field is non-empty, so the optional half runs. It adds a blank line, an Input header, and the input text.

  6. 6
    Join and attach for B

    The two halves are joined, then the caller attaches the response.

Result

Entry B contains an Input section. Entry A does not. Both prompts share the same instruction half and the same opening sentence.

Loading the Spam File with read_csv

The example dataset is a collection of text messages. Each message has a label that says whether it is ham, meaning not spam, or spam. The dataset was saved earlier as a tab-separated text file named SMSSpamCollection.tsv inside a folder called sms_spam_collection. A tab-separated file uses tab characters, rather than commas, to divide one field from the next.

python
Notes on the code
  • data_file_path holds the location of the tab-separated file
  • sep="\t" tells pandas that a tab character separates one column from the next
  • header=None says the file has no header row to use as column names
  • names=["Label", "Text"] supplies the two column names directly

Each argument has a specific job. The sep argument tells pandas where one column ends and the next begins. Because header is set to None, pandas does not treat the first line of the file as column names, so the names argument provides them: Label for the first column and Text for the second. Writing df on its own line displays the table in a Jupyter notebook. Outside a notebook, print(df) gives a text version of the same table.

Reading the Shape and Contents of the DataFrame

A loaded DataFrame is a table with rows and columns. Its shape is written as rows by columns. The source reports the spam dataset as 5572 rows by 2 columns. The 2 matches the two named columns, Label and Text, that the read_csv call created. The 5572 counts the examples: each row is one text message together with its label.

Key point

Read the shape as two separate questions. The first number answers how many examples there are. The second answers how many fields each example has. If the second number is not what you expected, the column names or the separator are the first things to check.

Inspecting the shape and a few rows confirms that the load worked, before any deeper analysis. Only after the table looks right does it make sense to ask how the labels are distributed.

Counting Labels with value_counts

A classifier learns from examples of every class, so it matters whether one class has far more examples than the other. The df["Label"] part selects the single column of labels. The value_counts() method then counts how many times each distinct value appears in that column and returns the counts sorted from largest to smallest.

python
Output (expected)
A short listing with each label followed by its count, sorted from largest to smallest, and a footer naming the column and the type of the counts.
Notes on the code
  • df["Label"] selects the column of labels
  • value_counts() counts each distinct label

Read the output against the earlier prediction about the dataset. The source finds that ham is the far more frequent label. A large gap between the two counts is what the source calls a class imbalance, and that gap is the reason the next step, undersampling, is needed.

Why Imbalance Matters Before Fine-Tuning

If the training data holds far more ham than spam, the examples the model sees are dominated by one class. The source's reason for checking the counts is direct: a classifier learns from examples of every class, so a lopsided set of labels is a problem to fix before training begins, not after.

Undersampling to 747 per Class

Undersampling reduces the number of examples in the larger class so that the classes end up with equal counts. The source undersamples the dataset to include 747 instances from each class. The reasons it gives are simplicity and a preference for a small dataset, since a smaller dataset makes fine-tuning the LLM faster.

hammore than 747ham747spam747spam747reduced to 747unchanged
Before undersampling, ham has more examples than spam. After undersampling, both classes contain 747 instances. The spam class already had the target count, so nothing was removed from it.

The source says it uses a listing to perform the undersampling. That listing is not included in the material available for this article, so no code for it is reproduced here. What the source does establish is the goal of the step and the target count of 747 per class. Undersampling is one of several ways to handle class imbalance. The source acknowledges that other methods exist but treats them as beyond its scope, and it points readers to appendix B for them.

Locating Where a Prompt Goes Wrong

When a formatted string looks wrong, the bug is usually in one of a few predictable places. Work through format_input in the same order it runs, and stop at the first step whose output differs from what you expected.

  1. 1
    Check the instruction half: the opening sentence, the Instruction header, and the instruction text.
  2. 2
    Check the optional input half: whether it should be present, and if so, the blank line, the Input header, and the input text.
  3. 3
    Check the join: whether the two halves were combined in the right order with nothing missing or doubled.
  4. 4
    Check the response: confirm the caller attached it after the prompt, since the function never adds it.
  • Common mistake

    Expecting format_input to contain the response

    Why it fails

    The response is not built inside format_input. The caller attaches it after the prompt is returned.

    Do this instead

    When a training string is missing its answer, check the caller that attaches the response, not the formatter.

  • Common mistake

    Assuming an empty input field is still printed as an Input header

    Why it fails

    The Input section is added only when the input field contains a non-empty value.

    Do this instead

    Test the input field first. An empty field should produce a prompt with no Input section.

  • Common mistake

    Trusting a successful load without checking the shape

    Why it fails

    A dataset can load without error and still have the wrong shape, wrong column names, or lopsided labels.

    Do this instead

    Inspect the shape and a few rows, then run value_counts() on the Label column before training.

  • Common mistake

    Using the default comma separator on a tab-separated file

    Why it fails

    The file divides fields with tab characters, so the separator must be a tab.

    Do this instead

    Pass sep set to a tab character when calling pd.read_csv().

Applying the Checks to a New Dataset

MEDIUM

A colleague loads a tab-separated file of instruction records and reports that the prompt for one record has no Input section, even though the record has a visible input. Using the branch test, explain what you would check first and why.

Hints
  • Look at what the input field actually contains, not what the record looks like on screen.
  • The Input section depends on a single test on the input field.
EASY

Your spam file loads with a shape of 5572 rows by 2 columns, but value_counts() on the Label column shows one class far larger than the other. Explain what the shape tells you, what the counts tell you, and what step the source takes next.

Hints
  • Separate the two dimensions of the shape: examples and fields.
  • The source reduces the larger class to a fixed count.

Key Takeaways

  • format_input turns one dataset entry into a prompt string; the Instruction half always appears, and the Input half appears only when the input field is non-empty.
  • The response is not built by format_input. The caller attaches it after the prompt is returned, so debug the formatter and the caller in that order.
  • pd.read_csv() with sep set to a tab, header set to None, and names set to Label and Text loads the spam file into a DataFrame with two named columns.
  • The shape is rows by columns. The spam dataset is 5572 rows by 2 columns, and value_counts() on the Label column reveals class imbalance before fine-tuning.
  • Undersampling reduces each class to 747 instances, giving equal class counts and a smaller dataset that fine-tunes faster.

Related concepts

More concepts starting with L