Commit c7c477c7 authored by chenych's avatar chenych
Browse files

add grpo

parents
Pipeline #2942 failed with stages
in 0 seconds
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING
from ...extras.misc import get_current_memory
from ...extras.packages import is_gradio_available
if is_gradio_available():
import gradio as gr
if TYPE_CHECKING:
from gradio.components import Component
def get_device_memory() -> "gr.Slider":
free, total = get_current_memory()
if total != -1:
used = round((total - free) / (1024**3), 2)
total = round(total / (1024**3), 2)
return gr.Slider(minimum=0, maximum=total, value=used, step=0.01, visible=True)
else:
return gr.Slider(visible=False)
def create_footer() -> dict[str, "Component"]:
with gr.Row():
device_memory = gr.Slider(visible=False, interactive=False)
timer = gr.Timer(value=5)
timer.tick(get_device_memory, outputs=[device_memory], queue=False)
return dict(device_memory=device_memory)
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING
from ...extras.packages import is_gradio_available
from ..common import is_multimodal
from .chatbot import create_chat_box
if is_gradio_available():
import gradio as gr
if TYPE_CHECKING:
from gradio.components import Component
from ..engine import Engine
def create_infer_tab(engine: "Engine") -> dict[str, "Component"]:
input_elems = engine.manager.get_base_elems()
elem_dict = dict()
with gr.Row():
infer_backend = gr.Dropdown(choices=["huggingface", "vllm", "sglang"], value="huggingface")
infer_dtype = gr.Dropdown(choices=["auto", "float16", "bfloat16", "float32"], value="auto")
extra_args = gr.Textbox(value='{"vllm_enforce_eager": true}')
with gr.Row():
load_btn = gr.Button()
unload_btn = gr.Button()
info_box = gr.Textbox(show_label=False, interactive=False)
input_elems.update({infer_backend, infer_dtype, extra_args})
elem_dict.update(
dict(
infer_backend=infer_backend,
infer_dtype=infer_dtype,
extra_args=extra_args,
load_btn=load_btn,
unload_btn=unload_btn,
info_box=info_box,
)
)
chatbot, messages, chat_elems = create_chat_box(engine, visible=False)
elem_dict.update(chat_elems)
load_btn.click(engine.chatter.load_model, input_elems, [info_box]).then(
lambda: gr.Column(visible=engine.chatter.loaded), outputs=[chat_elems["chat_box"]]
)
unload_btn.click(engine.chatter.unload_model, input_elems, [info_box]).then(
lambda: ([], []), outputs=[chatbot, messages]
).then(lambda: gr.Column(visible=engine.chatter.loaded), outputs=[chat_elems["chat_box"]])
engine.manager.get_elem_by_id("top.model_name").change(
lambda model_name: gr.Column(visible=is_multimodal(model_name)),
[engine.manager.get_elem_by_id("top.model_name")],
[chat_elems["mm_box"]],
)
return elem_dict
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING
from ...data import TEMPLATES
from ...extras.constants import METHODS, SUPPORTED_MODELS
from ...extras.misc import use_modelscope, use_openmind
from ...extras.packages import is_gradio_available
from ..common import save_config
from ..control import can_quantize, can_quantize_to, check_template, get_model_info, list_checkpoints, switch_hub
if is_gradio_available():
import gradio as gr
if TYPE_CHECKING:
from gradio.components import Component
def create_top() -> dict[str, "Component"]:
with gr.Row():
lang = gr.Dropdown(choices=["en", "ru", "zh", "ko", "ja"], value=None, scale=1)
available_models = list(SUPPORTED_MODELS.keys()) + ["Custom"]
model_name = gr.Dropdown(choices=available_models, value=None, scale=2)
model_path = gr.Textbox(scale=2)
default_hub = "modelscope" if use_modelscope() else "openmind" if use_openmind() else "huggingface"
hub_name = gr.Dropdown(choices=["huggingface", "modelscope", "openmind"], value=default_hub, scale=2)
with gr.Row():
finetuning_type = gr.Dropdown(choices=METHODS, value="lora", scale=1)
checkpoint_path = gr.Dropdown(multiselect=True, allow_custom_value=True, scale=6)
with gr.Row():
quantization_bit = gr.Dropdown(choices=["none", "8", "4"], value="none", allow_custom_value=True)
quantization_method = gr.Dropdown(choices=["bnb", "hqq", "eetq"], value="bnb")
template = gr.Dropdown(choices=list(TEMPLATES.keys()), value="default")
rope_scaling = gr.Dropdown(choices=["none", "linear", "dynamic", "yarn", "llama3"], value="none")
booster = gr.Dropdown(choices=["auto", "flashattn2", "unsloth", "liger_kernel"], value="auto")
model_name.change(get_model_info, [model_name], [model_path, template], queue=False).then(
list_checkpoints, [model_name, finetuning_type], [checkpoint_path], queue=False
).then(check_template, [lang, template])
model_name.input(save_config, inputs=[lang, hub_name, model_name], queue=False)
model_path.input(save_config, inputs=[lang, hub_name, model_name, model_path], queue=False)
finetuning_type.change(can_quantize, [finetuning_type], [quantization_bit], queue=False).then(
list_checkpoints, [model_name, finetuning_type], [checkpoint_path], queue=False
)
checkpoint_path.focus(list_checkpoints, [model_name, finetuning_type], [checkpoint_path], queue=False)
quantization_method.change(can_quantize_to, [quantization_method], [quantization_bit], queue=False)
hub_name.change(switch_hub, inputs=[hub_name], queue=False).then(
get_model_info, [model_name], [model_path, template], queue=False
).then(list_checkpoints, [model_name, finetuning_type], [checkpoint_path], queue=False).then(
check_template, [lang, template]
)
hub_name.input(save_config, inputs=[lang, hub_name], queue=False)
return dict(
lang=lang,
model_name=model_name,
model_path=model_path,
hub_name=hub_name,
finetuning_type=finetuning_type,
checkpoint_path=checkpoint_path,
quantization_bit=quantization_bit,
quantization_method=quantization_method,
template=template,
rope_scaling=rope_scaling,
booster=booster,
)
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING
from transformers.trainer_utils import SchedulerType
from ...extras.constants import TRAINING_STAGES
from ...extras.misc import get_device_count
from ...extras.packages import is_gradio_available
from ..common import DEFAULT_DATA_DIR
from ..control import change_stage, list_checkpoints, list_config_paths, list_datasets, list_output_dirs
from .data import create_preview_box
if is_gradio_available():
import gradio as gr
if TYPE_CHECKING:
from gradio.components import Component
from ..engine import Engine
def create_train_tab(engine: "Engine") -> dict[str, "Component"]:
input_elems = engine.manager.get_base_elems()
elem_dict = dict()
with gr.Row():
stages = list(TRAINING_STAGES.keys())
training_stage = gr.Dropdown(choices=stages, value=stages[0], scale=1)
dataset_dir = gr.Textbox(value=DEFAULT_DATA_DIR, scale=1)
dataset = gr.Dropdown(multiselect=True, allow_custom_value=True, scale=4)
preview_elems = create_preview_box(dataset_dir, dataset)
input_elems.update({training_stage, dataset_dir, dataset})
elem_dict.update(dict(training_stage=training_stage, dataset_dir=dataset_dir, dataset=dataset, **preview_elems))
with gr.Row():
learning_rate = gr.Textbox(value="5e-5")
num_train_epochs = gr.Textbox(value="3.0")
max_grad_norm = gr.Textbox(value="1.0")
max_samples = gr.Textbox(value="100000")
compute_type = gr.Dropdown(choices=["bf16", "fp16", "fp32", "pure_bf16"], value="bf16")
input_elems.update({learning_rate, num_train_epochs, max_grad_norm, max_samples, compute_type})
elem_dict.update(
dict(
learning_rate=learning_rate,
num_train_epochs=num_train_epochs,
max_grad_norm=max_grad_norm,
max_samples=max_samples,
compute_type=compute_type,
)
)
with gr.Row():
cutoff_len = gr.Slider(minimum=4, maximum=131072, value=2048, step=1)
batch_size = gr.Slider(minimum=1, maximum=1024, value=2, step=1)
gradient_accumulation_steps = gr.Slider(minimum=1, maximum=1024, value=8, step=1)
val_size = gr.Slider(minimum=0, maximum=1, value=0, step=0.001)
lr_scheduler_type = gr.Dropdown(choices=[scheduler.value for scheduler in SchedulerType], value="cosine")
input_elems.update({cutoff_len, batch_size, gradient_accumulation_steps, val_size, lr_scheduler_type})
elem_dict.update(
dict(
cutoff_len=cutoff_len,
batch_size=batch_size,
gradient_accumulation_steps=gradient_accumulation_steps,
val_size=val_size,
lr_scheduler_type=lr_scheduler_type,
)
)
with gr.Accordion(open=False) as extra_tab:
with gr.Row():
logging_steps = gr.Slider(minimum=1, maximum=1000, value=5, step=5)
save_steps = gr.Slider(minimum=10, maximum=5000, value=100, step=10)
warmup_steps = gr.Slider(minimum=0, maximum=5000, value=0, step=1)
neftune_alpha = gr.Slider(minimum=0, maximum=10, value=0, step=0.1)
extra_args = gr.Textbox(value='{"optim": "adamw_torch"}')
with gr.Row():
with gr.Column():
packing = gr.Checkbox()
neat_packing = gr.Checkbox()
with gr.Column():
train_on_prompt = gr.Checkbox()
mask_history = gr.Checkbox()
with gr.Column():
resize_vocab = gr.Checkbox()
use_llama_pro = gr.Checkbox()
with gr.Column():
enable_thinking = gr.Checkbox(value=True)
report_to = gr.Dropdown(
choices=["none", "wandb", "mlflow", "neptune", "tensorboard", "all"],
value="none",
allow_custom_value=True,
)
input_elems.update(
{
logging_steps,
save_steps,
warmup_steps,
neftune_alpha,
extra_args,
packing,
neat_packing,
train_on_prompt,
mask_history,
resize_vocab,
use_llama_pro,
enable_thinking,
report_to,
}
)
elem_dict.update(
dict(
extra_tab=extra_tab,
logging_steps=logging_steps,
save_steps=save_steps,
warmup_steps=warmup_steps,
neftune_alpha=neftune_alpha,
extra_args=extra_args,
packing=packing,
neat_packing=neat_packing,
train_on_prompt=train_on_prompt,
mask_history=mask_history,
resize_vocab=resize_vocab,
use_llama_pro=use_llama_pro,
enable_thinking=enable_thinking,
report_to=report_to,
)
)
with gr.Accordion(open=False) as freeze_tab:
with gr.Row():
freeze_trainable_layers = gr.Slider(minimum=-128, maximum=128, value=2, step=1)
freeze_trainable_modules = gr.Textbox(value="all")
freeze_extra_modules = gr.Textbox()
input_elems.update({freeze_trainable_layers, freeze_trainable_modules, freeze_extra_modules})
elem_dict.update(
dict(
freeze_tab=freeze_tab,
freeze_trainable_layers=freeze_trainable_layers,
freeze_trainable_modules=freeze_trainable_modules,
freeze_extra_modules=freeze_extra_modules,
)
)
with gr.Accordion(open=False) as lora_tab:
with gr.Row():
lora_rank = gr.Slider(minimum=1, maximum=1024, value=8, step=1)
lora_alpha = gr.Slider(minimum=1, maximum=2048, value=16, step=1)
lora_dropout = gr.Slider(minimum=0, maximum=1, value=0, step=0.01)
loraplus_lr_ratio = gr.Slider(minimum=0, maximum=64, value=0, step=0.01)
create_new_adapter = gr.Checkbox()
with gr.Row():
use_rslora = gr.Checkbox()
use_dora = gr.Checkbox()
use_pissa = gr.Checkbox()
lora_target = gr.Textbox(scale=2)
additional_target = gr.Textbox(scale=2)
input_elems.update(
{
lora_rank,
lora_alpha,
lora_dropout,
loraplus_lr_ratio,
create_new_adapter,
use_rslora,
use_dora,
use_pissa,
lora_target,
additional_target,
}
)
elem_dict.update(
dict(
lora_tab=lora_tab,
lora_rank=lora_rank,
lora_alpha=lora_alpha,
lora_dropout=lora_dropout,
loraplus_lr_ratio=loraplus_lr_ratio,
create_new_adapter=create_new_adapter,
use_rslora=use_rslora,
use_dora=use_dora,
use_pissa=use_pissa,
lora_target=lora_target,
additional_target=additional_target,
)
)
with gr.Accordion(open=False) as rlhf_tab:
with gr.Row():
pref_beta = gr.Slider(minimum=0, maximum=1, value=0.1, step=0.01)
pref_ftx = gr.Slider(minimum=0, maximum=10, value=0, step=0.01)
pref_loss = gr.Dropdown(choices=["sigmoid", "hinge", "ipo", "kto_pair", "orpo", "simpo"], value="sigmoid")
reward_model = gr.Dropdown(multiselect=True, allow_custom_value=True)
with gr.Column():
ppo_score_norm = gr.Checkbox()
ppo_whiten_rewards = gr.Checkbox()
input_elems.update({pref_beta, pref_ftx, pref_loss, reward_model, ppo_score_norm, ppo_whiten_rewards})
elem_dict.update(
dict(
rlhf_tab=rlhf_tab,
pref_beta=pref_beta,
pref_ftx=pref_ftx,
pref_loss=pref_loss,
reward_model=reward_model,
ppo_score_norm=ppo_score_norm,
ppo_whiten_rewards=ppo_whiten_rewards,
)
)
with gr.Accordion(open=False) as mm_tab:
with gr.Row():
freeze_vision_tower = gr.Checkbox(value=True)
freeze_multi_modal_projector = gr.Checkbox(value=True)
freeze_language_model = gr.Checkbox(value=False)
with gr.Row():
image_max_pixels = gr.Textbox(value="768*768")
image_min_pixels = gr.Textbox(value="32*32")
video_max_pixels = gr.Textbox(value="256*256")
video_min_pixels = gr.Textbox(value="16*16")
input_elems.update(
{
freeze_vision_tower,
freeze_multi_modal_projector,
freeze_language_model,
image_max_pixels,
image_min_pixels,
video_max_pixels,
video_min_pixels,
}
)
elem_dict.update(
dict(
mm_tab=mm_tab,
freeze_vision_tower=freeze_vision_tower,
freeze_multi_modal_projector=freeze_multi_modal_projector,
freeze_language_model=freeze_language_model,
image_max_pixels=image_max_pixels,
image_min_pixels=image_min_pixels,
video_max_pixels=video_max_pixels,
video_min_pixels=video_min_pixels,
)
)
with gr.Accordion(open=False) as galore_tab:
with gr.Row():
use_galore = gr.Checkbox()
galore_rank = gr.Slider(minimum=1, maximum=1024, value=16, step=1)
galore_update_interval = gr.Slider(minimum=1, maximum=2048, value=200, step=1)
galore_scale = gr.Slider(minimum=0, maximum=100, value=2.0, step=0.1)
galore_target = gr.Textbox(value="all")
input_elems.update({use_galore, galore_rank, galore_update_interval, galore_scale, galore_target})
elem_dict.update(
dict(
galore_tab=galore_tab,
use_galore=use_galore,
galore_rank=galore_rank,
galore_update_interval=galore_update_interval,
galore_scale=galore_scale,
galore_target=galore_target,
)
)
with gr.Accordion(open=False) as apollo_tab:
with gr.Row():
use_apollo = gr.Checkbox()
apollo_rank = gr.Slider(minimum=1, maximum=1024, value=16, step=1)
apollo_update_interval = gr.Slider(minimum=1, maximum=2048, value=200, step=1)
apollo_scale = gr.Slider(minimum=0, maximum=100, value=32.0, step=0.1)
apollo_target = gr.Textbox(value="all")
input_elems.update({use_apollo, apollo_rank, apollo_update_interval, apollo_scale, apollo_target})
elem_dict.update(
dict(
apollo_tab=apollo_tab,
use_apollo=use_apollo,
apollo_rank=apollo_rank,
apollo_update_interval=apollo_update_interval,
apollo_scale=apollo_scale,
apollo_target=apollo_target,
)
)
with gr.Accordion(open=False) as badam_tab:
with gr.Row():
use_badam = gr.Checkbox()
badam_mode = gr.Dropdown(choices=["layer", "ratio"], value="layer")
badam_switch_mode = gr.Dropdown(choices=["ascending", "descending", "random", "fixed"], value="ascending")
badam_switch_interval = gr.Slider(minimum=1, maximum=1024, value=50, step=1)
badam_update_ratio = gr.Slider(minimum=0, maximum=1, value=0.05, step=0.01)
input_elems.update({use_badam, badam_mode, badam_switch_mode, badam_switch_interval, badam_update_ratio})
elem_dict.update(
dict(
badam_tab=badam_tab,
use_badam=use_badam,
badam_mode=badam_mode,
badam_switch_mode=badam_switch_mode,
badam_switch_interval=badam_switch_interval,
badam_update_ratio=badam_update_ratio,
)
)
with gr.Accordion(open=False) as swanlab_tab:
with gr.Row():
use_swanlab = gr.Checkbox()
swanlab_project = gr.Textbox(value="llamafactory")
swanlab_run_name = gr.Textbox()
swanlab_workspace = gr.Textbox()
swanlab_api_key = gr.Textbox()
swanlab_mode = gr.Dropdown(choices=["cloud", "local"], value="cloud")
swanlab_link = gr.Markdown(visible=False)
input_elems.update(
{
use_swanlab,
swanlab_project,
swanlab_run_name,
swanlab_workspace,
swanlab_api_key,
swanlab_mode,
swanlab_link,
}
)
elem_dict.update(
dict(
swanlab_tab=swanlab_tab,
use_swanlab=use_swanlab,
swanlab_project=swanlab_project,
swanlab_run_name=swanlab_run_name,
swanlab_workspace=swanlab_workspace,
swanlab_api_key=swanlab_api_key,
swanlab_mode=swanlab_mode,
swanlab_link=swanlab_link,
)
)
with gr.Row():
cmd_preview_btn = gr.Button()
arg_save_btn = gr.Button()
arg_load_btn = gr.Button()
start_btn = gr.Button(variant="primary")
stop_btn = gr.Button(variant="stop")
with gr.Row():
with gr.Column(scale=3):
with gr.Row():
current_time = gr.Textbox(visible=False, interactive=False)
output_dir = gr.Dropdown(allow_custom_value=True)
config_path = gr.Dropdown(allow_custom_value=True)
with gr.Row():
device_count = gr.Textbox(value=str(get_device_count() or 1), interactive=False)
ds_stage = gr.Dropdown(choices=["none", "2", "3"], value="none")
ds_offload = gr.Checkbox()
with gr.Row():
resume_btn = gr.Checkbox(visible=False, interactive=False)
progress_bar = gr.Slider(visible=False, interactive=False)
with gr.Row():
output_box = gr.Markdown()
with gr.Column(scale=1):
loss_viewer = gr.Plot()
input_elems.update({output_dir, config_path, ds_stage, ds_offload})
elem_dict.update(
dict(
cmd_preview_btn=cmd_preview_btn,
arg_save_btn=arg_save_btn,
arg_load_btn=arg_load_btn,
start_btn=start_btn,
stop_btn=stop_btn,
current_time=current_time,
output_dir=output_dir,
config_path=config_path,
device_count=device_count,
ds_stage=ds_stage,
ds_offload=ds_offload,
resume_btn=resume_btn,
progress_bar=progress_bar,
output_box=output_box,
loss_viewer=loss_viewer,
)
)
output_elems = [output_box, progress_bar, loss_viewer, swanlab_link]
cmd_preview_btn.click(engine.runner.preview_train, input_elems, output_elems, concurrency_limit=None)
start_btn.click(engine.runner.run_train, input_elems, output_elems)
stop_btn.click(engine.runner.set_abort)
resume_btn.change(engine.runner.monitor, outputs=output_elems, concurrency_limit=None)
lang = engine.manager.get_elem_by_id("top.lang")
model_name: gr.Dropdown = engine.manager.get_elem_by_id("top.model_name")
finetuning_type: gr.Dropdown = engine.manager.get_elem_by_id("top.finetuning_type")
arg_save_btn.click(engine.runner.save_args, input_elems, output_elems, concurrency_limit=None)
arg_load_btn.click(
engine.runner.load_args, [lang, config_path], list(input_elems) + [output_box], concurrency_limit=None
)
dataset.focus(list_datasets, [dataset_dir, training_stage], [dataset], queue=False)
training_stage.change(change_stage, [training_stage], [dataset, packing], queue=False)
reward_model.focus(list_checkpoints, [model_name, finetuning_type], [reward_model], queue=False)
model_name.change(list_output_dirs, [model_name, finetuning_type, current_time], [output_dir], queue=False)
finetuning_type.change(list_output_dirs, [model_name, finetuning_type, current_time], [output_dir], queue=False)
output_dir.change(
list_output_dirs, [model_name, finetuning_type, current_time], [output_dir], concurrency_limit=None
)
output_dir.input(
engine.runner.check_output_dir,
[lang, model_name, finetuning_type, output_dir],
list(input_elems) + [output_box],
concurrency_limit=None,
)
config_path.change(list_config_paths, [current_time], [config_path], queue=False)
return elem_dict
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
from typing import Any, Optional
from transformers.trainer_utils import get_last_checkpoint
from ..extras.constants import (
CHECKPOINT_NAMES,
PEFT_METHODS,
RUNNING_LOG,
STAGES_USE_PAIR_DATA,
SWANLAB_CONFIG,
TRAINER_LOG,
TRAINING_STAGES,
)
from ..extras.packages import is_gradio_available, is_matplotlib_available
from ..extras.ploting import gen_loss_plot
from ..model import QuantizationMethod
from .common import DEFAULT_CONFIG_DIR, DEFAULT_DATA_DIR, get_model_path, get_save_dir, get_template, load_dataset_info
from .locales import ALERTS
if is_gradio_available():
import gradio as gr
def switch_hub(hub_name: str) -> None:
r"""Switch model hub.
Inputs: top.hub_name
"""
os.environ["USE_MODELSCOPE_HUB"] = "1" if hub_name == "modelscope" else "0"
os.environ["USE_OPENMIND_HUB"] = "1" if hub_name == "openmind" else "0"
def can_quantize(finetuning_type: str) -> "gr.Dropdown":
r"""Judge if the quantization is available in this finetuning type.
Inputs: top.finetuning_type
Outputs: top.quantization_bit
"""
if finetuning_type not in PEFT_METHODS:
return gr.Dropdown(value="none", interactive=False)
else:
return gr.Dropdown(interactive=True)
def can_quantize_to(quantization_method: str) -> "gr.Dropdown":
r"""Get the available quantization bits.
Inputs: top.quantization_method
Outputs: top.quantization_bit
"""
if quantization_method == QuantizationMethod.BNB:
available_bits = ["none", "8", "4"]
elif quantization_method == QuantizationMethod.HQQ:
available_bits = ["none", "8", "6", "5", "4", "3", "2", "1"]
elif quantization_method == QuantizationMethod.EETQ:
available_bits = ["none", "8"]
return gr.Dropdown(choices=available_bits)
def change_stage(training_stage: str = list(TRAINING_STAGES.keys())[0]) -> tuple[list[str], bool]:
r"""Modify states after changing the training stage.
Inputs: train.training_stage
Outputs: train.dataset, train.packing
"""
return [], TRAINING_STAGES[training_stage] == "pt"
def get_model_info(model_name: str) -> tuple[str, str]:
r"""Get the necessary information of this model.
Inputs: top.model_name
Outputs: top.model_path, top.template
"""
return get_model_path(model_name), get_template(model_name)
def check_template(lang: str, template: str) -> None:
r"""Check if an instruct model is used.
Please use queue=True to show the warning message.
Inputs: top.lang, top.template
"""
if template == "default":
gr.Warning(ALERTS["warn_no_instruct"][lang])
def get_trainer_info(lang: str, output_path: os.PathLike, do_train: bool) -> tuple[str, "gr.Slider", dict[str, Any]]:
r"""Get training infomation for monitor.
If do_train is True:
Inputs: top.lang, train.output_path
Outputs: train.output_box, train.progress_bar, train.loss_viewer, train.swanlab_link
If do_train is False:
Inputs: top.lang, eval.output_path
Outputs: eval.output_box, eval.progress_bar, None, None
"""
running_log = ""
running_progress = gr.Slider(visible=False)
running_info = {}
running_log_path = os.path.join(output_path, RUNNING_LOG)
if os.path.isfile(running_log_path):
with open(running_log_path, encoding="utf-8") as f:
running_log = "```\n" + f.read()[-20000:] + "\n```\n" # avoid lengthy log
trainer_log_path = os.path.join(output_path, TRAINER_LOG)
if os.path.isfile(trainer_log_path):
trainer_log: list[dict[str, Any]] = []
with open(trainer_log_path, encoding="utf-8") as f:
for line in f:
trainer_log.append(json.loads(line))
if len(trainer_log) != 0:
latest_log = trainer_log[-1]
percentage = latest_log["percentage"]
label = "Running {:d}/{:d}: {} < {}".format(
latest_log["current_steps"],
latest_log["total_steps"],
latest_log["elapsed_time"],
latest_log["remaining_time"],
)
running_progress = gr.Slider(label=label, value=percentage, visible=True)
if do_train and is_matplotlib_available():
running_info["loss_viewer"] = gr.Plot(gen_loss_plot(trainer_log))
swanlab_config_path = os.path.join(output_path, SWANLAB_CONFIG)
if os.path.isfile(swanlab_config_path):
with open(swanlab_config_path, encoding="utf-8") as f:
swanlab_public_config = json.load(f)
swanlab_link = swanlab_public_config["cloud"]["experiment_url"]
if swanlab_link is not None:
running_info["swanlab_link"] = gr.Markdown(
ALERTS["info_swanlab_link"][lang] + swanlab_link, visible=True
)
return running_log, running_progress, running_info
def list_checkpoints(model_name: str, finetuning_type: str) -> "gr.Dropdown":
r"""List all available checkpoints.
Inputs: top.model_name, top.finetuning_type
Outputs: top.checkpoint_path
"""
checkpoints = []
if model_name:
save_dir = get_save_dir(model_name, finetuning_type)
if save_dir and os.path.isdir(save_dir):
for checkpoint in os.listdir(save_dir):
if os.path.isdir(os.path.join(save_dir, checkpoint)) and any(
os.path.isfile(os.path.join(save_dir, checkpoint, name)) for name in CHECKPOINT_NAMES
):
checkpoints.append(checkpoint)
if finetuning_type in PEFT_METHODS:
return gr.Dropdown(value=[], choices=checkpoints, multiselect=True)
else:
return gr.Dropdown(value=None, choices=checkpoints, multiselect=False)
def list_config_paths(current_time: str) -> "gr.Dropdown":
r"""List all the saved configuration files.
Inputs: train.current_time
Outputs: train.config_path
"""
config_files = [f"{current_time}.yaml"]
if os.path.isdir(DEFAULT_CONFIG_DIR):
for file_name in os.listdir(DEFAULT_CONFIG_DIR):
if file_name.endswith(".yaml") and file_name not in config_files:
config_files.append(file_name)
return gr.Dropdown(choices=config_files)
def list_datasets(dataset_dir: str = None, training_stage: str = list(TRAINING_STAGES.keys())[0]) -> "gr.Dropdown":
r"""List all available datasets in the dataset dir for the training stage.
Inputs: *.dataset_dir, *.training_stage
Outputs: *.dataset
"""
dataset_info = load_dataset_info(dataset_dir if dataset_dir is not None else DEFAULT_DATA_DIR)
ranking = TRAINING_STAGES[training_stage] in STAGES_USE_PAIR_DATA
datasets = [k for k, v in dataset_info.items() if v.get("ranking", False) == ranking]
return gr.Dropdown(choices=datasets)
def list_output_dirs(model_name: Optional[str], finetuning_type: str, current_time: str) -> "gr.Dropdown":
r"""List all the directories that can resume from.
Inputs: top.model_name, top.finetuning_type, train.current_time
Outputs: train.output_dir
"""
output_dirs = [f"train_{current_time}"]
if model_name:
save_dir = get_save_dir(model_name, finetuning_type)
if save_dir and os.path.isdir(save_dir):
for folder in os.listdir(save_dir):
output_dir = os.path.join(save_dir, folder)
if os.path.isdir(output_dir) and get_last_checkpoint(output_dir) is not None:
output_dirs.append(folder)
return gr.Dropdown(choices=output_dirs)
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
CSS = r"""
.duplicate-button {
margin: auto !important;
color: white !important;
background: black !important;
border-radius: 100vh !important;
}
.thinking-summary {
padding: 8px !important;
}
.thinking-summary span {
border-radius: 4px !important;
padding: 4px !important;
cursor: pointer !important;
font-size: 14px !important;
background: rgb(245, 245, 245) !important;
}
.dark .thinking-summary span {
background: rgb(73, 73, 73) !important;
}
.thinking-container {
border-left: 2px solid #a6a6a6 !important;
padding-left: 10px !important;
margin: 4px 0 !important;
}
.thinking-container p {
color: #a6a6a6 !important;
}
.modal-box {
position: fixed !important;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* center horizontally */
max-width: 1000px;
max-height: 750px;
overflow-y: auto;
background-color: var(--input-background-fill);
flex-wrap: nowrap !important;
border: 2px solid black !important;
z-index: 1000;
padding: 10px;
}
.dark .modal-box {
border: 2px solid white !important;
}
"""
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING, Any
from .chatter import WebChatModel
from .common import create_ds_config, get_time, load_config
from .locales import LOCALES
from .manager import Manager
from .runner import Runner
if TYPE_CHECKING:
from gradio.components import Component
class Engine:
r"""A general engine to control the behaviors of Web UI."""
def __init__(self, demo_mode: bool = False, pure_chat: bool = False) -> None:
self.demo_mode = demo_mode
self.pure_chat = pure_chat
self.manager = Manager()
self.runner = Runner(self.manager, demo_mode)
self.chatter = WebChatModel(self.manager, demo_mode, lazy_init=(not pure_chat))
if not demo_mode:
create_ds_config()
def _update_component(self, input_dict: dict[str, dict[str, Any]]) -> dict["Component", "Component"]:
r"""Update gradio components according to the (elem_id, properties) mapping."""
output_dict: dict[Component, Component] = {}
for elem_id, elem_attr in input_dict.items():
elem = self.manager.get_elem_by_id(elem_id)
output_dict[elem] = elem.__class__(**elem_attr)
return output_dict
def resume(self):
r"""Get the initial value of gradio components and restores training status if necessary."""
user_config = load_config() if not self.demo_mode else {} # do not use config in demo mode
lang = user_config.get("lang") or "en"
init_dict = {"top.lang": {"value": lang}, "infer.chat_box": {"visible": self.chatter.loaded}}
if not self.pure_chat:
current_time = get_time()
hub_name = user_config.get("hub_name") or "huggingface"
init_dict["top.hub_name"] = {"value": hub_name}
init_dict["train.current_time"] = {"value": current_time}
init_dict["train.output_dir"] = {"value": f"train_{current_time}"}
init_dict["train.config_path"] = {"value": f"{current_time}.yaml"}
init_dict["eval.output_dir"] = {"value": f"eval_{current_time}"}
init_dict["infer.mm_box"] = {"visible": False}
if user_config.get("last_model", None):
init_dict["top.model_name"] = {"value": user_config["last_model"]}
yield self._update_component(init_dict)
if self.runner.running and not self.demo_mode and not self.pure_chat:
yield {elem: elem.__class__(value=value) for elem, value in self.runner.running_data.items()}
if self.runner.do_train:
yield self._update_component({"train.resume_btn": {"value": True}})
else:
yield self._update_component({"eval.resume_btn": {"value": True}})
def change_lang(self, lang: str):
r"""Update the displayed language of gradio components."""
return {
elem: elem.__class__(**LOCALES[elem_name][lang])
for elem_name, elem in self.manager.get_elem_iter()
if elem_name in LOCALES
}
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import platform
from ..extras.misc import fix_proxy, is_env_enabled
from ..extras.packages import is_gradio_available
from .common import save_config
from .components import (
create_chat_box,
create_eval_tab,
create_export_tab,
create_footer,
create_infer_tab,
create_top,
create_train_tab,
)
from .css import CSS
from .engine import Engine
if is_gradio_available():
import gradio as gr
def create_ui(demo_mode: bool = False) -> "gr.Blocks":
engine = Engine(demo_mode=demo_mode, pure_chat=False)
hostname = os.getenv("HOSTNAME", os.getenv("COMPUTERNAME", platform.node())).split(".")[0]
with gr.Blocks(title=f"LLaMA Factory ({hostname})", css=CSS) as demo:
title = gr.HTML()
subtitle = gr.HTML()
if demo_mode:
gr.DuplicateButton(value="Duplicate Space for private use", elem_classes="duplicate-button")
engine.manager.add_elems("head", {"title": title, "subtitle": subtitle})
engine.manager.add_elems("top", create_top())
lang: gr.Dropdown = engine.manager.get_elem_by_id("top.lang")
with gr.Tab("Train"):
engine.manager.add_elems("train", create_train_tab(engine))
with gr.Tab("Evaluate & Predict"):
engine.manager.add_elems("eval", create_eval_tab(engine))
with gr.Tab("Chat"):
engine.manager.add_elems("infer", create_infer_tab(engine))
if not demo_mode:
with gr.Tab("Export"):
engine.manager.add_elems("export", create_export_tab(engine))
engine.manager.add_elems("footer", create_footer())
demo.load(engine.resume, outputs=engine.manager.get_elem_list(), concurrency_limit=None)
lang.change(engine.change_lang, [lang], engine.manager.get_elem_list(), queue=False)
lang.input(save_config, inputs=[lang], queue=False)
return demo
def create_web_demo() -> "gr.Blocks":
engine = Engine(pure_chat=True)
hostname = os.getenv("HOSTNAME", os.getenv("COMPUTERNAME", platform.node())).split(".")[0]
with gr.Blocks(title=f"LLaMA Factory Web Demo ({hostname})", css=CSS) as demo:
lang = gr.Dropdown(choices=["en", "ru", "zh", "ko", "ja"], scale=1)
engine.manager.add_elems("top", dict(lang=lang))
_, _, chat_elems = create_chat_box(engine, visible=True)
engine.manager.add_elems("infer", chat_elems)
demo.load(engine.resume, outputs=engine.manager.get_elem_list(), concurrency_limit=None)
lang.change(engine.change_lang, [lang], engine.manager.get_elem_list(), queue=False)
lang.input(save_config, inputs=[lang], queue=False)
return demo
def run_web_ui() -> None:
gradio_ipv6 = is_env_enabled("GRADIO_IPV6")
gradio_share = is_env_enabled("GRADIO_SHARE")
server_name = os.getenv("GRADIO_SERVER_NAME", "[::]" if gradio_ipv6 else "0.0.0.0")
print("Visit http://ip:port for Web UI, e.g., http://127.0.0.1:7860")
fix_proxy(ipv6_enabled=gradio_ipv6)
create_ui().queue().launch(share=gradio_share, server_name=server_name, inbrowser=True)
def run_web_demo() -> None:
gradio_ipv6 = is_env_enabled("GRADIO_IPV6")
gradio_share = is_env_enabled("GRADIO_SHARE")
server_name = os.getenv("GRADIO_SERVER_NAME", "[::]" if gradio_ipv6 else "0.0.0.0")
print("Visit http://ip:port for Web UI, e.g., http://127.0.0.1:7860")
fix_proxy(ipv6_enabled=gradio_ipv6)
create_web_demo().queue().launch(share=gradio_share, server_name=server_name, inbrowser=True)
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
LOCALES = {
"title": {
"en": {
"value": "<h1><center>🦙🏭LLaMA Factory: Unified Efficient Fine-Tuning of 100+ LLMs</center></h1>",
},
"ru": {
"value": "<h1><center>🦙🏭LLaMA Factory: Унифицированная эффективная тонкая настройка 100+ LLMs</center></h1>",
},
"zh": {
"value": "<h1><center>🦙🏭LLaMA Factory: 一站式大模型高效微调平台</center></h1>",
},
"ko": {
"value": "<h1><center>🦙🏭LLaMA Factory: 100+ LLMs를 위한 통합 효율적인 튜닝</center></h1>",
},
"ja": {
"value": "<h1><center>🦙🏭LLaMA Factory: 100+ LLMs の統合効率的なチューニング</center></h1>",
},
},
"subtitle": {
"en": {
"value": (
"<h3><center>Visit <a href='https://github.com/hiyouga/LLaMA-Factory' target='_blank'>"
"GitHub Page</a></center></h3>"
),
},
"ru": {
"value": (
"<h3><center>Посетить <a href='https://github.com/hiyouga/LLaMA-Factory' target='_blank'>"
"страницу GitHub</a></center></h3>"
),
},
"zh": {
"value": (
"<h3><center>访问 <a href='https://github.com/hiyouga/LLaMA-Factory' target='_blank'>"
"GitHub 主页</a></center></h3>"
),
},
"ko": {
"value": (
"<h3><center><a href='https://github.com/hiyouga/LLaMA-Factory' target='_blank'>"
"GitHub 페이지</a>를 방문하세요.</center></h3>"
),
},
"ja": {
"value": (
"<h3><center><a href='https://github.com/hiyouga/LLaMA-Factory' target='_blank'>"
"GitHub ページ</a>にアクセスする</center></h3>"
),
},
},
"lang": {
"en": {
"label": "Language",
},
"ru": {
"label": "Язык",
},
"zh": {
"label": "语言",
},
"ko": {
"label": "언어",
},
"ja": {
"label": "言語",
},
},
"model_name": {
"en": {
"label": "Model name",
"info": "Input the initial name to search for the model.",
},
"ru": {
"label": "Название модели",
"info": "Введите начальное имя для поиска модели.",
},
"zh": {
"label": "模型名称",
"info": "输入首单词以检索模型。",
},
"ko": {
"label": "모델 이름",
"info": "모델을 검색할 초기 이름을 입력하세요.",
},
"ja": {
"label": "モデル名",
"info": "モデルを検索するための初期名を入力してください。",
},
},
"model_path": {
"en": {
"label": "Model path",
"info": "Path to pretrained model or model identifier from Hugging Face.",
},
"ru": {
"label": "Путь к модели",
"info": "Путь к предварительно обученной модели или идентификатор модели от Hugging Face.",
},
"zh": {
"label": "模型路径",
"info": "本地模型的文件路径或 Hugging Face 的模型标识符。",
},
"ko": {
"label": "모델 경로",
"info": "사전 훈련된 모델의 경로 또는 Hugging Face의 모델 식별자.",
},
"ja": {
"label": "モデルパス",
"info": "事前学習済みモデルへのパス、または Hugging Face のモデル識別子。",
},
},
"hub_name": {
"en": {
"label": "Hub name",
"info": "Choose the model download source.",
},
"ru": {
"label": "Имя хаба",
"info": "Выберите источник загрузки модели.",
},
"zh": {
"label": "模型下载源",
"info": "选择模型下载源。(网络受限环境推荐使用 ModelScope)",
},
"ko": {
"label": "모델 다운로드 소스",
"info": "모델 다운로드 소스를 선택하세요.",
},
"ja": {
"label": "モデルダウンロードソース",
"info": "モデルをダウンロードするためのソースを選択してください。",
},
},
"finetuning_type": {
"en": {
"label": "Finetuning method",
},
"ru": {
"label": "Метод дообучения",
},
"zh": {
"label": "微调方法",
},
"ko": {
"label": "파인튜닝 방법",
},
"ja": {
"label": "ファインチューニング方法",
},
},
"checkpoint_path": {
"en": {
"label": "Checkpoint path",
},
"ru": {
"label": "Путь контрольной точки",
},
"zh": {
"label": "检查点路径",
},
"ko": {
"label": "체크포인트 경로",
},
"ja": {
"label": "チェックポイントパス",
},
},
"quantization_bit": {
"en": {
"label": "Quantization bit",
"info": "Enable quantization (QLoRA).",
},
"ru": {
"label": "Уровень квантования",
"info": "Включить квантование (QLoRA).",
},
"zh": {
"label": "量化等级",
"info": "启用量化(QLoRA)。",
},
"ko": {
"label": "양자화 비트",
"info": "양자화 활성화 (QLoRA).",
},
"ja": {
"label": "量子化ビット",
"info": "量子化を有効にする (QLoRA)。",
},
},
"quantization_method": {
"en": {
"label": "Quantization method",
"info": "Quantization algorithm to use.",
},
"ru": {
"label": "Метод квантования",
"info": "Алгоритм квантования, который следует использовать.",
},
"zh": {
"label": "量化方法",
"info": "使用的量化算法。",
},
"ko": {
"label": "양자화 방법",
"info": "사용할 양자화 알고리즘.",
},
"ja": {
"label": "量子化方法",
"info": "使用する量子化アルゴリズム。",
},
},
"template": {
"en": {
"label": "Chat template",
"info": "The chat template used in constructing prompts.",
},
"ru": {
"label": "Шаблон чата",
"info": "Шаблон чата используемый для составления подсказок.",
},
"zh": {
"label": "对话模板",
"info": "构建提示词时使用的模板。",
},
"ko": {
"label": "채팅 템플릿",
"info": "프롬프트 작성에 사용되는 채팅 템플릿.",
},
"ja": {
"label": "チャットテンプレート",
"info": "プロンプトの構築に使用されるチャットテンプレート。",
},
},
"rope_scaling": {
"en": {
"label": "RoPE scaling",
"info": "RoPE scaling method to use.",
},
"ru": {
"label": "Масштабирование RoPE",
"info": "Метод масштабирования RoPE для использования.",
},
"zh": {"label": "RoPE 插值方法", "info": "RoPE 插值时使用的方法。"},
"ko": {
"label": "RoPE 스케일링",
"info": "사용할 RoPE 스케일링 방법.",
},
"ja": {
"label": "RoPE スケーリング",
"info": "使用する RoPE スケーリング方法。",
},
},
"booster": {
"en": {
"label": "Booster",
"info": "Approach used to boost training speed.",
},
"ru": {
"label": "Ускоритель",
"info": "Подход, используемый для ускорения обучения.",
},
"zh": {"label": "加速方式", "info": "使用的加速方法。"},
"ko": {
"label": "부스터",
"info": "훈련 속도를 향상시키기 위해 사용된 접근 방식.",
},
"ja": {
"label": "ブースター",
"info": "トレーニング速度を向上させるためのアプローチ。",
},
},
"training_stage": {
"en": {
"label": "Stage",
"info": "The stage to perform in training.",
},
"ru": {
"label": "Этап",
"info": "Этап выполнения обучения.",
},
"zh": {
"label": "训练阶段",
"info": "目前采用的训练方式。",
},
"ko": {
"label": "학습 단계",
"info": "수행할 학습 방법.",
},
"ja": {
"label": "ステージ",
"info": "トレーニングで実行するステージ。",
},
},
"dataset_dir": {
"en": {
"label": "Data dir",
"info": "Path to the data directory.",
},
"ru": {
"label": "Директория данных",
"info": "Путь к директории данных.",
},
"zh": {
"label": "数据路径",
"info": "数据文件夹的路径。",
},
"ko": {
"label": "데이터 디렉토리",
"info": "데이터 디렉토리의 경로.",
},
"ja": {
"label": "データディレクトリ",
"info": "データディレクトリへのパス。",
},
},
"dataset": {
"en": {
"label": "Dataset",
},
"ru": {
"label": "Набор данных",
},
"zh": {
"label": "数据集",
},
"ko": {
"label": "데이터셋",
},
"ja": {
"label": "データセット",
},
},
"data_preview_btn": {
"en": {
"value": "Preview dataset",
},
"ru": {
"value": "Просмотреть набор данных",
},
"zh": {
"value": "预览数据集",
},
"ko": {
"value": "데이터셋 미리보기",
},
"ja": {
"value": "データセットをプレビュー",
},
},
"preview_count": {
"en": {
"label": "Count",
},
"ru": {
"label": "Количество",
},
"zh": {
"label": "数量",
},
"ko": {
"label": "개수",
},
"ja": {
"label": "カウント",
},
},
"page_index": {
"en": {
"label": "Page",
},
"ru": {
"label": "Страница",
},
"zh": {
"label": "页数",
},
"ko": {
"label": "페이지",
},
"ja": {
"label": "ページ",
},
},
"prev_btn": {
"en": {
"value": "Prev",
},
"ru": {
"value": "Предыдущая",
},
"zh": {
"value": "上一页",
},
"ko": {
"value": "이전",
},
"ja": {
"value": "前へ",
},
},
"next_btn": {
"en": {
"value": "Next",
},
"ru": {
"value": "Следующая",
},
"zh": {
"value": "下一页",
},
"ko": {
"value": "다음",
},
"ja": {
"value": "次へ",
},
},
"close_btn": {
"en": {
"value": "Close",
},
"ru": {
"value": "Закрыть",
},
"zh": {
"value": "关闭",
},
"ko": {
"value": "닫기",
},
"ja": {
"value": "閉じる",
},
},
"preview_samples": {
"en": {
"label": "Samples",
},
"ru": {
"label": "Примеры",
},
"zh": {
"label": "样例",
},
"ko": {
"label": "샘플",
},
"ja": {
"label": "サンプル",
},
},
"learning_rate": {
"en": {
"label": "Learning rate",
"info": "Initial learning rate for AdamW.",
},
"ru": {
"label": "Скорость обучения",
"info": "Начальная скорость обучения для AdamW.",
},
"zh": {
"label": "学习率",
"info": "AdamW 优化器的初始学习率。",
},
"ko": {
"label": "학습률",
"info": "AdamW의 초기 학습률.",
},
"ja": {
"label": "学習率",
"info": "AdamW の初期学習率。",
},
},
"num_train_epochs": {
"en": {
"label": "Epochs",
"info": "Total number of training epochs to perform.",
},
"ru": {
"label": "Эпохи",
"info": "Общее количество эпох обучения.",
},
"zh": {
"label": "训练轮数",
"info": "需要执行的训练总轮数。",
},
"ko": {
"label": "에포크",
"info": "수행할 총 학습 에포크 수.",
},
"ja": {
"label": "エポック数",
"info": "実行するトレーニングの総エポック数。",
},
},
"max_grad_norm": {
"en": {
"label": "Maximum gradient norm",
"info": "Norm for gradient clipping.",
},
"ru": {
"label": "Максимальная норма градиента",
"info": "Норма для обрезки градиента.",
},
"zh": {
"label": "最大梯度范数",
"info": "用于梯度裁剪的范数。",
},
"ko": {
"label": "최대 그레디언트 노름(norm)",
"info": "그레디언트 클리핑을 위한 노름(norm).",
},
"ja": {
"label": "最大勾配ノルム",
"info": "勾配クリッピングのためのノルム。",
},
},
"max_samples": {
"en": {
"label": "Max samples",
"info": "Maximum samples per dataset.",
},
"ru": {
"label": "Максимальное количество образцов",
"info": "Максимальное количество образцов на набор данных.",
},
"zh": {
"label": "最大样本数",
"info": "每个数据集的最大样本数。",
},
"ko": {
"label": "최대 샘플 수",
"info": "데이터셋 당 최대 샘플 수.",
},
"ja": {
"label": "最大サンプル数",
"info": "データセットごとの最大サンプル数。",
},
},
"compute_type": {
"en": {
"label": "Compute type",
"info": "Whether to use mixed precision training.",
},
"ru": {
"label": "Тип вычислений",
"info": "Использовать ли обучение смешанной точности.",
},
"zh": {
"label": "计算类型",
"info": "是否使用混合精度训练。",
},
"ko": {
"label": "연산 유형",
"info": "혼합 정밀도 훈련을 사용할지 여부.",
},
"ja": {
"label": "計算タイプ",
"info": "混合精度トレーニングを使用するかどうか。",
},
},
"cutoff_len": {
"en": {
"label": "Cutoff length",
"info": "Max tokens in input sequence.",
},
"ru": {
"label": "Длина обрезки",
"info": "Максимальное количество токенов во входной последовательности.",
},
"zh": {
"label": "截断长度",
"info": "输入序列分词后的最大长度。",
},
"ko": {
"label": "컷오프 길이",
"info": "입력 시퀀스의 최대 토큰 수.",
},
"ja": {
"label": "カットオフ長",
"info": "入力シーケンスの最大トークン数。",
},
},
"batch_size": {
"en": {
"label": "Batch size",
"info": "Number of samples processed on each GPU.",
},
"ru": {
"label": "Размер пакета",
"info": "Количество образцов для обработки на каждом GPU.",
},
"zh": {
"label": "批处理大小",
"info": "每个 GPU 处理的样本数量。",
},
"ko": {
"label": "배치 크기",
"info": "각 GPU에서 처리되는 샘플 수.",
},
"ja": {
"label": "バッチサイズ",
"info": "各 GPU で処理されるサンプル数。",
},
},
"gradient_accumulation_steps": {
"en": {
"label": "Gradient accumulation",
"info": "Number of steps for gradient accumulation.",
},
"ru": {
"label": "Накопление градиента",
"info": "Количество шагов накопления градиента.",
},
"zh": {
"label": "梯度累积",
"info": "梯度累积的步数。",
},
"ko": {
"label": "그레디언트 누적",
"info": "그레디언트 누적 단계 수.",
},
"ja": {
"label": "勾配累積",
"info": "勾配累積のステップ数。",
},
},
"val_size": {
"en": {
"label": "Val size",
"info": "Percentage of validation set from the entire dataset.",
},
"ru": {
"label": "Размер валидации",
"info": "Пропорция данных в наборе для разработки.",
},
"zh": {
"label": "验证集比例",
"info": "验证集占全部样本的百分比。",
},
"ko": {
"label": "검증 데이터셋 크기",
"info": "개발 데이터셋에서 검증 데이터의 비율.",
},
"ja": {
"label": "検証セットサイズ",
"info": "データセット全体に対する検証セットの割合。",
},
},
"lr_scheduler_type": {
"en": {
"label": "LR scheduler",
"info": "Name of the learning rate scheduler.",
},
"ru": {
"label": "Планировщик скорости обучения",
"info": "Название планировщика скорости обучения.",
},
"zh": {
"label": "学习率调节器",
"info": "学习率调度器的名称。",
},
"ko": {
"label": "LR 스케줄러",
"info": "학습률 스케줄러의 이름.",
},
"ja": {
"label": "学習率スケジューラ",
"info": "学習率スケジューラの名前。",
},
},
"extra_tab": {
"en": {
"label": "Extra configurations",
},
"ru": {
"label": "Дополнительные конфигурации",
},
"zh": {
"label": "其它参数设置",
},
"ko": {
"label": "추가 구성(configuration)",
},
"ja": {
"label": "追加設定",
},
},
"logging_steps": {
"en": {
"label": "Logging steps",
"info": "Number of steps between two logs.",
},
"ru": {
"label": "Шаги логирования",
"info": "Количество шагов между двумя записями в журнале.",
},
"zh": {
"label": "日志间隔",
"info": "每两次日志输出间的更新步数。",
},
"ko": {
"label": "로깅 스텝",
"info": "이전 로깅과 다음 로깅 간 스텝 수.",
},
"ja": {
"label": "ロギングステップ",
"info": "2 つのログ間のステップ数。",
},
},
"save_steps": {
"en": {
"label": "Save steps",
"info": "Number of steps between two checkpoints.",
},
"ru": {
"label": "Шаги сохранения",
"info": "Количество шагов между двумя контрольными точками.",
},
"zh": {
"label": "保存间隔",
"info": "每两次断点保存间的更新步数。",
},
"ko": {
"label": "저장 스텝",
"info": "이전 체크포인트와 다음 체크포인트 사이의 스텝 수.",
},
"ja": {
"label": "保存ステップ",
"info": "2 つのチェックポイント間のステップ数。",
},
},
"warmup_steps": {
"en": {
"label": "Warmup steps",
"info": "Number of steps used for warmup.",
},
"ru": {
"label": "Шаги прогрева",
"info": "Количество шагов, используемых для прогрева.",
},
"zh": {
"label": "预热步数",
"info": "学习率预热采用的步数。",
},
"ko": {
"label": "Warmup 스텝",
"info": "Warmup에 사용되는 스텝 수.",
},
"ja": {
"label": "ウォームアップステップ",
"info": "ウォームアップに使用されるステップ数。",
},
},
"neftune_alpha": {
"en": {
"label": "NEFTune alpha",
"info": "Magnitude of noise adding to embedding vectors.",
},
"ru": {
"label": "NEFTune alpha",
"info": "Величина шума, добавляемого к векторам вложений.",
},
"zh": {
"label": "NEFTune 噪声参数",
"info": "嵌入向量所添加的噪声大小。",
},
"ko": {
"label": "NEFTune 알파",
"info": "임베딩 벡터에 추가되는 노이즈의 크기.",
},
"ja": {
"label": "NEFTune alpha",
"info": "埋め込みベクトルに追加されるノイズの大きさ。",
},
},
"extra_args": {
"en": {
"label": "Extra arguments",
"info": "Extra arguments passed to the trainer in JSON format.",
},
"ru": {
"label": "Дополнительные аргументы",
"info": "Дополнительные аргументы, которые передаются тренеру в формате JSON.",
},
"zh": {
"label": "额外参数",
"info": "以 JSON 格式传递给训练器的额外参数。",
},
"ko": {
"label": "추가 인수",
"info": "JSON 형식으로 트레이너에게 전달할 추가 인수입니다.",
},
"ja": {
"label": "追加引数",
"info": "JSON 形式でトレーナーに渡される追加引数。",
},
},
"packing": {
"en": {
"label": "Pack sequences",
"info": "Pack sequences into samples of fixed length.",
},
"ru": {
"label": "Упаковка последовательностей",
"info": "Упаковка последовательностей в образцы фиксированной длины.",
},
"zh": {
"label": "序列打包",
"info": "将序列打包为等长样本。",
},
"ko": {
"label": "시퀀스 패킹",
"info": "고정된 길이의 샘플로 시퀀스를 패킹합니다.",
},
"ja": {
"label": "シーケンスパッキング",
"info": "シーケンスを固定長のサンプルにパッキングします。",
},
},
"neat_packing": {
"en": {
"label": "Use neat packing",
"info": "Avoid cross-attention between packed sequences.",
},
"ru": {
"label": "Используйте аккуратную упаковку",
"info": "избегайте перекрестного внимания между упакованными последовательностями.",
},
"zh": {
"label": "使用无污染打包",
"info": "避免打包后的序列产生交叉注意力。",
},
"ko": {
"label": "니트 패킹 사용",
"info": "패킹된 시퀀스 간의 크로스 어텐션을 피합니다.",
},
"ja": {
"label": "無汚染パッキングを使用",
"info": "パッキング後のシーケンス間のクロスアテンションを避けます。",
},
},
"train_on_prompt": {
"en": {
"label": "Train on prompt",
"info": "Disable the label mask on the prompt (only for SFT).",
},
"ru": {
"label": "Тренировка на подсказке",
"info": "Отключить маску меток на подсказке (только для SFT).",
},
"zh": {
"label": "学习提示词",
"info": "不在提示词的部分添加掩码(仅适用于 SFT)。",
},
"ko": {
"label": "프롬프트도 학습",
"info": "프롬프트에서 라벨 마스킹을 비활성화합니다 (SFT에만 해당).",
},
"ja": {
"label": "プロンプトで学習",
"info": "プロンプト部分にマスクを追加しない(SFT のみ)。",
},
},
"mask_history": {
"en": {
"label": "Mask history",
"info": "Train on the last turn only (only for SFT).",
},
"ru": {
"label": "История масок",
"info": "Тренироваться только на последнем шаге (только для SFT).",
},
"zh": {
"label": "不学习历史对话",
"info": "仅学习最后一轮对话(仅适用于 SFT)。",
},
"ko": {
"label": "히스토리 마스킹",
"info": "대화 데이터의 마지막 턴만 학습합니다 (SFT에만 해당).",
},
"ja": {
"label": "履歴をマスク",
"info": "最後のターンのみを学習する(SFT のみ)。",
},
},
"resize_vocab": {
"en": {
"label": "Resize token embeddings",
"info": "Resize the tokenizer vocab and the embedding layers.",
},
"ru": {
"label": "Изменение размера токенных эмбеддингов",
"info": "Изменить размер словаря токенизатора и слоев эмбеддинга.",
},
"zh": {
"label": "更改词表大小",
"info": "更改分词器词表和嵌入层的大小。",
},
"ko": {
"label": "토큰 임베딩의 사이즈 조정",
"info": "토크나이저 어휘와 임베딩 레이어의 크기를 조정합니다.",
},
"ja": {
"label": "トークン埋め込みのサイズ変更",
"info": "トークナイザーの語彙と埋め込み層のサイズを変更します。",
},
},
"use_llama_pro": {
"en": {
"label": "Enable LLaMA Pro",
"info": "Make the parameters in the expanded blocks trainable.",
},
"ru": {
"label": "Включить LLaMA Pro",
"info": "Сделать параметры в расширенных блоках обучаемыми.",
},
"zh": {
"label": "使用 LLaMA Pro",
"info": "仅训练块扩展后的参数。",
},
"ko": {
"label": "LLaMA Pro 사용",
"info": "확장된 블록의 매개변수를 학습 가능하게 만듭니다.",
},
"ja": {
"label": "LLaMA Pro を有効化",
"info": "拡張ブロックのパラメータのみをトレーニングします。",
},
},
"enable_thinking": {
"en": {
"label": "Enable thinking",
"info": "Whether or not to enable thinking mode for reasoning models.",
},
"ru": {
"label": "Включить мысли",
"info": "Включить режим мысли для моделей решающего характера.",
},
"zh": {
"label": "启用思考模式",
"info": "是否启用推理模型的思考模式。",
},
"ko": {
"label": "생각 모드 활성화",
"info": "추론 모델의 생각 모드를 활성화할지 여부.",
},
"ja": {
"label": "思考モードを有効化",
"info": "推論モデルの思考モードを有効にするかどうか。",
},
},
"report_to": {
"en": {
"label": "Enable external logger",
"info": "Use TensorBoard or wandb to log experiment.",
},
"ru": {
"label": "Включить внешний регистратор",
"info": "Использовать TensorBoard или wandb для ведения журнала экспериментов.",
},
"zh": {
"label": "启用外部记录面板",
"info": "使用 TensorBoard 或 wandb 记录实验。",
},
"ko": {
"label": "외부 logger 활성화",
"info": "TensorBoard 또는 wandb를 사용하여 실험을 기록합니다.",
},
"ja": {
"label": "外部ロガーを有効化",
"info": "TensorBoard または wandb を使用して実験を記録します。",
},
},
"freeze_tab": {
"en": {
"label": "Freeze tuning configurations",
},
"ru": {
"label": "конфигурации для настройки заморозки",
},
"zh": {
"label": "部分参数微调设置",
},
"ko": {
"label": "Freeze tuning 설정",
},
"ja": {
"label": "フリーズチューニング設定",
},
},
"freeze_trainable_layers": {
"en": {
"label": "Trainable layers",
"info": "Number of the last(+)/first(-) hidden layers to be set as trainable.",
},
"ru": {
"label": "Обучаемые слои",
"info": "Количество последних (+)/первых (-) скрытых слоев, которые будут установлены как обучаемые.",
},
"zh": {
"label": "可训练层数",
"info": "最末尾(+)/最前端(-)可训练隐藏层的数量。",
},
"ko": {
"label": "학습 가능한 레이어",
"info": "학습 가능하게 설정할 마지막(+)/처음(-) 히든 레이어의 수.",
},
"ja": {
"label": "学習可能なレイヤー",
"info": "最後(+)/最初(-)の学習可能な隠れ層の数。",
},
},
"freeze_trainable_modules": {
"en": {
"label": "Trainable modules",
"info": "Name(s) of trainable modules. Use commas to separate multiple modules.",
},
"ru": {
"label": "Обучаемые модули",
"info": "Название обучаемых модулей. Используйте запятые для разделения нескольких модулей.",
},
"zh": {
"label": "可训练模块",
"info": "可训练模块的名称。使用英文逗号分隔多个名称。",
},
"ko": {
"label": "학습 가능한 모듈",
"info": "학습 가능한 모듈의 이름. 여러 모듈을 구분하려면 쉼표(,)를 사용하세요.",
},
"ja": {
"label": "学習可能なモジュール",
"info": "学習可能なモジュールの名前。複数のモジュールを区切るにはカンマを使用します。",
},
},
"freeze_extra_modules": {
"en": {
"label": "Extra modules (optional)",
"info": (
"Name(s) of modules apart from hidden layers to be set as trainable. "
"Use commas to separate multiple modules."
),
},
"ru": {
"label": "Дополнительные модули (опционально)",
"info": (
"Имена модулей, кроме скрытых слоев, которые следует установить в качестве обучаемых. "
"Используйте запятые для разделения нескольких модулей."
),
},
"zh": {
"label": "额外模块(非必填)",
"info": "除隐藏层以外的可训练模块名称。使用英文逗号分隔多个名称。",
},
"ko": {
"label": "추가 모듈 (선택 사항)",
"info": "히든 레이어 외에 학습 가능하게 설정할 모듈의 이름. 모듈 간에는 쉼표(,)로 구분하십시오.",
},
"ja": {
"label": "追加モジュール(オプション)",
"info": "隠れ層以外の学習可能なモジュールの名前。複数のモジュールを区切るにはカンマを使用します。",
},
},
"lora_tab": {
"en": {
"label": "LoRA configurations",
},
"ru": {
"label": "Конфигурации LoRA",
},
"zh": {
"label": "LoRA 参数设置",
},
"ko": {
"label": "LoRA 구성",
},
"ja": {
"label": "LoRA 設定",
},
},
"lora_rank": {
"en": {
"label": "LoRA rank",
"info": "The rank of LoRA matrices.",
},
"ru": {
"label": "Ранг матриц LoRA",
"info": "Ранг матриц LoRA.",
},
"zh": {
"label": "LoRA 秩",
"info": "LoRA 矩阵的秩大小。",
},
"ko": {
"label": "LoRA 랭크",
"info": "LoRA 행렬의 랭크.",
},
"ja": {
"label": "LoRA ランク",
"info": "LoRA 行列のランク。",
},
},
"lora_alpha": {
"en": {
"label": "LoRA alpha",
"info": "Lora scaling coefficient.",
},
"ru": {
"label": "LoRA alpha",
"info": "Коэффициент масштабирования LoRA.",
},
"zh": {
"label": "LoRA 缩放系数",
"info": "LoRA 缩放系数大小。",
},
"ko": {
"label": "LoRA 알파",
"info": "LoRA 스케일링 계수.",
},
"ja": {
"label": "LoRA alpha",
"info": "LoRA スケーリング係数。",
},
},
"lora_dropout": {
"en": {
"label": "LoRA dropout",
"info": "Dropout ratio of LoRA weights.",
},
"ru": {
"label": "Вероятность отсева LoRA",
"info": "Вероятность отсева весов LoRA.",
},
"zh": {
"label": "LoRA 随机丢弃",
"info": "LoRA 权重随机丢弃的概率。",
},
"ko": {
"label": "LoRA 드롭아웃",
"info": "LoRA 가중치의 드롭아웃 비율.",
},
"ja": {
"label": "LoRA ドロップアウト",
"info": "LoRA 重みのドロップアウト確率。",
},
},
"loraplus_lr_ratio": {
"en": {
"label": "LoRA+ LR ratio",
"info": "The LR ratio of the B matrices in LoRA.",
},
"ru": {
"label": "LoRA+ LR коэффициент",
"info": "Коэффициент LR матриц B в LoRA.",
},
"zh": {
"label": "LoRA+ 学习率比例",
"info": "LoRA+ 中 B 矩阵的学习率倍数。",
},
"ko": {
"label": "LoRA+ LR 비율",
"info": "LoRA에서 B 행렬의 LR 비율.",
},
"ja": {
"label": "LoRA+ LR 比率",
"info": "LoRA+ の B 行列の学習率倍率。",
},
},
"create_new_adapter": {
"en": {
"label": "Create new adapter",
"info": "Create a new adapter with randomly initialized weight upon the existing one.",
},
"ru": {
"label": "Создать новый адаптер",
"info": "Создать новый адаптер с случайной инициализацией веса на основе существующего.",
},
"zh": {
"label": "新建适配器",
"info": "在现有的适配器上创建一个随机初始化后的新适配器。",
},
"ko": {
"label": "새 어댑터 생성",
"info": "기존 어댑터 위에 무작위로 초기화된 가중치를 가진 새 어댑터를 생성합니다.",
},
"ja": {
"label": "新しいアダプターを作成",
"info": "既存のアダプター上にランダムに初期化された新しいアダプターを作成します。",
},
},
"use_rslora": {
"en": {
"label": "Use rslora",
"info": "Use the rank stabilization scaling factor for LoRA layer.",
},
"ru": {
"label": "Использовать rslora",
"info": "Использовать коэффициент масштабирования стабилизации ранга для слоя LoRA.",
},
"zh": {
"label": "使用 rslora",
"info": "对 LoRA 层使用秩稳定缩放方法。",
},
"ko": {
"label": "rslora 사용",
"info": "LoRA 레이어에 랭크 안정화 스케일링 계수를 사용합니다.",
},
"ja": {
"label": "rslora を使用",
"info": "LoRA 層にランク安定化スケーリング方法を使用します。",
},
},
"use_dora": {
"en": {
"label": "Use DoRA",
"info": "Use weight-decomposed LoRA.",
},
"ru": {
"label": "Используйте DoRA",
"info": "Используйте LoRA с декомпозицией весов.",
},
"zh": {
"label": "使用 DoRA",
"info": "使用权重分解的 LoRA。",
},
"ko": {
"label": "DoRA 사용",
"info": "가중치-분해 LoRA를 사용합니다.",
},
"ja": {
"label": "DoRA を使用",
"info": "重み分解された LoRA を使用します。",
},
},
"use_pissa": {
"en": {
"label": "Use PiSSA",
"info": "Use PiSSA method.",
},
"ru": {
"label": "используйте PiSSA",
"info": "Используйте метод PiSSA.",
},
"zh": {
"label": "使用 PiSSA",
"info": "使用 PiSSA 方法。",
},
"ko": {
"label": "PiSSA 사용",
"info": "PiSSA 방법을 사용합니다.",
},
"ja": {
"label": "PiSSA を使用",
"info": "PiSSA メソッドを使用します。",
},
},
"lora_target": {
"en": {
"label": "LoRA modules (optional)",
"info": "Name(s) of modules to apply LoRA. Use commas to separate multiple modules.",
},
"ru": {
"label": "Модули LoRA (опционально)",
"info": "Имена модулей для применения LoRA. Используйте запятые для разделения нескольких модулей.",
},
"zh": {
"label": "LoRA 作用模块(非必填)",
"info": "应用 LoRA 的模块名称。使用英文逗号分隔多个名称。",
},
"ko": {
"label": "LoRA 모듈 (선택 사항)",
"info": "LoRA를 적용할 모듈의 이름. 모듈 간에는 쉼표(,)로 구분하십시오.",
},
"ja": {
"label": "LoRA モジュール(オプション)",
"info": "LoRA を適用するモジュールの名前。複数のモジュールを区切るにはカンマを使用します。",
},
},
"additional_target": {
"en": {
"label": "Additional modules (optional)",
"info": (
"Name(s) of modules apart from LoRA layers to be set as trainable. "
"Use commas to separate multiple modules."
),
},
"ru": {
"label": "Дополнительные модули (опционально)",
"info": (
"Имена модулей, кроме слоев LoRA, которые следует установить в качестве обучаемых. "
"Используйте запятые для разделения нескольких модулей."
),
},
"zh": {
"label": "附加模块(非必填)",
"info": "除 LoRA 层以外的可训练模块名称。使用英文逗号分隔多个名称。",
},
"ko": {
"label": "추가 모듈 (선택 사항)",
"info": "LoRA 레이어 외에 학습 가능하게 설정할 모듈의 이름. 모듈 간에는 쉼표(,)로 구분하십시오.",
},
"ja": {
"label": "追加モジュール(オプション)",
"info": "LoRA 層以外の学習可能なモジュールの名前。複数のモジュールを区切るにはカンマを使用します。",
},
},
"rlhf_tab": {
"en": {
"label": "RLHF configurations",
},
"ru": {
"label": "Конфигурации RLHF",
},
"zh": {
"label": "RLHF 参数设置",
},
"ko": {
"label": "RLHF 구성",
},
"ja": {
"label": "RLHF 設定",
},
},
"pref_beta": {
"en": {
"label": "Beta value",
"info": "Value of the beta parameter in the loss.",
},
"ru": {
"label": "Бета значение",
"info": "Значение параметра бета в функции потерь.",
},
"zh": {
"label": "Beta 参数",
"info": "损失函数中 beta 超参数大小。",
},
"ko": {
"label": "베타 값",
"info": "손실 함수에서 베타 매개 변수의 값.",
},
"ja": {
"label": "Beta 値",
"info": "損失関数における beta ハイパーパラメータの値。",
},
},
"pref_ftx": {
"en": {
"label": "Ftx gamma",
"info": "The weight of SFT loss in the final loss.",
},
"ru": {
"label": "Ftx гамма",
"info": "Вес потери SFT в итоговой потере.",
},
"zh": {
"label": "Ftx gamma",
"info": "损失函数中 SFT 损失的权重大小。",
},
"ko": {
"label": "Ftx 감마",
"info": "최종 로스 함수에서 SFT 로스의 가중치.",
},
"ja": {
"label": "Ftx gamma",
"info": "損失関数における SFT 損失の重み。",
},
},
"pref_loss": {
"en": {
"label": "Loss type",
"info": "The type of the loss function.",
},
"ru": {
"label": "Тип потерь",
"info": "Тип функции потерь.",
},
"zh": {
"label": "损失类型",
"info": "损失函数的类型。",
},
"ko": {
"label": "로스 유형",
"info": "로스 함수의 유형.",
},
"ja": {
"label": "損失タイプ",
"info": "損失関数のタイプ。",
},
},
"reward_model": {
"en": {
"label": "Reward model",
"info": "Adapter of the reward model in PPO training.",
},
"ru": {
"label": "Модель вознаграждения",
"info": "Адаптер модели вознаграждения для обучения PPO.",
},
"zh": {
"label": "奖励模型",
"info": "PPO 训练中奖励模型的适配器路径。",
},
"ko": {
"label": "리워드 모델",
"info": "PPO 학습에서 사용할 리워드 모델의 어댑터.",
},
"ja": {
"label": "報酬モデル",
"info": "PPO トレーニングにおける報酬モデルのアダプター。",
},
},
"ppo_score_norm": {
"en": {
"label": "Score norm",
"info": "Normalizing scores in PPO training.",
},
"ru": {
"label": "Норма оценок",
"info": "Нормализация оценок в тренировке PPO.",
},
"zh": {
"label": "归一化分数",
"info": "PPO 训练中归一化奖励分数。",
},
"ko": {
"label": "스코어 정규화",
"info": "PPO 학습에서 스코어를 정규화합니다.",
},
"ja": {
"label": "スコア正規化",
"info": "PPO トレーニングにおける報酬スコアの正規化。",
},
},
"ppo_whiten_rewards": {
"en": {
"label": "Whiten rewards",
"info": "Whiten the rewards in PPO training.",
},
"ru": {
"label": "Белые вознаграждения",
"info": "Осветлите вознаграждения в обучении PPO.",
},
"zh": {
"label": "白化奖励",
"info": "PPO 训练中将奖励分数做白化处理。",
},
"ko": {
"label": "보상 백화",
"info": "PPO 훈련에서 보상을 백화(Whiten)합니다.",
},
"ja": {
"label": "報酬のホワイトニング",
"info": "PPO トレーニングにおいて報酬スコアをホワイトニング処理します。",
},
},
"mm_tab": {
"en": {
"label": "Multimodal configurations",
},
"ru": {
"label": "Конфигурации мультимедиа",
},
"zh": {
"label": "多模态参数设置",
},
"ko": {
"label": "멀티모달 구성",
},
"ja": {
"label": "多モーダル設定",
},
},
"freeze_vision_tower": {
"en": {
"label": "Freeze vision tower",
"info": "Freeze the vision tower in the model.",
},
"ru": {
"label": "Заморозить башню визиона",
"info": "Заморозить башню визиона в модели.",
},
"zh": {
"label": "冻结视觉编码器",
"info": "冻结模型中的视觉编码器。",
},
"ko": {
"label": "비전 타워 고정",
"info": "모델의 비전 타워를 고정합니다.",
},
"ja": {
"label": "ビジョンタワーの固定",
"info": "モデルのビジョンタワーを固定します。",
},
},
"freeze_multi_modal_projector": {
"en": {
"label": "Freeze multi-modal projector",
"info": "Freeze the multi-modal projector in the model.",
},
"ru": {
"label": "Заморозить мультимодальный проектор",
"info": "Заморозить мультимодальный проектор в модели.",
},
"zh": {
"label": "冻结多模态投影器",
"info": "冻结模型中的多模态投影器。",
},
"ko": {
"label": "멀티모달 프로젝터 고정",
"info": "모델의 멀티모달 프로젝터를 고정합니다.",
},
"ja": {
"label": "多モーダルプロジェクターの固定",
"info": "モデルの多モーダルプロジェクターを固定します。",
},
},
"freeze_language_model": {
"en": {
"label": "Freeze language model",
"info": "Freeze the language model in the model.",
},
"ru": {
"label": "Заморозить язык модели",
"info": "Заморозить язык модели в модели.",
},
"zh": {
"label": "冻结语言模型",
"info": "冻结模型中的语言模型。",
},
"ko": {
"label": "언어 모델 고정",
"info": "모델의 언어 모델을 고정합니다.",
},
"ja": {
"label": "言語モデルの固定",
"info": "モデルの言語モデルを固定します。",
},
},
"image_max_pixels": {
"en": {
"label": "Image max pixels",
"info": "The maximum number of pixels of image inputs.",
},
"ru": {
"label": "Максимальное количество пикселей изображения",
"info": "Максимальное количество пикселей изображения.",
},
"zh": {
"label": "图像最大像素",
"info": "输入图像的最大像素数。",
},
"ko": {
"label": "이미지 최대 픽셀",
"info": "이미지 입력의 최대 픽셀 수입니다.",
},
"ja": {
"label": "画像最大ピクセル",
"info": "画像入力の最大ピクセル数です。",
},
},
"image_min_pixels": {
"en": {
"label": "Image min pixels",
"info": "The minimum number of pixels of image inputs.",
},
"ru": {
"label": "Минимальное количество пикселей изображения",
"info": "Минимальное количество пикселей изображения.",
},
"zh": {
"label": "图像最小像素",
"info": "输入图像的最小像素数。",
},
"ko": {
"label": "이미지 최소 픽셀",
"info": "이미지 입력의 최소 픽셀 수입니다.",
},
"ja": {
"label": "画像最小ピクセル",
"info": "画像入力の最小ピクセル数です。",
},
},
"video_max_pixels": {
"en": {
"label": "Video max pixels",
"info": "The maximum number of pixels of video inputs.",
},
"ru": {
"label": "Максимальное количество пикселей видео",
"info": "Максимальное количество пикселей видео.",
},
"zh": {
"label": "视频最大像素",
"info": "输入视频的最大像素数。",
},
"ko": {
"label": "비디오 최대 픽셀",
"info": "비디오 입력의 최대 픽셀 수입니다.",
},
"ja": {
"label": "ビデオ最大ピクセル",
"info": "ビデオ入力の最大ピクセル数です。",
},
},
"video_min_pixels": {
"en": {
"label": "Video min pixels",
"info": "The minimum number of pixels of video inputs.",
},
"ru": {
"label": "Минимальное количество пикселей видео",
"info": "Минимальное количество пикселей видео.",
},
"zh": {
"label": "视频最小像素",
"info": "输入视频的最小像素数。",
},
"ko": {
"label": "비디오 최소 픽셀",
"info": "비디오 입력의 최소 픽셀 수입니다.",
},
"ja": {
"label": "ビデオ最小ピクセル",
"info": "ビデオ入力の最小ピクセル数です。",
},
},
"galore_tab": {
"en": {
"label": "GaLore configurations",
},
"ru": {
"label": "Конфигурации GaLore",
},
"zh": {
"label": "GaLore 参数设置",
},
"ko": {
"label": "GaLore 구성",
},
"ja": {
"label": "GaLore 設定",
},
},
"use_galore": {
"en": {
"label": "Use GaLore",
"info": "Use [GaLore](https://github.com/jiaweizzhao/GaLore) optimizer.",
},
"ru": {
"label": "Использовать GaLore",
"info": "Используйте оптимизатор [GaLore](https://github.com/jiaweizzhao/GaLore).",
},
"zh": {
"label": "使用 GaLore",
"info": "使用 [GaLore](https://github.com/jiaweizzhao/GaLore) 优化器。",
},
"ko": {
"label": "GaLore 사용",
"info": "[GaLore](https://github.com/jiaweizzhao/GaLore) 최적화를 사용하세요.",
},
"ja": {
"label": "GaLore を使用",
"info": "[GaLore](https://github.com/jiaweizzhao/GaLore) オプティマイザーを使用します。",
},
},
"galore_rank": {
"en": {
"label": "GaLore rank",
"info": "The rank of GaLore gradients.",
},
"ru": {
"label": "Ранг GaLore",
"info": "Ранг градиентов GaLore.",
},
"zh": {
"label": "GaLore 秩",
"info": "GaLore 梯度的秩大小。",
},
"ko": {
"label": "GaLore 랭크",
"info": "GaLore 그레디언트의 랭크.",
},
"ja": {
"label": "GaLore ランク",
"info": "GaLore 勾配のランク。",
},
},
"galore_update_interval": {
"en": {
"label": "Update interval",
"info": "Number of steps to update the GaLore projection.",
},
"ru": {
"label": "Интервал обновления",
"info": "Количество шагов для обновления проекции GaLore.",
},
"zh": {
"label": "更新间隔",
"info": "相邻两次投影更新的步数。",
},
"ko": {
"label": "업데이트 간격",
"info": "GaLore 프로젝션을 업데이트할 간격의 스텝 수.",
},
"ja": {
"label": "更新間隔",
"info": "隣接する 2 回の投影更新間のステップ数。",
},
},
"galore_scale": {
"en": {
"label": "GaLore scale",
"info": "GaLore scaling coefficient.",
},
"ru": {
"label": "LoRA Alpha",
"info": "Коэффициент масштабирования GaLore.",
},
"zh": {
"label": "GaLore 缩放系数",
"info": "GaLore 缩放系数大小。",
},
"ko": {
"label": "GaLore 스케일",
"info": "GaLore 스케일링 계수.",
},
"ja": {
"label": "GaLore スケール",
"info": "GaLore スケーリング係数。",
},
},
"galore_target": {
"en": {
"label": "GaLore modules",
"info": "Name(s) of modules to apply GaLore. Use commas to separate multiple modules.",
},
"ru": {
"label": "Модули GaLore",
"info": "Имена модулей для применения GaLore. Используйте запятые для разделения нескольких модулей.",
},
"zh": {
"label": "GaLore 作用模块",
"info": "应用 GaLore 的模块名称。使用英文逗号分隔多个名称。",
},
"ko": {
"label": "GaLore 모듈",
"info": "GaLore를 적용할 모듈의 이름. 모듈 간에는 쉼표(,)로 구분하십시오.",
},
"ja": {
"label": "GaLore モジュール",
"info": "GaLore を適用するモジュールの名前。複数のモジュールを区切るにはカンマを使用します。",
},
},
"apollo_tab": {
"en": {
"label": "APOLLO configurations",
},
"ru": {
"label": "Конфигурации APOLLO",
},
"zh": {
"label": "APOLLO 参数设置",
},
"ko": {
"label": "APOLLO 구성",
},
"ja": {
"label": "APOLLO 設定",
},
},
"use_apollo": {
"en": {
"label": "Use APOLLO",
"info": "Use [APOLLO](https://github.com/zhuhanqing/APOLLO) optimizer.",
},
"ru": {
"label": "Использовать APOLLO",
"info": "Используйте оптимизатор [APOLLO](https://github.com/zhuhanqing/APOLLO).",
},
"zh": {
"label": "使用 APOLLO",
"info": "使用 [APOLLO](https://github.com/zhuhanqing/APOLLO) 优化器。",
},
"ko": {
"label": "APOLLO 사용",
"info": "[APOLLO](https://github.com/zhuhanqing/APOLLO) 최적화를 사용하세요.",
},
"ja": {
"label": "APOLLO を使用",
"info": "[APOLLO](https://github.com/zhuhanqing/APOLLO) オプティマイザーを使用します。",
},
},
"apollo_rank": {
"en": {
"label": "APOLLO rank",
"info": "The rank of APOLLO gradients.",
},
"ru": {
"label": "Ранг APOLLO",
"info": "Ранг градиентов APOLLO.",
},
"zh": {
"label": "APOLLO 秩",
"info": "APOLLO 梯度的秩大小。",
},
"ko": {
"label": "APOLLO 랭크",
"info": "APOLLO 그레디언트의 랭크.",
},
"ja": {
"label": "APOLLO ランク",
"info": "APOLLO 勾配のランク。",
},
},
"apollo_update_interval": {
"en": {
"label": "Update interval",
"info": "Number of steps to update the APOLLO projection.",
},
"ru": {
"label": "Интервал обновления",
"info": "Количество шагов для обновления проекции APOLLO.",
},
"zh": {
"label": "更新间隔",
"info": "相邻两次投影更新的步数。",
},
"ko": {
"label": "업데이트 간격",
"info": "APOLLO 프로젝션을 업데이트할 간격의 스텝 수.",
},
"ja": {
"label": "更新間隔",
"info": "隣接する 2 回の投影更新間のステップ数。",
},
},
"apollo_scale": {
"en": {
"label": "APOLLO scale",
"info": "APOLLO scaling coefficient.",
},
"ru": {
"label": "LoRA Alpha",
"info": "Коэффициент масштабирования APOLLO.",
},
"zh": {
"label": "APOLLO 缩放系数",
"info": "APOLLO 缩放系数大小。",
},
"ko": {
"label": "APOLLO 스케일",
"info": "APOLLO 스케일링 계수.",
},
"ja": {
"label": "APOLLO スケール",
"info": "APOLLO スケーリング係数。",
},
},
"apollo_target": {
"en": {
"label": "APOLLO modules",
"info": "Name(s) of modules to apply APOLLO. Use commas to separate multiple modules.",
},
"ru": {
"label": "Модули APOLLO",
"info": "Имена модулей для применения APOLLO. Используйте запятые для разделения нескольких модулей.",
},
"zh": {
"label": "APOLLO 作用模块",
"info": "应用 APOLLO 的模块名称。使用英文逗号分隔多个名称。",
},
"ko": {
"label": "APOLLO 모듈",
"info": "APOLLO를 적용할 모듈의 이름. 모듈 간에는 쉼표(,)로 구분하십시오.",
},
"ja": {
"label": "APOLLO モジュール",
"info": "APOLLO を適用するモジュールの名前。複数のモジュールを区切るにはカンマを使用します。",
},
},
"badam_tab": {
"en": {
"label": "BAdam configurations",
},
"ru": {
"label": "Конфигурации BAdam",
},
"zh": {
"label": "BAdam 参数设置",
},
"ko": {
"label": "BAdam 설정",
},
"ja": {
"label": "BAdam 設定",
},
},
"use_badam": {
"en": {
"label": "Use BAdam",
"info": "Enable the [BAdam](https://github.com/Ledzy/BAdam) optimizer.",
},
"ru": {
"label": "Использовать BAdam",
"info": "Включите оптимизатор [BAdam](https://github.com/Ledzy/BAdam).",
},
"zh": {
"label": "使用 BAdam",
"info": "使用 [BAdam](https://github.com/Ledzy/BAdam) 优化器。",
},
"ko": {
"label": "BAdam 사용",
"info": "[BAdam](https://github.com/Ledzy/BAdam) 옵티마이저를 사용합니다.",
},
"ja": {
"label": "BAdam を使用",
"info": "[BAdam](https://github.com/Ledzy/BAdam) オプティマイザーを使用します。",
},
},
"badam_mode": {
"en": {
"label": "BAdam mode",
"info": "Whether to use layer-wise or ratio-wise BAdam optimizer.",
},
"ru": {
"label": "Режим BAdam",
"info": "Использовать ли оптимизатор BAdam с послоевой или пропорциональной настройкой.",
},
"zh": {
"label": "BAdam 模式",
"info": "使用 layer-wise 或 ratio-wise BAdam 优化器。",
},
"ko": {
"label": "BAdam 모드",
"info": "레이어-BAdam 옵티마이저인지 비율-BAdam 옵티마이저인지.",
},
"ja": {
"label": "BAdam モード",
"info": "layer-wise または ratio-wise BAdam オプティマイザーを使用します。",
},
},
"badam_switch_mode": {
"en": {
"label": "Switch mode",
"info": "The strategy of picking block to update for layer-wise BAdam.",
},
"ru": {
"label": "Режим переключения",
"info": "Стратегия выбора блока для обновления для послойного BAdam.",
},
"zh": {
"label": "切换策略",
"info": "Layer-wise BAdam 优化器的块切换策略。",
},
"ko": {
"label": "스위치 모드",
"info": "레이어-BAdam을 위한 블록 선택 전략.",
},
"ja": {
"label": "切り替え戦略",
"info": "Layer-wise BAdam オプティマイザーのブロック切り替え戦略。",
},
},
"badam_switch_interval": {
"en": {
"label": "Switch interval",
"info": "Number of steps to update the block for layer-wise BAdam.",
},
"ru": {
"label": "Интервал переключения",
"info": "количество шагов для обновления блока для пошагового BAdam.",
},
"zh": {
"label": "切换频率",
"info": "Layer-wise BAdam 优化器的块切换频率。",
},
"ko": {
"label": "전환 간격",
"info": "레이어-BAdam을 위한 블록 업데이트 간 스텝 수.",
},
"ja": {
"label": "切り替え頻度",
"info": "Layer-wise BAdam オプティマイザーのブロック切り替え頻度。",
},
},
"badam_update_ratio": {
"en": {
"label": "Update ratio",
"info": "The ratio of the update for ratio-wise BAdam.",
},
"ru": {
"label": "Коэффициент обновления",
"info": "Коэффициент обновления для BAdam с учётом соотношений.",
},
"zh": {
"label": "Block 更新比例",
"info": "Ratio-wise BAdam 优化器的更新比例。",
},
"ko": {
"label": "업데이트 비율",
"info": "비율-BAdam의 업데이트 비율.",
},
"ja": {
"label": "ブロック更新比率",
"info": "Ratio-wise BAdam オプティマイザーの更新比率。",
},
},
"swanlab_tab": {
"en": {
"label": "SwanLab configurations",
},
"ru": {
"label": "Конфигурации SwanLab",
},
"zh": {
"label": "SwanLab 参数设置",
},
"ko": {
"label": "SwanLab 설정",
},
"ja": {
"label": "SwanLab 設定",
},
},
"use_swanlab": {
"en": {
"label": "Use SwanLab",
"info": "Enable [SwanLab](https://swanlab.cn/) for experiment tracking and visualization.",
},
"ru": {
"label": "Использовать SwanLab",
"info": "Включить [SwanLab](https://swanlab.cn/) для отслеживания и визуализации экспериментов.",
},
"zh": {
"label": "使用 SwanLab",
"info": "启用 [SwanLab](https://swanlab.cn/) 进行实验跟踪和可视化。",
},
"ko": {
"label": "SwanLab 사용",
"info": "[SwanLab](https://swanlab.cn/) 를 사용하여 실험을 추적하고 시각화합니다.",
},
"ja": {
"label": "SwanLab を使用",
"info": "[SwanLab](https://swanlab.cn/) を有効にして実験の追跡と可視化を行います。",
},
},
"swanlab_project": {
"en": {
"label": "SwanLab project",
},
"ru": {
"label": "SwanLab Проект",
},
"zh": {
"label": "SwanLab 项目名",
},
"ko": {
"label": "SwanLab 프로젝트",
},
"ja": {
"label": "SwanLab プロジェクト",
},
},
"swanlab_run_name": {
"en": {
"label": "SwanLab experiment name (optional)",
},
"ru": {
"label": "SwanLab Имя эксперимента (опционально)",
},
"zh": {
"label": "SwanLab 实验名(非必填)",
},
"ko": {
"label": "SwanLab 실험 이름 (선택 사항)",
},
"ja": {
"label": "SwanLab 実験名(オプション)",
},
},
"swanlab_workspace": {
"en": {
"label": "SwanLab workspace (optional)",
"info": "Workspace for SwanLab. Defaults to the personal workspace.",
},
"ru": {
"label": "SwanLab Рабочая область (опционально)",
"info": "Рабочая область SwanLab, если не заполнено, то по умолчанию в личной рабочей области.",
},
"zh": {
"label": "SwanLab 工作区(非必填)",
"info": "SwanLab 的工作区,默认在个人工作区下。",
},
"ko": {
"label": "SwanLab 작업 영역 (선택 사항)",
"info": "SwanLab 조직의 작업 영역, 비어 있으면 기본적으로 개인 작업 영역에 있습니다.",
},
"ja": {
"label": "SwanLab ワークスペース(オプション)",
"info": "SwanLab のワークスペース。デフォルトでは個人ワークスペースです。",
},
},
"swanlab_api_key": {
"en": {
"label": "SwanLab API key (optional)",
"info": "API key for SwanLab.",
},
"ru": {
"label": "SwanLab API ключ (опционально)",
"info": "API ключ для SwanLab.",
},
"zh": {
"label": "SwanLab API 密钥(非必填)",
"info": "用于在编程环境登录 SwanLab,已登录则无需填写。",
},
"ko": {
"label": "SwanLab API 키 (선택 사항)",
"info": "SwanLab의 API 키.",
},
"ja": {
"label": "SwanLab API キー(オプション)",
"info": "SwanLab の API キー。",
},
},
"swanlab_mode": {
"en": {
"label": "SwanLab mode",
"info": "Cloud or offline version.",
},
"ru": {
"label": "SwanLab Режим",
"info": "Версия в облаке или локальная версия.",
},
"zh": {
"label": "SwanLab 模式",
"info": "使用云端版或离线版 SwanLab。",
},
"ko": {
"label": "SwanLab 모드",
"info": "클라우드 버전 또는 오프라인 버전.",
},
"ja": {
"label": "SwanLab モード",
"info": "クラウド版またはオフライン版 SwanLab を使用します。",
},
},
"swanlab_logdir": {
"en": {
"label": "SwanLab log directory",
"info": "The log directory for SwanLab.",
},
"ru": {
"label": "SwanLab 로그 디렉토리",
"info": "SwanLab의 로그 디렉토리.",
},
"zh": {
"label": "SwanLab 日志目录",
"info": "SwanLab 的日志目录。",
},
"ko": {
"label": "SwanLab 로그 디렉토리",
"info": "SwanLab의 로그 디렉토리.",
},
"ja": {
"label": "SwanLab ログ ディレクトリ",
"info": "SwanLab のログ ディレクトリ。",
},
},
"cmd_preview_btn": {
"en": {
"value": "Preview command",
},
"ru": {
"value": "Просмотр команды",
},
"zh": {
"value": "预览命令",
},
"ko": {
"value": "명령어 미리보기",
},
"ja": {
"value": "コマンドをプレビュー",
},
},
"arg_save_btn": {
"en": {
"value": "Save arguments",
},
"ru": {
"value": "Сохранить аргументы",
},
"zh": {
"value": "保存训练参数",
},
"ko": {
"value": "Argument 저장",
},
"ja": {
"value": "引数を保存",
},
},
"arg_load_btn": {
"en": {
"value": "Load arguments",
},
"ru": {
"value": "Загрузить аргументы",
},
"zh": {
"value": "载入训练参数",
},
"ko": {
"value": "Argument 불러오기",
},
"ja": {
"value": "引数を読み込む",
},
},
"start_btn": {
"en": {
"value": "Start",
},
"ru": {
"value": "Начать",
},
"zh": {
"value": "开始",
},
"ko": {
"value": "시작",
},
"ja": {
"value": "開始",
},
},
"stop_btn": {
"en": {
"value": "Abort",
},
"ru": {
"value": "Прервать",
},
"zh": {
"value": "中断",
},
"ko": {
"value": "중단",
},
"ja": {
"value": "中断",
},
},
"output_dir": {
"en": {
"label": "Output dir",
"info": "Directory for saving results.",
},
"ru": {
"label": "Выходной каталог",
"info": "Каталог для сохранения результатов.",
},
"zh": {
"label": "输出目录",
"info": "保存结果的路径。",
},
"ko": {
"label": "출력 디렉토리",
"info": "결과를 저장할 디렉토리.",
},
"ja": {
"label": "出力ディレクトリ",
"info": "結果を保存するパス。",
},
},
"config_path": {
"en": {
"label": "Config path",
"info": "Path to config saving arguments.",
},
"ru": {
"label": "Путь к конфигурации",
"info": "Путь для сохранения аргументов конфигурации.",
},
"zh": {
"label": "配置路径",
"info": "保存训练参数的配置文件路径。",
},
"ko": {
"label": "설정 경로",
"info": "Arguments 저장 파일 경로.",
},
"ja": {
"label": "設定パス",
"info": "トレーニングパラメータを保存する設定ファイルのパス。",
},
},
"device_count": {
"en": {
"label": "Device count",
"info": "Number of devices available.",
},
"ru": {
"label": "Количество устройств",
"info": "Количество доступных устройств.",
},
"zh": {
"label": "设备数量",
"info": "当前可用的运算设备数。",
},
"ko": {
"label": "디바이스 수",
"info": "사용 가능한 디바이스 수.",
},
"ja": {
"label": "デバイス数",
"info": "現在利用可能な演算デバイス数。",
},
},
"ds_stage": {
"en": {
"label": "DeepSpeed stage",
"info": "DeepSpeed stage for distributed training.",
},
"ru": {
"label": "Этап DeepSpeed",
"info": "Этап DeepSpeed для распределенного обучения.",
},
"zh": {
"label": "DeepSpeed stage",
"info": "多卡训练的 DeepSpeed stage。",
},
"ko": {
"label": "DeepSpeed 단계",
"info": "분산 학습을 위한 DeepSpeed 단계.",
},
"ja": {
"label": "DeepSpeed stage",
"info": "マルチ GPU トレーニングの DeepSpeed stage。",
},
},
"ds_offload": {
"en": {
"label": "Enable offload",
"info": "Enable DeepSpeed offload (slow down training).",
},
"ru": {
"label": "Включить выгрузку",
"info": "включить выгрузку DeepSpeed (замедлит обучение).",
},
"zh": {
"label": "使用 offload",
"info": "使用 DeepSpeed offload(会减慢速度)。",
},
"ko": {
"label": "오프로딩 활성화",
"info": "DeepSpeed 오프로딩 활성화 (훈련 속도 느려짐).",
},
"ja": {
"label": "オフロードを使用",
"info": "DeepSpeed オフロードを使用します(速度が遅くなります)。",
},
},
"output_box": {
"en": {
"value": "Ready.",
},
"ru": {
"value": "Готово.",
},
"zh": {
"value": "准备就绪。",
},
"ko": {
"value": "준비 완료.",
},
"ja": {
"value": "準備完了。",
},
},
"loss_viewer": {
"en": {
"label": "Loss",
},
"ru": {
"label": "Потери",
},
"zh": {
"label": "损失",
},
"ko": {
"label": "손실",
},
"ja": {
"label": "損失",
},
},
"predict": {
"en": {
"label": "Save predictions",
},
"ru": {
"label": "Сохранить предсказания",
},
"zh": {
"label": "保存预测结果",
},
"ko": {
"label": "예측 결과 저장",
},
"ja": {
"label": "予測結果を保存",
},
},
"infer_backend": {
"en": {
"label": "Inference engine",
},
"ru": {
"label": "Инференс движок",
},
"zh": {
"label": "推理引擎",
},
"ko": {
"label": "추론 엔진",
},
"ja": {
"label": "推論エンジン",
},
},
"infer_dtype": {
"en": {
"label": "Inference data type",
},
"ru": {
"label": "Тип данных для вывода",
},
"zh": {
"label": "推理数据类型",
},
"ko": {
"label": "추론 데이터 유형",
},
"ja": {
"label": "推論データタイプ",
},
},
"load_btn": {
"en": {
"value": "Load model",
},
"ru": {
"value": "Загрузить модель",
},
"zh": {
"value": "加载模型",
},
"ko": {
"value": "모델 불러오기",
},
"ja": {
"value": "モデルを読み込む",
},
},
"unload_btn": {
"en": {
"value": "Unload model",
},
"ru": {
"value": "Выгрузить модель",
},
"zh": {
"value": "卸载模型",
},
"ko": {
"value": "모델 언로드",
},
"ja": {
"value": "モデルをアンロード",
},
},
"info_box": {
"en": {
"value": "Model unloaded, please load a model first.",
},
"ru": {
"value": "Модель не загружена, загрузите модель сначала.",
},
"zh": {
"value": "模型未加载,请先加载模型。",
},
"ko": {
"value": "모델이 언로드되었습니다. 모델을 먼저 불러오십시오.",
},
"ja": {
"value": "モデルがロードされていません。最初にモデルをロードしてください。",
},
},
"role": {
"en": {
"label": "Role",
},
"ru": {
"label": "Роль",
},
"zh": {
"label": "角色",
},
"ko": {
"label": "역할",
},
"ja": {
"label": "役割",
},
},
"system": {
"en": {
"placeholder": "System prompt (optional)",
},
"ru": {
"placeholder": "Системный запрос (по желанию)",
},
"zh": {
"placeholder": "系统提示词(非必填)",
},
"ko": {
"placeholder": "시스템 프롬프트 (선택 사항)",
},
"ja": {
"placeholder": "システムプロンプト(オプション)",
},
},
"tools": {
"en": {
"placeholder": "Tools (optional)",
},
"ru": {
"placeholder": "Инструменты (по желанию)",
},
"zh": {
"placeholder": "工具列表(非必填)",
},
"ko": {
"placeholder": "툴 (선택 사항)",
},
"ja": {
"placeholder": "ツールリスト(オプション)",
},
},
"image": {
"en": {
"label": "Image (optional)",
},
"ru": {
"label": "Изображение (по желанию)",
},
"zh": {
"label": "图像(非必填)",
},
"ko": {
"label": "이미지 (선택 사항)",
},
"ja": {
"label": "画像(オプション)",
},
},
"video": {
"en": {
"label": "Video (optional)",
},
"ru": {
"label": "Видео (по желанию)",
},
"zh": {
"label": "视频(非必填)",
},
"ko": {
"label": "비디오 (선택 사항)",
},
"ja": {
"label": "動画(オプション)",
},
},
"query": {
"en": {
"placeholder": "Input...",
},
"ru": {
"placeholder": "Ввод...",
},
"zh": {
"placeholder": "输入...",
},
"ko": {
"placeholder": "입력...",
},
"ja": {
"placeholder": "入力...",
},
},
"submit_btn": {
"en": {
"value": "Submit",
},
"ru": {
"value": "Отправить",
},
"zh": {
"value": "提交",
},
"ko": {
"value": "제출",
},
"ja": {
"value": "送信",
},
},
"max_length": {
"en": {
"label": "Maximum length",
},
"ru": {
"label": "Максимальная длина",
},
"zh": {
"label": "最大长度",
},
"ko": {
"label": "최대 길이",
},
"ja": {
"label": "最大長",
},
},
"max_new_tokens": {
"en": {
"label": "Maximum new tokens",
},
"ru": {
"label": "Максимальное количество новых токенов",
},
"zh": {
"label": "最大生成长度",
},
"ko": {
"label": "응답의 최대 길이",
},
"ja": {
"label": "最大生成長",
},
},
"top_p": {
"en": {
"label": "Top-p",
},
"ru": {
"label": "Лучшие-p",
},
"zh": {
"label": "Top-p 采样值",
},
"ko": {
"label": "Top-p",
},
"ja": {
"label": "Top-p",
},
},
"temperature": {
"en": {
"label": "Temperature",
},
"ru": {
"label": "Температура",
},
"zh": {
"label": "温度系数",
},
"ko": {
"label": "온도",
},
"ja": {
"label": "温度",
},
},
"skip_special_tokens": {
"en": {
"label": "Skip special tokens",
},
"ru": {
"label": "Пропустить специальные токены",
},
"zh": {
"label": "跳过特殊 token",
},
"ko": {
"label": "스페셜 토큰을 건너뛰기",
},
"ja": {
"label": "スペシャルトークンをスキップ",
},
},
"escape_html": {
"en": {
"label": "Escape HTML tags",
},
"ru": {
"label": "Исключить HTML теги",
},
"zh": {
"label": "转义 HTML 标签",
},
"ko": {
"label": "HTML 태그 이스케이프",
},
"ja": {
"label": "HTML タグをエスケープ",
},
},
"clear_btn": {
"en": {
"value": "Clear history",
},
"ru": {
"value": "Очистить историю",
},
"zh": {
"value": "清空历史",
},
"ko": {
"value": "기록 지우기",
},
"ja": {
"value": "履歴をクリア",
},
},
"export_size": {
"en": {
"label": "Max shard size (GB)",
"info": "The maximum size for a model file.",
},
"ru": {
"label": "Максимальный размер фрагмента (ГБ)",
"info": "Максимальный размер файла модели.",
},
"zh": {
"label": "最大分块大小(GB)",
"info": "单个模型文件的最大大小。",
},
"ko": {
"label": "최대 샤드 크기 (GB)",
"info": "모델 파일의 최대 크기.",
},
"ja": {
"label": "最大シャードサイズ(GB)",
"info": "単一のモデルファイルの最大サイズ。",
},
},
"export_quantization_bit": {
"en": {
"label": "Export quantization bit.",
"info": "Quantizing the exported model.",
},
"ru": {
"label": "Экспорт бита квантования",
"info": "Квантование экспортируемой модели.",
},
"zh": {
"label": "导出量化等级",
"info": "量化导出模型。",
},
"ko": {
"label": "양자화 비트 내보내기",
"info": "내보낸 모델의 양자화.",
},
"ja": {
"label": "量子化ビットをエクスポート",
"info": "エクスポートするモデルを量子化します。",
},
},
"export_quantization_dataset": {
"en": {
"label": "Export quantization dataset",
"info": "The calibration dataset used for quantization.",
},
"ru": {
"label": "Экспорт набора данных для квантования",
"info": "Набор данных калибровки, используемый для квантования.",
},
"zh": {
"label": "导出量化数据集",
"info": "量化过程中使用的校准数据集。",
},
"ko": {
"label": "양자화 데이터셋 내보내기",
"info": "양자화에 사용되는 교정 데이터셋.",
},
"ja": {
"label": "量子化データセットをエクスポート",
"info": "量子化プロセスで使用されるキャリブレーションデータセット。",
},
},
"export_device": {
"en": {
"label": "Export device",
"info": "Which device should be used to export model.",
},
"ru": {
"label": "Экспорт устройство",
"info": "Какое устройство следует использовать для экспорта модели.",
},
"zh": {
"label": "导出设备",
"info": "导出模型使用的设备类型。",
},
"ko": {
"label": "내보낼 장치",
"info": "모델을 내보내는 데 사용할 장치.",
},
"ja": {
"label": "エクスポートデバイス",
"info": "モデルをエクスポートするために使用するデバイスタイプ。",
},
},
"export_legacy_format": {
"en": {
"label": "Export legacy format",
"info": "Do not use safetensors to save the model.",
},
"ru": {
"label": "Экспорт в устаревший формат",
"info": "Не использовать safetensors для сохранения модели.",
},
"zh": {
"label": "导出旧格式",
"info": "不使用 safetensors 格式保存模型。",
},
"ko": {
"label": "레거시 형식 내보내기",
"info": "모델을 저장하는 데 safetensors를 사용하지 않습니다.",
},
"ja": {
"label": "レガシーフォーマットをエクスポート",
"info": "safetensors フォーマットを使用せずにモデルを保存します。",
},
},
"export_dir": {
"en": {
"label": "Export dir",
"info": "Directory to save exported model.",
},
"ru": {
"label": "Каталог экспорта",
"info": "Каталог для сохранения экспортированной модели.",
},
"zh": {
"label": "导出目录",
"info": "保存导出模型的文件夹路径。",
},
"ko": {
"label": "내보내기 디렉토리",
"info": "내보낸 모델을 저장할 디렉토리.",
},
"ja": {
"label": "エクスポートディレクトリ",
"info": "エクスポートしたモデルを保存するフォルダのパス。",
},
},
"export_hub_model_id": {
"en": {
"label": "HF Hub ID (optional)",
"info": "Repo ID for uploading model to Hugging Face hub.",
},
"ru": {
"label": "HF Hub ID (опционально)",
"info": "Идентификатор репозитория для загрузки модели на Hugging Face hub.",
},
"zh": {
"label": "HF Hub ID(非必填)",
"info": "用于将模型上传至 Hugging Face Hub 的仓库 ID。",
},
"ko": {
"label": "HF 허브 ID (선택 사항)",
"info": "모델을 Hugging Face 허브에 업로드하기 위한 레포 ID.",
},
"ja": {
"label": "HF Hub ID(オプション)",
"info": "Hugging Face Hub にモデルをアップロードするためのリポジトリ ID。",
},
},
"export_btn": {
"en": {
"value": "Export",
},
"ru": {
"value": "Экспорт",
},
"zh": {
"value": "开始导出",
},
"ko": {
"value": "내보내기",
},
"ja": {
"value": "エクスポート",
},
},
"device_memory": {
"en": {
"label": "Device memory",
"info": "Current memory usage of the device (GB).",
},
"ru": {
"label": "Память устройства",
"info": "Текущая память на устройстве (GB).",
},
"zh": {
"label": "设备显存",
"info": "当前设备的显存(GB)。",
},
"ko": {
"label": "디바이스 메모리",
"info": "지금 사용 중인 기기 메모리 (GB).",
},
"ja": {
"label": "デバイスメモリ",
"info": "現在のデバイスのメモリ(GB)。",
},
},
}
ALERTS = {
"err_conflict": {
"en": "A process is in running, please abort it first.",
"ru": "Процесс уже запущен, пожалуйста, сначала прервите его.",
"zh": "任务已存在,请先中断训练。",
"ko": "프로세스가 실행 중입니다. 먼저 중단하십시오.",
"ja": "プロセスが実行中です。最初に中断してください。",
},
"err_exists": {
"en": "You have loaded a model, please unload it first.",
"ru": "Вы загрузили модель, сначала разгрузите ее.",
"zh": "模型已存在,请先卸载模型。",
"ko": "모델이 로드되었습니다. 먼저 언로드하십시오.",
"ja": "モデルがロードされています。最初にアンロードしてください。",
},
"err_no_model": {
"en": "Please select a model.",
"ru": "Пожалуйста, выберите модель.",
"zh": "请选择模型。",
"ko": "모델을 선택하십시오.",
"ja": "モデルを選択してください。",
},
"err_no_path": {
"en": "Model not found.",
"ru": "Модель не найдена.",
"zh": "模型未找到。",
"ko": "모델을 찾을 수 없습니다.",
"ja": "モデルが見つかりません。",
},
"err_no_dataset": {
"en": "Please choose a dataset.",
"ru": "Пожалуйста, выберите набор данных.",
"zh": "请选择数据集。",
"ko": "데이터 세트를 선택하십시오.",
"ja": "データセットを選択してください。",
},
"err_no_adapter": {
"en": "Please select an adapter.",
"ru": "Пожалуйста, выберите адаптер.",
"zh": "请选择适配器。",
"ko": "어댑터를 선택하십시오.",
"ja": "アダプターを選択してください。",
},
"err_no_output_dir": {
"en": "Please provide output dir.",
"ru": "Пожалуйста, укажите выходную директорию.",
"zh": "请填写输出目录。",
"ko": "출력 디렉토리를 제공하십시오.",
"ja": "出力ディレクトリを入力してください。",
},
"err_no_reward_model": {
"en": "Please select a reward model.",
"ru": "Пожалуйста, выберите модель вознаграждения.",
"zh": "请选择奖励模型。",
"ko": "리워드 모델을 선택하십시오.",
"ja": "報酬モデルを選択してください。",
},
"err_no_export_dir": {
"en": "Please provide export dir.",
"ru": "Пожалуйста, укажите каталог для экспорта.",
"zh": "请填写导出目录。",
"ko": "Export 디렉토리를 제공하십시오.",
"ja": "エクスポートディレクトリを入力してください。",
},
"err_gptq_lora": {
"en": "Please merge adapters before quantizing the model.",
"ru": "Пожалуйста, объедините адаптеры перед квантованием модели.",
"zh": "量化模型前请先合并适配器。",
"ko": "모델을 양자화하기 전에 어댑터를 병합하십시오.",
"ja": "モデルを量子化する前にアダプターをマージしてください。",
},
"err_failed": {
"en": "Failed.",
"ru": "Ошибка.",
"zh": "训练出错。",
"ko": "실패했습니다.",
"ja": "失敗しました。",
},
"err_demo": {
"en": "Training is unavailable in demo mode, duplicate the space to a private one first.",
"ru": "Обучение недоступно в демонстрационном режиме, сначала скопируйте пространство в частное.",
"zh": "展示模式不支持训练,请先复制到私人空间。",
"ko": "데모 모드에서는 훈련을 사용할 수 없습니다. 먼저 프라이빗 레포지토리로 작업 공간을 복제하십시오.",
"ja": "デモモードではトレーニングは利用できません。最初にプライベートスペースに複製してください。",
},
"err_tool_name": {
"en": "Tool name not found.",
"ru": "Имя инструмента не найдено.",
"zh": "工具名称未找到。",
"ko": "툴 이름을 찾을 수 없습니다.",
"ja": "ツール名が見つかりません。",
},
"err_json_schema": {
"en": "Invalid JSON schema.",
"ru": "Неверная схема JSON.",
"zh": "Json 格式错误。",
"ko": "잘못된 JSON 스키마입니다.",
"ja": "JSON スキーマが無効です。",
},
"err_config_not_found": {
"en": "Config file is not found.",
"ru": "Файл конфигурации не найден.",
"zh": "未找到配置文件。",
"ko": "Config 파일을 찾을 수 없습니다.",
"ja": "設定ファイルが見つかりません。",
},
"warn_no_cuda": {
"en": "CUDA environment was not detected.",
"ru": "Среда CUDA не обнаружена.",
"zh": "未检测到 CUDA 环境。",
"ko": "CUDA 환경이 감지되지 않았습니다.",
"ja": "CUDA 環境が検出されませんでした。",
},
"warn_output_dir_exists": {
"en": "Output dir already exists, will resume training from here.",
"ru": "Выходной каталог уже существует, обучение будет продолжено отсюда.",
"zh": "输出目录已存在,将从该断点恢复训练。",
"ko": "출력 디렉토리가 이미 존재합니다. 위 출력 디렉토리에 저장된 학습을 재개합니다.",
"ja": "出力ディレクトリが既に存在します。このチェックポイントからトレーニングを再開します。",
},
"warn_no_instruct": {
"en": "You are using a non-instruct model, please fine-tune it first.",
"ru": "Вы используете модель без инструкции, пожалуйста, primeros выполните донастройку этой модели.",
"zh": "您正在使用非指令模型,请先对其进行微调。",
"ko": "당신은 지시하지 않은 모델을 사용하고 있습니다. 먼저 이를 미세 조정해 주세요.",
"ja": "インストラクションモデルを使用していません。まずモデルをアダプターに適合させてください。",
},
"info_aborting": {
"en": "Aborted, wait for terminating...",
"ru": "Прервано, ожидание завершения...",
"zh": "训练中断,正在等待进程结束……",
"ko": "중단되었습니다. 종료를 기다리십시오...",
"ja": "トレーニングが中断されました。プロセスの終了を待っています...",
},
"info_aborted": {
"en": "Ready.",
"ru": "Готово.",
"zh": "准备就绪。",
"ko": "준비되었습니다.",
"ja": "準備完了。",
},
"info_finished": {
"en": "Finished.",
"ru": "Завершено.",
"zh": "训练完毕。",
"ko": "완료되었습니다.",
"ja": "トレーニングが完了しました。",
},
"info_config_saved": {
"en": "Arguments have been saved at: ",
"ru": "Аргументы были сохранены по адресу: ",
"zh": "训练参数已保存至:",
"ko": "매개변수가 저장되었습니다: ",
"ja": "トレーニングパラメータが保存されました: ",
},
"info_config_loaded": {
"en": "Arguments have been restored.",
"ru": "Аргументы были восстановлены.",
"zh": "训练参数已载入。",
"ko": "매개변수가 복원되었습니다.",
"ja": "トレーニングパラメータが読み込まれました。",
},
"info_loading": {
"en": "Loading model...",
"ru": "Загрузка модели...",
"zh": "加载中……",
"ko": "모델 로딩 중...",
"ja": "モデルをロード中...",
},
"info_unloading": {
"en": "Unloading model...",
"ru": "Выгрузка модели...",
"zh": "卸载中……",
"ko": "모델 언로딩 중...",
"ja": "モデルをアンロード中...",
},
"info_loaded": {
"en": "Model loaded, now you can chat with your model!",
"ru": "Модель загружена, теперь вы можете общаться с вашей моделью!",
"zh": "模型已加载,可以开始聊天了!",
"ko": "모델이 로드되었습니다. 이제 모델과 채팅할 수 있습니다!",
"ja": "モデルがロードされました。チャットを開始できます!",
},
"info_unloaded": {
"en": "Model unloaded.",
"ru": "Модель выгружена.",
"zh": "模型已卸载。",
"ko": "모델이 언로드되었습니다.",
"ja": "モデルがアンロードされました。",
},
"info_thinking": {
"en": "🌀 Thinking...",
"ru": "🌀 Думаю...",
"zh": "🌀 思考中...",
"ko": "🌀 생각 중...",
"ja": "🌀 考えています...",
},
"info_thought": {
"en": "✅ Thought",
"ru": "✅ Думать закончено",
"zh": "✅ 思考完成",
"ko": "✅ 생각이 완료되었습니다",
"ja": "✅ 思考完了",
},
"info_exporting": {
"en": "Exporting model...",
"ru": "Экспорт модели...",
"zh": "正在导出模型……",
"ko": "모델 내보내기 중...",
"ja": "モデルをエクスポート中...",
},
"info_exported": {
"en": "Model exported.",
"ru": "Модель экспортирована.",
"zh": "模型导出完成。",
"ko": "모델이 내보내졌습니다.",
"ja": "モデルのエクスポートが完了しました。",
},
"info_swanlab_link": {
"en": "### SwanLab Link\n",
"ru": "### SwanLab ссылка\n",
"zh": "### SwanLab 链接\n",
"ko": "### SwanLab 링크\n",
"ja": "### SwanLab リンク\n",
},
}
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from collections.abc import Generator
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from gradio.components import Component
class Manager:
r"""A class to manage all the gradio components in Web UI."""
def __init__(self) -> None:
self._id_to_elem: dict[str, Component] = {}
self._elem_to_id: dict[Component, str] = {}
def add_elems(self, tab_name: str, elem_dict: dict[str, "Component"]) -> None:
r"""Add elements to manager."""
for elem_name, elem in elem_dict.items():
elem_id = f"{tab_name}.{elem_name}"
self._id_to_elem[elem_id] = elem
self._elem_to_id[elem] = elem_id
def get_elem_list(self) -> list["Component"]:
r"""Return the list of all elements."""
return list(self._id_to_elem.values())
def get_elem_iter(self) -> Generator[tuple[str, "Component"], None, None]:
r"""Return an iterator over all elements with their names."""
for elem_id, elem in self._id_to_elem.items():
yield elem_id.split(".")[-1], elem
def get_elem_by_id(self, elem_id: str) -> "Component":
r"""Get element by id.
Example: top.lang, train.dataset
"""
return self._id_to_elem[elem_id]
def get_id_by_elem(self, elem: "Component") -> str:
r"""Get id by element."""
return self._elem_to_id[elem]
def get_base_elems(self) -> set["Component"]:
r"""Get the base elements that are commonly used."""
return {
self._id_to_elem["top.lang"],
self._id_to_elem["top.model_name"],
self._id_to_elem["top.model_path"],
self._id_to_elem["top.finetuning_type"],
self._id_to_elem["top.checkpoint_path"],
self._id_to_elem["top.quantization_bit"],
self._id_to_elem["top.quantization_method"],
self._id_to_elem["top.template"],
self._id_to_elem["top.rope_scaling"],
self._id_to_elem["top.booster"],
}
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
import os
from collections.abc import Generator
from copy import deepcopy
from subprocess import PIPE, Popen, TimeoutExpired
from typing import TYPE_CHECKING, Any, Optional
from transformers.utils import is_torch_npu_available
from ..extras.constants import LLAMABOARD_CONFIG, MULTIMODAL_SUPPORTED_MODELS, PEFT_METHODS, TRAINING_STAGES
from ..extras.misc import is_accelerator_available, torch_gc
from ..extras.packages import is_gradio_available
from .common import (
DEFAULT_CACHE_DIR,
DEFAULT_CONFIG_DIR,
abort_process,
calculate_pixels,
gen_cmd,
get_save_dir,
load_args,
load_config,
load_eval_results,
save_args,
save_cmd,
)
from .control import get_trainer_info
from .locales import ALERTS, LOCALES
if is_gradio_available():
import gradio as gr
if TYPE_CHECKING:
from gradio.components import Component
from .manager import Manager
class Runner:
r"""A class to manage the running status of the trainers."""
def __init__(self, manager: "Manager", demo_mode: bool = False) -> None:
r"""Init a runner."""
self.manager = manager
self.demo_mode = demo_mode
""" Resume """
self.trainer: Optional[Popen] = None
self.do_train = True
self.running_data: dict[Component, Any] = None
""" State """
self.aborted = False
self.running = False
def set_abort(self) -> None:
self.aborted = True
if self.trainer is not None:
abort_process(self.trainer.pid)
def _initialize(self, data: dict["Component", Any], do_train: bool, from_preview: bool) -> str:
r"""Validate the configuration."""
get = lambda elem_id: data[self.manager.get_elem_by_id(elem_id)]
lang, model_name, model_path = get("top.lang"), get("top.model_name"), get("top.model_path")
dataset = get("train.dataset") if do_train else get("eval.dataset")
if self.running:
return ALERTS["err_conflict"][lang]
if not model_name:
return ALERTS["err_no_model"][lang]
if not model_path:
return ALERTS["err_no_path"][lang]
if not dataset:
return ALERTS["err_no_dataset"][lang]
if not from_preview and self.demo_mode:
return ALERTS["err_demo"][lang]
if do_train:
if not get("train.output_dir"):
return ALERTS["err_no_output_dir"][lang]
try:
json.loads(get("train.extra_args"))
except json.JSONDecodeError:
return ALERTS["err_json_schema"][lang]
stage = TRAINING_STAGES[get("train.training_stage")]
if stage == "ppo" and not get("train.reward_model"):
return ALERTS["err_no_reward_model"][lang]
else:
if not get("eval.output_dir"):
return ALERTS["err_no_output_dir"][lang]
if not from_preview and not is_accelerator_available():
gr.Warning(ALERTS["warn_no_cuda"][lang])
return ""
def _finalize(self, lang: str, finish_info: str) -> None:
r"""Clean the cached memory and resets the runner."""
finish_info = ALERTS["info_aborted"][lang] if self.aborted else finish_info
gr.Info(finish_info)
self.trainer = None
self.aborted = False
self.running = False
self.running_data = None
torch_gc()
def _parse_train_args(self, data: dict["Component", Any]) -> dict[str, Any]:
r"""Build and validate the training arguments."""
get = lambda elem_id: data[self.manager.get_elem_by_id(elem_id)]
model_name, finetuning_type = get("top.model_name"), get("top.finetuning_type")
user_config = load_config()
args = dict(
stage=TRAINING_STAGES[get("train.training_stage")],
do_train=True,
model_name_or_path=get("top.model_path"),
cache_dir=user_config.get("cache_dir", None),
preprocessing_num_workers=16,
finetuning_type=finetuning_type,
template=get("top.template"),
rope_scaling=get("top.rope_scaling") if get("top.rope_scaling") != "none" else None,
flash_attn="fa2" if get("top.booster") == "flashattn2" else "auto",
use_unsloth=(get("top.booster") == "unsloth"),
enable_liger_kernel=(get("top.booster") == "liger_kernel"),
dataset_dir=get("train.dataset_dir"),
dataset=",".join(get("train.dataset")),
cutoff_len=get("train.cutoff_len"),
learning_rate=float(get("train.learning_rate")),
num_train_epochs=float(get("train.num_train_epochs")),
max_samples=int(get("train.max_samples")),
per_device_train_batch_size=get("train.batch_size"),
gradient_accumulation_steps=get("train.gradient_accumulation_steps"),
lr_scheduler_type=get("train.lr_scheduler_type"),
max_grad_norm=float(get("train.max_grad_norm")),
logging_steps=get("train.logging_steps"),
save_steps=get("train.save_steps"),
warmup_steps=get("train.warmup_steps"),
neftune_noise_alpha=get("train.neftune_alpha") or None,
packing=get("train.packing") or get("train.neat_packing"),
neat_packing=get("train.neat_packing"),
train_on_prompt=get("train.train_on_prompt"),
mask_history=get("train.mask_history"),
resize_vocab=get("train.resize_vocab"),
use_llama_pro=get("train.use_llama_pro"),
enable_thinking=get("train.enable_thinking"),
report_to=get("train.report_to"),
use_galore=get("train.use_galore"),
use_apollo=get("train.use_apollo"),
use_badam=get("train.use_badam"),
use_swanlab=get("train.use_swanlab"),
output_dir=get_save_dir(model_name, finetuning_type, get("train.output_dir")),
fp16=(get("train.compute_type") == "fp16"),
bf16=(get("train.compute_type") == "bf16"),
pure_bf16=(get("train.compute_type") == "pure_bf16"),
plot_loss=True,
trust_remote_code=True,
ddp_timeout=180000000,
include_num_input_tokens_seen=True,
)
args.update(json.loads(get("train.extra_args")))
# checkpoints
if get("top.checkpoint_path"):
if finetuning_type in PEFT_METHODS: # list
args["adapter_name_or_path"] = ",".join(
[get_save_dir(model_name, finetuning_type, adapter) for adapter in get("top.checkpoint_path")]
)
else: # str
args["model_name_or_path"] = get_save_dir(model_name, finetuning_type, get("top.checkpoint_path"))
# quantization
if get("top.quantization_bit") != "none":
args["quantization_bit"] = int(get("top.quantization_bit"))
args["quantization_method"] = get("top.quantization_method")
args["double_quantization"] = not is_torch_npu_available()
# freeze config
if args["finetuning_type"] == "freeze":
args["freeze_trainable_layers"] = get("train.freeze_trainable_layers")
args["freeze_trainable_modules"] = get("train.freeze_trainable_modules")
args["freeze_extra_modules"] = get("train.freeze_extra_modules") or None
# lora config
if args["finetuning_type"] == "lora":
args["lora_rank"] = get("train.lora_rank")
args["lora_alpha"] = get("train.lora_alpha")
args["lora_dropout"] = get("train.lora_dropout")
args["loraplus_lr_ratio"] = get("train.loraplus_lr_ratio") or None
args["create_new_adapter"] = get("train.create_new_adapter")
args["use_rslora"] = get("train.use_rslora")
args["use_dora"] = get("train.use_dora")
args["pissa_init"] = get("train.use_pissa")
args["pissa_convert"] = get("train.use_pissa")
args["lora_target"] = get("train.lora_target") or "all"
args["additional_target"] = get("train.additional_target") or None
if args["use_llama_pro"]:
args["freeze_trainable_layers"] = get("train.freeze_trainable_layers")
# rlhf config
if args["stage"] == "ppo":
if finetuning_type in PEFT_METHODS:
args["reward_model"] = ",".join(
[get_save_dir(model_name, finetuning_type, adapter) for adapter in get("train.reward_model")]
)
else:
args["reward_model"] = get_save_dir(model_name, finetuning_type, get("train.reward_model"))
args["reward_model_type"] = "lora" if finetuning_type == "lora" else "full"
args["ppo_score_norm"] = get("train.ppo_score_norm")
args["ppo_whiten_rewards"] = get("train.ppo_whiten_rewards")
args["top_k"] = 0
args["top_p"] = 0.9
elif args["stage"] in ["dpo", "kto"]:
args["pref_beta"] = get("train.pref_beta")
args["pref_ftx"] = get("train.pref_ftx")
args["pref_loss"] = get("train.pref_loss")
# multimodal config
if model_name in MULTIMODAL_SUPPORTED_MODELS:
args["freeze_vision_tower"] = get("train.freeze_vision_tower")
args["freeze_multi_modal_projector"] = get("train.freeze_multi_modal_projector")
args["freeze_language_model"] = get("train.freeze_language_model")
args["image_max_pixels"] = calculate_pixels(get("train.image_max_pixels"))
args["image_min_pixels"] = calculate_pixels(get("train.image_min_pixels"))
args["video_max_pixels"] = calculate_pixels(get("train.video_max_pixels"))
args["video_min_pixels"] = calculate_pixels(get("train.video_min_pixels"))
# galore config
if args["use_galore"]:
args["galore_rank"] = get("train.galore_rank")
args["galore_update_interval"] = get("train.galore_update_interval")
args["galore_scale"] = get("train.galore_scale")
args["galore_target"] = get("train.galore_target")
# apollo config
if args["use_apollo"]:
args["apollo_rank"] = get("train.apollo_rank")
args["apollo_update_interval"] = get("train.apollo_update_interval")
args["apollo_scale"] = get("train.apollo_scale")
args["apollo_target"] = get("train.apollo_target")
# badam config
if args["use_badam"]:
args["badam_mode"] = get("train.badam_mode")
args["badam_switch_mode"] = get("train.badam_switch_mode")
args["badam_switch_interval"] = get("train.badam_switch_interval")
args["badam_update_ratio"] = get("train.badam_update_ratio")
# swanlab config
if get("train.use_swanlab"):
args["swanlab_project"] = get("train.swanlab_project")
args["swanlab_run_name"] = get("train.swanlab_run_name")
args["swanlab_workspace"] = get("train.swanlab_workspace")
args["swanlab_api_key"] = get("train.swanlab_api_key")
args["swanlab_mode"] = get("train.swanlab_mode")
# eval config
if get("train.val_size") > 1e-6 and args["stage"] != "ppo":
args["val_size"] = get("train.val_size")
args["eval_strategy"] = "steps"
args["eval_steps"] = args["save_steps"]
args["per_device_eval_batch_size"] = args["per_device_train_batch_size"]
# ds config
if get("train.ds_stage") != "none":
ds_stage = get("train.ds_stage")
ds_offload = "offload_" if get("train.ds_offload") else ""
args["deepspeed"] = os.path.join(DEFAULT_CACHE_DIR, f"ds_z{ds_stage}_{ds_offload}config.json")
return args
def _parse_eval_args(self, data: dict["Component", Any]) -> dict[str, Any]:
r"""Build and validate the evaluation arguments."""
get = lambda elem_id: data[self.manager.get_elem_by_id(elem_id)]
model_name, finetuning_type = get("top.model_name"), get("top.finetuning_type")
user_config = load_config()
args = dict(
stage="sft",
model_name_or_path=get("top.model_path"),
cache_dir=user_config.get("cache_dir", None),
preprocessing_num_workers=16,
finetuning_type=finetuning_type,
quantization_method=get("top.quantization_method"),
template=get("top.template"),
rope_scaling=get("top.rope_scaling") if get("top.rope_scaling") != "none" else None,
flash_attn="fa2" if get("top.booster") == "flashattn2" else "auto",
use_unsloth=(get("top.booster") == "unsloth"),
dataset_dir=get("eval.dataset_dir"),
eval_dataset=",".join(get("eval.dataset")),
cutoff_len=get("eval.cutoff_len"),
max_samples=int(get("eval.max_samples")),
per_device_eval_batch_size=get("eval.batch_size"),
predict_with_generate=True,
report_to="none",
max_new_tokens=get("eval.max_new_tokens"),
top_p=get("eval.top_p"),
temperature=get("eval.temperature"),
output_dir=get_save_dir(model_name, finetuning_type, get("eval.output_dir")),
trust_remote_code=True,
ddp_timeout=180000000,
)
if get("eval.predict"):
args["do_predict"] = True
else:
args["do_eval"] = True
# checkpoints
if get("top.checkpoint_path"):
if finetuning_type in PEFT_METHODS: # list
args["adapter_name_or_path"] = ",".join(
[get_save_dir(model_name, finetuning_type, adapter) for adapter in get("top.checkpoint_path")]
)
else: # str
args["model_name_or_path"] = get_save_dir(model_name, finetuning_type, get("top.checkpoint_path"))
# quantization
if get("top.quantization_bit") != "none":
args["quantization_bit"] = int(get("top.quantization_bit"))
args["quantization_method"] = get("top.quantization_method")
args["double_quantization"] = not is_torch_npu_available()
return args
def _preview(self, data: dict["Component", Any], do_train: bool) -> Generator[dict["Component", str], None, None]:
r"""Preview the training commands."""
output_box = self.manager.get_elem_by_id("{}.output_box".format("train" if do_train else "eval"))
error = self._initialize(data, do_train, from_preview=True)
if error:
gr.Warning(error)
yield {output_box: error}
else:
args = self._parse_train_args(data) if do_train else self._parse_eval_args(data)
yield {output_box: gen_cmd(args)}
def _launch(self, data: dict["Component", Any], do_train: bool) -> Generator[dict["Component", Any], None, None]:
r"""Start the training process."""
output_box = self.manager.get_elem_by_id("{}.output_box".format("train" if do_train else "eval"))
error = self._initialize(data, do_train, from_preview=False)
if error:
gr.Warning(error)
yield {output_box: error}
else:
self.do_train, self.running_data = do_train, data
args = self._parse_train_args(data) if do_train else self._parse_eval_args(data)
os.makedirs(args["output_dir"], exist_ok=True)
save_args(os.path.join(args["output_dir"], LLAMABOARD_CONFIG), self._build_config_dict(data))
env = deepcopy(os.environ)
env["LLAMABOARD_ENABLED"] = "1"
env["LLAMABOARD_WORKDIR"] = args["output_dir"]
if args.get("deepspeed", None) is not None:
env["FORCE_TORCHRUN"] = "1"
# NOTE: DO NOT USE shell=True to avoid security risk
self.trainer = Popen(["llamafactory-cli", "train", save_cmd(args)], env=env, stderr=PIPE, text=True)
yield from self.monitor()
def _build_config_dict(self, data: dict["Component", Any]) -> dict[str, Any]:
r"""Build a dictionary containing the current training configuration."""
config_dict = {}
skip_ids = ["top.lang", "top.model_path", "train.output_dir", "train.config_path"]
for elem, value in data.items():
elem_id = self.manager.get_id_by_elem(elem)
if elem_id not in skip_ids:
config_dict[elem_id] = value
return config_dict
def preview_train(self, data):
yield from self._preview(data, do_train=True)
def preview_eval(self, data):
yield from self._preview(data, do_train=False)
def run_train(self, data):
yield from self._launch(data, do_train=True)
def run_eval(self, data):
yield from self._launch(data, do_train=False)
def monitor(self):
r"""Monitorgit the training progress and logs."""
self.aborted = False
self.running = True
get = lambda elem_id: self.running_data[self.manager.get_elem_by_id(elem_id)]
lang, model_name, finetuning_type = get("top.lang"), get("top.model_name"), get("top.finetuning_type")
output_dir = get("{}.output_dir".format("train" if self.do_train else "eval"))
output_path = get_save_dir(model_name, finetuning_type, output_dir)
output_box = self.manager.get_elem_by_id("{}.output_box".format("train" if self.do_train else "eval"))
progress_bar = self.manager.get_elem_by_id("{}.progress_bar".format("train" if self.do_train else "eval"))
loss_viewer = self.manager.get_elem_by_id("train.loss_viewer") if self.do_train else None
swanlab_link = self.manager.get_elem_by_id("train.swanlab_link") if self.do_train else None
running_log = ""
return_code = -1
while return_code == -1:
if self.aborted:
yield {
output_box: ALERTS["info_aborting"][lang],
progress_bar: gr.Slider(visible=False),
}
else:
running_log, running_progress, running_info = get_trainer_info(lang, output_path, self.do_train)
return_dict = {
output_box: running_log,
progress_bar: running_progress,
}
if "loss_viewer" in running_info:
return_dict[loss_viewer] = running_info["loss_viewer"]
if "swanlab_link" in running_info:
return_dict[swanlab_link] = running_info["swanlab_link"]
yield return_dict
try:
stderr = self.trainer.communicate(timeout=2)[1]
return_code = self.trainer.returncode
except TimeoutExpired:
continue
if return_code == 0 or self.aborted:
finish_info = ALERTS["info_finished"][lang]
if self.do_train:
finish_log = ALERTS["info_finished"][lang] + "\n\n" + running_log
else:
finish_log = load_eval_results(os.path.join(output_path, "all_results.json")) + "\n\n" + running_log
else:
print(stderr)
finish_info = ALERTS["err_failed"][lang]
finish_log = ALERTS["err_failed"][lang] + f" Exit code: {return_code}\n\n```\n{stderr}\n```\n"
self._finalize(lang, finish_info)
return_dict = {output_box: finish_log, progress_bar: gr.Slider(visible=False)}
yield return_dict
def save_args(self, data):
r"""Save the training configuration to config path."""
output_box = self.manager.get_elem_by_id("train.output_box")
error = self._initialize(data, do_train=True, from_preview=True)
if error:
gr.Warning(error)
return {output_box: error}
lang = data[self.manager.get_elem_by_id("top.lang")]
config_path = data[self.manager.get_elem_by_id("train.config_path")]
os.makedirs(DEFAULT_CONFIG_DIR, exist_ok=True)
save_path = os.path.join(DEFAULT_CONFIG_DIR, config_path)
save_args(save_path, self._build_config_dict(data))
return {output_box: ALERTS["info_config_saved"][lang] + save_path}
def load_args(self, lang: str, config_path: str):
r"""Load the training configuration from config path."""
output_box = self.manager.get_elem_by_id("train.output_box")
config_dict = load_args(os.path.join(DEFAULT_CONFIG_DIR, config_path))
if config_dict is None:
gr.Warning(ALERTS["err_config_not_found"][lang])
return {output_box: ALERTS["err_config_not_found"][lang]}
output_dict: dict[Component, Any] = {output_box: ALERTS["info_config_loaded"][lang]}
for elem_id, value in config_dict.items():
output_dict[self.manager.get_elem_by_id(elem_id)] = value
return output_dict
def check_output_dir(self, lang: str, model_name: str, finetuning_type: str, output_dir: str):
r"""Restore the training status if output_dir exists."""
output_box = self.manager.get_elem_by_id("train.output_box")
output_dict: dict[Component, Any] = {output_box: LOCALES["output_box"][lang]["value"]}
if model_name and output_dir and os.path.isdir(get_save_dir(model_name, finetuning_type, output_dir)):
gr.Warning(ALERTS["warn_output_dir_exists"][lang])
output_dict[output_box] = ALERTS["warn_output_dir_exists"][lang]
output_dir = get_save_dir(model_name, finetuning_type, output_dir)
config_dict = load_args(os.path.join(output_dir, LLAMABOARD_CONFIG)) # load llamaboard config
for elem_id, value in config_dict.items():
output_dict[self.manager.get_elem_by_id(elem_id)] = value
return output_dict
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from llamafactory.train.tuner import run_exp
def main():
run_exp()
def _mp_fn(index):
# For xla_spawn (TPUs)
run_exp()
if __name__ == "__main__":
main()
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from llamafactory.extras.misc import fix_proxy, is_env_enabled
from llamafactory.webui.interface import create_ui
def main():
gradio_ipv6 = is_env_enabled("GRADIO_IPV6")
gradio_share = is_env_enabled("GRADIO_SHARE")
server_name = os.getenv("GRADIO_SERVER_NAME", "[::]" if gradio_ipv6 else "0.0.0.0")
print("Visit http://ip:port for Web UI, e.g., http://127.0.0.1:7860")
fix_proxy(ipv6_enabled=gradio_ipv6)
create_ui().queue().launch(share=gradio_share, server_name=server_name, inbrowser=True)
if __name__ == "__main__":
main()
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import sys
from pathlib import Path
KEYWORDS = ("Copyright", "2025", "LlamaFactory")
def main():
path_list: list[Path] = []
for check_dir in sys.argv[1:]:
path_list.extend(Path(check_dir).glob("**/*.py"))
for path in path_list:
with open(path.absolute(), encoding="utf-8") as f:
file_content = f.read().strip().split("\n")
if not file_content[0]:
continue
print(f"Check license: {path}")
assert all(keyword in file_content[0] for keyword in KEYWORDS), f"File {path} does not contain license."
if __name__ == "__main__":
main()
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import random
import pytest
from datasets import load_dataset
from transformers import AutoTokenizer
from llamafactory.extras.constants import IGNORE_INDEX
from llamafactory.train.test_utils import load_dataset_module
DEMO_DATA = os.getenv("DEMO_DATA", "llamafactory/demo_data")
TINY_LLAMA3 = os.getenv("TINY_LLAMA3", "llamafactory/tiny-random-Llama-3")
TRAIN_ARGS = {
"model_name_or_path": TINY_LLAMA3,
"stage": "kto",
"do_train": True,
"finetuning_type": "full",
"dataset": "kto_en_demo",
"dataset_dir": "REMOTE:" + DEMO_DATA,
"template": "llama3",
"cutoff_len": 8192,
"output_dir": "dummy_dir",
"overwrite_output_dir": True,
"fp16": True,
}
@pytest.mark.parametrize("num_samples", [16])
def test_feedback_data(num_samples: int):
train_dataset = load_dataset_module(**TRAIN_ARGS)["train_dataset"]
ref_tokenizer = AutoTokenizer.from_pretrained(TINY_LLAMA3)
original_data = load_dataset(DEMO_DATA, name="kto_en_demo", split="train")
indexes = random.choices(range(len(original_data)), k=num_samples)
for index in indexes:
messages = original_data["messages"][index]
ref_input_ids = ref_tokenizer.apply_chat_template(messages)
prompt_len = len(ref_tokenizer.apply_chat_template(messages[:-1], add_generation_prompt=True))
ref_labels = [IGNORE_INDEX] * prompt_len + ref_input_ids[prompt_len:]
assert train_dataset["input_ids"][index] == ref_input_ids
assert train_dataset["labels"][index] == ref_labels
assert train_dataset["kto_tags"][index] == original_data["label"][index]
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import random
import pytest
from datasets import load_dataset
from transformers import AutoTokenizer
from llamafactory.extras.constants import IGNORE_INDEX
from llamafactory.train.test_utils import load_dataset_module
DEMO_DATA = os.getenv("DEMO_DATA", "llamafactory/demo_data")
TINY_LLAMA3 = os.getenv("TINY_LLAMA3", "llamafactory/tiny-random-Llama-3")
TRAIN_ARGS = {
"model_name_or_path": TINY_LLAMA3,
"stage": "rm",
"do_train": True,
"finetuning_type": "full",
"dataset": "dpo_en_demo",
"dataset_dir": "REMOTE:" + DEMO_DATA,
"template": "llama3",
"cutoff_len": 8192,
"output_dir": "dummy_dir",
"overwrite_output_dir": True,
"fp16": True,
}
def _convert_sharegpt_to_openai(messages: list[dict[str, str]]) -> list[dict[str, str]]:
role_mapping = {"human": "user", "gpt": "assistant", "system": "system"}
new_messages = []
for message in messages:
new_messages.append({"role": role_mapping[message["from"]], "content": message["value"]})
return new_messages
@pytest.mark.parametrize("num_samples", [16])
def test_pairwise_data(num_samples: int):
train_dataset = load_dataset_module(**TRAIN_ARGS)["train_dataset"]
ref_tokenizer = AutoTokenizer.from_pretrained(TINY_LLAMA3)
original_data = load_dataset(DEMO_DATA, name="dpo_en_demo", split="train")
indexes = random.choices(range(len(original_data)), k=num_samples)
for index in indexes:
chosen_messages = original_data["conversations"][index] + [original_data["chosen"][index]]
rejected_messages = original_data["conversations"][index] + [original_data["rejected"][index]]
chosen_messages = _convert_sharegpt_to_openai(chosen_messages)
rejected_messages = _convert_sharegpt_to_openai(rejected_messages)
ref_chosen_input_ids = ref_tokenizer.apply_chat_template(chosen_messages)
chosen_prompt_len = len(ref_tokenizer.apply_chat_template(chosen_messages[:-1], add_generation_prompt=True))
ref_chosen_labels = [IGNORE_INDEX] * chosen_prompt_len + ref_chosen_input_ids[chosen_prompt_len:]
ref_rejected_input_ids = ref_tokenizer.apply_chat_template(rejected_messages)
rejected_prompt_len = len(
ref_tokenizer.apply_chat_template(rejected_messages[:-1], add_generation_prompt=True)
)
ref_rejected_labels = [IGNORE_INDEX] * rejected_prompt_len + ref_rejected_input_ids[rejected_prompt_len:]
assert train_dataset["chosen_input_ids"][index] == ref_chosen_input_ids
assert train_dataset["chosen_labels"][index] == ref_chosen_labels
assert train_dataset["rejected_input_ids"][index] == ref_rejected_input_ids
assert train_dataset["rejected_labels"][index] == ref_rejected_labels
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import pytest
from llamafactory.data.processor.processor_utils import infer_seqlen
@pytest.mark.parametrize(
"test_input,test_output",
[
((3000, 2000, 1000), (600, 400)),
((2000, 3000, 1000), (400, 600)),
((1000, 100, 1000), (900, 100)),
((100, 1000, 1000), (100, 900)),
((100, 500, 1000), (100, 500)),
((500, 100, 1000), (500, 100)),
((10, 10, 1000), (10, 10)),
],
)
def test_infer_seqlen(test_input: tuple[int, int, int], test_output: tuple[int, int]):
assert test_output == infer_seqlen(*test_input)
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import random
import pytest
from datasets import load_dataset
from transformers import AutoTokenizer
from llamafactory.extras.constants import IGNORE_INDEX
from llamafactory.train.test_utils import load_dataset_module
DEMO_DATA = os.getenv("DEMO_DATA", "llamafactory/demo_data")
TINY_LLAMA3 = os.getenv("TINY_LLAMA3", "llamafactory/tiny-random-Llama-3")
TINY_DATA = os.getenv("TINY_DATA", "llamafactory/tiny-supervised-dataset")
TRAIN_ARGS = {
"model_name_or_path": TINY_LLAMA3,
"stage": "sft",
"do_train": True,
"finetuning_type": "full",
"template": "llama3",
"cutoff_len": 8192,
"output_dir": "dummy_dir",
"overwrite_output_dir": True,
"fp16": True,
}
@pytest.mark.parametrize("num_samples", [16])
def test_supervised_single_turn(num_samples: int):
train_dataset = load_dataset_module(dataset_dir="ONLINE", dataset=TINY_DATA, **TRAIN_ARGS)["train_dataset"]
ref_tokenizer = AutoTokenizer.from_pretrained(TINY_LLAMA3)
original_data = load_dataset(TINY_DATA, split="train")
indexes = random.choices(range(len(original_data)), k=num_samples)
for index in indexes:
prompt = original_data["instruction"][index]
if original_data["input"][index]:
prompt += "\n" + original_data["input"][index]
messages = [
{"role": "user", "content": prompt},
{"role": "assistant", "content": original_data["output"][index]},
]
ref_input_ids = ref_tokenizer.apply_chat_template(messages)
assert train_dataset["input_ids"][index] == ref_input_ids
@pytest.mark.parametrize("num_samples", [8])
def test_supervised_multi_turn(num_samples: int):
train_dataset = load_dataset_module(dataset_dir="REMOTE:" + DEMO_DATA, dataset="system_chat", **TRAIN_ARGS)[
"train_dataset"
]
ref_tokenizer = AutoTokenizer.from_pretrained(TINY_LLAMA3)
original_data = load_dataset(DEMO_DATA, name="system_chat", split="train")
indexes = random.choices(range(len(original_data)), k=num_samples)
for index in indexes:
ref_input_ids = ref_tokenizer.apply_chat_template(original_data["messages"][index])
assert train_dataset["input_ids"][index] == ref_input_ids
@pytest.mark.parametrize("num_samples", [4])
def test_supervised_train_on_prompt(num_samples: int):
train_dataset = load_dataset_module(
dataset_dir="REMOTE:" + DEMO_DATA, dataset="system_chat", train_on_prompt=True, **TRAIN_ARGS
)["train_dataset"]
ref_tokenizer = AutoTokenizer.from_pretrained(TINY_LLAMA3)
original_data = load_dataset(DEMO_DATA, name="system_chat", split="train")
indexes = random.choices(range(len(original_data)), k=num_samples)
for index in indexes:
ref_ids = ref_tokenizer.apply_chat_template(original_data["messages"][index])
assert train_dataset["input_ids"][index] == ref_ids
assert train_dataset["labels"][index] == ref_ids
@pytest.mark.parametrize("num_samples", [4])
def test_supervised_mask_history(num_samples: int):
train_dataset = load_dataset_module(
dataset_dir="REMOTE:" + DEMO_DATA, dataset="system_chat", mask_history=True, **TRAIN_ARGS
)["train_dataset"]
ref_tokenizer = AutoTokenizer.from_pretrained(TINY_LLAMA3)
original_data = load_dataset(DEMO_DATA, name="system_chat", split="train")
indexes = random.choices(range(len(original_data)), k=num_samples)
for index in indexes:
messages = original_data["messages"][index]
ref_input_ids = ref_tokenizer.apply_chat_template(messages)
prompt_len = len(ref_tokenizer.apply_chat_template(messages[:-1], add_generation_prompt=True))
ref_label_ids = [IGNORE_INDEX] * prompt_len + ref_input_ids[prompt_len:]
assert train_dataset["input_ids"][index] == ref_input_ids
assert train_dataset["labels"][index] == ref_label_ids
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import random
import pytest
from datasets import load_dataset
from transformers import AutoTokenizer
from llamafactory.train.test_utils import load_dataset_module
DEMO_DATA = os.getenv("DEMO_DATA", "llamafactory/demo_data")
TINY_LLAMA3 = os.getenv("TINY_LLAMA3", "llamafactory/tiny-random-Llama-3")
TINY_DATA = os.getenv("TINY_DATA", "llamafactory/tiny-supervised-dataset")
TRAIN_ARGS = {
"model_name_or_path": TINY_LLAMA3,
"stage": "ppo",
"do_train": True,
"finetuning_type": "full",
"reward_model": "",
"reward_model_type": "full",
"dataset": "system_chat",
"dataset_dir": "REMOTE:" + DEMO_DATA,
"template": "llama3",
"cutoff_len": 8192,
"output_dir": "dummy_dir",
"overwrite_output_dir": True,
"fp16": True,
}
@pytest.mark.parametrize("num_samples", [16])
def test_unsupervised_data(num_samples: int):
train_dataset = load_dataset_module(**TRAIN_ARGS)["train_dataset"]
ref_tokenizer = AutoTokenizer.from_pretrained(TINY_LLAMA3)
original_data = load_dataset(DEMO_DATA, name="system_chat", split="train")
indexes = random.choices(range(len(original_data)), k=num_samples)
for index in indexes:
messages = original_data["messages"][index]
ref_ids = ref_tokenizer.apply_chat_template(messages)
ref_input_ids = ref_tokenizer.apply_chat_template(messages[:-1], add_generation_prompt=True)
ref_labels = ref_ids[len(ref_input_ids) :]
assert train_dataset["input_ids"][index] == ref_input_ids
assert train_dataset["labels"][index] == ref_labels
# Copyright 2025 the LlamaFactory team.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import torch
from PIL import Image
from transformers import AutoConfig, AutoModelForVision2Seq
from llamafactory.data import get_template_and_fix_tokenizer
from llamafactory.data.collator import MultiModalDataCollatorForSeq2Seq, prepare_4d_attention_mask
from llamafactory.extras.constants import IGNORE_INDEX
from llamafactory.hparams import get_infer_args
from llamafactory.model import load_tokenizer
TINY_LLAMA3 = os.getenv("TINY_LLAMA3", "llamafactory/tiny-random-Llama-3")
def test_base_collator():
model_args, data_args, *_ = get_infer_args({"model_name_or_path": TINY_LLAMA3, "template": "default"})
tokenizer_module = load_tokenizer(model_args)
template = get_template_and_fix_tokenizer(tokenizer_module["tokenizer"], data_args)
data_collator = MultiModalDataCollatorForSeq2Seq(
template=template,
pad_to_multiple_of=8,
label_pad_token_id=IGNORE_INDEX,
**tokenizer_module,
)
p = tokenizer_module["tokenizer"].pad_token_id
q = IGNORE_INDEX
features = [
{
"input_ids": [0, 1, 2, 3, 4, 5],
"attention_mask": [1, 1, 1, 1, 1, 1],
"labels": [q, q, 2, 3, 4, 5],
},
{
"input_ids": [6, 7],
"attention_mask": [1, 1],
"labels": [q, 7],
},
]
batch_input = data_collator(features)
expected_input = {
"input_ids": [
[0, 1, 2, 3, 4, 5, p, p],
[6, 7, p, p, p, p, p, p],
],
"attention_mask": [
[1, 1, 1, 1, 1, 1, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0],
],
"labels": [
[q, q, 2, 3, 4, 5, q, q],
[q, 7, q, q, q, q, q, q],
],
}
for k in batch_input.keys():
assert batch_input[k].eq(torch.tensor(expected_input[k])).all()
def test_multimodal_collator():
model_args, data_args, *_ = get_infer_args(
{"model_name_or_path": "Qwen/Qwen2-VL-2B-Instruct", "template": "qwen2_vl"}
)
tokenizer_module = load_tokenizer(model_args)
template = get_template_and_fix_tokenizer(tokenizer_module["tokenizer"], data_args)
config = AutoConfig.from_pretrained(model_args.model_name_or_path)
with torch.device("meta"):
model = AutoModelForVision2Seq.from_config(config)
data_collator = MultiModalDataCollatorForSeq2Seq(
template=template,
model=model,
pad_to_multiple_of=4,
label_pad_token_id=IGNORE_INDEX,
**tokenizer_module,
)
p = tokenizer_module["tokenizer"].pad_token_id
q = IGNORE_INDEX
s = tokenizer_module["tokenizer"].convert_tokens_to_ids("<|vision_start|>")
e = tokenizer_module["tokenizer"].convert_tokens_to_ids("<|vision_end|>")
m = tokenizer_module["tokenizer"].convert_tokens_to_ids("<|image_pad|>")
fake_image = Image.new("RGB", (64, 64), (255, 255, 255))
features = [
{
"input_ids": [0, 1, 2, 3],
"attention_mask": [1, 1, 1, 1],
"labels": [0, 1, 2, 3],
},
]
batch_input = data_collator(features)
expected_input = {
"input_ids": [
[0, 1, 2, 3, s, m, m, m, m, e, p, p],
],
"attention_mask": [
[1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
],
"labels": [
[0, 1, 2, 3, q, q, q, q, q, q, q, q],
],
"position_ids": [
[[0, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1]],
[[0, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1]],
[[0, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1]],
],
"rope_deltas": [[-8]],
**tokenizer_module["processor"].image_processor(fake_image),
}
assert batch_input.keys() == expected_input.keys()
for k in batch_input.keys():
assert batch_input[k].eq(torch.tensor(expected_input[k])).all()
def test_4d_attention_mask():
o = 0.0
x = torch.finfo(torch.float16).min
attention_mask_with_indices = torch.tensor(
[
[1, 1, 2, 2, 2, 0],
[1, 2, 2, 3, 3, 3],
]
)
attention_mask_computed = prepare_4d_attention_mask(attention_mask_with_indices, torch.float16)
attention_mask_expected = torch.tensor(
[
[
[
[o, x, x, x, x, x],
[o, o, x, x, x, x],
[x, x, o, x, x, x],
[x, x, o, o, x, x],
[x, x, o, o, o, x],
[x, x, x, x, x, x],
]
],
[
[
[o, x, x, x, x, x],
[x, o, x, x, x, x],
[x, o, o, x, x, x],
[x, x, x, o, x, x],
[x, x, x, o, o, x],
[x, x, x, o, o, o],
]
],
],
dtype=torch.float16,
)
assert list(attention_mask_computed.size()) == [2, 1, 6, 6]
assert torch.all(attention_mask_computed == attention_mask_expected)
if __name__ == "__main__":
test_multimodal_collator()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment