DiTy's picture
Update README.md
2ca1653 verified
metadata
base_model: google/gemma-2-9b-it
datasets:
  - DiTy/function-calling
language:
  - ru
library_name: transformers
license: apache-2.0
pipeline_tag: text-generation
tags:
  - conversational
  - gemma2
  - function-calling
  - trl

DiTy/gemma-2-9b-it-russian-function-calling-GGUF

This model is a fine-tuned version of google/gemma-2-9b-it for the Function Calling task on non-synthetic data, fully annotated by humans only, on the Russian version of the DiTy/function-calling dataset.

In addition to safetensors, the model is available in GGUF formats (in this case, you need to download only a single file (how to inference GGUF model)):

Filename Quant type File Size Description
gemma-2-9B-it-russian-function-calling-F16.gguf F16 18.5GB Base model with float16
gemma-2-9B-it-russian-function-calling-Q8_0.gguf Q8_0 9.83GB Extremely high quality, generally unneeded but max available quant.
gemma-2-9B-it-russian-function-calling-Q6_K.gguf Q6_K 7.59GB Very high quality, near perfect, recommended.
gemma-2-9B-it-russian-function-calling-Q5_K_M.gguf Q5_K_M 6.65GB High quality, very usable.
gemma-2-9B-it-russian-function-calling-Q5_K_S.gguf Q5_K_S 6.48GB High quality, very usable.

Model card разделы

Использование (HuggingFace Transformers)

Ниже представлены некоторые фрагменты кода о том, как быстро приступить к запуску модели. Сначала установите библиотеку Transformers с помощью:

pip install -U transformers

Как подготовить ваши функции (tools) для Function Calling

Вы должны написать функции (инструменты), используемые моделью, в коде на Python и обязательно добавить Python docstrings, как в примере ниже:

def get_weather(city: str):
    """
    Функция, которая возвращает погоду в заданном городе.
    
    Args:
        city: Город, для которого надо узнать погоду.
    """
    import random
    
    return "sunny" if random.random() > 0.5 else "rainy"


def get_sunrise_sunset_times(city: str):
    """
    Функция, которая возвращает время восхода и заката для заданного города для текущей даты (дата от пользователя не требуется), в формате списка: [sunrise_time, sunset_time].
    
    Args:
        city: Город, в котором можно узнать время восхода и захода солнца.
    """

    return ["6:00", "18:00"]

Просто используйте chat template для генерации

Далее вам нужно загрузить модель и токенизатор:

import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(
    "DiTy/gemma-2-9b-it-russian-function-calling-GGUF",
    device_map="auto",
    torch_dtype=torch.bfloat16,  # use float16 or float32 if bfloat16 is not available to you.
    cache_dir=PATH_TO_MODEL_DIR,  # optional
)
tokenizer = AutoTokenizer.from_pretrained(
    "DiTy/gemma-2-9b-it-russian-function-calling-GGUF",
    cache_dir=PATH_TO_MODEL_DIR,  # optional
)

Чтобы получить результат генерации, просто используйте apply_chat_template. Чтобы учесть наши написанные функции (инструменты), нам нужно передать их в виде списка через атрибут tools, а также использовать add_prompt_generation=True.

history_messages = [
    {"role": "system", "content": "Ты - полезный помощник, имеющий доступ к следующим функциям. Используйте их при необходимости - "},
    {"role": "user", "content": "Привет, не мог бы ты сказать мне, во сколько в Краснодаре восходит солнце?"}
]
inputs = tokenizer.apply_chat_template(
    history_messages,
    tokenize=False,
    add_generation_prompt=True,  # adding prompt for generation
    tools=[get_weather, get_sunrise_sunset_times],  # our functions (tools)
)
print(inputs)

Тогда наш inputs будет выглядеть следующим образом:

<bos><start_of_turn>user
Ты - полезный помощник, имеющий доступ к следующим функциям. Используйте их при необходимости - {
    "name": "get_weather",
    "description": "Функция, которая возвращает погоду в заданном городе.",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "Город, для которого надо узнать погоду."
            }
        },
        "required": [
            "city"
        ]
    }
},
{
    "name": "get_sunrise_sunset_times",
    "description": "Функция, которая возвращает время восхода и заката для заданного города для текущей даты (дата от пользователя не требуется), в формате списка: [sunrise_time, sunset_time].",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "Город, в котором можно узнать время восхода и захода солнца."
            }
        },
        "required": [
            "city"
        ]
    }
}

