# 数据集指南

## 什么是数据集？

对于 LLM 来说，数据集是可用于训练我们模型的数据集合。为了在训练中发挥作用，文本数据需要采用可进行分词的格式。你还将学习如何 [在 Unsloth 中使用数据集](#applying-chat-templates-with-unsloth).

创建数据集的关键部分之一是你的 [聊天模板](/docs/zh/ji-chu/chat-templates.md) 以及你将如何设计它。分词也很重要，因为它会把文本拆分成 token，这些 token 可以是词、子词或字符，从而使 LLM 能够有效处理。随后，这些 token 会被转换为嵌入，并进行调整，以帮助模型理解含义和上下文。

### 数据格式

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

<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 和 Wikipedia 都是很好的数据集来源，而如果你想训练模型学习一种语言，Wikipedia 尤其有用。

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

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

## 🦥 Unsloth 数据配方

[Unsloth 数据配方](/docs/zh/xin/studio/data-recipe.md) 可以让你上传 PDF 或 CSV 等文档，并将其转换为可用的数据集。通过图节点工作流以可视化方式创建和编辑数据集。

配方页面是主要入口。配方会保存在浏览器本地，因此你之后可以回到已保存的工作。你可以从这里创建一个空白配方，或打开一个带引导的学习配方。

<div data-with-frame="true"><figure><img src="/files/1a3a53c44a59a493bdab62f046b2394ef4c81b59" alt=""><figcaption></figcaption></figure></div>

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

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

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

{% content-ref url="/pages/7223afcfd2df87e1fe32a963c0b5ef0e45f563c5" %}
[Data Recipes](/docs/zh/xin/studio/data-recipe.md)
{% endcontent-ref %}

## 数据格式化

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

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

关于 [**继续预训练**](/docs/zh/ji-chu/continued-pretraining.md)，我们使用没有特定结构的原始文本格式：

```json
  "text": "卡邦尼意面是一道传统的罗马意大利面料理。酱汁是通过将生鸡蛋与磨碎的佩科里诺罗马诺奶酪和黑胡椒混合制成的。然后将热意面与酥脆的 guanciale（腌制猪颊肉）和蛋液拌匀，利用余温形成奶油般的酱汁。尽管普遍认为如此，正宗的卡邦尼意面从不包含奶油或大蒜。这道菜很可能起源于 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": "正宗的罗马卡邦尼意面只用几种食材：意面、guanciale、鸡蛋、佩科里诺罗马诺奶酪和黑胡椒。你想要详细食谱吗？"
    }
  ]
}
```

模板格式使用 "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` 将正确的聊天模板应用到你的 tokenizer：\\

  ```
  from unsloth.chat_templates import get_chat_template

  tokenizer = get_chat_template(
      tokenizer,
      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, }
  ```

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

  ```
  # 导入并加载数据集
  from datasets import load_dataset
  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` 函数将其转换。修改后的代码现在如下：\
  \\

  ```
  # 导入数据集
  from datasets import load_dataset
  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 [notebook ](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` 当模型最初由原始模型所有者上传时，attribute 有时可能包含错误，并且可能需要一段时间才能更新。相比之下，在 Unsloth，我们会彻底检查并修复 `chat_template` 中每个模型的错误，当我们将量化版本上传到我们的仓库时。此外，我们的 `get_chat_template` 以及 `apply_chat_template` 方法提供了高级数据操作功能，并且在我们的 Chat Templates 文档 [页面](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 等推理引擎来生成合成数据，但这需要一些手工工作来收集数据并提示生成更多数据。合成数据有 3 个目标：

* 生成全新的数据——可以从零开始，也可以基于你现有的数据集
* 使你的数据集多样化，这样你的模型就不会 [过拟合](/docs/zh/kai-shi-shi-yong/fine-tuning-llms-guide/lora-hyperparameters-guide.md#avoiding-overfitting-and-underfitting) 并变得过于具体
* 增强现有数据，例如自动将你的数据集整理成所选的正确格式

### 使用 Unsloth 生成合成数据

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

<div data-with-frame="true"><figure><img src="/files/d7a623c1009dd96e330afd7e279e05a2e03ae91b" alt="" width="563"><figcaption></figcaption></figure></div>

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

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

* **为现有数据集生成更多对话的提示词**:

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

  {% code overflow="wrap" %}

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

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

  {% code overflow="wrap" %}

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

  {% endcode %}

建议检查生成数据的质量，以删除或改进无关或质量较差的回复。根据你的数据集，它在许多方面也可能需要平衡，以免你的模型过拟合。然后你可以将这个清理后的数据集重新输入 LLM 以重新生成数据，并提供更多指导。

## 数据集 FAQ + 提示

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

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

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

如果你想微调一个已经具备推理能力的模型，例如 DeepSeek-R1 的蒸馏版本（例如 DeepSeek-R1-Distill-Llama-8B），你仍然需要遵循问题/任务与答案配对的形式；不过对于答案，你需要修改它，使其包含推理/思维链过程以及得出答案所采取的步骤。\
\
对于一个不具备推理能力、而你想训练它以便日后具备推理能力的模型，你需要使用标准数据集，但这次答案中不要包含推理。这种训练过程被称为 [强化学习和 GRPO](/docs/zh/kai-shi-shi-yong/reinforcement-learning-rl-guide.md).

### 多个数据集

如果你有多个用于微调的数据集，你可以：

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

### 我可以多次微调同一个模型吗？

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

## 在 Unsloth 中使用数据集

### Alpaca 数据集

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

<figure><img src="/files/6bd7211a584e8e186a35e687888a7d41336816d3" 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="/files/18ab8cf1c142db8d4ae4237b715b4af08ee5f629" alt=""><figcaption></figcaption></figure>

你可以看到每一行有 3 列——指令、输入和输出。我们基本上会把每一行合并成如下所示的一个大提示词。然后我们用它来微调语言模型，这使它变得非常像 ChatGPT。我们把这个过程称为 **监督式指令微调**.

<figure><img src="/files/c0b5a28a20ff7ae93f2c84d93c1f0f1843c402cf" alt=""><figcaption></figcaption></figure>

### 用于微调的多列

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

<figure><img src="/files/27ef926c80bbe911b2a6a03ea4cb3e51388853a4" alt=""><figcaption></figcaption></figure>

这实际上意味着，为了让微调真正生效，我们必须把多列“合并”成 1 个大提示词！

例如，著名的 Titanic 数据集有很多很多列。你的任务是根据乘客年龄、舱位、票价等信息预测乘客是生还还是死亡。我们不能直接把这些信息传给 ChatGPT，而是必须把这些信息“合并”成 1 个大提示词。

<figure><img src="/files/51237682d24fcdd7f522c9264e74e906ecce8881" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/988e3dabf006d4e98a3b064c888c3db5ece2ee14" alt=""><figcaption></figcaption></figure>

其他微调库要求你手动准备用于微调的数据集，把所有列合并成 1 个提示词。在 Unsloth 中，我们只需提供一个名为 `to_sharegpt` 的函数，它可以一次性完成这件事！

<figure><img src="/files/e817fa08b58a208b6effb272b63172d38cfab498" alt=""><figcaption></figcaption></figure>

现在这会稍微复杂一些，因为我们允许很多自定义，但有几个要点：

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

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

<figure><img src="/files/c97fec182823138023625a74acd8bf72566768a0" alt=""><figcaption></figcaption></figure>

例如，假设数据集长这样，并且有很多缺失数据：

| Embarked | Age | Fare |
| -------- | --- | ---- |
| S        | 23  |      |
|          | 18  | 7.25 |

那么，我们不希望结果是：

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

相反，通过使用 `[[]]`将列设为可选，我们可以完全排除这些信息。

1. \[\[The passenger embarked from S.]] \[\[Their age is 23.]] \[\[Their fare is **空白**.]]
2. \[\[The passenger embarked from **空白**.]] \[\[Their age is 18.]] \[\[Their fare is $7.25.]]

会变成：

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

### 多轮对话

如果你没注意到，一个问题是 Alpaca 数据集是单轮对话，而你还记得 ChatGPT 是交互式的，你可以和它进行多轮对话。例如，左边是我们想要的，而右边的 Alpaca 数据集只提供单次对话。我们希望微调后的语言模型能够以某种方式学会像 ChatGPT 一样进行多轮对话。

<figure><img src="/files/02f83b44488171e282ef1bf51fde26acb96a6a7b" alt=""><figcaption></figcaption></figure>

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

<figure><img src="/files/4849fe401f1d094fbfcce60d2dcb75189316c9ac" alt=""><figcaption></figcaption></figure>

然后把 `output_column_name` 设为预测 / 输出列。对于 Alpaca 数据集来说，它就是 output 列。

然后我们使用 `standardize_sharegpt` 函数把数据集整理成适合微调的正确格式！一定要调用这个！

<figure><img src="/files/1e924f8e8f23e8ce40da2876066b9340c6f25e0a" 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，使其成为医疗专业人员有用的分析工具。

让我们看看这个数据集，并检查第 1 个示例展示了什么：

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

| 图像                                                                                      | 说明文字                                     |
| --------------------------------------------------------------------------------------- | ---------------------------------------- |
| <img src="/files/e86577dd0fc6ec21972a8e1e764eea71135b9fac" 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)
```

结果如下：

```
这张放射影像看起来是上颌和下颌牙列的全景图，具体来说是全景片（OPG）。

* 该全景放射影像显示出正常的牙科结构。
* 右上方有一个异常区域，表现为一片透亮的骨区，对应于上颌窦。

**关键观察**

* 左上牙之间的骨质相对不透光。
* 图像上方有两个大箭头，提示需要更仔细地检查该区域。其中一个箭头位于左侧位置，另一个位于右侧位置。不过，只有
```

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://unsloth.ai/docs/zh/kai-shi-shi-yong/fine-tuning-llms-guide/datasets-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
