# 数据集指南

## 什么是数据集？

对于大型语言模型（LLM）来说，数据集是可用于训练我们模型的数据集合。为了对训练有用，文本数据需要以可以进行分词（tokenize）的格式存在。你还将学习如何 [在 Unsloth 内使用数据集](#applying-chat-templates-with-unsloth).

创建数据集的关键部分之一是你的 [聊天 模板](https://unsloth.ai/docs/zh/ji-chu/chat-templates) 以及你将如何设计它。分词也很重要，因为它将文本拆分为令牌（tokens），这些令牌可以是单词、子词或字符，以便大型语言模型能够有效处理。然后这些令牌被转换为嵌入（embeddings），并进行调整以帮助模型理解含义和上下文。

### 数据格式

为了实现分词过程，数据集需要采用一个分词器能够读取的格式。

<table data-full-width="false"><thead><tr><th>格式</th><th>说明</th><th>训练类型</th></tr></thead><tbody><tr><td>原始语料</td><td>来自网站、书籍或文章等来源的原始文本。</td><td>继续预训练（CPT）</td></tr><tr><td>指令型</td><td>为模型提供要遵循的指令以及期望输出的示例。</td><td>监督微调（SFT）</td></tr><tr><td>对话</td><td>用户与 AI 助手之间的多轮对话。</td><td>监督微调（SFT）</td></tr><tr><td>RLHF（基于人类反馈的强化学习）</td><td>用户与 AI 助手之间的对话，其中助手的回复由脚本、另一个模型或人工评估者进行排序。</td><td>强化学习（RL）</td></tr></tbody></table>

{% hint style="info" %}
值得注意的是，每种类型存在不同风格的格式。
{% endhint %}

## 入门

在我们格式化数据之前，我们要确定以下内容：

{% stepper %}
{% step %} <mark style="color:绿色;">数据集目的</mark>

了解数据集的目的将帮助我们确定需要哪些数据以及使用什么格式。

目的可以是，将模型适配到一个新任务（例如摘要），或提高模型扮演特定角色的能力。例如：

* 基于聊天的对话（问答、学习新语言、客户支持、闲聊）。
* 结构化任务（[分类](https://colab.research.google.com/github/timothelaborie/text_classification_scripts/blob/main/unsloth_classification.ipynb)、摘要、生成任务）。
* 特定领域数据（医学、金融、技术）。
  {% endstep %}

{% step %} <mark style="color:绿色;">输出风格</mark>

输出风格将让我们知道要使用哪些数据源以达成期望的输出。

例如，你想要达到的输出类型可能是 JSON、HTML、文本或代码。或者你可能希望输出为西班牙语、英语或德语等。
{% endstep %}

{% step %} <mark style="color:绿色;">数据来源</mark>

当我们知道所需数据的目的和风格时，我们需要分析数据的质量和 [数量](#how-big-should-my-dataset-be) Hugging Face 和维基百科是很好的数据集来源，若你希望训练模型学习一种语言，维基百科尤其有用。

数据来源可以是 CSV 文件、PDF 甚至网站。你也可以 [合成生成](#synthetic-data-generation) 数据，但需要额外注意以确保每个示例都高质量且相关。
{% endstep %}
{% endstepper %}

{% hint style="success" %}
创建更好数据集的最佳方法之一是将其与来自 Hugging Face 的更通用数据集（如 ShareGPT）结合，以使你的模型更聪明且更具多样性。你也可以添加 [合成生成的数据](#synthetic-data-generation).
{% endhint %}

## 🦥 Unsloth 数据配方

[Unsloth 数据配方](https://unsloth.ai/docs/zh/xin-zeng/studio/data-recipe) 允许你上传 PDF 或 CSV 等文档并将它们转换为可用的数据集。通过图节点工作流以可视方式创建和编辑数据集。

recipes 页面是主要入口点。Recipes 存储在浏览器本地，因此您可以稍后返回已保存的工作。从这里，您可以创建一个空白 recipe 或打开一个学习引导的 recipe。

<div data-with-frame="true"><figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fc5m3JX1kUA3UwmdcJcxH%2FArea.gif?alt=media&#x26;token=33bbd908-7d6c-456a-bc58-ce495c0adca1" alt=""><figcaption></figcaption></figure></div>

数据配方遵循相同的基本路径。打开配方页面，创建或选择一个配方，在编辑器中构建工作流，验证并运行预览，然后在输出看起来正确后运行完整数据集。添加种子数据和生成块，验证工作流，预览样本输出，然后运行完整数据集构建。

概览：通常的工作流应如下所示：

1. 打开 recipes 页面。
2. 创建一个新的 recipe 或打开一个已有的 recipe。
3. 添加模块以定义您的数据集工作流。
4. 点击 **验证** 以便及早发现配置问题。
5. 运行预览以快速检查样本行。
6. 当 recipe 准备好后运行完整的数据集构建。
7. 在图形中或在 **执行** 视图中实时查看进度和输出以获取更多细节。
8. 在 **Studio** 并微调模型。阅读更多：

{% content-ref url="../../xin-zeng/studio/data-recipe" %}
[data-recipe](https://unsloth.ai/docs/zh/xin-zeng/studio/data-recipe)
{% endcontent-ref %}

## 数据格式化

当我们确定相关标准并收集到必要数据后，就可以将数据格式化为机器可读、可用于训练的格式。

### 用于 LLM 训练的常见数据格式

对于 [**（GRPO、DPO）、**](https://unsloth.ai/docs/zh/ji-chu/continued-pretraining)，我们使用不带特定结构的原始文本格式：

```json
  "text": "意大利培根蛋面（Pasta carbonara）是一道传统的罗马意大利面菜肴。酱汁是将生鸡蛋与磨碎的佩科里诺·罗马诺奶酪和黑胡椒混合制成。热意面随后与脆香的猪颊肉（guanciale）和鸡蛋混合物拌匀，利用残留热量形成奶油状的酱汁。尽管普遍认为如此，正宗的 carbonara 从不包含奶油或大蒜。该菜肴很可能起源于 20 世纪中叶的罗马，尽管其确切起源仍有争议……"
```

此格式保留自然语言流并允许模型从连续文本中学习。

如果我们要将模型适配到一项新任务，并希望模型根据一组特定指令在单轮中输出文本，我们可以使用 **指令式** 格式在 [Alpaca 风格](https://docs.unsloth.ai/basics/tutorial-how-to-finetune-llama-3-and-use-in-ollama#id-6.-alpaca-dataset)

```json
"Instruction": "我们希望模型执行的任务。"

"Input": "可选，但有用，基本上会是用户的查询。"

"Output": "任务的预期结果以及模型的输出。"
```

当我们希望多轮对话时，我们可以使用 ShareGPT 格式：

```json
{
  "conversations": [
    {
      "from": "human",
      "value": "你能帮我做意大利培根蛋面吗？"
    },
    {
      "from": "gpt",
      "value": "你想要传统的罗马食谱，还是更简单的版本？"
    },
    {
      "from": "human",
      "value": "请给我传统版本"
    },
    {
      "from": "gpt",
      "value": "正宗的罗马 carbonara 只使用少量食材：意面、猪颊肉、鸡蛋、佩科里诺·罗马诺和黑胡椒。你想要详细的配方吗？"
    }
  ]
}
```

该模板格式使用 "from"/"value" 属性键，消息在 `human`和 `gpt`之间交替，允许自然的对话流程。

另一种常见格式是 OpenAI 的 ChatML 格式，也是 Hugging Face 的默认格式。这可能是最常用的格式，在消息中交替使用 `user` 和 `assistant`

```
{
  "messages": [
    {
      "role": "user",
      "content": "1+1 等于多少？"
    },
    {
      "role": "assistant",
      "content": "是 2！"
    },
  ]
}
```

### 在 Unsloth 中应用聊天模板

对于通常遵循通用 chatml 格式的数据集，将数据集准备用于训练或微调的过程包含四个简单步骤：

* 检查 Unsloth 当前支持的聊天模板：\\

  ```
  from unsloth.chat_templates import CHAT_TEMPLATES
  print(list(CHAT_TEMPLATES.keys()))
  ```

  \
  这将打印出 Unsloth 当前支持的模板列表。下面是示例输出：\\

  ```
  ['unsloth', 'zephyr', 'chatml', 'mistral', 'llama', 'vicuna', 'vicuna_old', 'vicuna old', 'alpaca', 'gemma', 'gemma_chatml', 'gemma2', 'gemma2_chatml', 'llama-3', 'llama3', 'phi-3', 'phi-35', 'phi-3.5', 'llama-3.1', 'llama-31', 'llama-3.2', 'llama-3.3', 'llama-32', 'llama-33', 'qwen-2.5', 'qwen-25', 'qwen25', 'qwen2.5', 'phi-4', 'gemma-3', 'gemma3']
  ```

  \\
* 使用 `get_chat_template` 将合适的聊天模板应用到你的分词器：\\

  ```
  from unsloth.chat_templates import get_chat_template

  tokenizer = get_chat_template(
      "your-username/model-name",
      chat_template = "gemma-3", # 将此更改为正确的 chat_template 名称
  )
  ```

  \\
* 定义你的格式化函数。示例：\\

  ```
  def formatting_prompts_func(examples):
     convos = examples["conversations"]
     texts = [tokenizer.apply_chat_template(convo, tokenize = False, add_generation_prompt = False) for convo in convos]
     return { "text" : texts, }
  ```

  \
  \
  该函数遍历数据集，对每个样本应用你定义的聊天模板。\\
* 最后，让我们加载数据集并对其应用所需的修改： \\

  ```
  # 导入并加载数据集
  import torch
  dataset = load_dataset("repo_name/dataset_name", split = "train")

  # 使用 map 方法将格式化函数应用于你的数据集
  dataset = dataset.map(formatting_prompts_func, batched = True,)
  ```

  \
  如果你的数据集使用 ShareGPT 格式且使用 "from"/"value" 键而不是 ChatML 的 "role"/"content" 格式，你可以先使用 `standardize_sharegpt` 函数将其转换。修改后的代码如下所示：\
  \\

  ```
  # 导入数据集
  import torch
  dataset = load_dataset("mlabonne/FineTome-100k", split = "train")

  # 如有必要，将你的数据集转换为 "role"/"content" 格式
  from unsloth.chat_templates import standardize_sharegpt
  dataset = standardize_sharegpt(dataset)

  # 使用 map 方法将格式化函数应用于你的数据集
  dataset = dataset.map(formatting_prompts_func, batched = True,)
  ```

### 数据格式化 问答

<mark style="color:绿色;">**问：**</mark> 如何使用 Alpaca 的指令格式？

<mark style="color:绿色;">**答：**</mark> 如果你的数据集已经是 Alpaca 格式，则按照 Llama3.1 中所示的格式化步骤进行。 [笔记本 ](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Llama3.1_\(8B\)-Alpaca.ipynb#scrollTo=LjY75GoYUCB8)如果你需要将数据转换为 Alpaca 格式，一种方法是创建一个 Python 脚本来处理你的原始数据。如果你正在做摘要任务，可以使用本地 LLM 为每个示例生成指令和输出。

<mark style="color:绿色;">**问：**</mark> 我是否应该始终使用 standardize\_sharegpt 方法？

<mark style="color:绿色;">**答：**</mark> 仅当你的目标数据集是以 sharegpt 格式编写，但你的模型期望的是 ChatML 格式时，才使用 standardize\_sharegpt 方法。

\ <mark style="color:绿色;">**问：**</mark> 为什么不使用随分词器一起提供的 apply\_chat\_template 函数？

<mark style="color:绿色;">**答：**</mark> 该 `chat_template` 属性在模型最初由原始模型所有者上传时有时包含错误，并且可能需要时间才能更新。相比之下，在 Unsloth，我们在将量化版本上传到我们的仓库时会彻底检查并修复每个模型的 `chat_template` 以确保正确性。此外，我们的 `get_chat_template` 和 `apply_chat_template` 方法提供高级的数据操作功能，这些功能在我们的聊天模板文档页面上有完整说明。 [页面](https://docs.unsloth.ai/basics/chat-templates).

<mark style="color:绿色;">**问：**</mark> 如果我的模板当前未被 Unsloth 支持怎么办？

<mark style="color:绿色;">**答：**</mark> 在 unsloth 的 GitHub issues 上提交功能请求 [论坛](https://github.com/unslothai/unsloth)。作为临时解决方案，你也可以使用分词器自身的 apply\_chat\_template 函数，直到你的功能请求被批准并合并。

## 合成数据生成

你也可以使用任何本地 LLM，如 Llama 3.3 (70B) 或 OpenAI 的 GPT-4.5 来生成合成数据。通常，使用像 Llama 3.3 (70B) 这样更大的模型可以确保输出质量最高。你可以直接使用推理引擎如 vLLM、Ollama 或 llama.cpp 来生成合成数据，但这需要一些手动工作来收集并提示生成更多数据。合成数据有三项目标：

* 生成全新的数据——要么从头生成，要么从现有数据集中生成
* 使数据集多样化，这样你的模型就不会 [过拟合](https://unsloth.ai/docs/zh/kai-shi-shi-yong/lora-hyperparameters-guide#avoiding-overfitting-and-underfitting) 并变得过于具体
* 增强现有数据，例如自动将数据集结构化为所选的正确格式

### 在 Unsloth 中使用合成数据

你可以轻松将任何非结构化或结构化数据上传到 Unsloth Studio 的 [数据配方](https://unsloth.ai/docs/zh/xin-zeng/studio/data-recipe) ，它会自动将其转换为可用/合成数据集。更多细节见 [我们的指南](https://unsloth.ai/docs/zh/xin-zeng/studio/data-recipe).

<div data-with-frame="true"><figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2FQ6e19jESrJg0VjHnX58c%2Fdata%20recipes%20final.png?alt=media&#x26;token=8d74e453-815d-4790-83d1-76d0bc80a3ce" alt="" width="563"><figcaption></figcaption></figure></div>

### 使用本地 LLM 或 ChatGPT 生成合成数据

你的目标是提示模型生成并处理符合你指定格式的问答数据。模型需要学习你提供的结构以及上下文，因此确保你至少已经有 10 个示例数据。示例提示：

* **用于在现有数据集上生成更多对话的提示**:

  <pre data-overflow="wrap"><code><strong>使用我提供的数据集示例，遵循结构并根据示例生成对话。
  </strong></code></pre>
* **如果你没有数据集的提示**:

  {% code overflow="wrap" %}

  ```
  为可口可乐创建 10 个产品评论示例，并将其分类为正面、负面或中性。
  ```

  {% endcode %}
* **用于未格式化数据集的提示**:

  {% code overflow="wrap" %}

  ```
  将我的数据集结构化为用于微调的 QA ChatML 格式。然后生成 5 个具有相同主题和格式的合成数据示例。
  ```

  {% endcode %}

建议检查生成数据的质量，以删除或改进无关或低质量的回答。根据你的数据集，它可能还需要在许多方面平衡，以防止模型过拟合。然后你可以将清理后的数据集重新输入到 LLM 中以在有更多指导的情况下重新生成数据。

## 数据集常见问题 + 提示

### 我的数据集应该有多大？

我们通常建议至少使用至少 100 行数据作为微调的最低限度，以达到合理的结果。为了获得最佳性能，建议使用超过 1,000 行的数据集，在这种情况下，更多数据通常会带来更好结果。如果你的数据集太小，你也可以添加合成数据或从 Hugging Face 添加一个数据集以增加多样性。然而，你的微调模型的有效性在很大程度上取决于数据集的质量，因此请确保彻底清理和准备你的数据。

### 如果我想微调一个推理能力模型，我应该如何构建数据集？

如果你想微调一个已经具有推理能力的模型（例如 DeepSeek-R1 的蒸馏版本，如 DeepSeek-R1-Distill-Llama-8B），你仍然需要遵循问题/任务与答案对的格式，但你的答案需要包含推理/链式思考（chain-of-thought）过程以及得出答案所采取的步骤。\
\
如果模型尚不具备推理能力，而你希望训练它以便将来具备推理能力，则需要使用标准数据集，但这次答案中不包含推理。这种训练过程被称为 [强化学习与 GRPO](https://unsloth.ai/docs/zh/kai-shi-shi-yong/reinforcement-learning-rl-guide).

### 多个数据集

如果你有多个用于微调的数据集，你可以采取以下两种方式之一：

* 将所有数据集的格式标准化，将它们合并为单一数据集，然后在该统一数据集上进行微调。
* 使用 [多个数据集](https://colab.research.google.com/drive/1njCCbE1YVal9xC83hjdo2hiGItpY_D6t?usp=sharing) 笔记本 直接在多个数据集上进行微调。

### 我可以对同一模型进行多次微调吗？

你可以对已经微调过的模型再次进行微调，但最好将所有数据集合并并在单次流程中完成微调。对已微调模型的再次训练可能会改变先前微调过程中获得的质量和知识。

## 在 Unsloth 中使用数据集

### Alpaca 数据集

在 Google Colab 上查看在 Unsloth 中使用 Alpaca 数据集的示例：

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-1d66d8714e44d90513dd87b9356eec67886ab3f7%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

我们现在将使用由调用 GPT-4 本身创建的 Alpaca 数据集。它包含 52,000 条指令与输出的列表，在 Llama-1 发布时非常受欢迎，因为它使微调基础 LLM 与 ChatGPT 具有竞争力。

你可以访问 Alpaca 数据集的 GPT4 版本 [这里](https://huggingface.co/datasets/vicgalle/alpaca-gpt4.)。以下展示了该数据集的一些示例：

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-0dde50e386e7b245d3e8a57e10a4a81755b3769a%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

你可以看到每行有 3 列——一条指令、一个输入和一个输出。我们本质上将每一行合并为一个大的提示，如下。然后我们使用它来微调语言模型，这使其非常类似于 ChatGPT。我们称此过程为 **监督指令微调**.

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-8b3663c5d80adcb935ff77661500f08e13c9af2d%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

### 用于微调的多列

但一个大问题是对于 ChatGPT 风格的助手，我们只允许一条指令/一条提示，而不是多列/多输入。例如在 ChatGPT 中，你必须提交一条提示，而不是多条提示。

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-d90162c2685ced871f4151369aadcaee40a9c54f%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

这基本上意味着我们必须将多列“合并”成一条大型提示，微调才能真正起作用！

例如非常著名的 Titanic（泰坦尼克号）数据集有很多列。你的任务是根据乘客的年龄、舱位、票价等预测乘客是生存还是死亡。我们不能简单地将这些直接传给 ChatGPT，而是必须将这些信息“合并”成一条大型提示。

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-a2df04874bfc879182cb66c789341d49700227ea%2FMerge.png?alt=media" alt=""><figcaption></figcaption></figure>

例如，如果我们用包含该乘客所有信息的“合并”单条提示询问 ChatGPT，我们就可以让它猜测或预测该乘客是生还还是死亡。

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-b3da2b36afe37469cd3962f37186e758871864a5%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

其他微调库要求你手动准备微调数据集，通过将所有列合并成一条提示。在 Unsloth 中，我们提供了名为 `to_sharegpt` 的函数，它可以一次性完成此操作！

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-62b94dc44f2e343020d31de575f52eb22be4b0fc%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

现在这有点复杂，因为我们允许大量自定义，但有几点：

* 你必须用大括号将所有列括起来 `{}`。这些是实际 CSV / Excel 文件中的列名。
* 可选的文本组件必须用 `[[]]`括起来。例如如果列 "input" 为空，合并函数将不会显示该文本并会跳过它。这对于存在缺失值的数据集很有用。
* 在 `output_column_name`中选择输出或目标/预测列。对于 Alpaca 数据集，这将是 `output`.

例如在 Titanic 数据集中，我们可以创建如下大型合并提示格式，其中每列/文本片段都是可选的。

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-e6228cf6e5c0bb4e4b45e6f3e045910d567c33d2%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

例如，假设数据集看起来像下面这样且有许多缺失数据：

| 登船港口（Embarked） | 年龄（Age） | 票价（Fare） |
| -------------- | ------- | -------- |
| S              | 23      |          |
|                | 18      | 7.25     |

然后，我们不想要的结果是：

1. 该乘客从 S 登船。他们的年龄是 23。他们的票价是 **空（EMPTY）**.
2. 该乘客从 **空（EMPTY）**&#x767B;船。他们的年龄是 18。他们的票价是 $7.25。

相反，通过使用可选括号将列括起来， `[[]]`我们可以完全排除此信息。

1. \[\[该乘客从 S 登船。]] \[\[他们的年龄是 23。]] \[\[他们的票价是 **空（EMPTY）**.]]
2. \[\[该乘客从 **空（EMPTY）**&#x767B;船。]] \[\[他们的年龄是 18。]] \[\[他们的票价是 $7.25。]]

变为：

1. 该乘客从 S 登船。他们的年龄是 23。
2. 他们的年龄是 18。他们的票价是 $7.25。

### 多轮对话

如果你没注意到，Alpaca 数据集是单轮的，而记得使用 ChatGPT 是交互式的，可以进行多轮对话。例如，左侧是我们想要的，但右侧即 Alpaca 数据集仅提供单次对话。我们希望微调后的语言模型以某种方式学会像 ChatGPT 一样进行多轮对话。

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-2a65cd74ddd03a6bcbbc9827d9d034e4879a8e6a%2Fdiff.png?alt=media" alt=""><figcaption></figcaption></figure>

因此我们引入了 `conversation_extension` 参数，它本质上是在你的单轮数据集中随机选择若干行并将它们合并成一段对话！例如，如果你把它设置为 3，我们会随机选择 3 行并将它们合并为 1 条对话！设置得太长会使训练变慢，但可能会使你的聊天机器人和最终微调效果更好！

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-2b1b3494b260f1102942d86143a885225c6a06f2%2Fcombine.png?alt=media" alt=""><figcaption></figcaption></figure>

然后将 `output_column_name` 设置为预测/输出列。对于 Alpaca 数据集，它将是 output 列。

然后我们使用 `standardize_sharegpt` 函数仅将数据集转换为适合微调的正确格式！务必调用此函数！

<figure><img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-7bf83bf802191bda9e417bbe45afa181e7f24f38%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

## 视觉微调

用于微调视觉或多模态模型的数据集还包括图像输入。例如， [Llama 3.2 视觉笔记本](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Llama3.2_\(11B\)-Vision.ipynb#scrollTo=vITh0KVJ10qX) 使用一个放射学病例展示 AI 如何帮助医疗专业人员更高效地分析 X 光片、CT 扫描和超声。

我们将使用 ROCO 放射学数据集的抽样版本。你可以访问该数据集 [这里](https://www.google.com/url?q=https%3A%2F%2Fhuggingface.co%2Fdatasets%2Funsloth%2FRadiology_mini)。该数据集包含展示医疗状况和疾病的 X 光、CT 扫描和超声图像。每张图像都有专家撰写的描述。目标是微调一个视觉语言模型（VLM），使其成为医疗专业人员的有用分析工具。

让我们查看该数据集，并检查第一个示例显示的内容：

```
Dataset({
    features: ['image', 'image_id', 'caption', 'cui'],
    num_rows: 1978
})
```

| 图像                                                                                                                                                                                                                                     | 描述                                    |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| <img src="https://2657992854-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FxhOjnexMCB3dmuQFQ2Zq%2Fuploads%2Fgit-blob-97d4489827403bd4795494f33d01a10979788c30%2Fxray.png?alt=media" alt="" data-size="original"> | 全景放射影像显示右上颌后部的溶骨性病变，并伴随上颌窦底的吸收（箭头所示）。 |

要格式化数据集，所有视觉微调任务应按如下方式格式化：

```python
[
{ "role": "user",
  "content": [{"type": "text",  "text": instruction}, {"type": "image", "image": image} ]
},
{ "role": "assistant",
  "content": [{"type": "text",  "text": answer} ]
},
]
```

我们将设计一个自定义指令，要求 VLM 成为一名放射影像学专家。还要注意，不仅仅是 1 条指令，你可以添加多轮对话使其成为更动态的对话。

```notebook-python
instruction = "你是一名放射影像学专家。请准确描述你在此图像中看到的内容。"

def convert_to_conversation(sample):
    conversation = [
        { "role": "user",
          "content" : [
            {"type" : "text",  "text"  : instruction},
            {"type" : "image", "image" : sample["image"]} ]
        },
        { "role" : "assistant",
          "content" : [
            {"type" : "text",  "text"  : sample["caption"]} ]
        },
    ]
    return { "messages" : conversation }
pass
```

让我们将数据集转换为用于微调的“正确”格式：

```notebook-python
converted_dataset = [convert_to_conversation(sample) for sample in dataset]
```

第一个示例现在结构如下：

```notebook-python
converted_dataset[0]
```

{% code overflow="wrap" %}

```
{'messages': [{'role': 'user',
   'content': [{'type': 'text',
     'text': '你是一名放射影像学专家。请准确描述你在此图像中看到的内容。'},
    {'type': 'image',
     'image': <PIL.PngImagePlugin.PngImageFile image mode=L size=657x442>}]},
  {'role': 'assistant',
   'content': [{'type': 'text',
     'text': '全景放射影像显示右上颌后部的溶骨性病变，并伴随上颌窦底的吸收（箭头所示）。'}]}]}
```

{% endcode %}

在我们进行任何微调之前，也许视觉模型已经知道如何分析这些图像？让我们检查是否是这种情况！

```notebook-python
FastVisionModel.for_inference(model) # 启用推理！

image = dataset[0]["image"]
instruction = "你是一名放射影像学专家。请准确描述你在此图像中看到的内容。"

messages = [
    {"role": "user", "content": [
        {"type": "image"},
        {"type": "text", "text": instruction}
    ]}
]
input_text = tokenizer.apply_chat_template(messages, add_generation_prompt = True)
inputs = tokenizer(
    image,
    input_text,
    add_special_tokens = False,
    return_tensors = "pt",
).to("cuda")

from transformers import TextStreamer
text_streamer = TextStreamer(tokenizer, skip_prompt = True)
_ = model.generate(**inputs, streamer = text_streamer, max_new_tokens = 128,
                   use_cache = True, temperature = 1.5, min_p = 0.1)
```

结果为：

```
这张放射影像似乎是上下牙列的全景视图，具体是正位全景断层片（Orthopantomogram，OPG）。

* 全景放射影像显示正常的牙齿结构。
* 右上方有一处异常区域，表现为放射透亮的骨质区，对应上颌窦。

**主要观察**

* 左上牙之间的骨质相对放射致密。
* 图像上方有两个大箭头，提示需要对该区域进行更仔细的检查。其中一个箭头位于左侧位置，另一个位于右侧位置。然而，仅有
```

更多详情请查看我们在 [此处的笔记本 对数据集部分的说明](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Llama3.2_\(11B\)-Vision.ipynb#scrollTo=vITh0KVJ10qX).