Привет, не мог бы ты сказать мне, во сколько в Краснодаре восходит солнце?<end_of_turn>
<start_of_turn>model

Теперь мы можем сгенерировать ответ модели. Будьте осторожны, потому что после apply_chat_template нет необходимости добавлять специальные токены во время токенизации. Поэтому используем add_special_tokens=False:

terminator_ids = [
    tokenizer.eos_token_id,
    tokenizer.convert_tokens_to_ids("<end_of_turn>"),
]
prompt_ids =  tokenizer.encode(inputs, add_special_tokens=False, return_tensors='pt').to(model.device)
generated_ids = model.generate(
    prompt_ids,
    max_new_tokens=512,
    eos_token_id=terminator_ids,
    bos_token_id=tokenizer.bos_token_id,
)
generated_response = tokenizer.decode(generated_ids[0][prompt_ids.shape[-1]:], skip_special_tokens=False)  # `skip_special_tokens=False` for debug
print(generated_response)

Мы получаем генерацию в виде вызова функции:

Вызов функции: {"name": "get_sunrise_sunset_times", "arguments": {"city": "Краснодар"}}<end_of_turn>

Отлично, теперь мы можем получать и обрабатывать результаты с помощью нашей вызываемой функции, а затем предоставлять модели ответ функции:

history_messages = [
    {"role": "system", "content": "Ты - полезный помощник, имеющий доступ к следующим функциям. Используйте их при необходимости - "},
    {"role": "user", "content": "Привет, не мог бы ты сказать мне, во сколько в Краснодаре восходит солнце?"},
    {"role": "function-call", "content": '{"name": "get_sunrise_sunset_times", "arguments": {"city": "Los Angeles"}}'},
    {"role": "function-response", "content": '{"times_list": ["6:00", "18:00"]}'},  # гипотетический ответ от нашей функции
]
inputs = tokenizer.apply_chat_template(
    history_messages,
    tokenize=False,
    add_generation_prompt=True,  # добавление запроса для генерации
    tools=[get_weather, get_sunrise_sunset_times],  # наши функции (tools)
)
print(inputs)

Давайте убедимся, что inputs верны:

<bos><start_of_turn>user
Ты - полезный помощник, имеющий доступ к следующим функциям. Используйте их при необходимости - {
    "name": "get_weather",
    "description": "Функция, которая возвращает погоду в заданном городе.",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "Город, для которого надо узнать погоду."
            }
        },
        "required": [
            "city"
        ]
    }
},
{
    "name": "get_sunrise_sunset_times",
    "description": "Функция, которая возвращает время восхода и заката для заданного города для текущей даты (дата от пользователя не требуется), в формате списка: [sunrise_time, sunset_time].",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "Город, в котором можно узнать время восхода и захода солнца."
            }
        },
        "required": [
            "city"
        ]
    }
}

Привет, не мог бы ты сказать мне, во сколько в Краснодаре восходит солнце?<end_of_turn>
<start_of_turn>model
Вызов функции: {"name": "get_sunrise_sunset_times", "arguments": {"city": "Краснодар"}}<end_of_turn>
<start_of_turn>user
Ответ от функции: {"times_list": ["6:00", "18:00"]}<end_of_turn>
<start_of_turn>model

Аналогично, мы генерируем ответ модели:

prompt_ids =  tokenizer.encode(inputs, add_special_tokens=False, return_tensors='pt').to(model.device)
generated_ids = model.generate(
    prompt_ids,
    max_new_tokens=512,
    eos_token_id=terminator_ids,
    bos_token_id=tokenizer.bos_token_id,
)
generated_response = tokenizer.decode(generated_ids[0][prompt_ids.shape[-1]:], skip_special_tokens=False)  # `skip_special_tokens=False` for debug
print(generated_response)

В результате мы получаем ответ модели:

В Краснодаре солнце восходит в 6:00 утра и заходит в 18:00 вечера.<end_of_turn>

Использование через transformers pipeline

