lets try functiongemma instead

This commit is contained in:
Alex O'Connell
2025-12-20 10:24:08 -05:00
parent 04e9bc1ee6
commit ee2d2e7640
8 changed files with 206 additions and 154 deletions

View File

@@ -520,7 +520,7 @@ def generate_status_request(template: dict, persona: str, language: str, max_dev
else:
return result
def format_example_sharegpt(example, persona, language, use_system_role, use_service_names):
def format_example_sharegpt(example, persona, language, use_system_role, use_service_names, tool_response_format):
piles = get_dataset_piles(language)
sys_prompt = generate_system_prompt(example, persona, language, piles.pile_of_system_prompts)
question = example["question"]
@@ -567,21 +567,26 @@ def format_example_sharegpt(example, persona, language, use_system_role, use_ser
]
if len(tool_calls) > 0:
conversation.extend([
{
"role": "assistant",
"content": [{ "type": "text", "text": answer_starting }],
"tool_calls": tool_calls
},
{
assistant_starting_block = {
"role": "assistant",
"content": [{ "type": "text", "text": answer_starting }],
"tool_calls": [ { "function": tc } for tc in tool_calls ]
}
if tool_response_format == "text":
tool_response_block = {
"role": "tool",
"content": [{ "type": "text", "text": json.dumps(result) } for result in tool_results]
},
{
"role": "assistant",
"content": [{ "type": "text", "text": answers }],
},
])
}
elif tool_response_format == "functiongemma":
tool_response_block = {
"role": "tool",
"content": [{ "name": result["tool_name"], "response": {"result": result["tool_result"]} } for result in tool_results]
}
assistant_confirmation_block = {
"role": "assistant",
"content": [{ "type": "text", "text": answers }],
}
conversation.extend([assistant_starting_block, tool_response_block, assistant_confirmation_block])
else:
conversation.extend([
{
@@ -595,7 +600,19 @@ def format_example_sharegpt(example, persona, language, use_system_role, use_ser
"tools": SERVICE_TOOLS if use_service_names else HASS_TOOLS
}
def generate_sft_file(filename: str, seed: int, format_func: Callable, use_system_role: bool, use_service_names: bool, personas: list[str], language: str, *, static_factor: float, template_factor: int, status_request_factor: int):
def generate_sft_file(
filename: str,
seed: int,
format_func: Callable,
use_system_role: bool,
use_service_names: bool,
personas: list[str],
language: str,
tool_response_format: str,
*,
static_factor: float,
template_factor: int,
status_request_factor: int):
random.seed(seed)
np.random.seed(seed)
piles = get_dataset_piles(language)
@@ -605,10 +622,10 @@ def generate_sft_file(filename: str, seed: int, format_func: Callable, use_syste
def run_factor_times(func, examples, data, persona, factor, language):
if factor >= 1:
for i in range(factor):
examples.append(format_func(func(data, persona, language, use_service_names=use_service_names), persona, language, use_system_role, use_service_names))
examples.append(format_func(func(data, persona, language, use_service_names=use_service_names), persona, language, use_system_role, use_service_names, tool_response_format))
else:
if random.random() < factor:
examples.append(format_func(func(data, persona, language, use_service_names=use_service_names), persona, language, use_system_role, use_service_names))
examples.append(format_func(func(data, persona, language, use_service_names=use_service_names), persona, language, use_system_role, use_service_names, tool_response_format))
generated_examples = []
@@ -680,6 +697,7 @@ def main(args=None):
parser.add_argument("--train", action="store_true", help="Set this flag to enable generation of the train dataset.")
parser.add_argument("--language", nargs="+", default=["english"], help="List of languages to generate: english, german, french, spanish, polish")
parser.add_argument("--no-system-role", action="store_true", help="Set this flag to disable the system role. It will be combined with the user role")
parser.add_argument("--tool-response-format", default="text", choices=["text", "functiongemma"], help="Format to use for tool responses.")
train_size_group = parser.add_mutually_exclusive_group()
train_size_group.add_argument('--small', action='store_const', const='small', dest='size')
@@ -704,6 +722,7 @@ def main(args=None):
use_system_role = not args.no_system_role
use_service_names = args.use_service_names
tool_response_format = args.tool_response_format
for language in args.language:
piles = get_dataset_piles(language)
@@ -711,20 +730,20 @@ def main(args=None):
suffix = f"_{language}" if len(args.language) > 1 else ""
if args.sample:
generate_sft_file(f"sample{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, static_factor=1, template_factor=1, status_request_factor=1)
generate_sft_file(f"sample{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, tool_response_format, static_factor=1, template_factor=1, status_request_factor=1)
if args.train:
if args.size == "small":
generate_sft_file(f"home_assistant_train{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, static_factor=1, template_factor=10, status_request_factor=8)
generate_sft_file(f"home_assistant_train{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, tool_response_format, static_factor=1, template_factor=10, status_request_factor=8)
elif args.size == "medium":
generate_sft_file(f"home_assistant_train{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, static_factor=5, template_factor=15, status_request_factor=12)
generate_sft_file(f"home_assistant_train{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, tool_response_format, static_factor=5, template_factor=15, status_request_factor=12)
elif args.size == "large":
generate_sft_file(f"home_assistant_train{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, static_factor=5, template_factor=20, status_request_factor=15)
generate_sft_file(f"home_assistant_train{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, tool_response_format, static_factor=5, template_factor=20, status_request_factor=15)
elif args.size == "xl":
generate_sft_file(f"home_assistant_train{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, static_factor=7, template_factor=25, status_request_factor=18)
generate_sft_file(f"home_assistant_train{suffix}", 42, format_func, use_system_role, use_service_names, personas, language, tool_response_format, static_factor=7, template_factor=25, status_request_factor=18)
else:
raise Exception(f"Unrecognized dataset size: {args.size}")
if args.test:
generate_sft_file(f"home_assistant_test{suffix}", 12345, format_func, use_system_role, use_service_names, personas, language, static_factor=0.25, template_factor=1, status_request_factor=2)
generate_sft_file(f"home_assistant_test{suffix}", 12345, format_func, use_system_role, use_service_names, personas, language, tool_response_format, static_factor=0.25, template_factor=1, status_request_factor=2)
if len(args.language) > 1:
if args.sample:

View File

@@ -53,7 +53,7 @@ SERVICE_TO_TOOL_MAP = {
# Home Assistant Intent Tools Definition
HASS_TOOLS = [
{
{"function": {
"name": TOOL_TURN_ON,
"description": "Turns on/opens/unlocks a device or entity",
"parameters": {
@@ -67,8 +67,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_TURN_OFF,
"description": "Turns off/closes/locks a device or entity",
"parameters": {
@@ -82,8 +82,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_TOGGLE,
"description": "Toggles a device or entity",
"parameters": {
@@ -97,8 +97,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_SET_POSITION,
"description": "Sets the position of a device or entity (e.g., blinds, covers)",
"parameters": {
@@ -111,8 +111,8 @@ HASS_TOOLS = [
},
"required": ["position"]
}
},
{
}},
{"function": {
"name": TOOL_LIGHT_SET,
"description": "Sets the brightness or color of a light",
"parameters": {
@@ -127,8 +127,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_CLIMATE_SET_TEMPERATURE,
"description": "Sets the target temperature of a climate device",
"parameters": {
@@ -141,8 +141,8 @@ HASS_TOOLS = [
},
"required": ["temperature"]
}
},
{
}},
{"function": {
"name": TOOL_SET_HUMIDITY,
"description": "Sets the target humidity level of a humidifier device",
"parameters": {
@@ -153,8 +153,8 @@ HASS_TOOLS = [
},
"required": ["name", "humidity"]
}
},
{
}},
{"function": {
"name": TOOL_SET_HUMIDIFIER_MODE,
"description": "Sets the mode of a humidifier device",
"parameters": {
@@ -165,8 +165,8 @@ HASS_TOOLS = [
},
"required": ["name", "mode"]
}
},
{
}},
{"function": {
"name": TOOL_MEDIA_UNPAUSE,
"description": "Resumes playback on a media player",
"parameters": {
@@ -178,8 +178,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_MEDIA_PAUSE,
"description": "Pauses playback on a media player",
"parameters": {
@@ -191,8 +191,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_MEDIA_NEXT,
"description": "Skips to the next media item on a media player",
"parameters": {
@@ -204,8 +204,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_SET_VOLUME,
"description": "Sets the volume of a media player",
"parameters": {
@@ -218,8 +218,8 @@ HASS_TOOLS = [
},
"required": ["volume_level"]
}
},
{
}},
{"function": {
"name": TOOL_VACUUM_START,
"description": "Starts a vacuum",
"parameters": {
@@ -231,8 +231,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_VACUUM_RETURN_TO_BASE,
"description": "Returns a vacuum to its base",
"parameters": {
@@ -244,8 +244,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_LIST_ADD_ITEM,
"description": "Adds an item to a todo list",
"parameters": {
@@ -256,8 +256,8 @@ HASS_TOOLS = [
},
"required": ["item"]
}
},
{
}},
{"function": {
"name": TOOL_START_TIMER,
"description": "Starts a timer",
"parameters": {
@@ -268,8 +268,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_CANCEL_TIMER,
"description": "Cancels a timer",
"parameters": {
@@ -279,8 +279,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_PAUSE_TIMER,
"description": "Pauses a timer",
"parameters": {
@@ -290,8 +290,8 @@ HASS_TOOLS = [
},
"required": []
}
},
{
}},
{"function": {
"name": TOOL_UNPAUSE_TIMER,
"description": "Resumes a paused timer",
"parameters": {
@@ -301,7 +301,7 @@ HASS_TOOLS = [
},
"required": []
}
}
}}
]
SERVICE_TOOL_ALLOWED_SERVICES = ["turn_on", "turn_off", "toggle", "press", "increase_speed", "decrease_speed", "open_cover", "close_cover", "stop_cover", "lock", "unlock",
@@ -309,7 +309,7 @@ SERVICE_TOOL_ALLOWED_SERVICES = ["turn_on", "turn_off", "toggle", "press", "incr
SERVICE_TOOL_ALLOWED_DOMAINS = ["light", "switch", "button", "fan", "cover", "lock", "media_player", "climate", "vacuum", "todo", "timer", "script"]
SERVICE_TOOLS = [
{
{"function": {
"name": "<sample>",
"description": "",
"parameters": {
@@ -330,8 +330,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "light.turn_on",
"description": "",
"parameters": {
@@ -345,8 +345,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "light.turn_off",
"description": "",
"parameters": {
@@ -358,8 +358,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "light.toggle",
"description": "",
"parameters": {
@@ -371,8 +371,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "switch.turn_on",
"description": "",
"parameters": {
@@ -384,8 +384,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "switch.turn_off",
"description": "",
"parameters": {
@@ -397,8 +397,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "switch.toggle",
"description": "",
"parameters": {
@@ -410,8 +410,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "fan.turn_on",
"description": "",
"parameters": {
@@ -423,8 +423,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "fan.turn_off",
"description": "",
"parameters": {
@@ -436,8 +436,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "fan.toggle",
"description": "",
"parameters": {
@@ -449,8 +449,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "fan.set_speed",
"description": "",
"parameters": {
@@ -464,8 +464,8 @@ SERVICE_TOOLS = [
"fan_mode"
]
}
},
{
}},
{"function": {
"name": "fan.increase_speed",
"description": "",
"parameters": {
@@ -477,8 +477,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "fan.decrease_speed",
"description": "",
"parameters": {
@@ -490,8 +490,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "button.press",
"description": "",
"parameters": {
@@ -503,8 +503,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "cover.open_cover",
"description": "",
"parameters": {
@@ -516,8 +516,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "cover.close_cover",
"description": "",
"parameters": {
@@ -529,8 +529,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "cover.stop_cover",
"description": "",
"parameters": {
@@ -542,8 +542,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "cover.set_cover_position",
"description": "",
"parameters": {
@@ -557,8 +557,8 @@ SERVICE_TOOLS = [
"position"
]
}
},
{
}},
{"function": {
"name": "lock.unlock",
"description": "",
"parameters": {
@@ -570,8 +570,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "lock.lock",
"description": "",
"parameters": {
@@ -583,8 +583,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "vacuum.start",
"description": "",
"parameters": {
@@ -596,8 +596,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "vacuum.stop",
"description": "",
"parameters": {
@@ -609,8 +609,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "vacuum.return_to_base",
"description": "",
"parameters": {
@@ -622,8 +622,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "media_player.media_play_pause",
"description": "",
"parameters": {
@@ -635,8 +635,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "media_player.media_pause",
"description": "",
"parameters": {
@@ -648,8 +648,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "media_player.media_play",
"description": "",
"parameters": {
@@ -661,8 +661,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "media_player.media_next_track",
"description": "",
"parameters": {
@@ -674,8 +674,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "media_player.media_previous_track",
"description": "",
"parameters": {
@@ -687,8 +687,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "media_player.volume_set",
"description": "",
"parameters": {
@@ -702,8 +702,8 @@ SERVICE_TOOLS = [
"volume_level"
]
}
},
{
}},
{"function": {
"name": "todo.add_item",
"description": "",
"parameters": {
@@ -717,8 +717,8 @@ SERVICE_TOOLS = [
"item"
]
}
},
{
}},
{"function": {
"name": "timer.start",
"description": "",
"parameters": {
@@ -731,8 +731,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "timer.cancel",
"description": "",
"parameters": {
@@ -744,8 +744,8 @@ SERVICE_TOOLS = [
"target_device"
]
}
},
{
}},
{"function": {
"name": "climate.set_temperature",
"description": "",
"parameters": {
@@ -759,8 +759,8 @@ SERVICE_TOOLS = [
"temperature"
]
}
},
{
}},
{"function": {
"name": "climate.set_humidity",
"description": "",
"parameters": {
@@ -774,8 +774,8 @@ SERVICE_TOOLS = [
"humidity"
]
}
},
{
}},
{"function": {
"name": "climate.set_hvac_mode",
"description": "",
"parameters": {
@@ -789,8 +789,8 @@ SERVICE_TOOLS = [
"hvac_mode"
]
}
},
{
}},
{"function": {
"name": "climate.set_preset_mode",
"description": "",
"parameters": {
@@ -804,8 +804,8 @@ SERVICE_TOOLS = [
"preset_mode"
]
}
},
{
}},
{"function": {
"name": "climate.set_fan_mode",
"description": "",
"parameters": {
@@ -819,5 +819,5 @@ SERVICE_TOOLS = [
"fan_mode"
]
}
}
}}
]

View File

@@ -2,7 +2,7 @@
{%- if not tools or tools | length == 0 %}No tools were provided. If the user requests you interact with a device, tell them you are unable to do so.{% else %}
Tools:
{% for tool in tools %}
- {{ tool['name'] }}({{ tool['parameters']['properties'].keys() | join(', ') }}): {{ tool['description'] }}
- {{ tool['function']['name'] }}({{ tool['function']['parameters']['properties'].keys() | join(', ') }}): {{ tool['function']['description'] }}
{% endfor -%}
{%- endif -%}
{%- for message in messages -%}
@@ -13,8 +13,7 @@ Tools:
{%- else -%}
{%- set role = message['role'] -%}
{%- endif -%}
{{ '<start_of_turn>' + role + '
' }}
{{ '<start_of_turn>' + role + '\n' }}
{%- if role == "tool" -%}
{{ '<tool_result>' }}
{%- endif -%}
@@ -41,13 +40,7 @@ Tools:
{%- endif -%}
{%- if message['tool_calls'] is defined and message['tool_calls'] | length > 0 %}
{%- for tool_call in message["tool_calls"] -%}
{{ '\n<tool_call>{"name": "' + tool_call['name'] + '", "arguments": ' + ('"' + tool_call['arguments'] + '"' if tool_call['arguments'] is string else tool_call['arguments'] | tojson) + '"}</tool_call>' }}
{{ '\n<tool_call>{"name": "' + tool_call['function']['name'] + '", "arguments": ' + ('"' + tool_call['function']['arguments'] + '"' if tool_call['function']['arguments'] is string else tool_call['function']['arguments'] | tojson) + '"}</tool_call>' }}
{%- endfor %}
{%- endif -%}
{{ '<end_of_turn>
' }}
{%- endfor -%}
{%- if add_generation_prompt -%}
{{'<start_of_turn>model
'}}
{%- endif -%}
{{ '<end_of_turn>\n' }}

View File

@@ -0,0 +1,43 @@
base_model: google/functiongemma-270m-it
model_type: Gemma3ForCausalLM
# gemma3 doesn't seem to play nice with ddp
ddp_find_unused_parameters: true
datasets:
- path: /workspace/data/datasets/sample.jsonl
ds_type: json
type: chat_template
roles_to_train:
- assistant
val_set_size: 0.0
output_dir: /workspace/data/training-runs/Home-Gemma3-270m
sequence_len: 4096
sample_packing: true
eval_sample_packing: false
use_tensorboard: true
# batch size = 16
gradient_accumulation_steps: 16
micro_batch_size: 1
num_epochs: 1
optimizer: adamw_bnb_8bit
lr_scheduler: cosine
learning_rate: 0.0002
bf16: true
gradient_checkpointing: true
gradient_checkpointing_kwargs:
use_reentrant: false
resume_from_checkpoint:
logging_steps: 1
flash_attention: true
warmup_ratio: 0.1
evals_per_epoch:
saves_per_epoch: 1
weight_decay: 0.0

View File

@@ -10,7 +10,7 @@ chat_template_jinja: |
{%- if not tools or tools | length == 0 %}No tools were provided. If the user requests you interact with a device, tell them you are unable to do so.{% else %}
Tools:
{% for tool in tools %}
- {{ tool['name'] }}({{ tool['parameters']['properties'].keys() | join(', ') }}): {{ tool['description'] }}
- {{ tool['function']['name'] }}({{ tool['function']['parameters']['properties'].keys() | join(', ') }}): {{ tool['function']['description'] }}
{% endfor -%}
{%- endif -%}
{%- for message in messages -%}
@@ -21,8 +21,7 @@ chat_template_jinja: |
{%- else -%}
{%- set role = message['role'] -%}
{%- endif -%}
{{ '<start_of_turn>' + role + '
' }}
{{ '<start_of_turn>' + role + '\n' }}
{%- if role == "tool" -%}
{{ '<tool_result>' }}
{%- endif -%}
@@ -49,15 +48,13 @@ chat_template_jinja: |
{%- endif -%}
{%- if message['tool_calls'] is defined and message['tool_calls'] | length > 0 %}
{%- for tool_call in message["tool_calls"] -%}
{{ '\n<tool_call>{"name": "' + tool_call['name'] + '", "arguments": ' + ('"' + tool_call['arguments'] + '"' if tool_call['arguments'] is string else tool_call['arguments'] | tojson) + '"}</tool_call>' }}
{{ '\n<tool_call>{"name": "' + tool_call['function']['name'] + '", "arguments": ' + ('"' + tool_call['function']['arguments'] + '"' if tool_call['function']['arguments'] is string else tool_call['function']['arguments'] | tojson) + '"}</tool_call>' }}
{%- endfor %}
{%- endif -%}
{{ '<end_of_turn>
' }}
{{ '<end_of_turn>\n' }}
{%- endfor -%}
{%- if add_generation_prompt -%}
{{'<start_of_turn>model
'}}
{{'<start_of_turn>model\n'}}
{%- endif -%}
special_tokens:
eot_tokens: