Open6

sarashina2.2のunslothを使ったfinetuningについて

kurogane_himaki/鐵火卷8号🍣😈バーチャル一般人kurogane_himaki/鐵火卷8号🍣😈バーチャル一般人

unslothを使ったsarashina2.2のfinetuningのメモを残します

そのままやると、train_on_responses_onlyのところで以下のエラーが出て学習が終わりません。
chat tenplateが誤ってるっぽいです。

ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-10-4f9c74a86b96> in <cell line: 0>()
      1 from unsloth.chat_templates import train_on_responses_only
----> 2 trainer = train_on_responses_only(
      3     trainer,
      4     instruction_part = "<|start_header_id|>user<|end_header_id|>\n\n",
      5     response_part = "<|start_header_id|>assistant<|end_header_id|>\n\n",

/usr/local/lib/python3.11/dist-packages/unsloth_zoo/dataset_utils.py in train_on_responses_only(trainer, instruction_part, response_part, force_match, tokenizer, return_function)
    359     # Check if all labels randomnly got masked to nothing - maybe wrong chat template?
    360     from .training_utils import fix_zero_training_loss
--> 361     fix_zero_training_loss(None, tokenizer, trainer.train_dataset)
    362     return trainer
    363 pass

/usr/local/lib/python3.11/dist-packages/torch/utils/_contextlib.py in decorate_context(*args, **kwargs)
    114     def decorate_context(*args, **kwargs):
    115         with ctx_factory():
--> 116             return func(*args, **kwargs)
    117 
    118     return decorate_context

/usr/local/lib/python3.11/dist-packages/unsloth_zoo/training_utils.py in fix_zero_training_loss(model, tokenizer, train_dataset)
     70 
     71         elif seen_bad / (seen_bad + seen_good) == 1:
---> 72             raise ZeroDivisionError(
     73                 "Unsloth: All labels in your dataset are -100. Training losses will be all 0.\n"\
     74                 "For example, are you sure you used `train_on_responses_only` correctly?\n"\

ZeroDivisionError: Unsloth: All labels in your dataset are -100. Training losses will be all 0.
For example, are you sure you used `train_on_responses_only` correctly?
Or did you mask our tokens incorrectly? Maybe this is intended?
Maybe you're using a Llama chat template on a non Llama model for example?
kurogane_himaki/鐵火卷8号🍣😈バーチャル一般人kurogane_himaki/鐵火卷8号🍣😈バーチャル一般人

unsloth/unsloth/chat_templates.pyに以下を追加
chat_templates.py

自環境では、site-packageを直接編集して追加した。

# =========================================== sarashina22
# Obtained via
# print(tokenizer.chat_template.replace("}\n", "####").replace("\n", "\\n").replace("####", "}\n"))
sarashina22_template = \
"""\n{%- set user_messages = messages | selectattr('role', 'equalto', 'user') | list %}
{%- macro output_available_tools(tools, message) %}
{%- if tools and (message == user_messages[-1]) %}
    {{- '<|available_tools|>[' }}
    {%- for tool in tools %}
        {%- set tool = tool.function %}
        {{- "{" }}
        {%- for key, val in tool.items() if key != "return" %}
            {%- if val is string %}
                {{- "'" + key + "': '" + val + "'" }}
            {%- else %}
                {{- "'" + key + "': " + val|string }}
            {%- endif %}
            {%- if not loop.last %}
                {{- ", " }}
            {%- endif %}
        {%- endfor %}
        {{- "}" }}
        {%- if not loop.last %}
            {{- ", " }}
        {%- else %}
            {{- "]" }}
        {%- endif %}
    {%- endfor %}
    {{- eos_token -}}
{%- endif %}
{%- endmacro %}
\n{%- macro output_tool_results(tool_results) %}
{{- '<|tool_results|>[' }}
{%- for tool_result in tool_results %}
    {{- "{'content': " + tool_result.content|string + ", 'call_id': '" + tool_result.call_id + "'}" }}
{%- endfor %}
{{- ']' }}
{{- eos_token -}}
{%- endmacro %}
\n{%- macro output_tool_calls(tool_calls) %}
{{- '<|tool_calls|>[' }}
{%- for tool_call in tool_calls %}
    {{- "{'id': '" + tool_call.id + "', 'name': '" + tool_call.name + "', 'arguments': " + tool_call.arguments|string + '}' }}
{%- endfor %}
{{- ']' }}
{%- endmacro %}
\n{%- for message in messages %}
    {%- if message['role'] == 'user' %}
        {%- if tools is defined %}
            {{- output_available_tools(tools, message) }}
        {%- endif %}
        {{- '<|user|>' + message['content'] + eos_token -}}
    {%- elif message['role'] == 'system' %}
        {{- '<|system|>' + message['content'] + eos_token -}}
    {%- elif message['role'] == 'assistant' %}
        {% set assistant_content = "" %}
        {%- if message.content is defined %}
            {% set assistant_content = message.content %}
        {%- endif %}
        {%- if message.tool_calls is defined and message.tool_calls -%}
            {{- '<|assistant|>' + assistant_content + output_tool_calls(message['tool_calls']) + eos_token -}}
        {%- else %}
            {{- '<|assistant|>' + assistant_content + eos_token }}
        {%- endif %}
    {%- elif message['role'] == 'tool_results' %}
        {{- output_tool_results(message.tool_results) }}
    {%- endif %}
{%- if loop.last and add_generation_prompt -%}
  {{- '<|assistant|>' -}}
{%- endif -%}
{%- endfor %}
"""

# Ollama from https://ollama.com/library/gemma3/blobs/e0a42594d802
sarashina22_ollama = \
'''
FROM {__FILE_LOCATION__}
TEMPLATE """{{ if .System }}<|system|>{{ .System }}</s>{{ end }}{{ if .Prompt }}<|user|>{{ .Prompt }}</s>{{ end }}<|assistant|>{{ .Response }}</s>"""
PARAMETER stop "<|system|>"
PARAMETER stop "<|user|>"
PARAMETER stop "<|assistant|>"
PARAMETER temperature 0.1
PARAMETER min_p 0.0
PARAMETER top_k 64
PARAMETER top_p 0.95
'''

sarashina22_template_eos_token = "<s>"
CHAT_TEMPLATES["sarashina22"] = (sarashina22_template, sarashina22_template_eos_token, False, sarashina22_ollama,)
DEFAULT_SYSTEM_MESSAGE["sarashina22"] = None # No system message in Gemma-3

CHAT_TEMPLATES["sarashina-2-2"] = (sarashina22_template, sarashina22_template_eos_token, False, sarashina22_ollama,)
DEFAULT_SYSTEM_MESSAGE["sarashina-2-2"] = None # No system message in Gemma-3

多分46行目から1017行目の間なら多分どこでもいいです。

kurogane_himaki/鐵火卷8号🍣😈バーチャル一般人kurogane_himaki/鐵火卷8号🍣😈バーチャル一般人

デフォルトのノートブック内のchat templateの指定を変更

from unsloth.chat_templates import get_chat_template

tokenizer = get_chat_template(
    tokenizer,
    chat_template = "sarashina22",
)

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, }
pass

from datasets import load_dataset
dataset = load_dataset("mlabonne/FineTome-100k", split = "train")