Generation via pipeline
from transformers import pipeline
generation_pipeline = pipeline(
    "text-generation",
    model="DiTy/gemma-2-9b-it-russian-function-calling-GGUF",
    model_kwargs={
        "torch_dtype": torch.bfloat16,  # use float16 or float32 if bfloat16 is not supported for you. 
        "cache_dir": PATH_TO_MODEL_DIR,  # OPTIONAL
    },
    device_map="auto",
)
history_messages = [
    {"role": "system", "content": "Ты - полезный помощник, имеющий доступ к следующим функциям. Используйте их при необходимости - "},
    {"role": "user", "content": "Привет, не мог бы ты сказать мне, во сколько в Краснодаре восходит солнце?"},
    {"role": "function-call", "content": '{"name": "get_sunrise_sunset_times", "arguments": {"city": "Краснодар"}}'},
    {"role": "function-response", "content": '{"times_list": ["6:00", "18:00"]}'}
]
inputs = generation_pipeline.tokenizer.apply_chat_template(
    history_messages,
    tokenize=False,
    add_generation_prompt=True,
    tools=[get_weather, get_sunrise_sunset_times],
)
terminator_ids = [
    generation_pipeline.tokenizer.eos_token_id,
    generation_pipeline.tokenizer.convert_tokens_to_ids("<end_of_turn>")
]
outputs = generation_pipeline(
    inputs,
    max_new_tokens=512,
    eos_token_id=terminator_ids,
)
print(outputs[0]["generated_text"][len(inputs):])

Prompt структура и ожидаемый контент

Для наиболее корректной работы модели предполагается, что будет использоваться apply_chat_template. Необходимо передать историю сообщений в определенном формате.

history_messages = [
    {"role": "...", "content": "..."},
    ...
]

Для использования доступны следующие роли:

  • system - это необязательная роль, ее содержимое всегда размещается в самом начале и перед перечислением функций, доступных модели (инструментов). Вы всегда можете воспользоваться стандартным вариантом, который использовался во время обучения: "Ты - полезный помощник, имеющий доступ к следующим функциям. Используйте их при необходимости - "
  • user - запрос пользователя передается через эту роль.
  • function-call - тело вызова функции передается через эту роль. Хотя модель обучена генерировать вызов функции в виде "Вызов функции: {...}<end_of_turn>", вы все равно должны передать только тело "{...}" в поле "content", поскольку используя apply_chat_template, постскриптум в инструкциях добавляется автоматически.
  • function-response - в этой роли мы должны передать ответ нашей функции в поле "content" в виде словаря '{"name_returnable_value": value}'.
  • model - содержимое, относящееся к этой роли, считается сгенерированным текстом модели.

Структура истории чата для Function Calling

[
    {"role": "system", "content": "Ты - полезный помощник, имеющий доступ к следующим функциям. Используйте их при необходимости - "},
    {"role": "user", "content": "Привет, не мог бы ты сказать мне, во сколько в Краснодаре восходит солнце?"},
    {"role": "function-call", "content": '{"name": "get_sunrise_sunset_times", "arguments": {"city": "Краснодар"}}'},
    {"role": "function-response", "content": '{"times_list": ["6:00", "18:00"]}'}
]

Это выглядит как:

<bos><start_of_turn>user
Ты - полезный помощник, имеющий доступ к следующим функциям. Используйте их при необходимости - {
    "name": "get_weather",
    "description": "Функция, которая возвращает погоду в заданном городе.",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "Город, для которого надо узнать погоду."
            }
        },
        "required": [
            "city"
        ]
    }
},
{
    "name": "get_sunrise_sunset_times",
    "description": "Функция, которая возвращает время восхода и заката для заданного города для текущей даты (дата от пользователя не требуется), в формате списка: [sunrise_time, sunset_time].",
    "parameters": {
        "type": "object",
        "properties": {
            "city": {
                "type": "string",
                "description": "Город, в котором можно узнать время восхода и захода солнца."
            }
        },
        "required": [
            "city"
        ]
    }
}

Привет, не мог бы ты сказать мне, во сколько в Краснодаре восходит солнце?<end_of_turn>
<start_of_turn>model
Вызов функции: {"name": "get_sunrise_sunset_times", "arguments": {"city": "Краснодар"}}<end_of_turn>
<start_of_turn>user
Ответ от функции: {"times_list": ["6:00", "18:00"]}<end_of_turn>

Структура истории чата для обычного user-model шаблона

[
    {"role": "system", "content": "Ты добрый помощник"},
    {"role": "user", "content": "Расскажи мне о Москве"}
]

Это выглядит как:

<bos><start_of_turn>user
Ты добрый помощник

Расскажи мне о Москве<end_of_turn>

Оценка моделей

В процессе обучения ошибка валидации была приближена к следующим значениям:

Citation

@article{gemma_2024,
    title={Gemma},
    url={https://www.kaggle.com/m/3301},
    DOI={10.34740/KAGGLE/M/3301},
    publisher={Kaggle},
    author={Gemma Team},
    year={2024}
}