diff --git a/localize_zh.py b/localize_zh.py new file mode 100644 index 000000000..b7363611d --- /dev/null +++ b/localize_zh.py @@ -0,0 +1,106 @@ +""" +OneTrainer UI 汉化脚本 +读取 zh_cn_map.py 中的翻译映射,替换 Base*.py 和 PySide6*.py 中的英文字符串。 +""" +import os +import re +import sys + +# 确保 UTF-8 +sys.stdout.reconfigure(encoding='utf-8') + +UI_DIR = os.path.join(os.path.dirname(__file__), 'modules', 'ui') + +def load_translations(): + """加载翻译映射""" + map_file = os.path.join(os.path.dirname(__file__), 'zh_cn_map.py') + if not os.path.exists(map_file): + print(f"Error: {map_file} not found") + sys.exit(1) + + # 动态导入 + import importlib.util + spec = importlib.util.spec_from_file_location("zh_cn_map", map_file) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod.TRANSLATIONS + +def apply_translations(translations, dry_run=False): + """应用翻译到 UI 文件""" + stats = {"files_modified": 0, "strings_replaced": 0, "strings_not_found": []} + + for filename in sorted(os.listdir(UI_DIR)): + if not filename.endswith('.py'): + continue + # 只处理 Base 和 PySide6 文件 + if not (filename.startswith('Base') or filename.startswith('PySide6')): + continue + + filepath = os.path.join(UI_DIR, filename) + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + + original = content + file_replacements = 0 + + for en, zh in translations.items(): + # 匹配带引号的英文字符串 + # 注意:要精确匹配,避免替换到变量名 + pattern = '"' + re.escape(en) + '"' + replacement = '"' + zh + '"' + + new_content = re.sub(pattern, replacement, content) + if new_content != content: + count = len(re.findall(pattern, content)) + file_replacements += count + content = new_content + + if content != original: + if not dry_run: + with open(filepath, 'w', encoding='utf-8') as f: + f.write(content) + stats["files_modified"] += 1 + stats["strings_replaced"] += file_replacements + print(f" {'[DRY] ' if dry_run else ''}{filename}: {file_replacements} replacements") + + # 检查未匹配的翻译 + for en in translations: + found = False + for filename in os.listdir(UI_DIR): + if not filename.endswith('.py'): + continue + if not (filename.startswith('Base') or filename.startswith('PySide6')): + continue + filepath = os.path.join(UI_DIR, filename) + with open(filepath, 'r', encoding='utf-8') as f: + if f'"{en}"' in f.read(): + found = True + break + if not found: + stats["strings_not_found"].append(en) + + return stats + +def main(): + dry_run = '--dry-run' in sys.argv + + print("Loading translations...") + translations = load_translations() + print(f"Loaded {len(translations)} translations") + + print(f"\n{'[DRY RUN] ' if dry_run else ''}Applying translations to UI files...") + stats = apply_translations(translations, dry_run) + + print(f"\n=== Results ===") + print(f"Files modified: {stats['files_modified']}") + print(f"Strings replaced: {stats['strings_replaced']}") + + if stats["strings_not_found"]: + print(f"Strings not found in UI files ({len(stats['strings_not_found'])}):") + for s in stats["strings_not_found"][:10]: + print(f" - {s}") + if len(stats["strings_not_found"]) > 10: + print(f" ... and {len(stats['strings_not_found']) - 10} more") + +if __name__ == '__main__': + main() diff --git a/modules/ui/BaseAdditionalEmbeddingsTabView.py b/modules/ui/BaseAdditionalEmbeddingsTabView.py index 37321ad04..ad64aff30 100644 --- a/modules/ui/BaseAdditionalEmbeddingsTabView.py +++ b/modules/ui/BaseAdditionalEmbeddingsTabView.py @@ -34,7 +34,7 @@ def build_content(self, top_frame, bottom_frame, ui_state, i, save_command, remo # embedding model names self.components.label(top_frame, 0, 2, "base embedding:", - tooltip="The base embedding to train on. Leave empty to create a new embedding") + tooltip="训练的基础嵌入,留空创建新嵌入") self.components.path_entry( top_frame, 0, 3, self.ui_state, "model_name", mode="file", path_modifier=path_util.json_path_modifier @@ -42,12 +42,12 @@ def build_content(self, top_frame, bottom_frame, ui_state, i, save_command, remo # placeholder self.components.label(top_frame, 0, 4, "placeholder:", - tooltip="The placeholder used when using the embedding in a prompt") + tooltip="在提示词中使用嵌入的占位符") self.components.entry(top_frame, 0, 5, self.ui_state, "placeholder") # token count self.components.label(top_frame, 0, 6, "token count:", - tooltip="The token count used when creating a new embedding. Leave empty to auto detect from the initial embedding text.") + tooltip="新嵌入的Token数,留空自动检测") self.components.entry(top_frame, 0, 7, self.ui_state, "token_count", width=40) # trainable @@ -56,17 +56,17 @@ def build_content(self, top_frame, bottom_frame, ui_state, i, save_command, remo # output embedding self.components.label(bottom_frame, 0, 2, "output embedding:", - tooltip="Output embeddings are calculated at the output of the text encoder, not the input. This can improve results for larger text encoders and lower VRAM usage.") + tooltip="在文本编码器输出处计算嵌入,可改善大文本编码器效果并降低显存") self.components.switch(bottom_frame, 0, 3, self.ui_state, "is_output_embedding", width=40) # stop training after self.components.label(bottom_frame, 0, 4, "stop training after:", - tooltip="When to stop training the embedding") + tooltip="何时停止训练嵌入") self.components.time_entry(bottom_frame, 0, 5, self.ui_state, "stop_training_after", "stop_training_after_unit") # initial embedding text self.components.label(bottom_frame, 0, 6, "initial embedding text:", - tooltip="The initial embedding text used when creating a new embedding") + tooltip="创建新嵌入时的初始文本") self.components.entry(bottom_frame, 0, 7, self.ui_state, "initial_embedding_text") def configure_element(self): diff --git a/modules/ui/BaseCaptionUIView.py b/modules/ui/BaseCaptionUIView.py index c53ca84d8..307c8faac 100644 --- a/modules/ui/BaseCaptionUIView.py +++ b/modules/ui/BaseCaptionUIView.py @@ -25,27 +25,27 @@ def draw_mask_editing_mode(self, *args): pass def fill_mask_editing_mode(self, *args): pass def build_top_bar(self, frame, controller, ui_state): - self.components.button(frame, 0, 0, "Open", self.open_directory, - tooltip="open a new directory") - self.components.button(frame, 0, 1, "Generate Masks", self.open_mask_window, - tooltip="open a dialog to automatically generate masks") - self.components.button(frame, 0, 2, "Generate Captions", self.open_caption_window, - tooltip="open a dialog to automatically generate captions") + self.components.button(frame, 0, 0, "打开", self.open_directory, + tooltip="打开新目录") + self.components.button(frame, 0, 1, "生成遮罩", self.open_mask_window, + tooltip="打开自动生成遮罩对话框") + self.components.button(frame, 0, 2, "生成标签", self.open_caption_window, + tooltip="打开自动生成标签对话框") if platform.system() == "Windows": - self.components.button(frame, 0, 3, "Open in Explorer", self.open_in_explorer, - tooltip="open the current image in Explorer") + self.components.button(frame, 0, 3, "在资源管理器中打开", self.open_in_explorer, + tooltip="在资源管理器中打开当前图像") self.components.switch(frame, 0, 4, ui_state, "include_subdirectories", text="include subdirectories") frame.grid_columnconfigure(5, weight=1) - self.components.button(frame, 0, 6, "Help", controller.print_help, + self.components.button(frame, 0, 6, "帮助", controller.print_help, tooltip=controller.help_text) def build_mask_buttons(self, right_frame): - self.components.button(right_frame, 0, 0, "Draw", self.draw_mask_editing_mode, - tooltip="draw a mask using a brush") - self.components.button(right_frame, 0, 1, "Fill", self.fill_mask_editing_mode, - tooltip="draw a mask using a fill tool") + self.components.button(right_frame, 0, 0, "绘制", self.draw_mask_editing_mode, + tooltip="用画笔绘制遮罩") + self.components.button(right_frame, 0, 1, "填充", self.fill_mask_editing_mode, + tooltip="用填充工具绘制遮罩") diff --git a/modules/ui/BaseCloudTabView.py b/modules/ui/BaseCloudTabView.py index 3f20b5674..adec1791a 100644 --- a/modules/ui/BaseCloudTabView.py +++ b/modules/ui/BaseCloudTabView.py @@ -25,161 +25,161 @@ def _make_create_frame(self, frame): pass def _on_set_gpu_types(self): pass def build_content(self, frame, controller, ui_state): - self.components.label(frame, 0, 0, "Enabled", - tooltip="Enable cloud training") + self.components.label(frame, 0, 0, "启用", + tooltip="启用云端训练") self.components.switch(frame, 0, 1, ui_state, "cloud.enabled") - self.components.label(frame, 1, 0, "Type", - tooltip="Choose LINUX to connect to a linux machine via SSH. Choose RUNPOD for additional functionality such as automatically creating and deleting pods.") + self.components.label(frame, 1, 0, "类型", + tooltip="LINUX通过SSH连接Linux机器,RUNPOD自动创建和删除Pod") self.components.options_kv(frame, 1, 1, [ ("RUNPOD", CloudType.RUNPOD), ("LINUX", CloudType.LINUX), ], ui_state, "cloud.type") - self.components.label(frame, 2, 0, "File sync method", - tooltip="Choose NATIVE_SCP to use scp.exe to transfer files. FABRIC_SFTP uses the Paramiko/Fabric SFTP implementation for file transfers instead.") + self.components.label(frame, 2, 0, "文件同步方式", + tooltip="NATIVE_SCP使用scp.exe传输,FABRIC_SFTP使用Paramiko SFTP") self.components.options_kv(frame, 2, 1, [ ("NATIVE_SCP", CloudFileSync.NATIVE_SCP), ("FABRIC_SFTP", CloudFileSync.FABRIC_SFTP), ], ui_state, "cloud.file_sync") - self.components.label(frame, 3, 0, "API key", - tooltip="Cloud service API key for RUNPOD. Leave empty for LINUX. This value is stored separately, not saved to your configuration file. ") + self.components.label(frame, 3, 0, "API密钥", + tooltip="RUNPOD云服务API密钥,LINUX留空。单独存储不保存到配置文件") self.components.entry(frame, 3, 1, ui_state, "secrets.cloud.api_key") - self.components.label(frame, 4, 0, "Hostname", - tooltip="SSH server hostname or IP. Leave empty if you have a Cloud ID or want to automatically create a new cloud.") + self.components.label(frame, 4, 0, "主机名", + tooltip="SSH服务器主机名或IP,有Cloud ID时留空") self.components.entry(frame, 4, 1, ui_state, "secrets.cloud.host") - self.components.label(frame, 5, 0, "Port", - tooltip="SSH server port. Leave empty if you have a Cloud ID or want to automatically create a new cloud.") + self.components.label(frame, 5, 0, "端口", + tooltip="SSH服务器端口,有Cloud ID时留空") self.components.entry(frame, 5, 1, ui_state, "secrets.cloud.port") - self.components.label(frame, 6, 0, "User", - tooltip='SSH username. Use "root" for RUNPOD. Your SSH client must be set up to connect to the cloud using a public key, without a password. For RUNPOD, create an ed25519 key locally, and copy the contents of the public keyfile to your "SSH Public Keys" on the RunPod website.') + self.components.label(frame, 6, 0, "用户", + tooltip='SSH username. Use "root" for RUNPOD. Your SSH client must be set up to connect to the cloud using a public key, without a password. For RUNPOD, create an ed25519 key locally, and copy the contents of the public keyfile to your "SSH公钥" on the RunPod website.') self.components.entry(frame, 6, 1, ui_state, "secrets.cloud.user") - self.components.label(frame, 7, 0, "SSH keyfile path", - tooltip="Absolute path to the private key file used for SSH connections. Leave empty to rely on your system SSH configuration.") + self.components.label(frame, 7, 0, "SSH密钥路径", + tooltip="SSH私钥文件绝对路径,留空使用系统SSH配置") self.components.path_entry(frame, 7, 1, ui_state, "secrets.cloud.key_file", mode="file") - self.components.label(frame, 8, 0, "SSH password", - tooltip="SSH password for password-based authentication. If you try to use native SCP requires sshpass to be installed. Leave empty to use key-based authentication.") + self.components.label(frame, 8, 0, "SSH密码", + tooltip="SSH密码认证,留空使用密钥认证") self.components.entry(frame, 8, 1, ui_state, "secrets.cloud.password") - self.components.label(frame, 9, 0, "Cloud id", - tooltip="RUNPOD Cloud ID. The cloud service must have a public IP and SSH service. Leave empty if you want to automatically create a new RUNPOD cloud, or if you're connecting to another cloud provider via SSH Hostname and Port.") + self.components.label(frame, 9, 0, "云ID", + tooltip="RUNPOD云ID,需要有公网IP和SSH服务") self.components.entry(frame, 9, 1, ui_state, "secrets.cloud.id") - self.components.label(frame, 10, 0, "Tensorboard TCP tunnel", - tooltip="Instead of starting tensorboard locally, make a TCP tunnel to a tensorboard on the cloud") + self.components.label(frame, 10, 0, "Tensorboard TCP隧道", + tooltip="通过TCP隧道连接云端Tensorboard") self.components.switch(frame, 10, 1, ui_state, "cloud.tensorboard_tunnel") - self.components.label(frame, 1, 2, "Remote Directory", - tooltip="The directory on the cloud where files will be uploaded and downloaded.") + self.components.label(frame, 1, 2, "远程目录", + tooltip="云端上传下载文件的目录") self.components.entry(frame, 1, 3, ui_state, "cloud.remote_dir") - self.components.label(frame, 2, 2, "OneTrainer Directory", - tooltip="The directory for OneTrainer on the cloud.") + self.components.label(frame, 2, 2, "OneTrainer目录", + tooltip="云端OneTrainer目录") self.components.entry(frame, 2, 3, ui_state, "cloud.onetrainer_dir") - self.components.label(frame, 3, 2, "Huggingface cache Directory", - tooltip="Huggingface models are downloaded to this remote directory.") + self.components.label(frame, 3, 2, "Hugging Face缓存目录", + tooltip="Huggingface模型下载到此远程目录") self.components.entry(frame, 3, 3, ui_state, "cloud.huggingface_cache_dir") - self.components.label(frame, 4, 2, "Install OneTrainer", - tooltip="Automatically install OneTrainer from GitHub if the directory doesn't already exist.") + self.components.label(frame, 4, 2, "安装OneTrainer", + tooltip="如果目录不存在,自动从GitHub安装OneTrainer") self.components.switch(frame, 4, 3, ui_state, "cloud.install_onetrainer") - self.components.label(frame, 5, 2, "Install command", - tooltip="The command for installing OneTrainer. Leave the default, unless you want to use a development branch of OneTrainer.") + self.components.label(frame, 5, 2, "安装命令", + tooltip="OneTrainer安装命令,默认即可") self.components.entry(frame, 5, 3, ui_state, "cloud.install_cmd") - self.components.label(frame, 6, 2, "Update OneTrainer", - tooltip="Update OneTrainer if it already exists on the cloud.") + self.components.label(frame, 6, 2, "更新OneTrainer", + tooltip="如果云端已存在则更新OneTrainer") self.components.switch(frame, 6, 3, ui_state, "cloud.update_onetrainer") - self.components.label(frame, 8, 2, "Detach remote trainer", - tooltip="Allows the trainer to keep running even if your connection to the cloud is lost.") + self.components.label(frame, 8, 2, "断开远程训练器", + tooltip="允许训练器在断连后继续运行") self.components.switch(frame, 8, 3, ui_state, "cloud.detach_trainer") - self.components.label(frame, 9, 2, "Reattach id", - tooltip="An id identifying the remotely running trainer. In case you have lost connection or closed OneTrainer, it will try to reattach to this id instead of starting a new remote trainer.") + self.components.label(frame, 9, 2, "重连ID", + tooltip="远程训练器标识ID,断连后可重新连接") reattach_frame = self._make_reattach_frame(frame) self.components.entry(reattach_frame, 0, 0, ui_state, "cloud.run_id", width=60) - self.components.button(reattach_frame, 0, 1, "Reattach now", controller.do_reattach) + self.components.button(reattach_frame, 0, 1, "立即重连", controller.do_reattach) - self.components.label(frame, 11, 2, "Download samples", - tooltip="Download samples from the remote workspace directory to your local machine.") + self.components.label(frame, 11, 2, "下载样本", + tooltip="从远程下载样本到本地") self.components.switch(frame, 11, 3, ui_state, "cloud.download_samples") - self.components.label(frame, 12, 2, "Download output model", - tooltip="Download the final model after training. You can disable this if you plan to use an automatically saved checkpoint instead.") + self.components.label(frame, 12, 2, "下载输出模型", + tooltip="训练后下载最终模型") self.components.switch(frame, 12, 3, ui_state, "cloud.download_output_model") - self.components.label(frame, 13, 2, "Download saved checkpoints", - tooltip="Download the automatically saved training checkpoints from the remote workspace directory to your local machine.") + self.components.label(frame, 13, 2, "下载已保存检查点", + tooltip="从远程下载训练检查点到本地") self.components.switch(frame, 13, 3, ui_state, "cloud.download_saves") - self.components.label(frame, 14, 2, "Download backups", - tooltip="Download backups from the remote workspace directory to your local machine. It's usually not necessary to download them, because as long as the backups are still available on the cloud, the training can be restarted using one of the cloud's backups.") + self.components.label(frame, 14, 2, "下载备份", + tooltip="从远程下载备份到本地") self.components.switch(frame, 14, 3, ui_state, "cloud.download_backups") - self.components.label(frame, 15, 2, "Download tensorboard logs", - tooltip="Download TensorBoard event logs from the remote workspace directory to your local machine. They can then be viewed locally in TensorBoard. It is recommended to disable \"Sample to TensorBoard\" to reduce the event log size.") + self.components.label(frame, 15, 2, "下载Tensorboard日志", + tooltip="从远程下载Tensorboard日志到本地查看") self.components.switch(frame, 15, 3, ui_state, "cloud.download_tensorboard") - self.components.label(frame, 16, 2, "Delete remote workspace", - tooltip="Delete the workspace directory on the cloud after training has finished successfully and data has been downloaded.") + self.components.label(frame, 16, 2, "删除远程工作空间", + tooltip="训练完成并下载数据后删除云端工作空间目录") self.components.switch(frame, 16, 3, ui_state, "cloud.delete_workspace") - self.components.label(frame, 1, 4, "Create cloud via API", - tooltip="Automatically creates a new cloud instance if both Host:Port and Cloud ID are empty. Currently supported for RUNPOD.") + self.components.label(frame, 1, 4, "通过API创建云", + tooltip="主机和云ID为空时自动创建云实例,目前支持RUNPOD") create_frame = self._make_create_frame(frame) self.components.switch(create_frame, 0, 0, ui_state, "cloud.create") - self.components.button(create_frame, 0, 1, "Create cloud via website", controller.open_create_cloud_url) + self.components.button(create_frame, 0, 1, "通过网站创建云", controller.open_create_cloud_url) - self.components.label(frame, 2, 4, "Cloud name", - tooltip="The name of the new cloud instance.") + self.components.label(frame, 2, 4, "云名称", + tooltip="新云实例名称") self.components.entry(frame, 2, 5, ui_state, "cloud.name") - self.components.label(frame, 3, 4, "Type", - tooltip="Select the RunPod cloud type. See RunPod's website for details.") + self.components.label(frame, 3, 4, "类型", + tooltip="选择RunPod云类型,详见RunPod网站") self.components.options_kv(frame, 3, 5, [ ("", ""), - ("Community", "COMMUNITY"), - ("Secure", "SECURE"), + ("社区", "COMMUNITY"), + ("安全", "SECURE"), ], ui_state, "cloud.sub_type") self.components.label(frame, 4, 4, "GPU", - tooltip="Select the GPU type. Enter an API key before pressing the button.") + tooltip="选择GPU类型,请先输入API密钥") _, gpu_components = self.components.options_adv(frame, 4, 5, [("")], ui_state, "cloud.gpu_type", adv_command=self._on_set_gpu_types) self.gpu_types_menu = gpu_components['component'] - self.components.label(frame, 5, 4, "Volume size", - tooltip="Set the storage volume size in GB. This volume persists only until the cloud is deleted - not a RunPod network volume") + self.components.label(frame, 5, 4, "卷大小", + tooltip="存储卷大小(GB),云删除后不保留") self.components.entry(frame, 5, 5, ui_state, "cloud.volume_size") - self.components.label(frame, 6, 4, "Min download", - tooltip="Set the minimum download speed of the cloud in Mbps.") + self.components.label(frame, 6, 4, "最小下载速度", + tooltip="云端最小下载速度(Mbps)") self.components.entry(frame, 6, 5, ui_state, "cloud.min_download") - self.components.label(frame, 8, 4, "Action on finish", - tooltip="What to do when training finishes and the data has been fully downloaded: Stop or delete the cloud, or do nothing.") + self.components.label(frame, 8, 4, "完成时操作", + tooltip="训练完成且数据下载后的操作") self.components.options_kv(frame, 8, 5, [ - ("None", CloudAction.NONE), + ("无", CloudAction.NONE), ("Stop", CloudAction.STOP), - ("Delete", CloudAction.DELETE), + ("删除", CloudAction.DELETE), ], ui_state, "cloud.on_finish") - self.components.label(frame, 9, 4, "Action on error", - tooltip="What to do if training stops due to an error: Stop or delete the cloud, or do nothing. Data may be lost.") + self.components.label(frame, 9, 4, "错误时操作", + tooltip="训练出错时的操作,数据可能丢失") self.components.options_kv(frame, 9, 5, [ - ("None", CloudAction.NONE), + ("无", CloudAction.NONE), ("Stop", CloudAction.STOP), - ("Delete", CloudAction.DELETE), + ("删除", CloudAction.DELETE), ], ui_state, "cloud.on_error") - self.components.label(frame, 10, 4, "Action on detached finish", - tooltip="What to do when training finishes, but the client has been detached and cannot download data. Data may be lost.") + self.components.label(frame, 10, 4, "断连完成时操作", + tooltip="训练完成但客户端已断连时的操作") self.components.options_kv(frame, 10, 5, [ - ("None", CloudAction.NONE), + ("无", CloudAction.NONE), ("Stop", CloudAction.STOP), - ("Delete", CloudAction.DELETE), + ("删除", CloudAction.DELETE), ], ui_state, "cloud.on_detached_finish") - self.components.label(frame, 11, 4, "Action on detached error", - tooltip="What to if training stops due to an error, but the client has been detached and cannot download data. Data may be lost.") + self.components.label(frame, 11, 4, "断连错误时操作", + tooltip="训练出错且客户端已断连时的操作") self.components.options_kv(frame, 11, 5, [ - ("None", CloudAction.NONE), + ("无", CloudAction.NONE), ("Stop", CloudAction.STOP), - ("Delete", CloudAction.DELETE), + ("删除", CloudAction.DELETE), ], ui_state, "cloud.on_detached_error") diff --git a/modules/ui/BaseConceptWindowView.py b/modules/ui/BaseConceptWindowView.py index 0b94e50d1..3c4cfa3d0 100644 --- a/modules/ui/BaseConceptWindowView.py +++ b/modules/ui/BaseConceptWindowView.py @@ -15,34 +15,34 @@ def __init__(self, components): def build_general_tab(self, frame, controller, ui_state, text_ui_state): # name - self.components.label(frame, 0, 0, "Name", - tooltip="Name of the concept") + self.components.label(frame, 0, 0, "名称", + tooltip="数据集名称") self.components.entry(frame, 0, 1, ui_state, "name") # enabled - self.components.label(frame, 1, 0, "Enabled", - tooltip="Enable or disable this concept") + self.components.label(frame, 1, 0, "启用", + tooltip="启用或禁用此数据集") self.components.switch(frame, 1, 1, ui_state, "enabled") # concept type - self.components.label(frame, 2, 0, "Concept Type", + self.components.label(frame, 2, 0, "数据集类型", tooltip="STANDARD: Standard finetuning with the sample as training target\n" "VALIDATION: Use concept for validation instead of training\n" "PRIOR_PREDICTION: Use the sample to make a prediction using the model as it was before training. This prediction is then used as the training target " "for the model in training. This can be used as regularisation and to preserve prior model knowledge while finetuning the model on other concepts. " - "Only implemented for LoRA.", + "仅对LoRA实现", wide_tooltip=True) self.components.options(frame, 2, 1, [str(x) for x in list(ConceptType)], ui_state, "type") # path - self.components.label(frame, 3, 0, "Path", - tooltip="Path where the training data is located") + self.components.label(frame, 3, 0, "路径", + tooltip="训练数据所在路径") self.components.path_entry(frame, 3, 1, ui_state, "path", mode="dir") self.components.button(frame, 3, 2, text="download now", command=controller.download_dataset_threaded, - tooltip="Download dataset from Huggingface now, for the purpose of previewing and statistics. Otherwise, it will be downloaded when you start training. Path must be a Huggingface repository.") + tooltip="从Huggingface下载数据集用于预览和统计") # prompt source - self.components.label(frame, 4, 0, "Prompt Source", + self.components.label(frame, 4, 0, "提示词来源", tooltip="The source for prompts used during training. When selecting \"From single text file\", select a text file that contains a list of prompts") prompt_path_entry = self.components.path_entry(frame, 4, 2, text_ui_state, "prompt_path", mode="file") @@ -50,162 +50,162 @@ def set_prompt_path_entry_enabled(option: str): self.components.set_widget_enabled(prompt_path_entry, option == 'concept') self.components.options_kv(frame, 4, 1, [ - ("From text file per sample", 'sample'), - ("From single text file", 'concept'), - ("From image file name", 'filename'), + ("从每样本文本文件", 'sample'), + ("从单个文本文件", 'concept'), + ("从图像文件名", 'filename'), ], text_ui_state, "prompt_source", command=set_prompt_path_entry_enabled) set_prompt_path_entry_enabled(controller.concept.text.prompt_source) # include subdirectories - self.components.label(frame, 5, 0, "Include Subdirectories", - tooltip="Includes images from subdirectories into the dataset") + self.components.label(frame, 5, 0, "包含子目录", + tooltip="将子目录中的图像包含到数据集中") self.components.switch(frame, 5, 1, ui_state, "include_subdirectories") # image variations - self.components.label(frame, 6, 0, "Image Variations", - tooltip="The number of different image versions to cache if latent caching is enabled.") + self.components.label(frame, 6, 0, "图像变体", + tooltip="潜在缓存的图像版本数") self.components.entry(frame, 6, 1, ui_state, "image_variations") # text variations - self.components.label(frame, 7, 0, "Text Variations", - tooltip="The number of different text versions to cache if latent caching is enabled.") + self.components.label(frame, 7, 0, "文本变体", + tooltip="潜在缓存的文本版本数") self.components.entry(frame, 7, 1, ui_state, "text_variations") # balancing - self.components.label(frame, 8, 0, "Balancing", - tooltip="The number of samples used during training. Use repeats to multiply the concept, or samples to specify an exact number of samples used in each epoch.") + self.components.label(frame, 8, 0, "平衡策略", + tooltip="训练使用的样本数,用repeats倍乘或samples指定精确数") self.components.entry(frame, 8, 1, ui_state, "balancing") self.components.options(frame, 8, 2, [str(x) for x in list(BalancingStrategy)], ui_state, "balancing_strategy") # loss weight - self.components.label(frame, 9, 0, "Loss Weight", - tooltip="The loss multiplyer for this concept.") + self.components.label(frame, 9, 0, "损失权重", + tooltip="此数据集的损失乘数") self.components.entry(frame, 9, 1, ui_state, "loss_weight") def build_image_augmentation_tab(self, frame, controller, image_ui_state): # header - self.components.label(frame, 0, 1, "Random", - tooltip="Enable this augmentation with random values") - self.components.label(frame, 0, 2, "Fixed", - tooltip="Enable this augmentation with fixed values") + self.components.label(frame, 0, 1, "随机", + tooltip="以随机值启用此增强") + self.components.label(frame, 0, 2, "固定", + tooltip="以固定值启用此增强") # crop jitter - self.components.label(frame, 1, 0, "Crop Jitter", - tooltip="Enables random cropping of samples") + self.components.label(frame, 1, 0, "裁剪抖动", + tooltip="启用样本随机裁剪") self.components.switch(frame, 1, 1, image_ui_state, "enable_crop_jitter") # random flip - self.components.label(frame, 2, 0, "Random Flip", - tooltip="Randomly flip the sample during training") + self.components.label(frame, 2, 0, "随机翻转", + tooltip="训练时随机翻转样本") self.components.switch(frame, 2, 1, image_ui_state, "enable_random_flip") self.components.switch(frame, 2, 2, image_ui_state, "enable_fixed_flip") # random rotation - self.components.label(frame, 3, 0, "Random Rotation", - tooltip="Randomly rotates the sample during training") + self.components.label(frame, 3, 0, "随机旋转", + tooltip="训练时随机旋转样本") self.components.switch(frame, 3, 1, image_ui_state, "enable_random_rotate") self.components.switch(frame, 3, 2, image_ui_state, "enable_fixed_rotate") self.components.entry(frame, 3, 3, image_ui_state, "random_rotate_max_angle") # random brightness - self.components.label(frame, 4, 0, "Random Brightness", - tooltip="Randomly adjusts the brightness of the sample during training") + self.components.label(frame, 4, 0, "随机亮度", + tooltip="训练时随机调整样本亮度") self.components.switch(frame, 4, 1, image_ui_state, "enable_random_brightness") self.components.switch(frame, 4, 2, image_ui_state, "enable_fixed_brightness") self.components.entry(frame, 4, 3, image_ui_state, "random_brightness_max_strength") # random contrast - self.components.label(frame, 5, 0, "Random Contrast", - tooltip="Randomly adjusts the contrast of the sample during training") + self.components.label(frame, 5, 0, "随机对比度", + tooltip="训练时随机调整样本对比度") self.components.switch(frame, 5, 1, image_ui_state, "enable_random_contrast") self.components.switch(frame, 5, 2, image_ui_state, "enable_fixed_contrast") self.components.entry(frame, 5, 3, image_ui_state, "random_contrast_max_strength") # random saturation - self.components.label(frame, 6, 0, "Random Saturation", - tooltip="Randomly adjusts the saturation of the sample during training") + self.components.label(frame, 6, 0, "随机饱和度", + tooltip="训练时随机调整样本饱和度") self.components.switch(frame, 6, 1, image_ui_state, "enable_random_saturation") self.components.switch(frame, 6, 2, image_ui_state, "enable_fixed_saturation") self.components.entry(frame, 6, 3, image_ui_state, "random_saturation_max_strength") # random hue - self.components.label(frame, 7, 0, "Random Hue", - tooltip="Randomly adjusts the hue of the sample during training") + self.components.label(frame, 7, 0, "随机色相", + tooltip="训练时随机调整样本色相") self.components.switch(frame, 7, 1, image_ui_state, "enable_random_hue") self.components.switch(frame, 7, 2, image_ui_state, "enable_fixed_hue") self.components.entry(frame, 7, 3, image_ui_state, "random_hue_max_strength") # random circular mask shrink - self.components.label(frame, 8, 0, "Circular Mask Generation", - tooltip="Automatically create circular masks for masked training") + self.components.label(frame, 8, 0, "圆形遮罩生成", + tooltip="自动为遮罩训练创建圆形遮罩") self.components.switch(frame, 8, 1, image_ui_state, "enable_random_circular_mask_shrink") # random rotate and crop - self.components.label(frame, 9, 0, "Random Rotate and Crop", + self.components.label(frame, 9, 0, "随机旋转裁剪", tooltip="Randomly rotate the training samples and crop to the masked region") self.components.switch(frame, 9, 1, image_ui_state, "enable_random_mask_rotate_crop") # circular mask generation - self.components.label(frame, 10, 0, "Resolution Override", + self.components.label(frame, 10, 0, "分辨率覆盖", tooltip="Override the resolution for this concept. Optionally specify multiple resolutions separated by a comma, or a single exact resolution in the format x") self.components.switch(frame, 10, 2, image_ui_state, "enable_resolution_override") self.components.entry(frame, 10, 3, image_ui_state, "resolution_override") def build_text_augmentation_tab(self, frame, controller, text_ui_state): # tag shuffling - self.components.label(frame, 0, 0, "Tag Shuffling", - tooltip="Enables tag shuffling") + self.components.label(frame, 0, 0, "标签打乱", + tooltip="启用标签打乱") self.components.switch(frame, 0, 1, text_ui_state, "enable_tag_shuffling") # keep tag count - self.components.label(frame, 1, 0, "Tag Delimiter", - tooltip="The delimiter between tags") + self.components.label(frame, 1, 0, "标签分隔符", + tooltip="标签之间的分隔符") self.components.entry(frame, 1, 1, text_ui_state, "tag_delimiter") # keep tag count - self.components.label(frame, 2, 0, "Keep Tag Count", - tooltip="The number of tags at the start of the caption that are not shuffled or dropped") + self.components.label(frame, 2, 0, "保留标签数", + tooltip="标签开头不打乱不丢弃的标签数") self.components.entry(frame, 2, 1, text_ui_state, "keep_tags_count") # tag dropout - self.components.label(frame, 3, 0, "Tag Dropout", - tooltip="Enables random dropout for tags in the captions.") + self.components.label(frame, 3, 0, "标签丢弃", + tooltip="启用标签随机丢弃") self.components.switch(frame, 3, 1, text_ui_state, "tag_dropout_enable") - self.components.label(frame, 4, 0, "Dropout Mode", - tooltip="Method used to drop captions. 'Full' will drop the entire caption past the 'kept' tags with a certain probability, 'Random' will drop individual tags with the set probability, and 'Random Weighted' will linearly increase the probability of dropping tags, more likely to preseve tags near the front with full probability to drop at the end.") + self.components.label(frame, 4, 0, "丢弃模式", + tooltip="标签丢弃方式:Full整体丢弃,Random随机丢弃,Random Weighted加权丢弃") self.components.options_kv(frame, 4, 1, [ - ("Full", 'FULL'), - ("Random", 'RANDOM'), - ("Random Weighted", 'RANDOM WEIGHTED'), + ("全部", 'FULL'), + ("随机", 'RANDOM'), + ("随机加权", 'RANDOM WEIGHTED'), ], text_ui_state, "tag_dropout_mode", None) - self.components.label(frame, 4, 2, "Probability", - tooltip="Probability to drop tags, from 0 to 1.") + self.components.label(frame, 4, 2, "概率", + tooltip="标签丢弃概率,0到1") self.components.entry(frame, 4, 3, text_ui_state, "tag_dropout_probability") - self.components.label(frame, 5, 0, "Special Dropout Tags", - tooltip="List of tags which will be whitelisted/blacklisted by dropout. 'Whitelist' tags will never be dropped but all others may be, 'Blacklist' tags may be dropped but all others will never be, 'None' may drop any tags. Can specify either a delimiter-separated list in the field, or a file path to a .txt or .csv file with entries separated by newlines.") + self.components.label(frame, 5, 0, "特殊丢弃标签", + tooltip="丢弃白/黑名单标签列表,可输入分隔列表或文件路径") self.components.options_kv(frame, 5, 1, [ - ("None", 'NONE'), - ("Blacklist", 'BLACKLIST'), - ("Whitelist", 'WHITELIST'), + ("无", 'NONE'), + ("黑名单", 'BLACKLIST'), + ("白名单", 'WHITELIST'), ], text_ui_state, "tag_dropout_special_tags_mode", None) self.components.entry(frame, 5, 2, text_ui_state, "tag_dropout_special_tags") - self.components.label(frame, 6, 0, "Special Tags Regex", - tooltip="Interpret special tags with regex, such as 'photo.*' to match 'photo, photograph, photon' but not 'telephoto'. Includes exception for '/(' and '/)' syntax found in many booru/e6 tags.") + self.components.label(frame, 6, 0, "特殊标签正则", + tooltip="使用正则匹配特殊标签,如'photo.*'匹配'photo, photograph'") self.components.switch(frame, 6, 1, text_ui_state, "tag_dropout_special_tags_regex") #capitalization randomization - self.components.label(frame, 7, 0, "Randomize Capitalization", - tooltip="Enables randomization of capitalization for tags in the caption.") + self.components.label(frame, 7, 0, "随机大小写", + tooltip="启用标签大小写随机化") self.components.switch(frame, 7, 1, text_ui_state, "caps_randomize_enable") - self.components.label(frame, 7, 2, "Force Lowercase", - tooltip="If enabled, converts the caption to lowercase before any further processing.") + self.components.label(frame, 7, 2, "强制小写", + tooltip="启用后,将标签转为小写后再处理") self.components.switch(frame, 7, 3, text_ui_state, "caps_randomize_lowercase") - self.components.label(frame, 8, 0, "Captialization Mode", - tooltip="Comma-separated list of types of capitalization randomization to perform. 'capslock' for ALL CAPS, 'title' for First Letter Of Every Word, 'first' for First word only, 'random' for rAndOMiZeD lEtTERs.") + self.components.label(frame, 8, 0, "大小写模式", + tooltip="大小写随机化类型:capslock全大写,title首字母大写,first首词大写,random随机") self.components.entry(frame, 8, 1, text_ui_state, "caps_randomize_mode") - self.components.label(frame, 8, 2, "Probability", + self.components.label(frame, 8, 2, "概率", tooltip="Probability to randomize capitialization of each tag, from 0 to 1.") self.components.entry(frame, 8, 3, text_ui_state, "caps_randomize_probability") @@ -213,91 +213,91 @@ def build_concept_stats_tab(self, frame, controller): self.concept_stats_tab = frame #file size - self.file_size_label = self.components.label(frame, 1, 0, "Total Size", pad=0, - tooltip="Total size of all image, mask, and caption files in MB", underline=True) + self.file_size_label = self.components.label(frame, 1, 0, "总大小", pad=0, + tooltip="图像、遮罩和标签文件总大小(MB)", underline=True) self.file_size_preview = self.components.label(frame, 2, 0, pad=0, text="-") #subdirectory count - self.dir_count_label = self.components.label(frame, 1, 1, "Directories", pad=0, - tooltip="Total number of directories including and under (if 'include subdirectories' is enabled) the main concept directory", underline=True) + self.dir_count_label = self.components.label(frame, 1, 1, "目录数", pad=0, + tooltip="数据集目录及子目录总数", underline=True) self.dir_count_preview = self.components.label(frame, 2, 1, pad=0, text="-") #basic img/vid stats - count of each type in the concept #the \n at the start of the label gives it better vertical spacing with other rows self.image_count_label = self.components.label(frame, 3, 0, "\nTotal Images", pad=0, - tooltip="Total number of image files, any of the extensions " + str(path_util.SUPPORTED_IMAGE_EXTENSIONS) + ", excluding '-masklabel.png and -condlabel.png'", underline=True) + tooltip="图像文件总数,扩展名:" + str(path_util.SUPPORTED_IMAGE_EXTENSIONS) + ", excluding '-masklabel.png and -condlabel.png'", underline=True) self.image_count_preview = self.components.label(frame, 4, 0, pad=0, text="-") self.video_count_label = self.components.label(frame, 3, 1, "\nTotal Videos", pad=0, - tooltip="Total number of video files, any of the extensions " + str(path_util.SUPPORTED_VIDEO_EXTENSIONS), underline=True) + tooltip="视频文件总数,扩展名:" + str(path_util.SUPPORTED_VIDEO_EXTENSIONS), underline=True) self.video_count_preview = self.components.label(frame, 4, 1, pad=0, text="-") self.mask_count_label = self.components.label(frame, 3, 2, "\nTotal Masks", pad=0, - tooltip="Total number of mask files, any file ending in '-masklabel.png'", underline=True) + tooltip="遮罩文件总数(-masklabel.png结尾)", underline=True) self.mask_count_preview = self.components.label(frame, 4, 2, pad=0, text="-") self.caption_count_label = self.components.label(frame, 3, 3, "\nTotal Captions", pad=0, - tooltip="Total number of caption files, any .txt file. With advanced scan, includes the total number of captions on separate lines across all files in parentheses.", underline=True) + tooltip="标签文件总数(.txt文件)", underline=True) self.caption_count_preview = self.components.label(frame, 4, 3, pad=0, text="-") #advanced img/vid stats - how many img/vid files have a mask or caption of the same name self.image_count_mask_label = self.components.label(frame, 5, 0, "\nImages with Masks", pad=0, - tooltip="Total number of image files with an associated mask", underline=True) + tooltip="有关联遮罩的图像文件总数", underline=True) self.image_count_mask_preview = self.components.label(frame, 6, 0, pad=0, text="-") self.mask_count_label_unpaired = self.components.label(frame, 5, 1, "\nUnpaired Masks", pad=0, - tooltip="Total number of mask files which lack a corresponding image file - if >0, check your data set!", underline=True) + tooltip="缺少对应图像的遮罩文件数,>0请检查数据集", underline=True) self.mask_count_preview_unpaired = self.components.label(frame, 6, 1, pad=0, text="-") #currently no masks for videos? self.image_count_caption_label = self.components.label(frame, 7, 0, "\nImages with Captions", pad=0, - tooltip="Total number of image files with an associated caption", underline=True) + tooltip="有关联标签的图像文件总数", underline=True) self.image_count_caption_preview = self.components.label(frame, 8, 0, pad=0, text="-") self.video_count_caption_label = self.components.label(frame, 7, 1, "\nVideos with Captions", pad=0, - tooltip="Total number of video files with an associated caption", underline=True) + tooltip="有关联标签的视频文件总数", underline=True) self.video_count_caption_preview = self.components.label(frame, 8, 1, pad=0, text="-") self.caption_count_label_unpaired = self.components.label(frame, 7, 2, "\nUnpaired Captions", pad=0, - tooltip="Total number of caption files which lack a corresponding image file - if >0, check your data set! If using 'from file name' or 'from single text file' then this can be ignored.", underline=True) + tooltip="缺少对应图像的标签文件数,>0请检查数据集", underline=True) self.caption_count_preview_unpaired = self.components.label(frame, 8, 2, pad=0, text="-") #resolution info self.pixel_max_label = self.components.label(frame, 9, 0, "\nMax Pixels", pad=0, - tooltip="Largest image in the concept by number of pixels (width * height)", underline=True) + tooltip="最大图像尺寸(宽x高像素)", underline=True) self.pixel_max_preview = self.components.label(frame, 10, 0, pad=0, text="-", wraplength=150) self.pixel_avg_label = self.components.label(frame, 9, 1, "\nAvg Pixels", pad=0, - tooltip="Average size of images in the concept by number of pixels (width * height)", underline=True) + tooltip="图像平均尺寸(宽x高像素)", underline=True) self.pixel_avg_preview = self.components.label(frame, 10, 1, pad=0, text="-", wraplength=150) self.pixel_min_label = self.components.label(frame, 9, 2, "\nMin Pixels", pad=0, - tooltip="Smallest image in the concept by number of pixels (width * height)", underline=True) + tooltip="最小图像尺寸(宽x高像素)", underline=True) self.pixel_min_preview = self.components.label(frame, 10, 2, pad=0, text="-", wraplength=150) #video length info self.length_max_label = self.components.label(frame, 11, 0, "\nMax Length", pad=0, - tooltip="Longest video in the concept by number of frames", underline=True) + tooltip="数据集中帧数最多的视频", underline=True) self.length_max_preview = self.components.label(frame, 12, 0, pad=0, text="-", wraplength=150) self.length_avg_label = self.components.label(frame, 11, 1, "\nAvg Length", pad=0, - tooltip="Average length of videos in the concept by number of frames", underline=True) + tooltip="视频平均帧数", underline=True) self.length_avg_preview = self.components.label(frame, 12, 1, pad=0, text="-", wraplength=150) self.length_min_label = self.components.label(frame, 11, 2, "\nMin Length", pad=0, - tooltip="Shortest video in the concept by number of frames", underline=True) + tooltip="数据集中帧数最少的视频", underline=True) self.length_min_preview = self.components.label(frame, 12, 2, pad=0, text="-", wraplength=150) #video fps info self.fps_max_label = self.components.label(frame, 13, 0, "\nMax FPS", pad=0, - tooltip="Video in concept with highest fps", underline=True) + tooltip="数据集中最高帧率视频", underline=True) self.fps_max_preview = self.components.label(frame, 14, 0, pad=0, text="-", wraplength=150) self.fps_avg_label = self.components.label(frame, 13, 1, "\nAvg FPS", pad=0, - tooltip="Average fps of videos in the concept", underline=True) + tooltip="数据集中视频平均帧率", underline=True) self.fps_avg_preview = self.components.label(frame, 14, 1, pad=0, text="-", wraplength=150) self.fps_min_label = self.components.label(frame, 13, 2, "\nMin FPS", pad=0, - tooltip="Video in concept with the lowest fps", underline=True) + tooltip="数据集中最低帧率视频", underline=True) self.fps_min_preview = self.components.label(frame, 14, 2, pad=0, text="-", wraplength=150) #caption info self.caption_max_label = self.components.label(frame, 15, 0, "\nMax Caption Length", pad=0, - tooltip="Largest caption in concept by character count. For token count, assume ~2 tokens/word", underline=True) + tooltip="最长标签(字符数),Token数约2/词", underline=True) self.caption_max_preview = self.components.label(frame, 16, 0, pad=0, text="-", wraplength=150) self.caption_avg_label = self.components.label(frame, 15, 1, "\nAvg Caption Length", pad=0, - tooltip="Average length of caption in concept by character count. For token count, assume ~2 tokens/word", underline=True) + tooltip="标签平均长度(字符数),Token数约2/词", underline=True) self.caption_avg_preview = self.components.label(frame, 16, 1, pad=0, text="-", wraplength=150) self.caption_min_label = self.components.label(frame, 15, 2, "\nMin Caption Length", pad=0, - tooltip="Smallest caption in concept by character count. For token count, assume ~2 tokens/word", underline=True) + tooltip="最短标签(字符数),Token数约2/词", underline=True) self.caption_min_preview = self.components.label(frame, 16, 2, pad=0, text="-", wraplength=150) #aspect bucket info @@ -305,17 +305,17 @@ def build_concept_stats_tab(self, frame, controller): tooltip="Graph of all possible buckets and the number of images in each one, defined as height/width. Buckets range from 0.25 (4:1 extremely wide) to 4 (1:4 extremely tall). \ Images which don't match a bucket exactly are cropped to the nearest one.", underline=True) self.small_bucket_label = self.components.label(frame, 17, 1, "\nSmallest Buckets", pad=0, - tooltip="Image buckets with the least nonzero total images - if 'batch size' is larger than this, these images will be ignored during training! See the wiki for more details.", underline=True) + tooltip="非零图像最少的桶,批次大小超过此值时这些图像将被忽略", underline=True) self.small_bucket_preview = self.components.label(frame, 18, 1, pad=0, text="-") #refresh stats - must be after all labels are defined or will give error - self.refresh_basic_stats_button = self.components.button(master=frame, row=0, column=0, text="Refresh Basic", command=lambda: controller.get_concept_stats_threaded(self, False, 9999), - tooltip="Reload basic statistics for the concept directory") - self.refresh_advanced_stats_button = self.components.button(master=frame, row=0, column=1, text="Refresh Advanced", command=lambda: controller.get_concept_stats_threaded(self, True, 9999), - tooltip="Reload advanced statistics for the concept directory") #run "basic" scan first before "advanced", seems to help the system cache the directories and run faster - self.cancel_stats_button = self.components.button(master=frame, row=0, column=2, text="Abort Scan", command=lambda: self._cancel_concept_stats(controller), - tooltip="Stop the currently running scan if it's taking a long time - advanced scan will be slow on large folders and on HDDs") - self.processing_time = self.components.label(frame, 0, 3, text="-", tooltip="Time taken to process concept directory") + self.refresh_basic_stats_button = self.components.button(master=frame, row=0, column=0, text="刷新基本", command=lambda: controller.get_concept_stats_threaded(self, False, 9999), + tooltip="重新加载数据集目录的基本统计") + self.refresh_advanced_stats_button = self.components.button(master=frame, row=0, column=1, text="刷新高级", command=lambda: controller.get_concept_stats_threaded(self, True, 9999), + tooltip="重新加载数据集目录的高级统计") #run "basic" scan first before "advanced", seems to help the system cache the directories and run faster + self.cancel_stats_button = self.components.button(master=frame, row=0, column=2, text="中止扫描", command=lambda: self._cancel_concept_stats(controller), + tooltip="如果扫描时间过长则中止——高级扫描对大文件夹和HDD较慢") + self.processing_time = self.components.label(frame, 0, 3, text="-", tooltip="处理数据集目录耗时") def _update_concept_stats(self, controller): #file size @@ -424,7 +424,7 @@ def _update_concept_stats(self, controller): self.bucket_ax.bar_label(b, color=self.text_color) sec = self.bucket_ax.secondary_xaxis(location=-0.1) sec.spines["bottom"].set_linewidth(0) - sec.set_xticks([0, (len(aspects)-1)/2, len(aspects)-1], labels=["Wide", "Square", "Tall"]) + sec.set_xticks([0, (len(aspects)-1)/2, len(aspects)-1], labels=["宽图", "方形", "长图"]) sec.tick_params('x', length=0) self.canvas.draw() diff --git a/modules/ui/BaseConfigListView.py b/modules/ui/BaseConfigListView.py index b97aeaf4a..ef3fb1b3b 100644 --- a/modules/ui/BaseConfigListView.py +++ b/modules/ui/BaseConfigListView.py @@ -102,7 +102,7 @@ def build( self.__load_current_config(getattr(self.controller.train_config, self.attr_name)) self.__create_configs_dropdown() - self.components.button(self.top_frame, 0, 1, "Add Config", self.__add_config, tooltip="Adds a new config, which are containers for concepts, which themselves contain your dataset", width=20, padx=5) + self.components.button(self.top_frame, 0, 1, "添加配置", self.__add_config, tooltip="添加新配置,配置是数据集的容器", width=20, padx=5) self.components.button(self.top_frame, 0, 2, add_button_text, self.__add_element, tooltip=add_button_tooltip, width=30, padx=5) else: self.top_frame = self._create_top_frame(master) @@ -115,7 +115,7 @@ def build( if show_toggle_button: # tooltips break if you initialize with an empty string, default to a single space - self.toggle_button = self.components.button(self.top_frame, 0, 3, " ", self._toggle, tooltip="Disables/Enables all visible items in the current view", width=30, padx=5) + self.toggle_button = self.components.button(self.top_frame, 0, 3, " ", self._toggle, tooltip="禁用/启用当前视图中的所有可见项", width=30, padx=5) self._update_toggle_button_text() def _update_item_enabled_state(self): @@ -131,7 +131,7 @@ def _update_toggle_button_text(self): return self._update_item_enabled_state() if self.toggle_button is not None: - self.toggle_button.configure(text="Disable" if self._is_current_item_enabled else "Enable") + self.toggle_button.configure(text="禁用" if self._is_current_item_enabled else "启用") def _toggle(self): self._toggle_items() diff --git a/modules/ui/BaseConvertModelUIView.py b/modules/ui/BaseConvertModelUIView.py index 69cb64925..c6a0fa3a0 100644 --- a/modules/ui/BaseConvertModelUIView.py +++ b/modules/ui/BaseConvertModelUIView.py @@ -11,8 +11,8 @@ def __init__(self, components): def build_content(self, frame, controller, ui_state, on_model_or_method_change): # model type - self.components.label(frame, 0, 0, "Model Type", - tooltip="Type of the model") + self.components.label(frame, 0, 0, "模型类型", + tooltip="模型类型") self.components.options_kv(frame, 0, 1, [ #TODO simplify ("Stable Diffusion 1.5", ModelType.STABLE_DIFFUSION_15), ("Stable Diffusion 1.5 Inpainting", ModelType.STABLE_DIFFUSION_15_INPAINTING), @@ -40,12 +40,12 @@ def build_content(self, frame, controller, ui_state, on_model_or_method_change): ], ui_state, "model_type", command=on_model_or_method_change) # training method - self.components.label(frame, 1, 0, "Model Type", - tooltip="The type of model to convert") + self.components.label(frame, 1, 0, "模型类型", + tooltip="要转换的模型类型") self.components.options_kv(frame, 1, 1, [ - ("Base Model", TrainingMethod.FINE_TUNE), + ("基础模型", TrainingMethod.FINE_TUNE), ("LoRA", TrainingMethod.LORA), - ("Embedding", TrainingMethod.EMBEDDING), + ("嵌入", TrainingMethod.EMBEDDING), ], ui_state, "training_method", command=on_model_or_method_change) # input name @@ -57,7 +57,7 @@ def build_content(self, frame, controller, ui_state, on_model_or_method_change): ) # output data type - self.components.label(frame, 3, 0, "Output Data Type", + self.components.label(frame, 3, 0, "输出数据类型", tooltip="Precision to use when saving the output model") self.components.options_kv(frame, 3, 1, [ ("float32", DataType.FLOAT_32), @@ -69,15 +69,15 @@ def build_content(self, frame, controller, ui_state, on_model_or_method_change): # method, so the view rebuilds it via on_model_or_method_change whenever either one changes. # output model destination - self.components.label(frame, 5, 0, "Model Output Destination", - tooltip="Filename or directory where the output model is saved") + self.components.label(frame, 5, 0, "模型输出目标", + tooltip="输出模型保存的文件名或目录") self.components.path_entry( frame, 5, 1, ui_state, "output_model_destination", mode="file", io_type=PathIOType.MODEL, ) - self.button = self.components.button(frame, 6, 1, "Convert", controller.convert_model) + self.button = self.components.button(frame, 6, 1, "转换", controller.convert_model) def build_dynamic_content(self, frame, controller, ui_state): row = 0 @@ -86,8 +86,8 @@ def build_dynamic_content(self, frame, controller, ui_state): # module names (used to reverse KOHYA/LEGACY un-flattening); a fine-tune conversion's "Input name" # already is the base model, so this field only applies to LoRA/embedding conversions. if controller.convert_model_args.training_method in [TrainingMethod.LORA, TrainingMethod.EMBEDDING]: - self.components.label(frame, row, 0, "Base Model Name", - tooltip="Filename, directory or Hugging Face repository of the base model this LoRA/embedding was trained on") + self.components.label(frame, row, 0, "基础模型名称", + tooltip="此LoRA/嵌入训练的基础模型") self.components.path_entry( frame, row, 1, ui_state, "base_model_name", mode="file", path_modifier=path_util.json_path_modifier @@ -95,6 +95,6 @@ def build_dynamic_content(self, frame, controller, ui_state): row += 1 # output format - self.components.label(frame, row, 0, "Output Format", - tooltip="Format to use when saving the output model") + self.components.label(frame, row, 0, "输出格式", + tooltip="保存输出模型的格式") self.components.options_kv(frame, row, 1, controller.get_output_formats(), ui_state, "output_model_format") diff --git a/modules/ui/BaseLoraTabView.py b/modules/ui/BaseLoraTabView.py index 542247b82..adc243d71 100644 --- a/modules/ui/BaseLoraTabView.py +++ b/modules/ui/BaseLoraTabView.py @@ -9,8 +9,8 @@ def __init__(self, components): self.components = components def build(self, frame, controller, ui_state, setup_lora_callback): - self.components.label(frame, 0, 0, "Type", - tooltip="The type of low-parameter finetuning method.") + self.components.label(frame, 0, 0, "类型", + tooltip="低参数微调方法类型") self.components.options_kv(frame, 0, 1, controller.get_peft_types(), ui_state, "peft_type", command=setup_lora_callback) @@ -36,14 +36,14 @@ def build_lora_options(self, master, controller, ui_state, peft_type: PeftType): # LoRA decomposition if peft_type == PeftType.LORA: self.components.label(master, 1, 3, "Decompose Weights (DoRA)", - tooltip="Decompose LoRA Weights (aka, DoRA).") + tooltip="分解LoRA权重(即DoRA)") self.components.switch(master, 1, 4, ui_state, "lora_decompose") self.components.label(master, 2, 3, "Use Norm Epsilon (DoRA Only)", - tooltip="Add an epsilon to the norm divison calculation in DoRA. Can aid in training stability, and also acts as regularization.") + tooltip="在DoRA范数除法中添加epsilon,有助于训练稳定性") self.components.switch(master, 2, 4, ui_state, "lora_decompose_norm_epsilon") - self.components.label(master, 3, 3, "Apply on output axis (DoRA Only)", - tooltip="Apply the weight decomposition on the output axis instead of the input axis.") + self.components.label(master, 3, 3, "在输出轴应用(仅DoRA)", + tooltip="在输出轴而非输入轴应用权重分解") self.components.switch(master, 3, 4, ui_state, "lora_decompose_output_axis") # LoRA and LoHA shared settings @@ -59,8 +59,8 @@ def build_lora_options(self, master, controller, ui_state, peft_type: PeftType): self.components.entry(master, 2, 1, ui_state, "lora_alpha", required=True) # Dropout Percentage - self.components.label(master, 3, 0, "Dropout Probability", - tooltip="Dropout probability. This percentage of model nodes will be randomly ignored at each training step. Helps with overfitting. 0 disables, 1 maximum.") + self.components.label(master, 3, 0, "丢弃概率", + tooltip="丢弃概率,每步随机忽略此比例的模型节点,0=禁用") self.components.entry(master, 3, 1, ui_state, "dropout_probability") # weight dtype @@ -69,7 +69,7 @@ def build_lora_options(self, master, controller, ui_state, peft_type: PeftType): self.components.options_kv(master, 4, 1, controller.get_lora_weight_dtypes(), ui_state, "lora_weight_dtype") # For use with additional embeddings. - self.components.label(master, 5, 0, "Bundle Embeddings", + self.components.label(master, 5, 0, "捆绑嵌入", tooltip=f"Bundles any additional embeddings into the {name} output file, rather than as separate files") self.components.switch(master, 5, 1, ui_state, "bundle_additional_embeddings") @@ -81,17 +81,17 @@ def build_lora_options(self, master, controller, ui_state, peft_type: PeftType): self.components.entry(master, 1, 1, ui_state, "oft_block_size", required=True) # Block Share - self.components.label(master, 1, 3, "Block Share", - tooltip="Share the OFT parameters between blocks. A single rotation matrix is shared across all blocks within a layer, drastically cutting the number of trainable parameters and yielding very compact adapter files, potentially improving generalization but at the cost of significant expressiveness, which can lead to underfitting on more complex or diverse tasks.") + self.components.label(master, 1, 3, "块共享", + tooltip="块间共享OFT参数,大幅减少可训练参数,但可能降低表达能力") self.components.switch(master, 1, 4, ui_state, "oft_block_share") # Scaled OFT (SOFT) self.components.label(master, 2, 3, "Scaled OFT (SOFT)", - tooltip="Applies a scaling factor to the learned weights. This ensures that the effective learning rate remains consistent across different block sizes. Without this, different block sizes require significantly different learning rates.") + tooltip="学习权重缩放因子,确保不同块大小下有效学习率一致") self.components.switch(master, 2, 4, ui_state, "oft_scaled") # Dropout Percentage - self.components.label(master, 2, 0, "Dropout Probability", + self.components.label(master, 2, 0, "丢弃概率", tooltip="Dropout probability. This percentage of the rotated adapter nodes that will be randomly restored to the base model initial statue. Helps with overfitting. 0 disables, 1 maximum.") self.components.entry(master, 2, 1, ui_state, "dropout_probability") @@ -101,7 +101,7 @@ def build_lora_options(self, master, controller, ui_state, peft_type: PeftType): self.components.options_kv(master, 3, 1, controller.get_lora_weight_dtypes(), ui_state, "lora_weight_dtype") # For use with additional embeddings. - self.components.label(master, 4, 0, "Bundle Embeddings", + self.components.label(master, 4, 0, "捆绑嵌入", tooltip=f"Bundles any additional embeddings into the {name} output file, rather than as separate files") self.components.switch(master, 4, 1, ui_state, "bundle_additional_embeddings") @@ -109,11 +109,11 @@ def build_lora_options(self, master, controller, ui_state, peft_type: PeftType): elif peft_type == PeftType.LOKR: # LoKr Main Settings self.components.label(master, 1, 0, f"{name} dimension", - tooltip="The dimension parameter used for the secondary decomposition. Analogous to rank in LoRA.") + tooltip="二次分解的维度参数,类似于LoRA的秩") self.components.entry(master, 1, 1, ui_state, "lokr_dim") - self.components.label(master, 2, 0, "Decomposition Factor", - tooltip="Factor for Kronecker product decomposition. -1 for auto, which is recommended. Changing this drastically affects parameter count.") + self.components.label(master, 2, 0, "分解因子", + tooltip="Kronecker积分解因子,-1为自动(推荐)") self.components.entry(master, 2, 1, ui_state, "lokr_decompose_factor") # alpha @@ -122,8 +122,8 @@ def build_lora_options(self, master, controller, ui_state, peft_type: PeftType): self.components.entry(master, 3, 1, ui_state, "lora_alpha") # Dropout Percentage - self.components.label(master, 4, 0, "Dropout Probability", - tooltip="Dropout probability. This percentage of model nodes will be randomly ignored at each training step. Helps with overfitting. 0 disables, 1 maximum.") + self.components.label(master, 4, 0, "丢弃概率", + tooltip="丢弃概率,每步随机忽略此比例的模型节点,0=禁用") self.components.entry(master, 4, 1, ui_state, "dropout_probability") # LoKr weight dtype @@ -133,32 +133,32 @@ def build_lora_options(self, master, controller, ui_state, peft_type: PeftType): # LoKr Vectorization trick self.components.label(master, 6, 0, "Kronecker-Vec Trick", - tooltip="Uses an accelerated path that bypasses the materialization of the full Kronecker product. This delivers a massive speedup to the LoKr without sacrificing precision. Highly recommended.") + tooltip="使用加速路径绕过完整Kronecker积的实现,大幅加速LoKr") self.components.switch(master, 6, 1, ui_state, "lokr_vec_trick") # LoKr Decomposition Settings - self.components.label(master, 1, 3, "Decompose Both Matrices", - tooltip="Perform rank decomposition on both Kronecker product matrices (W1 and W2). Only effective for very small dimensions.") + self.components.label(master, 1, 3, "分解两个矩阵", + tooltip="对两个Kronecker积矩阵进行秩分解,仅对极小维度有效") self.components.switch(master, 1, 4, ui_state, "lokr_decompose_both") self.components.label(master, 2, 3, "Use Tucker Decomposition (Conv)", - tooltip="Use Tucker decomposition for convolutional layers. Can be more efficient for some architectures.") + tooltip="对卷积层使用Tucker分解,某些架构更高效") self.components.switch(master, 2, 4, ui_state, "lokr_use_tucker") self.components.label(master, 3, 3, "Force Full Matrix (W2)", - tooltip="Forces the second Kronecker matrix (W2) to be a full matrix, ignoring the dimension setting. For expert use.") + tooltip="强制第二个Kronecker矩阵为全矩阵,忽略维度设置") self.components.switch(master, 3, 4, ui_state, "lokr_full_matrix") # LoKr DoRA Settings self.components.label(master, 4, 3, "Decompose Weights (DoRA)", - tooltip="Apply weight decomposition (DoRA) on top of the LoKr update.") + tooltip="在LoKr更新上应用权重分解(DoRA)") self.components.switch(master, 4, 4, ui_state, "lokr_weight_decompose") - self.components.label(master, 5, 3, "Apply DoRA on Output Axis", - tooltip="Apply the DoRA weight decomposition on the output axis instead of the input axis.") + self.components.label(master, 5, 3, "在输出轴应用DoRA", + tooltip="在输出轴而非输入轴应用DoRA权重分解") self.components.switch(master, 5, 4, ui_state, "lokr_dora_on_output") # Additional embeddings - self.components.label(master, 6, 3, "Bundle Embeddings", + self.components.label(master, 6, 3, "捆绑嵌入", tooltip=f"Bundles any additional embeddings into the {name} output file, rather than as separate files") self.components.switch(master, 6, 4, ui_state, "bundle_additional_embeddings") diff --git a/modules/ui/BaseModelTabView.py b/modules/ui/BaseModelTabView.py index 4b7eda896..a7ca553ed 100644 --- a/modules/ui/BaseModelTabView.py +++ b/modules/ui/BaseModelTabView.py @@ -82,14 +82,14 @@ def __create_dtype_options(self, include_gguf: bool = False, include_a8: bool = def __create_base_dtype_components(self, frame, row: int, ui_state) -> int: # huggingface token - self.components.label(frame, row, 0, "Hugging Face Token", + self.components.label(frame, row, 0, "Hugging Face令牌", tooltip="Enter your Hugging Face access token if you have used a protected Hugging Face repository below.\nThis value is stored separately, not saved to your configuration file. " "Go to https://huggingface.co/settings/tokens to create an access token.", wide_tooltip=True) self.components.entry(frame, row, 1, ui_state, "secrets.huggingface_token") # offline mode - self.components.label(frame, row, 3, "Offline Mode", + self.components.label(frame, row, 3, "离线模式", tooltip="Skip the Hugging Face login and resolve every model from the local cache only. " "Enable this when you have no internet connection; only already-downloaded models can be loaded.", wide_tooltip=True) @@ -98,7 +98,7 @@ def __create_base_dtype_components(self, frame, row: int, ui_state) -> int: row += 1 # huggingface cache directory - self.components.label(frame, row, 0, "Hugging Face Cache Directory", + self.components.label(frame, row, 0, "Hugging Face缓存目录", tooltip="Directory used to cache Hugging Face model downloads. " "Leave empty to use the default Hugging Face cache directory shown as the placeholder.", wide_tooltip=True) @@ -110,16 +110,16 @@ def __create_base_dtype_components(self, frame, row: int, ui_state) -> int: row += 1 # base model - self.components.label(frame, row, 0, "Base Model", - tooltip="Filename, directory or Hugging Face repository of the base model") + self.components.label(frame, row, 0, "基础模型", + tooltip="基础模型文件名、目录或Hugging Face仓库") self.components.path_entry( frame, row, 1, ui_state, "base_model_name", mode="file", path_modifier=path_util.json_path_modifier ) # compile - self.components.label(frame, row, 3, "Compile transformer blocks", - tooltip="Uses torch.compile and Triton to significantly speed up training. Only applies to transformer/unet. Disable in case of compatibility issues.") + self.components.label(frame, row, 3, "编译Transformer块", + tooltip="使用torch.compile和Triton加速训练,如有兼容问题请禁用") self.components.switch(frame, row, 4, ui_state, "compile") row += 1 @@ -148,8 +148,8 @@ def __create_base_components( ) -> int: if has_unet: # unet weight dtype - self.components.label(frame, row, 3, "UNet Data Type", - tooltip="The unet weight data type") + self.components.label(frame, row, 3, "UNet数据类型", + tooltip="UNet权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(include_a8=True), ui_state, "unet.weight_dtype") @@ -158,16 +158,16 @@ def __create_base_components( if has_prior: if allow_override_prior: # prior model - self.components.label(frame, row, 0, "Prior Model", - tooltip="Filename, directory or Hugging Face repository of the prior model") + self.components.label(frame, row, 0, "Prior模型", + tooltip="Prior模型路径") self.components.path_entry( frame, row, 1, ui_state, "prior.model_name", mode="file", path_modifier=path_util.json_path_modifier ) # prior weight dtype - self.components.label(frame, row, 3, "Prior Data Type", - tooltip="The prior weight data type") + self.components.label(frame, row, 3, "Prior数据类型", + tooltip="Prior权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "prior.weight_dtype") @@ -177,15 +177,15 @@ def __create_base_components( if allow_override_transformer: # transformer model self.components.label(frame, row, 0, "Override Transformer / GGUF", - tooltip="Can be used to override the transformer in the base model. Safetensors and GGUF files are supported, local and on Huggingface. If a GGUF file is used, the DataType must also be set to GGUF") + tooltip="覆盖基础模型的Transformer,支持safetensors和GGUF") self.components.path_entry( frame, row, 1, ui_state, "transformer.model_name", mode="file", path_modifier=path_util.json_path_modifier ) # transformer weight dtype - self.components.label(frame, row, 3, "Transformer Data Type", - tooltip="The transformer weight data type") + self.components.label(frame, row, 3, "Transformer数据类型", + tooltip="Transformer权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(include_gguf=True, include_a8=True), ui_state, "transformer.weight_dtype") @@ -193,8 +193,8 @@ def __create_base_components( if has_unconditional_transformer: # unconditional transformer weight dtype - self.components.label(frame, row, 3, "Unconditional Transformer Data Type", - tooltip="The weight data type of the unconditional transformer, used for the negative branch of CFG during sampling") + self.components.label(frame, row, 3, "无条件Transformer数据类型", + tooltip="无条件Transformer权重数据类型,用于CFG负分支") self.components.options_kv(frame, row, 4, self.__create_dtype_options(include_a8=True), ui_state, "unconditional_transformer.weight_dtype") @@ -202,33 +202,33 @@ def __create_base_components( presets = controller.get_presets() - self.components.label(frame, row, 0, "Quantization") + self.components.label(frame, row, 0, "量化") self.components.layer_filter_entry(frame, row, 1, ui_state, preset_var_name="quantization.layer_filter_preset", presets=presets, - preset_label="Quantization Layer Filter", - preset_tooltip="Select a preset defining which layers to quantize. Quantization of certain layers can decrease model quality. Only applies to the transformer/unet", + preset_label="量化层过滤器", + preset_tooltip="选择量化层预设,量化某些层可能降低模型质量", entry_var_name="quantization.layer_filter", - entry_tooltip="Comma-separated list of layers to quantize. Regular expressions (if toggled) are supported. Any model layer with a matching name will be quantized", + entry_tooltip="逗号分隔的量化层列表,支持正则表达式", regex_var_name="quantization.layer_filter_regex", - regex_tooltip="If enabled, layer filter patterns are interpreted as regular expressions. Otherwise, simple substring matching is used.", + regex_tooltip="启用后层过滤器使用正则匹配,否则使用子串匹配", frame_color="transparent", ) # SVDQuant - create vertical grids to match the size of layer_filter_entry svd_label_frame, svd_entry_frame = self._make_svd_frames(frame, row) self.components.label(svd_label_frame, 0, 0, "SVDQuant", - tooltip="What datatype to use for SVDQuant weights decomposition.") + tooltip="SVDQuant权重分解的数据类型") self.components.options_kv(svd_entry_frame, 0, 0, [("disabled", DataType.NONE), ("float32", DataType.FLOAT_32), ("bfloat16", DataType.BFLOAT_16)], ui_state, "quantization.svd_dtype") - self.components.label(svd_label_frame, 1, 0, "SVDQuant Rank", - tooltip="Rank for SVDQuant weights decomposition") + self.components.label(svd_label_frame, 1, 0, "SVDQuant秩", + tooltip="SVDQuant权重分解的秩") self.components.entry(svd_entry_frame, 1, 0, ui_state, "quantization.svd_rank") row += 1 if has_text_encoder: # text encoder weight dtype - self.components.label(frame, row, 3, "Text Encoder Data Type", - tooltip="The text encoder weight data type") + self.components.label(frame, row, 3, "文本编码器数据类型", + tooltip="文本编码器权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "text_encoder.weight_dtype") @@ -237,7 +237,7 @@ def __create_base_components( if has_text_encoder_1: # text encoder 1 weight dtype self.components.label(frame, row, 3, "Text Encoder 1 Data Type", - tooltip="The text encoder 1 weight data type") + tooltip="文本编码器1权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "text_encoder.weight_dtype") @@ -246,7 +246,7 @@ def __create_base_components( if has_text_encoder_2: # text encoder 2 weight dtype self.components.label(frame, row, 3, "Text Encoder 2 Data Type", - tooltip="The text encoder 2 weight data type") + tooltip="文本编码器2权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "text_encoder_2.weight_dtype") @@ -255,7 +255,7 @@ def __create_base_components( if has_text_encoder_3: # text encoder 3 weight dtype self.components.label(frame, row, 3, "Text Encoder 3 Data Type", - tooltip="The text encoder 3 weight data type") + tooltip="文本编码器3权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "text_encoder_3.weight_dtype") @@ -265,7 +265,7 @@ def __create_base_components( if allow_override_text_encoder_4: # text encoder 4 weight dtype self.components.label(frame, row, 0, "Text Encoder 4 Override", - tooltip="Filename, directory or Hugging Face repository of the text encoder 4 model") + tooltip="文本编码器4模型路径") self.components.path_entry( frame, row, 1, ui_state, "text_encoder_4.model_name", mode="file", path_modifier=path_util.json_path_modifier @@ -273,7 +273,7 @@ def __create_base_components( # text encoder 4 weight dtype self.components.label(frame, row, 3, "Text Encoder 4 Data Type", - tooltip="The text encoder 4 weight data type") + tooltip="文本编码器4权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "text_encoder_4.weight_dtype") @@ -281,16 +281,16 @@ def __create_base_components( if has_vae: # base model - self.components.label(frame, row, 0, "VAE Override", - tooltip="Directory or Hugging Face repository of a VAE model in diffusers format. Can be used to override the VAE included in the base model. Using a safetensor VAE file will cause an error that the model cannot be loaded.") + self.components.label(frame, row, 0, "VAE覆盖", + tooltip="diffusers格式的VAE模型目录或Hugging Face仓库,用于覆盖基础模型的VAE") self.components.path_entry( frame, row, 1, ui_state, "vae.model_name", mode="file", path_modifier=path_util.json_path_modifier ) # vae weight dtype - self.components.label(frame, row, 3, "VAE Data Type", - tooltip="The vae weight data type") + self.components.label(frame, row, 3, "VAE数据类型", + tooltip="VAE权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "vae.weight_dtype") @@ -300,16 +300,16 @@ def __create_base_components( def __create_effnet_encoder_components(self, frame, row: int, ui_state) -> int: # effnet encoder model - self.components.label(frame, row, 0, "Effnet Encoder Model", - tooltip="Filename, directory or Hugging Face repository of the effnet encoder model") + self.components.label(frame, row, 0, "Effnet编码器模型", + tooltip="Effnet编码器模型路径") self.components.path_entry( frame, row, 1, ui_state, "effnet_encoder.model_name", mode="file", path_modifier=path_util.json_path_modifier ) # effnet encoder weight dtype - self.components.label(frame, row, 3, "Effnet Encoder Data Type", - tooltip="The effnet encoder weight data type") + self.components.label(frame, row, 3, "Effnet编码器数据类型", + tooltip="Effnet编码器权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "effnet_encoder.weight_dtype") @@ -325,16 +325,16 @@ def __create_decoder_components( has_text_encoder: bool, ) -> int: # decoder model - self.components.label(frame, row, 0, "Decoder Model", - tooltip="Filename, directory or Hugging Face repository of the decoder model") + self.components.label(frame, row, 0, "解码器模型", + tooltip="解码器模型路径") self.components.path_entry( frame, row, 1, ui_state, "decoder.model_name", mode="file", path_modifier=path_util.json_path_modifier ) # decoder weight dtype - self.components.label(frame, row, 3, "Decoder Data Type", - tooltip="The decoder weight data type") + self.components.label(frame, row, 3, "解码器数据类型", + tooltip="解码器权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "decoder.weight_dtype") @@ -342,16 +342,16 @@ def __create_decoder_components( if has_text_encoder: # decoder text encoder weight dtype - self.components.label(frame, row, 3, "Decoder Text Encoder Data Type", - tooltip="The decoder text encoder weight data type") + self.components.label(frame, row, 3, "解码器文本编码器数据类型", + tooltip="解码器文本编码器权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "decoder_text_encoder.weight_dtype") row += 1 # decoder vqgan weight dtype - self.components.label(frame, row, 3, "Decoder VQGAN Data Type", - tooltip="The decoder vqgan weight data type") + self.components.label(frame, row, 3, "解码器VQGAN数据类型", + tooltip="解码器VQGAN权重数据类型") self.components.options_kv(frame, row, 4, self.__create_dtype_options(), ui_state, "decoder_vqgan.weight_dtype") @@ -367,8 +367,8 @@ def __create_output_components( ui_state, ) -> int: # output model destination - self.components.label(frame, row, 0, "Model Output Destination", - tooltip="Filename or directory where the output model is saved") + self.components.label(frame, row, 0, "模型输出目标", + tooltip="输出模型保存的文件名或目录") self.components.path_entry( frame, row, 1, ui_state, "output_model_destination", mode="file", @@ -376,7 +376,7 @@ def __create_output_components( ) # output data type - self.components.label(frame, row, 3, "Output Data Type", + self.components.label(frame, row, 3, "输出数据类型", tooltip="Precision to use when saving the output model") self.components.options_kv(frame, row, 4, [ ("float16", DataType.FLOAT_16), @@ -391,19 +391,19 @@ def __create_output_components( # output format formats = controller.get_output_formats() - self.components.label(frame, row, 0, "Output Format", - tooltip="Format to use when saving the output model") + self.components.label(frame, row, 0, "输出格式", + tooltip="保存输出模型的格式") self.components.options_kv(frame, row, 1, formats, ui_state, "output_model_format") # include config - self.components.label(frame, row, 3, "Include Config", + self.components.label(frame, row, 3, "包含配置", tooltip="Include the training configuration in the final model. Only supported for safetensors files. " "None: No config is included. " "Settings: All training settings are included. " - "All: All settings, including the samples and concepts are included.") + "全部:包含所有设置、采样和数据集") self.components.options_kv(frame, row, 4, [ - ("None", ConfigPart.NONE), - ("Settings", ConfigPart.SETTINGS), + ("无", ConfigPart.NONE), + ("设置", ConfigPart.SETTINGS), ("All", ConfigPart.ALL), ], ui_state, "include_train_config") diff --git a/modules/ui/BaseOptimizerParamsWindowView.py b/modules/ui/BaseOptimizerParamsWindowView.py index b5a5c8911..99ebfc67b 100644 --- a/modules/ui/BaseOptimizerParamsWindowView.py +++ b/modules/ui/BaseOptimizerParamsWindowView.py @@ -12,18 +12,18 @@ def __init__(self, components): def build_content(self, frame, controller, ui_state, optimizer_ui_state, on_optimizer_change_cb, load_defaults_cb): # Optimizer - self.components.label(frame, 0, 0, "Optimizer", - tooltip="The type of optimizer") + self.components.label(frame, 0, 0, "优化器", + tooltip="优化器类型") # Create the optimizer dropdown menu and set the command self.components.options(frame, 0, 1, [str(x) for x in list(Optimizer)], optimizer_ui_state, "optimizer", command=on_optimizer_change_cb) # Defaults Button - self.components.label(frame, 0, 3, "Optimizer Defaults", - tooltip="Load default settings for the selected optimizer") - self.components.button(frame, 0, 4, "Load Defaults", load_defaults_cb, - tooltip="Load default settings for the selected optimizer") + self.components.label(frame, 0, 3, "优化器默认值", + tooltip="加载所选优化器的默认设置") + self.components.button(frame, 0, 4, "加载默认值", load_defaults_cb, + tooltip="加载所选优化器的默认设置") def build_dynamic_content(self, master, controller, optimizer_ui_state, update_user_pref_cb, open_muon_adam_cb): @@ -159,7 +159,7 @@ def build_dynamic_content(self, master, controller, optimizer_ui_state, self.muon_adam_button = self.components.button( frame, 0, 1, "...", open_muon_adam_cb, - tooltip="Configure the auxiliary AdamW_adv optimizer", + tooltip="配置辅助AdamW_adv优化器", width=20, padx=5) elif type != 'bool': self.components.entry(master, row, col + 1, optimizer_ui_state, key, diff --git a/modules/ui/BaseProfilingWindowView.py b/modules/ui/BaseProfilingWindowView.py index 8e0de3b64..9c67102d1 100644 --- a/modules/ui/BaseProfilingWindowView.py +++ b/modules/ui/BaseProfilingWindowView.py @@ -8,9 +8,9 @@ def __init__(self, components): def build_content(self, frame, bottom_bar, controller): self.components.button(frame, 0, 0, "Dump stack", controller.dump_stack) self._profile_button = self.components.button( - frame, 1, 0, "Start Profiling", controller.start_profiler, - tooltip="Turns on/off Scalene profiling. Only works when OneTrainer is launched with Scalene!") - self._message_label = self.components.label(bottom_bar, 0, 0, "Inactive") + frame, 1, 0, "开始分析", controller.start_profiler, + tooltip="开关Scalene性能分析,仅在使用Scalene启动时有效") + self._message_label = self.components.label(bottom_bar, 0, 0, "未激活") @abstractmethod def set_message(self, text): diff --git a/modules/ui/BaseSampleFrameView.py b/modules/ui/BaseSampleFrameView.py index eacd8c0ac..1737e39b2 100644 --- a/modules/ui/BaseSampleFrameView.py +++ b/modules/ui/BaseSampleFrameView.py @@ -31,12 +31,12 @@ def build_content(self, top_frame, bottom_frame, ui_state, controller, include_p if is_video_model: # frames self.components.label(bottom_frame, 1, 0, "frames:", - tooltip="Number of frames to generate. Only used when generating videos.") + tooltip="生成帧数,仅视频生成时使用") self.components.entry(bottom_frame, 1, 1, ui_state, "frames") # length self.components.label(bottom_frame, 1, 2, "length:", - tooltip="Length in seconds of audio output.") + tooltip="音频输出长度(秒)") self.components.entry(bottom_frame, 1, 3, ui_state, "length") # seed @@ -74,12 +74,12 @@ def build_content(self, top_frame, bottom_frame, ui_state, controller, include_p # inpainting if is_inpainting_model: self.components.label(bottom_frame, 5, 0, "inpainting:", - tooltip="Enables inpainting sampling. Only available when sampling from an inpainting model.") + tooltip="启用修复采样,仅修复模型可用") self.components.switch(bottom_frame, 5, 1, ui_state, "sample_inpainting") # base image path self.components.label(bottom_frame, 6, 0, "base image path:", - tooltip="The base image used when inpainting.") + tooltip="修复使用的基础图像") self.components.path_entry(bottom_frame, 6, 1, ui_state, "base_image_path", mode="file", allow_model_files=False, @@ -88,7 +88,7 @@ def build_content(self, top_frame, bottom_frame, ui_state, controller, include_p # mask image path self.components.label(bottom_frame, 6, 2, "mask image path:", - tooltip="The mask used when inpainting.") + tooltip="修复使用的遮罩") self.components.path_entry(bottom_frame, 6, 3, ui_state, "mask_image_path", mode="file", allow_model_files=False, diff --git a/modules/ui/BaseSchedulerParamsWindowView.py b/modules/ui/BaseSchedulerParamsWindowView.py index 1106d5227..6e9ea52c4 100644 --- a/modules/ui/BaseSchedulerParamsWindowView.py +++ b/modules/ui/BaseSchedulerParamsWindowView.py @@ -8,8 +8,8 @@ def __init__(self, components): def build_content(self, master, controller, ui_state): if controller.is_custom_scheduler(): - self.components.label(master, 0, 0, "Class Name", - tooltip="Python class module and name for the custom scheduler class, in the form of ..") + self.components.label(master, 0, 0, "类名", + tooltip="自定义调度器类,格式:<模块>.<类名>") self.components.entry(master, 0, 1, ui_state, "custom_learning_rate_scheduler") diff --git a/modules/ui/BaseTimestepDistributionWindowView.py b/modules/ui/BaseTimestepDistributionWindowView.py index 1f29e7079..f9896b7ff 100644 --- a/modules/ui/BaseTimestepDistributionWindowView.py +++ b/modules/ui/BaseTimestepDistributionWindowView.py @@ -9,38 +9,38 @@ def __init__(self, components): def build_content(self, frame, controller, ui_state): # timestep distribution - self.components.label(frame, 0, 0, "Timestep Distribution", - tooltip="Selects the function to sample timesteps during training", + self.components.label(frame, 0, 0, "时间步分布", + tooltip="选择训练时的时间步采样函数", wide_tooltip=True) self.components.options(frame, 0, 1, controller.get_distribution_options(), ui_state, "timestep_distribution") # min noising strength - self.components.label(frame, 1, 0, "Min Noising Strength", - tooltip="Specifies the minimum noising strength used during training. This can help to improve composition, but prevents finer details from being trained") + self.components.label(frame, 1, 0, "最小噪声强度", + tooltip="训练最小噪声强度,有助于构图但会阻碍细节训练") self.components.entry(frame, 1, 1, ui_state, "min_noising_strength") # max noising strength - self.components.label(frame, 2, 0, "Max Noising Strength", - tooltip="Specifies the maximum noising strength used during training. This can be useful to reduce overfitting, but also reduces the impact of training samples on the overall image composition") + self.components.label(frame, 2, 0, "最大噪声强度", + tooltip="训练最大噪声强度,可减少过拟合但降低样本对构图的影响") self.components.entry(frame, 2, 1, ui_state, "max_noising_strength") # noising weight - self.components.label(frame, 3, 0, "Noising Weight", - tooltip="Controls the weight parameter of the timestep distribution function. Use the preview to see more details.") + self.components.label(frame, 3, 0, "噪声权重", + tooltip="控制时间步分布函数的权重参数") self.components.entry(frame, 3, 1, ui_state, "noising_weight") # noising bias - self.components.label(frame, 4, 0, "Noising Bias", - tooltip="Controls the bias parameter of the timestep distribution function. Use the preview to see more details.") + self.components.label(frame, 4, 0, "噪声偏差", + tooltip="控制时间步分布函数的偏差参数") self.components.entry(frame, 4, 1, ui_state, "noising_bias") # timestep shift - self.components.label(frame, 5, 0, "Timestep Shift", - tooltip="Shift the timestep distribution. Use the preview to see more details.") + self.components.label(frame, 5, 0, "时间步偏移", + tooltip="偏移时间步分布,使用预览查看详情") self.components.entry(frame, 5, 1, ui_state, "timestep_shift") # dynamic timestep shifting - self.components.label(frame, 6, 0, "Dynamic Timestep Shifting", + self.components.label(frame, 6, 0, "动态时间步偏移", tooltip="Dynamically shift the timestep distribution based on resolution. If enabled, the shifting parameters are taken from the model's scheduler configuration and Timestep Shift is ignored. Dynamic Timestep Shifting is not shown in the preview. For Ideogram, the shifting instead follows the model's own resolution-aware sampling schedule. Note: For Z-Image, the dynamic shifting parameters are likely wrong and unknown. Use with care or set your own, fixed shift.", wide_tooltip=True) self.components.switch(frame, 6, 1, ui_state, "dynamic_timestep_shifting") diff --git a/modules/ui/BaseTopBarView.py b/modules/ui/BaseTopBarView.py index fec0372ca..bcd68ce6b 100644 --- a/modules/ui/BaseTopBarView.py +++ b/modules/ui/BaseTopBarView.py @@ -58,18 +58,18 @@ def build( # preset picker: model type -> presets for that type self.components.preset_menu_button( - self.frame, 0, 1, "Load Preset", self.preset_tree, self.__load_current_config, sticky="vew", + self.frame, 0, 1, "加载预设", self.preset_tree, self.__load_current_config, sticky="vew", ) # load config button - self.components.button(self.frame, 0, 2, "Load config", self.__load_config, + self.components.button(self.frame, 0, 2, "加载配置", self.__load_config, tooltip="Load one of your own saved configs", width=90, sticky="vew") # Wiki button self.components.button(self.frame, 0, 4, "Wiki", self.open_wiki, width=50, sticky="vew") # save button - self.components.button(self.frame, 0, 3, "Save config", self.__save_config, + self.components.button(self.frame, 0, 3, "保存配置", self.__save_config, tooltip="Save the current configuration in a custom preset", width=90, sticky="vew") # padding diff --git a/modules/ui/BaseTrainUIView.py b/modules/ui/BaseTrainUIView.py index 2f5598a33..4259964a7 100644 --- a/modules/ui/BaseTrainUIView.py +++ b/modules/ui/BaseTrainUIView.py @@ -103,105 +103,105 @@ def build_bottom_bar_content(self, frame, status_frame, controller, ui_state): self.set_step_progress, self.set_epoch_progress = self.components.double_progress(frame, 0, 0, "step", "epoch") self.status_label = self.components.label(status_frame, 0, 0, "", pad=0, - tooltip="Current status of the training run") + tooltip="训练运行当前状态") self.eta_label = self.components.label(status_frame, 1, 0, "", pad=0) - self.export_button = self.components.button(frame, 0, 3, "Export", self.export_training, + self.export_button = self.components.button(frame, 0, 3, "导出", self.export_training, width=60, padx=5, pady=(15, 0), - tooltip="Export the current configuration as a script to run without a UI") + tooltip="导出当前配置为无UI运行脚本") - self.components.button(frame, 0, 4, "Debug", self.generate_debug_package, + self.components.button(frame, 0, 4, "调试", self.generate_debug_package, width=60, padx=(5, 25), pady=(15, 0), - tooltip="Generate a zip file with config.json, debug_report.log and settings diff, use this to report bugs or issues") + tooltip="生成包含配置和调试报告的zip文件,用于报告问题") self.components.button(frame, 0, 5, "Tensorboard", self.open_tensorboard, width=100, padx=(0, 5), pady=(15, 0)) - self.training_button = self.components.button(frame, 0, 6, "Start Training", self.start_training, + self.training_button = self.components.button(frame, 0, 6, "开始训练", self.start_training, padx=(5, 20), pady=(15, 0)) def build_general_tab_content(self, frame, controller, ui_state): # workspace dir - self.components.label(frame, 0, 0, "Workspace Directory", - tooltip="The directory where all files of this training run are saved") + self.components.label(frame, 0, 0, "工作空间目录", + tooltip="此训练运行所有文件保存的目录") self.components.path_entry(frame, 0, 1, ui_state, "workspace_dir", mode="dir", command=controller._on_workspace_dir_change) # cache dir - self.components.label(frame, 0, 2, "Cache Directory", - tooltip="The directory where cached data is saved") + self.components.label(frame, 0, 2, "缓存目录", + tooltip="缓存数据保存的目录") self.components.path_entry(frame, 0, 3, ui_state, "cache_dir", mode="dir") # continue from previous backup - self.components.label(frame, 2, 0, "Continue from last backup", - tooltip="Automatically continues training from the last backup saved in /backup") + self.components.label(frame, 2, 0, "从上次备份继续", + tooltip="自动从/backup中的上次备份继续训练") self.components.switch(frame, 2, 1, ui_state, "continue_last_backup") # only cache - self.components.label(frame, 2, 2, "Only Cache", - tooltip="Only populate the cache, without any training") + self.components.label(frame, 2, 2, "仅缓存", + tooltip="仅填充缓存,不进行训练") self.components.switch(frame, 2, 3, ui_state, "only_cache") # TODO: In Phase 4 rework the general tab. # prevent overwrites - self.components.label(frame, 3, 0, "Prevent Overwrites", - tooltip="When enabled, output paths that already exist on disk will be flagged as invalid to avoid accidental overwrites") + self.components.label(frame, 3, 0, "防止覆盖", + tooltip="启用后,已存在的输出路径将被标记为无效以防止意外覆盖") self.components.switch(frame, 3, 1, ui_state, "prevent_overwrites") # debug - self.components.label(frame, 4, 0, "Debug mode", - tooltip="Save debug information during the training into the debug directory") + self.components.label(frame, 4, 0, "调试模式", + tooltip="训练时将调试信息保存到调试目录") self.components.switch(frame, 4, 1, ui_state, "debug_mode") - self.components.label(frame, 4, 2, "Debug Directory", - tooltip="The directory where debug data is saved") + self.components.label(frame, 4, 2, "调试目录", + tooltip="调试数据保存的目录") self.components.path_entry(frame, 4, 3, ui_state, "debug_dir", mode="dir", io_type=PathIOType.OUTPUT) # tensorboard self.components.label(frame, 6, 0, "Tensorboard", - tooltip="Starts the Tensorboard Web UI during training") + tooltip="训练时启动Tensorboard Web UI") self.components.switch(frame, 6, 1, ui_state, "tensorboard") - self.components.label(frame, 6, 2, "Always-On Tensorboard", - tooltip="Keep Tensorboard accessible even when not training. Useful for monitoring completed training sessions.") + self.components.label(frame, 6, 2, "常驻Tensorboard", + tooltip="非训练时也保持Tensorboard可访问") self.components.switch(frame, 6, 3, ui_state, "tensorboard_always_on", command=controller._on_always_on_tensorboard_toggle) - self.components.label(frame, 7, 0, "Expose Tensorboard", - tooltip="Exposes Tensorboard Web UI to all network interfaces (makes it accessible from the network)") + self.components.label(frame, 7, 0, "暴露Tensorboard", + tooltip="将Tensorboard暴露到所有网络接口") self.components.switch(frame, 7, 1, ui_state, "tensorboard_expose") - self.components.label(frame, 7, 2, "Tensorboard Port", - tooltip="Port to use for Tensorboard link") + self.components.label(frame, 7, 2, "Tensorboard端口", + tooltip="Tensorboard链接端口") self.components.entry(frame, 7, 3, ui_state, "tensorboard_port") # validation - self.components.label(frame, 8, 0, "Validation", - tooltip="Enable validation steps and add new graph in tensorboard") + self.components.label(frame, 8, 0, "验证", + tooltip="启用验证步骤并在Tensorboard添加图表") self.components.switch(frame, 8, 1, ui_state, "validation") - self.components.label(frame, 8, 2, "Validate after", - tooltip="The interval used when validate training") + self.components.label(frame, 8, 2, "验证间隔", + tooltip="训练验证间隔") self.components.time_entry(frame, 8, 3, ui_state, "validate_after", "validate_after_unit") # device - self.components.label(frame, 10, 0, "Dataloader Threads", - tooltip="Number of threads used for the data loader. Increase if your GPU has room during caching, decrease if it's going out of memory during caching.") + self.components.label(frame, 10, 0, "数据加载线程", + tooltip="数据加载线程数,缓存时GPU有余量可增加") self.components.entry(frame, 10, 1, ui_state, "dataloader_threads", required=True) - self.components.label(frame, 11, 0, "Train Device", + self.components.label(frame, 11, 0, "训练设备", tooltip="The device used for training. Can be \"cuda\", \"cuda:0\", \"cuda:1\" etc. Default:\"cuda\". Must be \"cuda\" for multi-GPU training.") self.components.entry(frame, 11, 1, ui_state, "train_device", required=True) - self.components.label(frame, 11, 2, "Async Offloading", - tooltip="Overlaps CPU<->GPU transfers with computation using CUDA streams. Applies to every offloaded component") + self.components.label(frame, 11, 2, "异步卸载", + tooltip="使用CUDA流重叠CPU<->GPU传输与计算") self.components.switch(frame, 11, 3, ui_state, "async_offloading") self.components.label(frame, 12, 0, "Multi-GPU", - tooltip="Enable multi-GPU training") + tooltip="启用多GPU训练") self.components.switch(frame, 12, 1, ui_state, "multi_gpu") - self.components.label(frame, 12, 2, "Device Indexes", - tooltip="Multi-GPU: A comma-separated list of device indexes. If empty, all your GPUs are used. With a list such as \"0,1,3,4\" you can omit a GPU, for example an on-board graphics GPU.") + self.components.label(frame, 12, 2, "设备索引", + tooltip="多GPU:逗号分隔的设备索引列表,留空使用所有GPU") self.components.entry(frame, 12, 3, ui_state, "device_indexes") - self.components.label(frame, 13, 0, "Gradient Reduce Precision", + self.components.label(frame, 13, 0, "梯度归约精度", tooltip="WEIGHT_DTYPE: Reduce gradients between GPUs in your weight data type; can be imprecise, but more efficient than float32\n" "WEIGHT_DTYPE_STOCHASTIC: Sum up the gradients in your weight data type, but average them in float32 and stochastically round if your weight data type is bfloat16\n" "FLOAT_32: Reduce gradients in float32\n" @@ -210,48 +210,48 @@ def build_general_tab_content(self, frame, controller, ui_state): self.components.options(frame, 13, 1, [str(x) for x in list(GradientReducePrecision)], ui_state, "gradient_reduce_precision") - self.components.label(frame, 13, 2, "Fused Gradient Reduce", - tooltip="Multi-GPU: Gradient synchronisation during the backward pass. Can be more efficient, especially with Async Gradient Reduce") + self.components.label(frame, 13, 2, "融合梯度归约", + tooltip="多GPU:反向传播时的梯度同步,配合异步梯度归约更高效") self.components.switch(frame, 13, 3, ui_state, "fused_gradient_reduce") - self.components.label(frame, 14, 0, "Async Gradient Reduce", - tooltip="Multi-GPU: Asynchroniously start the gradient reduce operations during the backward pass. Can be more efficient, but requires some VRAM.") + self.components.label(frame, 14, 0, "异步梯度归约", + tooltip="多GPU:反向传播时异步启动梯度归约,更高效但占用显存") self.components.switch(frame, 14, 1, ui_state, "async_gradient_reduce") self.components.label(frame, 14, 2, "Buffer size (MB)", tooltip="Multi-GPU: Maximum VRAM for \"Async Gradient Reduce\", in megabytes. A multiple of this value can be needed if combined with \"Fused Back Pass\" and/or \"Layer offload fraction\"") self.components.entry(frame, 14, 3, ui_state, "async_gradient_reduce_buffer") - self.components.label(frame, 15, 0, "Temp Device", + self.components.label(frame, 15, 0, "临时设备", tooltip="The device used to temporarily offload models while they are not used. Default:\"cpu\"") self.components.entry(frame, 15, 1, ui_state, "temp_device") def build_data_tab_content(self, frame, controller, ui_state): # aspect ratio bucketing - self.components.label(frame, 0, 0, "Aspect Ratio Bucketing", - tooltip="Aspect ratio bucketing enables training on images with different aspect ratios") + self.components.label(frame, 0, 0, "宽高比分桶", + tooltip="宽高比分桶允许在不同宽高比的图像上训练") self.components.switch(frame, 0, 1, ui_state, "aspect_ratio_bucketing") # latent caching - self.components.label(frame, 1, 0, "Latent Caching", - tooltip="Caching of intermediate training data that can be re-used between epochs") + self.components.label(frame, 1, 0, "潜在缓存", + tooltip="缓存可在轮次间复用的中间训练数据") self.components.switch(frame, 1, 1, ui_state, "latent_caching") # clear cache before training - self.components.label(frame, 2, 0, "Clear cache before training", - tooltip="Clears the cache directory before starting to train. Only disable this if you want to continue using the same cached data. Disabling this can lead to errors, if other settings are changed during a restart") + self.components.label(frame, 2, 0, "训练前清除缓存", + tooltip="训练前清除缓存目录,仅在使用相同缓存数据时禁用") self.components.switch(frame, 2, 1, ui_state, "clear_cache_before_training") def build_sampling_tab_header(self, top_frame, sub_frame, controller, ui_state): - self.components.label(top_frame, 0, 0, "Sample After", - tooltip="The interval used when automatically sampling from the model during training") + self.components.label(top_frame, 0, 0, "采样间隔", + tooltip="训练时自动采样的间隔") self.components.time_entry(top_frame, 0, 1, ui_state, "sample_after", "sample_after_unit") - self.components.label(top_frame, 0, 2, "Skip First", - tooltip="Start sampling automatically after this interval has elapsed.") + self.components.label(top_frame, 0, 2, "跳过首个", + tooltip="经过此间隔后自动开始采样") self.components.entry(top_frame, 0, 3, ui_state, "sample_skip_first", width=50, sticky="nw") self.components.label(top_frame, 0, 4, "Format", - tooltip="File Format used when saving samples") + tooltip="保存样本的文件格式") self.components.options_kv(top_frame, 0, 5, [ ("PNG", ImageFormat.PNG), ("JPG", ImageFormat.JPG), @@ -262,113 +262,113 @@ def build_sampling_tab_header(self, top_frame, sub_frame, controller, ui_state): self.components.button(top_frame, 0, 7, "manual sample", self.open_manual_sample_window) self.components.label(sub_frame, 0, 0, "Non-EMA Sampling", - tooltip="Whether to include non-ema sampling when using ema.") + tooltip="使用EMA时是否包含非EMA采样") self.components.switch(sub_frame, 0, 1, ui_state, "non_ema_sampling") - self.components.label(sub_frame, 0, 2, "Samples to Tensorboard", - tooltip="Whether to include sample images in the Tensorboard output.") + self.components.label(sub_frame, 0, 2, "采样到Tensorboard", + tooltip="是否在Tensorboard输出中包含采样图像") self.components.switch(sub_frame, 0, 3, ui_state, "samples_to_tensorboard") def build_backup_tab_content(self, frame, controller, ui_state): # backup after - self.components.label(frame, 0, 0, "Backup After", - tooltip="The interval used when automatically creating model backups during training") + self.components.label(frame, 0, 0, "备份间隔", + tooltip="训练时自动创建模型备份的间隔") self.components.time_entry(frame, 0, 1, ui_state, "backup_after", "backup_after_unit") # backup now self.components.button(frame, 0, 3, "backup now", self.backup_now) # rolling backup - self.components.label(frame, 1, 0, "Rolling Backup", - tooltip="If rolling backups are enabled, older backups are deleted automatically") + self.components.label(frame, 1, 0, "滚动备份", + tooltip="启用滚动备份后自动删除旧备份") self.components.switch(frame, 1, 1, ui_state, "rolling_backup") # rolling backup count - self.components.label(frame, 2, 0, "Rolling Backup Count", - tooltip="Defines the number of backups to keep if rolling backups are enabled") + self.components.label(frame, 2, 0, "滚动备份数量", + tooltip="滚动备份保留的数量") self.components.entry(frame, 2, 1, ui_state, "rolling_backup_count") # backup before save - self.components.label(frame, 3, 0, "Backup Before Save", - tooltip="Create a full backup before saving the final model") + self.components.label(frame, 3, 0, "保存前备份", + tooltip="保存最终模型前创建完整备份") self.components.switch(frame, 3, 1, ui_state, "backup_before_save") # save after - self.components.label(frame, 4, 0, "Save Every", - tooltip="The interval used when automatically saving the model during training") + self.components.label(frame, 4, 0, "保存间隔", + tooltip="训练时自动保存模型的间隔") self.components.time_entry(frame, 4, 1, ui_state, "save_every", "save_every_unit") # save now self.components.button(frame, 4, 3, "save now", self.save_now) # skip save - self.components.label(frame, 5, 0, "Skip First", + self.components.label(frame, 5, 0, "跳过首个", tooltip="Start saving automatically after this interval has elapsed") self.components.entry(frame, 5, 1, ui_state, "save_skip_first", width=50, sticky="nw") # save filename prefix - self.components.label(frame, 6, 0, "Save Filename Prefix", - tooltip="The prefix for filenames used when saving the model during training") + self.components.label(frame, 6, 0, "保存文件名前缀", + tooltip="训练时保存模型的文件名前缀") self.components.entry(frame, 6, 1, ui_state, "save_filename_prefix") def build_embedding_tab_content(self, frame, controller, ui_state): # embedding model name - self.components.label(frame, 0, 0, "Base embedding", - tooltip="The base embedding to train on. Leave empty to create a new embedding") + self.components.label(frame, 0, 0, "基础嵌入", + tooltip="训练的基础嵌入,留空创建新嵌入") self.components.path_entry( frame, 0, 1, ui_state, "embedding.model_name", mode="file", path_modifier=path_util.json_path_modifier ) # token count - self.components.label(frame, 1, 0, "Token count", - tooltip="The token count used when creating a new embedding. Leave empty to auto detect from the initial embedding text.") + self.components.label(frame, 1, 0, "Token数", + tooltip="新嵌入的Token数,留空自动检测") self.components.entry(frame, 1, 1, ui_state, "embedding.token_count") # initial embedding text - self.components.label(frame, 2, 0, "Initial embedding text", - tooltip="The initial embedding text used when creating a new embedding") + self.components.label(frame, 2, 0, "初始嵌入文本", + tooltip="创建新嵌入时的初始文本") self.components.entry(frame, 2, 1, ui_state, "embedding.initial_embedding_text") # embedding weight dtype - self.components.label(frame, 3, 0, "Embedding Weight Data Type", - tooltip="The Embedding weight data type used for training. This can reduce memory consumption, but reduces precision") + self.components.label(frame, 3, 0, "嵌入权重数据类型", + tooltip="嵌入权重数据类型,可减少内存但降低精度") self.components.options_kv(frame, 3, 1, [ ("float32", DataType.FLOAT_32), ("bfloat16", DataType.BFLOAT_16), ], ui_state, "embedding_weight_dtype") # placeholder - self.components.label(frame, 4, 0, "Placeholder", - tooltip="The placeholder used when using the embedding in a prompt") + self.components.label(frame, 4, 0, "占位符", + tooltip="在提示词中使用嵌入的占位符") self.components.entry(frame, 4, 1, ui_state, "embedding.placeholder") # output embedding - self.components.label(frame, 5, 0, "Output embedding", - tooltip="Output embeddings are calculated at the output of the text encoder, not the input. This can improve results for larger text encoders and lower VRAM usage.") + self.components.label(frame, 5, 0, "输出嵌入", + tooltip="在文本编码器输出处计算嵌入,可改善大文本编码器效果并降低显存") self.components.switch(frame, 5, 1, ui_state, "embedding.is_output_embedding") def build_tools_tab_content(self, frame, controller, ui_state): # dataset - self.components.label(frame, 0, 0, "Dataset Tools", - tooltip="Open the captioning tool") - self.components.button(frame, 0, 1, "Open", self.open_dataset_tool) + self.components.label(frame, 0, 0, "数据集工具", + tooltip="打开标签工具") + self.components.button(frame, 0, 1, "打开", self.open_dataset_tool) # video tools - self.components.label(frame, 1, 0, "Video Tools", - tooltip="Open the video tools") - self.components.button(frame, 1, 1, "Open", self.open_video_tool) + self.components.label(frame, 1, 0, "视频工具", + tooltip="打开视频工具") + self.components.button(frame, 1, 1, "打开", self.open_video_tool) # convert model - self.components.label(frame, 2, 0, "Convert Model Tools", - tooltip="Open the model conversion tool") - self.components.button(frame, 2, 1, "Open", self.open_convert_model_tool) + self.components.label(frame, 2, 0, "模型转换工具", + tooltip="打开模型转换工具") + self.components.button(frame, 2, 1, "打开", self.open_convert_model_tool) # sample - self.components.label(frame, 3, 0, "Sampling Tool", - tooltip="Open the model sampling tool") - self.components.button(frame, 3, 1, "Open", self.open_sampling_tool) + self.components.label(frame, 3, 0, "采样工具", + tooltip="打开模型采样工具") + self.components.button(frame, 3, 1, "打开", self.open_sampling_tool) - self.components.label(frame, 4, 0, "Profiling Tool", - tooltip="Open the profiling tools.") - self.components.button(frame, 4, 1, "Open", self.open_profiling_tool) + self.components.label(frame, 4, 0, "性能分析工具", + tooltip="打开性能分析工具") + self.components.button(frame, 4, 1, "打开", self.open_profiling_tool) diff --git a/modules/ui/BaseTrainingTabView.py b/modules/ui/BaseTrainingTabView.py index 29a54bb1e..ad39ab636 100644 --- a/modules/ui/BaseTrainingTabView.py +++ b/modules/ui/BaseTrainingTabView.py @@ -294,8 +294,8 @@ def __create_base_frame(self, master, row, controller, ui_state): frame = self.components.section_frame(master, row) # optimizer - self.components.label(frame, 0, 0, "Optimizer", - tooltip="The type of optimizer") + self.components.label(frame, 0, 0, "优化器", + tooltip="优化器类型") self.components.options_adv(frame, 0, 1, [str(x) for x in list(Optimizer)], ui_state, "optimizer.optimizer", command=self.restore_optimizer_config, adv_command=self.open_optimizer_params) @@ -305,8 +305,8 @@ def __create_base_frame(self, master, row, controller, ui_state): if hasattr(self, "lr_scheduler_comp"): delattr(self, "lr_scheduler_comp") delattr(self, "lr_scheduler_adv_comp") - self.components.label(frame, 1, 0, "Learning Rate Scheduler", - tooltip="Learning rate scheduler that automatically changes the learning rate during training") + self.components.label(frame, 1, 0, "学习率调度器", + tooltip="训练过程中自动调整学习率的调度器") _, d = self.components.options_adv(frame, 1, 1, [str(x) for x in list(LearningRateScheduler)], ui_state, "learning_rate_scheduler", command=self.restore_scheduler, @@ -317,50 +317,50 @@ def __create_base_frame(self, master, row, controller, ui_state): self.restore_scheduler(ui_state.get_var("learning_rate_scheduler").get()) # learning rate - self.components.label(frame, 2, 0, "Learning Rate", - tooltip="The base learning rate") + self.components.label(frame, 2, 0, "学习率", + tooltip="基础学习率") self.components.entry(frame, 2, 1, ui_state, "learning_rate", required=True) # learning rate warmup steps - self.components.label(frame, 3, 0, "Learning Rate Warmup Steps", - tooltip="The number of steps it takes to gradually increase the learning rate from 0 to the specified learning rate. Values >1 are interpeted as a fixed number of steps, values <=1 are intepreted as a percentage of the total training steps (ex. 0.2 = 20% of the total step count)") + self.components.label(frame, 3, 0, "学习率预热步数", + tooltip="学习率从0渐增到指定值的步数,>1为固定步数,<=1为总步数百分比") self.components.entry(frame, 3, 1, ui_state, "learning_rate_warmup_steps") # learning rate min factor - self.components.label(frame, 4, 0, "Learning Rate Min Factor", - tooltip="Unit = float. Method = percentage. For a factor of 0.1, the final LR will be 10% of the initial LR. If the initial LR is 1e-4, the final LR will be 1e-5.") + self.components.label(frame, 4, 0, "学习率最小因子", + tooltip="浮点数,百分比方式。如0.1则最终学习率为初始值的10%") self.components.entry(frame, 4, 1, ui_state, "learning_rate_min_factor", - extra_validate=check_range(lower=0, upper=0.99, message="Learning rate min factor must be between 0 and 0.99")) + extra_validate=check_range(lower=0, upper=0.99, message="学习率最小因子必须在0到0.99之间")) # learning rate cycles - self.components.label(frame, 5, 0, "Learning Rate Cycles", - tooltip="The number of learning rate cycles. This is only applicable if the learning rate scheduler supports cycles") + self.components.label(frame, 5, 0, "学习率周期数", + tooltip="学习率周期数,仅调度器支持时有效") self.components.entry(frame, 5, 1, ui_state, "learning_rate_cycles") # epochs - self.components.label(frame, 6, 0, "Epochs", - tooltip="The number of epochs for a full training run") + self.components.label(frame, 6, 0, "训练轮数", + tooltip="完整训练运行的轮数") self.components.entry(frame, 6, 1, ui_state, "epochs", required=True) # batch size - self.components.label(frame, 7, 0, "Local Batch Size", - tooltip="The batch size of one training step. If you use multiple GPUs, this is the batch size of each GPU (local batch size).") + self.components.label(frame, 7, 0, "本地批次大小", + tooltip="单步训练的批次大小。多GPU时每块GPU的批次大小") self.components.entry(frame, 7, 1, ui_state, "batch_size", required=True) # accumulation steps - self.components.label(frame, 8, 0, "Accumulation Steps", - tooltip="Number of accumulation steps. Increase this number to trade batch size for training speed") + self.components.label(frame, 8, 0, "梯度累积步数", + tooltip="梯度累积步数,增加此值以训练速度换取更大批次") self.components.entry(frame, 8, 1, ui_state, "gradient_accumulation_steps", required=True) # Learning Rate Scaler - self.components.label(frame, 9, 0, "Learning Rate Scaler", - tooltip="Selects the type of learning rate scaling to use during training. Functionally equated as: LR * SQRT(selection)") + self.components.label(frame, 9, 0, "学习率缩放器", + tooltip="学习率缩放类型,等效于: LR * SQRT(选择值)") self.components.options(frame, 9, 1, [str(x) for x in list(LearningRateScaler)], ui_state, "learning_rate_scaler") # clip grad norm - self.components.label(frame, 10, 0, "Clip Grad Norm", - tooltip="Clips the gradient norm. Leave empty to disable gradient clipping.") + self.components.label(frame, 10, 0, "梯度裁剪", + tooltip="梯度范数裁剪,留空则禁用") self.components.entry(frame, 10, 1, ui_state, "clip_grad_norm") def __create_base2_frame(self, master, row, controller, ui_state, video_training_enabled: bool = False, @@ -369,35 +369,35 @@ def __create_base2_frame(self, master, row, controller, ui_state, video_training row = 0 # attention mechanism - self.components.label(frame, row, 0, "Attention", - tooltip="The attention mechanism used during training. Use `torch SDPA` on linux. On windows, `flash-attn` can be faster, but it has to be installed manually and does not support all models. `torch cuDNN` is an alternative backend some models require or benefit from.") + self.components.label(frame, row, 0, "注意力机制", + tooltip="训练使用的注意力机制。Linux用torch SDPA,Windows可手动安装flash-attn") self.components.options_kv(frame, row, 1, controller.get_attention_mechanisms(), ui_state, "attention_mechanism") row += 1 # ema self.components.label(frame, row, 0, "EMA", - tooltip="EMA averages the training progress over many steps, better preserving different concepts in big datasets") + tooltip="EMA对多步训练取平均,更好地保留大数据集中的不同概念") self.components.options(frame, row, 1, [str(x) for x in list(EMAMode)], ui_state, "ema") row += 1 # ema decay - self.components.label(frame, row, 0, "EMA Decay", - tooltip="Decay parameter of the EMA model. Higher numbers will average more steps. For datasets of hundreds or thousands of images, set this to 0.9999. For smaller datasets, set it to 0.999 or even 0.998") + self.components.label(frame, row, 0, "EMA衰减", + tooltip="EMA模型衰减参数。大数据集设0.9999,小数据集设0.999或0.998") self.components.entry(frame, row, 1, ui_state, "ema_decay", extra_validate=check_range(lower=0.5, upper=1, - message="EMA decay must be between 0.5 and 1")) + message="EMA衰减必须在0.5到1之间")) row += 1 # ema update step interval - self.components.label(frame, row, 0, "EMA Update Step Interval", - tooltip="Number of steps between EMA update steps") + self.components.label(frame, row, 0, "EMA更新步间隔", + tooltip="EMA更新之间的步数") self.components.entry(frame, row, 1, ui_state, "ema_update_step_interval") row += 1 # train dtype - self.components.label(frame, row, 0, "Train Data Type", - tooltip="The mixed precision data type used for training. This can increase training speed, but reduces precision") + self.components.label(frame, row, 0, "训练数据类型", + tooltip="训练混合精度数据类型,可提高速度但降低精度") self.components.options_kv(frame, row, 1, [ ("float32", DataType.FLOAT_32), ("float16", DataType.FLOAT_16), @@ -407,8 +407,8 @@ def __create_base2_frame(self, master, row, controller, ui_state, video_training row += 1 # fallback train dtype - self.components.label(frame, row, 0, "Fallback Train Data Type", - tooltip="The mixed precision data type used for training stages that don't support float16 data types. This can increase training speed, but reduces precision") + self.components.label(frame, row, 0, "回退训练数据类型", + tooltip="不支持float16的训练阶段的混合精度数据类型") self.components.options_kv(frame, row, 1, [ ("float32", DataType.FLOAT_32), ("bfloat16", DataType.BFLOAT_16), @@ -416,48 +416,48 @@ def __create_base2_frame(self, master, row, controller, ui_state, video_training row += 1 # autocast cache - self.components.label(frame, row, 0, "Autocast Cache", - tooltip="Enables the autocast cache. Disabling this reduces memory usage, but increases training time") + self.components.label(frame, row, 0, "自动转换缓存", + tooltip="启用自动转换缓存,禁用可减少内存但增加训练时间") self.components.switch(frame, row, 1, ui_state, "enable_autocast_cache") row += 1 # resolution - self.components.label(frame, row, 0, "Resolution", - tooltip="The resolution used for training. Optionally specify multiple resolutions separated by a comma, or a single exact resolution in the format x") + self.components.label(frame, row, 0, "分辨率", + tooltip="训练分辨率,可用逗号分隔多个分辨率,或指定 <宽>x<高> 格式") self.components.entry(frame, row, 1, ui_state, "resolution", required=True, extra_validate=validate_resolution()) row += 1 # frames if video_training_enabled: - self.components.label(frame, row, 0, "Frames", - tooltip="The number of frames used for training.") + self.components.label(frame, row, 0, "帧数", + tooltip="训练使用的帧数") self.components.entry(frame, row, 1, ui_state, "frames", required=True) row += 1 # force circular padding if supports_circular_padding: - self.components.label(frame, row, 0, "Force Circular Padding", - tooltip="Enables circular padding for all conv layers to better train seamless images") + self.components.label(frame, row, 0, "强制循环填充", + tooltip="为所有卷积层启用循环填充,更好地训练无缝图像") self.components.switch(frame, row, 1, ui_state, "force_circular_padding") def __create_offloading_widgets(self, frame, row, ui_state, part, supports_checkpointing=True, supports_activation_offloading=False, supports_layer_offloading=True): if supports_checkpointing: - self.components.label(frame, row, 0, "Gradient Checkpointing", - tooltip="Enables gradient checkpointing for this component. Reduces VRAM usage at the cost of training speed") + self.components.label(frame, row, 0, "梯度检查点", + tooltip="启用梯度检查点,减少显存占用但降低训练速度") self.components.switch(frame, row, 1, ui_state, f"{part}.gradient_checkpointing") row += 1 if supports_layer_offloading: - self.components.label(frame, row, 0, "Layer Offload Fraction", - tooltip="Fraction of this component's layers to offload to CPU to reduce VRAM usage. Increases training time and RAM usage. 0=disabled, 1=all layers") + self.components.label(frame, row, 0, "层卸载比例", + tooltip="卸载到CPU的层比例,0=禁用,1=全部") self.components.entry(frame, row, 1, ui_state, f"{part}.offload_fraction") row += 1 if supports_activation_offloading: - self.components.label(frame, row, 0, "Offload Activations", - tooltip="Offloads this component's activations to CPU during training to reduce VRAM usage") + self.components.label(frame, row, 0, "卸载激活值", + tooltip="训练时将激活值卸载到CPU以减少显存占用") self.components.switch(frame, row, 1, ui_state, f"{part}.activation_offloading") row += 1 @@ -469,13 +469,13 @@ def __create_text_encoder_frame(self, master, row, ui_state, supports_clip_skip= row = 0 if supports_training: - self.components.label(frame, row, 0, "Train Text Encoder", - tooltip="Enables training the text encoder model") + self.components.label(frame, row, 0, "训练文本编码器", + tooltip="启用文本编码器训练") self.components.switch(frame, row, 1, ui_state, "text_encoder.train") row += 1 else: # no Train switch to act as the frame's header, so add an explicit one - self.components.label(frame, row, 0, "Text Encoder") + self.components.label(frame, row, 0, "文本编码器") row += 1 row = self.__create_offloading_widgets(frame, row, ui_state, "text_encoder", supports_checkpointing=supports_training, @@ -483,36 +483,36 @@ def __create_text_encoder_frame(self, master, row, ui_state, supports_clip_skip= if supports_dropout: # dropout - self.components.label(frame, row, 0, "Caption Dropout Probability", - tooltip="The Probability for dropping the text encoder conditioning") + self.components.label(frame, row, 0, "标签丢弃概率", + tooltip="丢弃文本编码器条件的概率") self.components.entry(frame, row, 1, ui_state, "text_encoder.dropout_probability") row += 1 if supports_training: # train text encoder epochs - self.components.label(frame, row, 0, "Stop Training After", - tooltip="When to stop training the text encoder") + self.components.label(frame, row, 0, "训练停止条件", + tooltip="何时停止训练文本编码器") self.components.time_entry(frame, row, 1, ui_state, "text_encoder.stop_training_after", "text_encoder.stop_training_after_unit", supports_time_units=False) row += 1 # text encoder learning rate - self.components.label(frame, row, 0, "Text Encoder Learning Rate", - tooltip="The learning rate of the text encoder. Overrides the base learning rate") + self.components.label(frame, row, 0, "文本编码器学习率", + tooltip="文本编码器学习率,覆盖基础学习率") self.components.entry(frame, row, 1, ui_state, "text_encoder.learning_rate") row += 1 if supports_clip_skip: # text encoder layer skip (clip skip) - self.components.label(frame, row, 0, "Clip Skip", - tooltip="The number of additional clip layers to skip. 0 = the model default") + self.components.label(frame, row, 0, "Clip跳层", + tooltip="额外跳过的Clip层数,0为模型默认") self.components.entry(frame, row, 1, ui_state, "text_encoder_layer_skip") row += 1 if supports_sequence_length: # text encoder sequence length - self.components.label(frame, row, 0, "Text Encoder Sequence Length", - tooltip="Number of tokens for captions") + self.components.label(frame, row, 0, "文本编码器序列长度", + tooltip="标签Token数") self.components.entry(frame, row, 1, ui_state, "text_encoder_sequence_length") row += 1 @@ -534,14 +534,14 @@ def __create_text_encoder_n_frame( if supports_include: # include text encoder - self.components.label(frame, row, 0, f"Include Text Encoder {i}", - tooltip=f"Includes text encoder {i} in the training run") + self.components.label(frame, row, 0, f"包含文本编码器{i}", + tooltip=f"在训练中包含文本编码器{i}") self.components.switch(frame, row, 1, ui_state, f"text_encoder{suffix}.include") row += 1 # train text encoder - self.components.label(frame, row, 0, f"Train Text Encoder {i}", - tooltip=f"Enables training the text encoder {i} model") + self.components.label(frame, row, 0, f"训练文本编码器{i}", + tooltip=f"启用文本编码器{i}训练") self.components.switch(frame, row, 1, ui_state, f"text_encoder{suffix}.train") row += 1 @@ -549,41 +549,41 @@ def __create_text_encoder_n_frame( supports_layer_offloading=supports_layer_offloading) # train text encoder embedding - self.components.label(frame, row, 0, f"Train Text Encoder {i} Embedding", - tooltip=f"Enables training embeddings for the text encoder {i} model") + self.components.label(frame, row, 0, f"训练文本编码器{i}嵌入", + tooltip=f"启用文本编码器{i}嵌入训练") self.components.switch(frame, row, 1, ui_state, f"text_encoder{suffix}.train_embedding") row += 1 # dropout - self.components.label(frame, row, 0, "Dropout Probability", - tooltip=f"The Probability for dropping the text encoder {i} conditioning") + self.components.label(frame, row, 0, "丢弃概率", + tooltip=f"丢弃文本编码器{i}条件的概率") self.components.entry(frame, row, 1, ui_state, f"text_encoder{suffix}.dropout_probability") row += 1 # train text encoder epochs - self.components.label(frame, row, 0, "Stop Training After", - tooltip=f"When to stop training the text encoder {i}") + self.components.label(frame, row, 0, "训练停止条件", + tooltip=f"何时停止训练文本编码器{i}") self.components.time_entry(frame, row, 1, ui_state, f"text_encoder{suffix}.stop_training_after", f"text_encoder{suffix}.stop_training_after_unit", supports_time_units=False) row += 1 # text encoder learning rate - self.components.label(frame, row, 0, f"Text Encoder {i} Learning Rate", - tooltip=f"The learning rate of the text encoder {i}. Overrides the base learning rate") + self.components.label(frame, row, 0, f"文本编码器{i}学习率", + tooltip=f"文本编码器{i}学习率,覆盖基础学习率") self.components.entry(frame, row, 1, ui_state, f"text_encoder{suffix}.learning_rate") row += 1 if supports_layer_skip: # text encoder layer skip (clip skip) - self.components.label(frame, row, 0, f"Text Encoder {i} Clip Skip", - tooltip="The number of additional clip layers to skip. 0 = the model default") + self.components.label(frame, row, 0, f"文本编码器{i} Clip跳层", + tooltip="额外跳过的Clip层数,0为模型默认") self.components.entry(frame, row, 1, ui_state, f"text_encoder{suffix}_layer_skip") row += 1 if supports_sequence_length: # text encoder sequence length - self.components.label(frame, row, 0, f"Text Encoder {i} Sequence Length", - tooltip="Overrides the number of tokens used for captions. If empty, the model default is used, which is 512 on Flux. Comfy samples with 256 tokens though. 77 is the default only for backwards compatibility.") + self.components.label(frame, row, 0, f"文本编码器{i}序列长度", + tooltip="覆盖标签Token数,留空使用模型默认值") self.components.entry(frame, row, 1, ui_state, f"text_encoder{suffix}_sequence_length") row += 1 @@ -591,13 +591,13 @@ def __create_embedding_frame(self, master, row, ui_state): frame = self.components.section_frame(master, row) # embedding learning rate - self.components.label(frame, 0, 0, "Embeddings Learning Rate", - tooltip="The learning rate of embeddings. Overrides the base learning rate") + self.components.label(frame, 0, 0, "嵌入学习率", + tooltip="嵌入学习率,覆盖基础学习率") self.components.entry(frame, 0, 1, ui_state, "embedding_learning_rate") # preserve embedding norm - self.components.label(frame, 1, 0, "Preserve Embedding Norm", - tooltip="Rescales each trained embedding to the median embedding norm") + self.components.label(frame, 1, 0, "保留嵌入范数", + tooltip="将每个训练嵌入重缩放至中位嵌入范数") self.components.switch(frame, 1, 1, ui_state, "preserve_embedding_norm") def __create_unet_frame(self, master, row, ui_state): @@ -605,29 +605,29 @@ def __create_unet_frame(self, master, row, ui_state): row = 0 # train unet - self.components.label(frame, row, 0, "Train UNet", - tooltip="Enables training the UNet model") + self.components.label(frame, row, 0, "训练UNet", + tooltip="启用UNet模型训练") self.components.switch(frame, row, 1, ui_state, "unet.train") row += 1 row = self.__create_offloading_widgets(frame, row, ui_state, "unet", supports_layer_offloading=False) # train unet epochs - self.components.label(frame, row, 0, "Stop Training After", - tooltip="When to stop training the UNet") + self.components.label(frame, row, 0, "训练停止条件", + tooltip="何时停止训练UNet") self.components.time_entry(frame, row, 1, ui_state, "unet.stop_training_after", "unet.stop_training_after_unit", supports_time_units=False) row += 1 # unet learning rate - self.components.label(frame, row, 0, "UNet Learning Rate", - tooltip="The learning rate of the UNet. Overrides the base learning rate") + self.components.label(frame, row, 0, "UNet学习率", + tooltip="UNet学习率,覆盖基础学习率") self.components.entry(frame, row, 1, ui_state, "unet.learning_rate") row += 1 # rescale noise scheduler to zero terminal SNR - self.components.label(frame, row, 0, "Rescale Noise Scheduler + V-pred", - tooltip="Rescales the noise scheduler to a zero terminal signal to noise ratio and switches the model to a v-prediction target", + self.components.label(frame, row, 0, "重缩放噪声调度+V预测", + tooltip="将噪声调度器重缩放至零终端信噪比,切换模型到v预测目标", wraplength=130) self.components.switch(frame, row, 1, ui_state, "rescale_noise_scheduler_to_zero_terminal_snr") row += 1 @@ -637,23 +637,23 @@ def __create_prior_frame(self, master, row, ui_state): row = 0 # train prior - self.components.label(frame, row, 0, "Train Prior", - tooltip="Enables training the Prior model") + self.components.label(frame, row, 0, "训练Prior", + tooltip="启用Prior模型训练") self.components.switch(frame, row, 1, ui_state, "prior.train") row += 1 row = self.__create_offloading_widgets(frame, row, ui_state, "prior", supports_layer_offloading=False) # train prior epochs - self.components.label(frame, row, 0, "Stop Training After", - tooltip="When to stop training the Prior") + self.components.label(frame, row, 0, "训练停止条件", + tooltip="何时停止训练Prior") self.components.time_entry(frame, row, 1, ui_state, "prior.stop_training_after", "prior.stop_training_after_unit", supports_time_units=False) row += 1 # prior learning rate - self.components.label(frame, row, 0, "Prior Learning Rate", - tooltip="The learning rate of the Prior. Overrides the base learning rate") + self.components.label(frame, row, 0, "Prior学习率", + tooltip="Prior学习率,覆盖基础学习率") self.components.entry(frame, row, 1, ui_state, "prior.learning_rate") row += 1 @@ -663,37 +663,37 @@ def __create_transformer_frame(self, master, row, ui_state, supports_guidance_sc row = 0 # train transformer - self.components.label(frame, row, 0, "Train Transformer", - tooltip="Enables training the Transformer model") + self.components.label(frame, row, 0, "训练Transformer", + tooltip="启用Transformer模型训练") self.components.switch(frame, row, 1, ui_state, "transformer.train") row += 1 row = self.__create_offloading_widgets(frame, row, ui_state, "transformer", supports_activation_offloading=True) # train transformer epochs - self.components.label(frame, row, 0, "Stop Training After", - tooltip="When to stop training the Transformer") + self.components.label(frame, row, 0, "训练停止条件", + tooltip="何时停止训练Transformer") self.components.time_entry(frame, row, 1, ui_state, "transformer.stop_training_after", "transformer.stop_training_after_unit", supports_time_units=False) row += 1 # transformer learning rate - self.components.label(frame, row, 0, "Transformer Learning Rate", - tooltip="The learning rate of the Transformer. Overrides the base learning rate") + self.components.label(frame, row, 0, "Transformer学习率", + tooltip="Transformer学习率,覆盖基础学习率") self.components.entry(frame, row, 1, ui_state, "transformer.learning_rate") row += 1 if supports_force_attention_mask: # transformer learning rate - self.components.label(frame, row, 0, "Force Attention Mask", - tooltip="Force enables passing of a text embedding attention mask to the transformer. This can improve training on shorter captions.") + self.components.label(frame, row, 0, "强制注意力遮罩", + tooltip="强制向Transformer传递文本嵌入注意力遮罩,可改善短标签训练") self.components.switch(frame, row, 1, ui_state, "transformer.attention_mask") row += 1 if supports_guidance_scale: # guidance scale - self.components.label(frame, row, 0, "Guidance Scale", - tooltip="The guidance scale of guidance distilled models passed to the transformer during training.") + self.components.label(frame, row, 0, "引导尺度", + tooltip="引导蒸馏模型传递给Transformer的引导尺度") self.components.entry(frame, row, 1, ui_state, "transformer.guidance_scale") row += 1 @@ -702,7 +702,7 @@ def __create_unconditional_transformer_frame(self, master, row, ui_state): row = 0 # include unconditional transformer - self.components.label(frame, row, 0, "Include Unconditional Transformer", + self.components.label(frame, row, 0, "包含无条件Transformer", tooltip="Loads the dedicated unconditional transformer used for the negative branch of CFG " "during sampling. If disabled, CFG above 1.0 still works by running an empty prompt " "through the conditional transformer instead, at reduced VRAM and load time") @@ -717,58 +717,58 @@ def __create_noise_frame(self, master, row, ui_state, frame = self.components.section_frame(master, row) # offset noise weight - self.components.label(frame, 0, 0, "Offset Noise Weight", - tooltip="The weight of offset noise added to each training step") + self.components.label(frame, 0, 0, "偏移噪声权重", + tooltip="每步训练添加的偏移噪声权重") self.components.entry(frame, 0, 1, ui_state, "offset_noise_weight") if supports_generalized_offset_noise: # generalized offset noise weight - self.components.label(frame, 1, 0, "Generalized Offset Noise", - tooltip="Per-timestep 'brightness knob' instead of a fixed offset - steadier training, better starts, and improved very dark/bright images. Compatible with V-pred and Eps-pred. Start with 0.02 and adjust as needed.", + self.components.label(frame, 1, 0, "广义偏移噪声", + tooltip="逐时间步的亮度调节,训练更稳定。建议从0.02开始", wraplength=130) self.components.switch(frame, 1, 1, ui_state, "generalized_offset_noise") # perturbation noise weight - self.components.label(frame, 2, 0, "Perturbation Noise Weight", - tooltip="The weight of perturbation noise added to each training step") + self.components.label(frame, 2, 0, "扰动噪声权重", + tooltip="每步训练添加的扰动噪声权重") self.components.entry(frame, 2, 1, ui_state, "perturbation_noise_weight") # timestep distribution - self.components.label(frame, 3, 0, "Timestep Distribution", - tooltip="Selects the function to sample timesteps during training", + self.components.label(frame, 3, 0, "时间步分布", + tooltip="选择训练时的时间步采样函数", wide_tooltip=True) self.components.options_adv(frame, 3, 1, [str(x) for x in list(TimestepDistribution)], ui_state, "timestep_distribution", adv_command=self.open_timestep_distribution) # min noising strength - self.components.label(frame, 4, 0, "Min Noising Strength", - tooltip="Specifies the minimum noising strength used during training. This can help to improve composition, but prevents finer details from being trained") + self.components.label(frame, 4, 0, "最小噪声强度", + tooltip="训练最小噪声强度,有助于构图但会阻碍细节训练") self.components.entry(frame, 4, 1, ui_state, "min_noising_strength", required=True) # max noising strength - self.components.label(frame, 5, 0, "Max Noising Strength", - tooltip="Specifies the maximum noising strength used during training. This can be useful to reduce overfitting, but also reduces the impact of training samples on the overall image composition") + self.components.label(frame, 5, 0, "最大噪声强度", + tooltip="训练最大噪声强度,可减少过拟合但降低样本对构图的影响") self.components.entry(frame, 5, 1, ui_state, "max_noising_strength", required=True) # noising weight - self.components.label(frame, 6, 0, "Noising Weight", - tooltip="Controls the weight parameter of the timestep distribution function. Use the preview to see more details.") + self.components.label(frame, 6, 0, "噪声权重", + tooltip="控制时间步分布函数的权重参数") self.components.entry(frame, 6, 1, ui_state, "noising_weight", required=True) # noising bias - self.components.label(frame, 7, 0, "Noising Bias", - tooltip="Controls the bias parameter of the timestep distribution function. Use the preview to see more details.") + self.components.label(frame, 7, 0, "噪声偏差", + tooltip="控制时间步分布函数的偏差参数") self.components.entry(frame, 7, 1, ui_state, "noising_bias", required=True) # timestep shift - self.components.label(frame, 8, 0, "Timestep Shift", - tooltip="Shift the timestep distribution. Use the preview to see more details.") + self.components.label(frame, 8, 0, "时间步偏移", + tooltip="偏移时间步分布,使用预览查看详情") self.components.entry(frame, 8, 1, ui_state, "timestep_shift", required=True) if supports_dynamic_timestep_shifting: # dynamic timestep shifting - self.components.label(frame, 9, 0, "Dynamic Timestep Shifting", + self.components.label(frame, 9, 0, "动态时间步偏移", tooltip="Dynamically shift the timestep distribution based on resolution. If enabled, the shifting parameters are taken from the model's scheduler configuration and Timestep Shift is ignored. For Ideogram, the shifting instead follows the model's own resolution-aware sampling schedule. Note: For Z-Image, the dynamic shifting parameters are likely wrong and unknown. Use with care or set your own, fixed shift.", wide_tooltip=True) self.components.switch(frame, 9, 1, ui_state, "dynamic_timestep_shifting") @@ -776,36 +776,36 @@ def __create_masked_frame(self, master, row, ui_state): frame = self.components.section_frame(master, row) # Masked Training - self.components.label(frame, 0, 0, "Masked Training", + self.components.label(frame, 0, 0, "遮罩训练", tooltip="Masks the training samples to let the model focus on certain parts of the image. When enabled, one mask image is loaded for each training sample.") self.components.switch(frame, 0, 1, ui_state, "masked_training") # unmasked probability - self.components.label(frame, 1, 0, "Unmasked Probability", - tooltip="When masked training is enabled, specifies the number of training steps done on unmasked samples") + self.components.label(frame, 1, 0, "未遮罩概率", + tooltip="遮罩训练时未遮罩样本的训练步数") self.components.entry(frame, 1, 1, ui_state, "unmasked_probability", - extra_validate=check_range(lower=0, upper=1, message="Unmasked probability must be between 0 and 1")) + extra_validate=check_range(lower=0, upper=1, message="未遮罩概率必须在0到1之间")) # unmasked weight - self.components.label(frame, 2, 0, "Unmasked Weight", - tooltip="When masked training is enabled, specifies the loss weight of areas outside the masked region") + self.components.label(frame, 2, 0, "未遮罩权重", + tooltip="遮罩训练时遮罩外区域的损失权重") self.components.entry(frame, 2, 1, ui_state, "unmasked_weight", - extra_validate=check_range(lower=0, upper=1, message="Unmasked weight must be between 0 and 1")) + extra_validate=check_range(lower=0, upper=1, message="未遮罩权重必须在0到1之间")) # normalize masked area loss - self.components.label(frame, 3, 0, "Normalize Masked Area Loss", - tooltip="When masked training is enabled, normalizes the loss for each sample based on the sizes of the masked region") + self.components.label(frame, 3, 0, "归一化遮罩区域损失", + tooltip="遮罩训练时按遮罩区域大小归一化损失") self.components.switch(frame, 3, 1, ui_state, "normalize_masked_area_loss") # masked prior preservation - self.components.label(frame, 4, 0, "Masked Prior Preservation Weight", - tooltip="Preserves regions outside the mask using the original untrained model output as a target. Only available for LoRA training. If enabled, use a low unmasked weight.") + self.components.label(frame, 4, 0, "遮罩Prior保留权重", + tooltip="使用原始未训练模型输出保留遮罩外区域,仅限LoRA训练") self.components.entry(frame, 4, 1, ui_state, "masked_prior_preservation_weight", - extra_validate=check_range(lower=0, upper=1, message="Masked prior preservation weight must be between 0 and 1")) + extra_validate=check_range(lower=0, upper=1, message="遮罩Prior保留权重必须在0到1之间")) # use custom conditioning image - self.components.label(frame, 5, 0, "Custom Conditioning Image", - tooltip="When custom conditioning image is enabled, will use png postfix with -condlabel instead of automatically generated.It's suitable for special scenarios, such as object removal, allowing the model to learn a certain behavior concept") + self.components.label(frame, 5, 0, "自定义条件图像", + tooltip="启用自定义条件图像,适用于对象移除等特殊场景") self.components.switch(frame, 5, 1, ui_state, "custom_conditioning_image") def __create_loss_frame(self, master, row, controller, ui_state, @@ -813,13 +813,13 @@ def __create_loss_frame(self, master, row, controller, ui_state, frame = self.components.section_frame(master, row) # MSE Strength - self.components.label(frame, 0, 0, "MSE Strength", - tooltip="Mean Squared Error strength for custom loss settings. Strengths should generally sum to 1.") + self.components.label(frame, 0, 0, "MSE强度", + tooltip="均方误差强度,强度总和应为1") self.components.entry(frame, 0, 1, ui_state, "mse_strength", required=True) # MAE Strength - self.components.label(frame, 1, 0, "MAE Strength", - tooltip="Mean Absolute Error strength for custom loss settings. Strengths should generally sum to 1.") + self.components.label(frame, 1, 0, "MAE强度", + tooltip="平均绝对误差强度,强度总和应为1") self.components.entry(frame, 1, 1, ui_state, "mae_strength", required=True) # log-cosh Strength @@ -828,24 +828,24 @@ def __create_loss_frame(self, master, row, controller, ui_state, self.components.entry(frame, 2, 1, ui_state, "log_cosh_strength", required=True) # Huber Strength - self.components.label(frame, 3, 0, "Huber Strength", - tooltip="Huber loss strength for custom loss settings. Less sensitive to outliers than MSE. Strengths should generally sum to 1.") + self.components.label(frame, 3, 0, "Huber强度", + tooltip="Huber损失强度,比MSE对异常值更不敏感") self.components.entry(frame, 3, 1, ui_state, "huber_strength", required=True) # Huber Delta self.components.label(frame, 4, 0, "Huber Delta", - tooltip="Delta parameter for huber loss") + tooltip="Huber损失的delta参数") self.components.entry(frame, 4, 1, ui_state, "huber_delta", required=True) if supports_vb_loss: # VB Strength - self.components.label(frame, 5, 0, "VB Strength", - tooltip="Variational lower-bound strength for custom loss settings. Should be set to 1 for variational diffusion models") + self.components.label(frame, 5, 0, "VB强度", + tooltip="变分下界强度,变分扩散模型应设为1") self.components.entry(frame, 5, 1, ui_state, "vb_loss_strength", required=True) # Loss Weight function - self.components.label(frame, 6, 0, "Loss Weight Function", - tooltip="Choice of loss weight function. Can help the model learn details more accurately.") + self.components.label(frame, 6, 0, "损失权重函数", + tooltip="损失权重函数选择,帮助模型更准确学习细节") self.components.options(frame, 6, 1, [str(x) for x in list(LossWeight) if x.supports_flow_matching() == controller.is_flow_matching() or x == LossWeight.CONSTANT @@ -857,14 +857,14 @@ def __create_loss_frame(self, master, row, controller, ui_state, # Loss weight strength if not controller.is_flow_matching(): self.components.label(frame, row, 0, "Gamma", - tooltip="Inverse strength of loss weighting. Range: 1-20, only applies to Min SNR and P2.") + tooltip="损失权重逆强度,范围1-20,仅用于Min SNR和P2") self.components.entry(frame, row, 1, ui_state, "loss_weight_strength", - extra_validate=check_range(lower=1, upper=20, message="Gamma must be between 1 and 20")) + extra_validate=check_range(lower=1, upper=20, message="Gamma必须在1到20之间")) row += 1 # Loss Scaler - self.components.label(frame, row, 0, "Loss Scaler", - tooltip="Selects the type of loss scaling to use during training. Functionally equated as: Loss * selection") + self.components.label(frame, row, 0, "损失缩放器", + tooltip="训练损失缩放类型,等效于: Loss * 选择值") self.components.options(frame, row, 1, [str(x) for x in list(LossScaler)], ui_state, "loss_scaler") row += 1 @@ -872,10 +872,10 @@ def __create_layer_frame(self, master, row, controller, ui_state): presets = controller.get_layer_presets() self.components.layer_filter_entry(master, row, 0, ui_state, preset_var_name="layer_filter_preset", presets=presets, - preset_label="Layer Filter", + preset_label="层过滤器", preset_tooltip="Select a preset defining which layers to train, or select 'Custom' to define your own.\nA blank 'custom' field or 'Full' will train all layers.", entry_var_name="layer_filter", - entry_tooltip="Comma-separated list of diffusion layers to train. Regular expressions (if toggled) are supported. Any model layer with a matching name will be trained", + entry_tooltip="逗号分隔的训练层列表,支持正则表达式", regex_var_name="layer_filter_regex", - regex_tooltip="If enabled, layer filter patterns are interpreted as regular expressions. Otherwise, simple substring matching is used.", + regex_tooltip="启用后层过滤器使用正则匹配,否则使用子串匹配", ) diff --git a/modules/ui/BaseVideoToolUIView.py b/modules/ui/BaseVideoToolUIView.py index e60247585..c635b9c14 100644 --- a/modules/ui/BaseVideoToolUIView.py +++ b/modules/ui/BaseVideoToolUIView.py @@ -8,11 +8,11 @@ def __init__(self, components): def build_clip_extract_tab(self, frame, controller, ui_state): # single video - self.components.label(frame, 0, 0, "Single Video", - tooltip="Link to single video file to process.") + self.components.label(frame, 0, 0, "单个视频", + tooltip="单个视频文件链接") self.components.path_entry(frame, 0, 1, ui_state, "clip_single", mode="file", allow_model_files=False, allow_video_files=True) - self.components.button(frame, 0, 2, "Extract Single", + self.components.button(frame, 0, 2, "提取单个", command=lambda: self._extract_clips(False, controller)) # time range @@ -24,14 +24,14 @@ def build_clip_extract_tab(self, frame, controller, ui_state): # directory of videos self.components.label(frame, 2, 0, "Directory", - tooltip="Path to directory with multiple videos to process, including in subdirectories.") + tooltip="包含子目录的多视频处理目录") self.components.path_entry(frame, 2, 1, ui_state, "clip_list", mode="dir") - self.components.button(frame, 2, 2, "Extract Directory", + self.components.button(frame, 2, 2, "提取目录", command=lambda: self._extract_clips(True, controller)) # output directory - self.components.label(frame, 3, 0, "Output", - tooltip="Path to folder where extracted clips will be saved.") + self.components.label(frame, 3, 0, "输出", + tooltip="提取片段保存目录") self.components.path_entry(frame, 3, 1, ui_state, "clip_output", mode="dir") # output to subdirectories @@ -41,39 +41,39 @@ def build_clip_extract_tab(self, frame, controller, ui_state): self.components.switch(frame, 4, 1, ui_state, "output_subdir_clip") # split at cuts - self.components.label(frame, 5, 0, "Split at Cuts", + self.components.label(frame, 5, 0, "按剪辑分割", tooltip="If enabled, detect cuts in the input video and split at those points. \ Otherwise will split at any point, and clips may contain cuts.") self.components.switch(frame, 5, 1, ui_state, "split_cuts") # maximum length self.components.label(frame, 6, 0, "Max Length (s)", - tooltip="Maximum length in seconds for saved clips, larger clips will be broken into multiple small clips.") + tooltip="保存片段最大长度(秒),超出则分割") self.components.entry(frame, 6, 1, ui_state, "clip_length", width=220) # Set FPS - self.components.label(frame, 7, 0, "Set FPS", - tooltip="FPS to convert output videos to, set to 0 to keep original rate.") + self.components.label(frame, 7, 0, "设置FPS", + tooltip="输出视频帧率,0保持原始") self.components.entry(frame, 7, 1, ui_state, "clip_fps", width=220) # Remove borders - self.components.label(frame, 8, 0, "Remove Borders", - tooltip="Remove black borders from output clip") + self.components.label(frame, 8, 0, "移除边框", + tooltip="移除输出片段的黑色边框") self.components.switch(frame, 8, 1, ui_state, "clip_bordercrop") # Crop Variation - self.components.label(frame, 9, 0, "Crop Variation", + self.components.label(frame, 9, 0, "裁剪变化", tooltip="Output clips will be randomly cropped to +- the base aspect ratio, \ somewhat biased towards making square videos. Set to 0 to use only base aspect.") self.components.entry(frame, 9, 1, ui_state, "clip_crop", width=220) def build_image_extract_tab(self, frame, controller, ui_state): # single video - self.components.label(frame, 0, 0, "Single Video", - tooltip="Link to single video file to process.") + self.components.label(frame, 0, 0, "单个视频", + tooltip="单个视频文件链接") self.components.path_entry(frame, 0, 1, ui_state, "image_single", mode="file", allow_model_files=False, allow_video_files=True) - self.components.button(frame, 0, 2, "Extract Single", + self.components.button(frame, 0, 2, "提取单个", command=lambda: self._extract_images(False, controller)) # time range @@ -85,14 +85,14 @@ def build_image_extract_tab(self, frame, controller, ui_state): # directory of videos self.components.label(frame, 2, 0, "Directory", - tooltip="Path to directory with multiple videos to process, including in subdirectories.") + tooltip="包含子目录的多视频处理目录") self.components.path_entry(frame, 2, 1, ui_state, "image_list", mode="dir") - self.components.button(frame, 2, 2, "Extract Directory", + self.components.button(frame, 2, 2, "提取目录", command=lambda: self._extract_images(True, controller)) # output directory - self.components.label(frame, 3, 0, "Output", - tooltip="Path to folder where extracted images will be saved.") + self.components.label(frame, 3, 0, "输出", + tooltip="提取图像保存目录") self.components.path_entry(frame, 3, 1, ui_state, "image_output", mode="dir") # output to subdirectories @@ -108,45 +108,45 @@ def build_image_extract_tab(self, frame, controller, ui_state): self.components.entry(frame, 5, 1, ui_state, "capture_rate", width=220) # blur removal - self.components.label(frame, 6, 0, "Blur Removal", + self.components.label(frame, 6, 0, "模糊移除", tooltip="Threshold for removal of blurry images, relative to all others. \ For example at 0.2, the blurriest 20%% of the final selected frames will not be saved.") self.components.entry(frame, 6, 1, ui_state, "blur_threshold", width=220) # Remove borders - self.components.label(frame, 7, 0, "Remove Borders", - tooltip="Remove black borders from output image") + self.components.label(frame, 7, 0, "移除边框", + tooltip="移除输出图像的黑色边框") self.components.switch(frame, 7, 1, ui_state, "image_bordercrop") # Crop Variation - self.components.label(frame, 8, 0, "Crop Variation", + self.components.label(frame, 8, 0, "裁剪变化", tooltip="Output images will be randomly cropped to +- the base aspect ratio, \ somewhat biased towards making square images. Set to 0 to use only base sapect.") self.components.entry(frame, 8, 1, ui_state, "image_crop", width=220) def build_video_download_tab(self, frame, controller, ui_state): # link - self.components.label(frame, 0, 0, "Single Link", - tooltip="Link to video/playlist to download. Uses yt-dlp, supports youtube, twitch, instagram, and many other sites.") + self.components.label(frame, 0, 0, "单个链接", + tooltip="视频/播放列表下载链接,支持YouTube等") self.components.entry(frame, 0, 1, ui_state, "download_link", width=220) - self.components.button(frame, 0, 2, "Download Link", + self.components.button(frame, 0, 2, "下载链接", command=lambda: self._download(False, controller)) # link list - self.components.label(frame, 1, 0, "Link List", - tooltip="Path to txt file with list of links separated by newlines.") + self.components.label(frame, 1, 0, "链接列表", + tooltip="链接列表txt文件路径") self.components.path_entry(frame, 1, 1, ui_state, "download_list", mode="file", allow_model_files=False) - self.components.button(frame, 1, 2, "Download List", + self.components.button(frame, 1, 2, "下载列表", command=lambda: self._download(True, controller)) # output directory - self.components.label(frame, 2, 0, "Output", - tooltip="Path to folder where downloaded videos will be saved.") + self.components.label(frame, 2, 0, "输出", + tooltip="下载视频保存目录") self.components.path_entry(frame, 2, 1, ui_state, "download_output", mode="dir") # additional args - self.components.label(frame, 3, 0, "Additional Args", + self.components.label(frame, 3, 0, "附加参数", tooltip="Any additional arguments to pass to yt-dlp, for example '--restrict-filenames --force-overwrite'. \ Default args will hide most terminal outputs.") self._create_textbox(frame, 3, 1, 220, 90, ui_state, "download_args") diff --git a/modules/ui/PySide6CaptionUIView.py b/modules/ui/PySide6CaptionUIView.py index 620e4faab..1b5ae8c30 100644 --- a/modules/ui/PySide6CaptionUIView.py +++ b/modules/ui/PySide6CaptionUIView.py @@ -4,7 +4,7 @@ class PySide6CaptionUIView(QDialog): def __init__(self, parent, controller): super().__init__(parent) - self.setWindowTitle("Dataset Tool") + self.setWindowTitle("数据集工具") lo = QVBoxLayout(self) lo.addWidget(QLabel("The dataset tool has not been ported to Qt6 yet.\nYou can still use it by launching the CustomTkinter UI: scripts/train_ui_ctk.py")) ok = QPushButton("OK") diff --git a/modules/ui/PySide6ConceptTabView.py b/modules/ui/PySide6ConceptTabView.py index a158dceed..04ad1f724 100644 --- a/modules/ui/PySide6ConceptTabView.py +++ b/modules/ui/PySide6ConceptTabView.py @@ -26,8 +26,8 @@ def __init__(self, master, controller: ConceptTabController, ui_state): attr_name="concept_file_name", config_dir="training_concepts", default_config_name="concepts.json", - add_button_text="Add Concept", - add_button_tooltip="Adds a new concept to the current config.", + add_button_text="添加数据集", + add_button_tooltip="向当前配置添加新数据集", is_full_width=False, show_toggle_button=True, ) @@ -72,7 +72,7 @@ def _on_filter(text): self.filter_var._bind_widget(lambda v: filter_combo.setCurrentText(v)) self.show_disabled_var = QtVar(True) - show_disabled_cb = QCheckBox("Show Disabled", toolbar) + show_disabled_cb = QCheckBox("显示禁用项", toolbar) show_disabled_cb.setChecked(True) row_lo.addWidget(show_disabled_cb) @@ -82,7 +82,7 @@ def _on_show_disabled(state): show_disabled_cb.stateChanged.connect(_on_show_disabled) self.show_disabled_var._bind_widget(lambda v: show_disabled_cb.setChecked(bool(v))) - clear_btn = QPushButton("Clear", toolbar) + clear_btn = QPushButton("清除", toolbar) clear_btn.setFixedWidth(50) clear_btn.clicked.connect(self._reset_filters) row_lo.addWidget(clear_btn) diff --git a/modules/ui/PySide6ConceptWindowView.py b/modules/ui/PySide6ConceptWindowView.py index bbe6f6dff..a6492f69b 100644 --- a/modules/ui/PySide6ConceptWindowView.py +++ b/modules/ui/PySide6ConceptWindowView.py @@ -39,7 +39,7 @@ def __init__( self._preview_augmentations = True self.bucket_fig = None - self.setWindowTitle("Concept") + self.setWindowTitle("数据集") self.resize(800, 700) outer = QGridLayout(self) @@ -60,7 +60,7 @@ def __init__( pyside6_components._layout(gen_frame).setColumnStretch(2, 1) self.build_general_tab(gen_frame, controller, ui_state, text_ui_state) pyside6_components._pack_form(gen_frame) - tabs.addTab(gen_scroll, "general") + tabs.addTab(gen_scroll, "常规") # --- image augmentation tab --- img_scroll = QScrollArea() @@ -94,12 +94,12 @@ def __init__( prev_btn = QPushButton("<", preview_panel) prev_btn.setFixedWidth(40) prev_btn.clicked.connect(self._prev_image_preview) - update_btn = QPushButton("Update Preview", preview_panel) + update_btn = QPushButton("更新预览", preview_panel) update_btn.clicked.connect(self._update_image_preview) next_btn = QPushButton(">", preview_panel) next_btn.setFixedWidth(40) next_btn.clicked.connect(self._next_image_preview) - self._aug_checkbox = QCheckBox("Show Augmentations", preview_panel) + self._aug_checkbox = QCheckBox("显示增强", preview_panel) self._aug_checkbox.setChecked(True) self._aug_checkbox.toggled.connect(lambda checked: self._on_aug_toggle(checked)) pb_lo.addWidget(prev_btn, 1, 0) @@ -119,7 +119,7 @@ def __init__( pb_lo.addWidget(self._caption_box, 4, 0, 1, 3) lo_img_outer.addWidget(preview_panel, 0, 1, Qt.AlignTop) - tabs.addTab(img_scroll, "image augmentation") + tabs.addTab(img_scroll, "图像增强") # --- text augmentation tab --- text_scroll = QScrollArea() @@ -130,7 +130,7 @@ def __init__( pyside6_components._layout(text_frame).setColumnStretch(3, 1) self.build_text_augmentation_tab(text_frame, controller, text_ui_state) pyside6_components._pack_form(text_frame) - tabs.addTab(text_scroll, "text augmentation") + tabs.addTab(text_scroll, "文本增强") # --- statistics tab --- stats_scroll = QScrollArea() @@ -167,7 +167,7 @@ def __init__( stats_lo.addWidget(self.canvas, 19, 0, 2, 4) - tabs.addTab(stats_scroll, "statistics") + tabs.addTab(stats_scroll, "统计") ok = QPushButton("ok", self) ok.clicked.connect(self._ok) diff --git a/modules/ui/PySide6ConfigListView.py b/modules/ui/PySide6ConfigListView.py index 6a369d6c7..2e2da6821 100644 --- a/modules/ui/PySide6ConfigListView.py +++ b/modules/ui/PySide6ConfigListView.py @@ -90,9 +90,9 @@ def _update_toggle_button_text(self): return self._update_item_enabled_state() if self.toggle_button is not None: - self.toggle_button.setText("Disable" if self._is_current_item_enabled else "Enable") + self.toggle_button.setText("禁用" if self._is_current_item_enabled else "启用") def _show_name_dialog(self, callback): - text, ok = QInputDialog.getText(self.master, "name", "Name") + text, ok = QInputDialog.getText(self.master, "name", "名称") if ok and text: callback(text) diff --git a/modules/ui/PySide6ConvertModelUIView.py b/modules/ui/PySide6ConvertModelUIView.py index 6a07be80b..51aff6aff 100644 --- a/modules/ui/PySide6ConvertModelUIView.py +++ b/modules/ui/PySide6ConvertModelUIView.py @@ -15,7 +15,7 @@ def __init__(self, parent, controller: ConvertModelUIController): self.ui_state = PySide6UIState(controller.convert_model_args) self._dynamic_frame = None - self.setWindowTitle("Convert models") + self.setWindowTitle("转换模型") self.resize(600, 380) _pad = pyside6_components.PAD diff --git a/modules/ui/PySide6GenerateCaptionsWindowView.py b/modules/ui/PySide6GenerateCaptionsWindowView.py index 09d82f74b..3363a5f06 100644 --- a/modules/ui/PySide6GenerateCaptionsWindowView.py +++ b/modules/ui/PySide6GenerateCaptionsWindowView.py @@ -18,24 +18,24 @@ def __init__(self, parent, controller: GenerateCaptionsWindowController, path, p self.controller = controller - self.mode_var = ctk.StringVar(self, "Create if absent") - self.modes = ["Replace all captions", "Create if absent", "Add as new line"] + self.mode_var = ctk.StringVar(self, "不存在则创建") + self.modes = ["替换所有标签", "不存在则创建", "添加为新行"] self.model_var = ctk.StringVar(self, "Blip") self.models = ["Blip", "Blip2", "WD14 VIT v2"] - self.title("Batch generate captions") + self.title("批量生成标签") self.geometry("360x360") self.resizable(True, True) self.frame = ctk.CTkFrame(self, width=600, height=300) self.frame.grid(row=0, column=0, sticky="nsew", padx=10, pady=10) - self.model_label = ctk.CTkLabel(self.frame, text="Model", width=100) + self.model_label = ctk.CTkLabel(self.frame, text="模型", width=100) self.model_label.grid(row=0, column=0, sticky="w", padx=5, pady=5) self.model_dropdown = ctk.CTkOptionMenu(self.frame, variable=self.model_var, values=self.models, dynamic_resizing=False, width=200) self.model_dropdown.grid(row=0, column=1, sticky="w", padx=5, pady=5) - self.path_label = ctk.CTkLabel(self.frame, text="Folder", width=100) + self.path_label = ctk.CTkLabel(self.frame, text="文件夹", width=100) self.path_label.grid(row=1, column=0, sticky="w",padx=5, pady=5) self.path_entry = ctk.CTkEntry(self.frame, width=150) self.path_entry.insert(0, path) @@ -43,7 +43,7 @@ def __init__(self, parent, controller: GenerateCaptionsWindowController, path, p self.path_button = ctk.CTkButton(self.frame, width=30, text="...", command=lambda: self.browse_for_path(self.path_entry)) self.path_button.grid(row=1, column=1, sticky="e", padx=5, pady=5) - self.caption_label = ctk.CTkLabel(self.frame, text="Initial Caption", width=100) + self.caption_label = ctk.CTkLabel(self.frame, text="初始标签", width=100) self.caption_label.grid(row=2, column=0, sticky="w", padx=5, pady=5) self.caption_entry = ctk.CTkEntry(self.frame, width=200) self.caption_entry.grid(row=2, column=1, sticky="w", padx=5, pady=5) @@ -74,7 +74,7 @@ def __init__(self, parent, controller: GenerateCaptionsWindowController, path, p self.progress = ctk.CTkProgressBar(self.frame, orientation="horizontal", mode="determinate", width=200) self.progress.grid(row=7, column=1, sticky="w", padx=5, pady=5) - self.create_captions_button = ctk.CTkButton(self.frame, text="Create Captions", width=310, command=self._on_create_captions) + self.create_captions_button = ctk.CTkButton(self.frame, text="创建标签", width=310, command=self._on_create_captions) self.create_captions_button.grid(row=8, column=0, columnspan=2, sticky="w", padx=5, pady=5) self.frame.pack(fill="both", expand=True) diff --git a/modules/ui/PySide6GenerateMasksWindowView.py b/modules/ui/PySide6GenerateMasksWindowView.py index 631179fac..7911559b0 100644 --- a/modules/ui/PySide6GenerateMasksWindowView.py +++ b/modules/ui/PySide6GenerateMasksWindowView.py @@ -25,24 +25,24 @@ def __init__(self, parent, controller: GenerateMasksWindowController, path, pare if path is None: path = "" - self.mode_var = ctk.StringVar(self, "Create if absent") - self.modes = ["Replace all masks", "Create if absent", "Add to existing", "Subtract from existing", "Blend with existing"] + self.mode_var = ctk.StringVar(self, "不存在则创建") + self.modes = ["替换所有遮罩", "不存在则创建", "添加到现有", "从现有减去", "与现有混合"] self.model_var = ctk.StringVar(self, "ClipSeg") - self.models = ["ClipSeg", "Rembg", "Rembg-Human", "Hex Color"] + self.models = ["ClipSeg", "Rembg", "Rembg-Human", "十六进制颜色"] - self.title("Batch generate masks") + self.title("批量生成遮罩") self.geometry("360x430") self.resizable(True, True) self.frame = ctk.CTkFrame(self, width=600, height=300) self.frame.grid(row=0, column=0, sticky="nsew", padx=10, pady=10) - self.model_label = ctk.CTkLabel(self.frame, text="Model", width=100) + self.model_label = ctk.CTkLabel(self.frame, text="模型", width=100) self.model_label.grid(row=0, column=0, sticky="w", padx=5, pady=5) self.model_dropdown = ctk.CTkOptionMenu(self.frame, variable=self.model_var, values=self.models, dynamic_resizing=False, width=200) self.model_dropdown.grid(row=0, column=1, sticky="w", padx=5, pady=5) - self.path_label = ctk.CTkLabel(self.frame, text="Folder", width=100) + self.path_label = ctk.CTkLabel(self.frame, text="文件夹", width=100) self.path_label.grid(row=1, column=0, sticky="w",padx=5, pady=5) self.path_entry = ctk.CTkEntry(self.frame, width=150) self.path_entry.insert(0, path) @@ -50,7 +50,7 @@ def __init__(self, parent, controller: GenerateMasksWindowController, path, pare self.path_button = ctk.CTkButton(self.frame, width=30, text="...", command=lambda: self.browse_for_path(self.path_entry)) self.path_button.grid(row=1, column=1, sticky="e", padx=5, pady=5) - self.prompt_label = ctk.CTkLabel(self.frame, text="Prompt", width=100) + self.prompt_label = ctk.CTkLabel(self.frame, text="提示词", width=100) self.prompt_label.grid(row=2, column=0, sticky="w",padx=5, pady=5) self.prompt_entry = ctk.CTkEntry(self.frame, width=200) self.prompt_entry.grid(row=2, column=1, sticky="w", padx=5, pady=5) @@ -60,19 +60,19 @@ def __init__(self, parent, controller: GenerateMasksWindowController, path, pare self.mode_dropdown = ctk.CTkOptionMenu(self.frame, variable=self.mode_var, values=self.modes, dynamic_resizing=False, width=200) self.mode_dropdown.grid(row=3, column=1, sticky="w", padx=5, pady=5) - self.threshold_label = ctk.CTkLabel(self.frame, text="Threshold", width=100) + self.threshold_label = ctk.CTkLabel(self.frame, text="阈值", width=100) self.threshold_label.grid(row=4, column=0, sticky="w", padx=5, pady=5) self.threshold_entry = ctk.CTkEntry(self.frame, width=200, placeholder_text="0.0 - 1.0") self.threshold_entry.insert(0, "0.3") self.threshold_entry.grid(row=4, column=1, sticky="w", padx=5, pady=5) - self.smooth_label = ctk.CTkLabel(self.frame, text="Smooth", width=100) + self.smooth_label = ctk.CTkLabel(self.frame, text="平滑", width=100) self.smooth_label.grid(row=5, column=0, sticky="w", padx=5, pady=5) self.smooth_entry = ctk.CTkEntry(self.frame, width=200, placeholder_text="5") self.smooth_entry.insert(0, 5) self.smooth_entry.grid(row=5, column=1, sticky="w", padx=5, pady=5) - self.expand_label = ctk.CTkLabel(self.frame, text="Expand", width=100) + self.expand_label = ctk.CTkLabel(self.frame, text="展开", width=100) self.expand_label.grid(row=6, column=0, sticky="w", padx=5, pady=5) self.expand_entry = ctk.CTkEntry(self.frame, width=200, placeholder_text="10") self.expand_entry.insert(0, 10) @@ -95,7 +95,7 @@ def __init__(self, parent, controller: GenerateMasksWindowController, path, pare self.progress = ctk.CTkProgressBar(self.frame, orientation="horizontal", mode="determinate", width=200) self.progress.grid(row=9, column=1, sticky="w", padx=5, pady=5) - self.create_masks_button = ctk.CTkButton(self.frame, text="Create Masks", width=310, command=self._on_create_masks) + self.create_masks_button = ctk.CTkButton(self.frame, text="创建遮罩", width=310, command=self._on_create_masks) self.create_masks_button.grid(row=10, column=0, columnspan=2, sticky="w", padx=5, pady=5) self.frame.pack(fill="both", expand=True) diff --git a/modules/ui/PySide6OptimizerParamsWindowView.py b/modules/ui/PySide6OptimizerParamsWindowView.py index 779e509ac..cf7e1f959 100644 --- a/modules/ui/PySide6OptimizerParamsWindowView.py +++ b/modules/ui/PySide6OptimizerParamsWindowView.py @@ -24,7 +24,7 @@ def __init__(self, parent, controller: OptimizerParamsWindowController, ui_state self.muon_adam_button = None self._dynamic_frame = None - self.setWindowTitle("Optimizer Settings") + self.setWindowTitle("优化器设置") self.resize(800, 500) outer = QGridLayout(self) diff --git a/modules/ui/PySide6ProfilingWindowView.py b/modules/ui/PySide6ProfilingWindowView.py index b8c0a41e1..721920139 100644 --- a/modules/ui/PySide6ProfilingWindowView.py +++ b/modules/ui/PySide6ProfilingWindowView.py @@ -15,7 +15,7 @@ def __init__(self, parent, controller: ProfilingWindowController): self._controller = controller - self.setWindowTitle("Profiling") + self.setWindowTitle("性能分析") self.resize(512, 512) outer = QGridLayout(self) @@ -33,13 +33,13 @@ def set_message(self, text: str): def set_profiling_active(self, active: bool): if active: self._message_label.setText("Profiling active...") - self._profile_button.setText("End Profiling") + self._profile_button.setText("结束分析") with contextlib.suppress(RuntimeError): self._profile_button.clicked.disconnect() self._profile_button.clicked.connect(self._controller.end_profiler) else: - self._message_label.setText("Inactive") - self._profile_button.setText("Start Profiling") + self._message_label.setText("未激活") + self._profile_button.setText("开始分析") with contextlib.suppress(RuntimeError): self._profile_button.clicked.disconnect() self._profile_button.clicked.connect(self._controller.start_profiler) diff --git a/modules/ui/PySide6SampleParamsWindowView.py b/modules/ui/PySide6SampleParamsWindowView.py index 054712ccc..59df7eda6 100644 --- a/modules/ui/PySide6SampleParamsWindowView.py +++ b/modules/ui/PySide6SampleParamsWindowView.py @@ -12,7 +12,7 @@ def __init__(self, parent, controller: SampleParamsWindowController, ui_state): QDialog.__init__(self, parent if isinstance(parent, QWidget) else None) BaseSampleParamsWindowView.__init__(self, pyside6_components) - self.setWindowTitle("Sample") + self.setWindowTitle("采样") self.resize(800, 500) outer = QGridLayout(self) diff --git a/modules/ui/PySide6SampleWindowView.py b/modules/ui/PySide6SampleWindowView.py index 6f49a62c8..3329d8b9c 100644 --- a/modules/ui/PySide6SampleWindowView.py +++ b/modules/ui/PySide6SampleWindowView.py @@ -22,7 +22,7 @@ def __init__(self, parent, controller: SampleWindowController): QDialog.__init__(self, parent) BaseSampleWindowView.__init__(self, pyside6_components) - self.setWindowTitle("Sample") + self.setWindowTitle("采样") self.resize(1200, 800) self.ui_state = PySide6UIState(controller.sample) diff --git a/modules/ui/PySide6SamplingTabView.py b/modules/ui/PySide6SamplingTabView.py index d1d7c5778..09399c7fb 100644 --- a/modules/ui/PySide6SamplingTabView.py +++ b/modules/ui/PySide6SamplingTabView.py @@ -17,8 +17,8 @@ def __init__(self, master, controller: SamplingTabController, ui_state): attr_name="sample_definition_file_name", config_dir="training_samples", default_config_name="samples.json", - add_button_text="Add Sample", - add_button_tooltip="Add a new sample configuration.", + add_button_text="添加采样", + add_button_tooltip="添加新的采样配置", is_full_width=True, show_toggle_button=True, ) diff --git a/modules/ui/PySide6SchedulerParamsWindowView.py b/modules/ui/PySide6SchedulerParamsWindowView.py index 68f9c5ef1..9e9f6daf0 100644 --- a/modules/ui/PySide6SchedulerParamsWindowView.py +++ b/modules/ui/PySide6SchedulerParamsWindowView.py @@ -41,13 +41,13 @@ def __init__(self, master, element, i, open_command, remove_command, clone_comma # Key self.key = pyside6_components.entry(self, 0, 1, self.ui_state, "key", - tooltip="Key name for an argument in your scheduler", + tooltip="调度器参数键名", wide_tooltip=True, width=50) self.key.editingFinished.connect(save_command) # Value self.value = pyside6_components.entry(self, 0, 2, self.ui_state, "value", - tooltip="Value for an argument in your scheduler. Some special values can be used, wrapped in percent signs: LR, EPOCHS, STEPS_PER_EPOCH, TOTAL_STEPS, SCHEDULER_STEPS. Note that OneTrainer calls step() after every individual learning step, not every epoch, so what Torch calls 'epoch' you should treat as 'step'.", + tooltip="调度器参数值,可用特殊值:LR, EPOCHS, TOTAL_STEPS等", wide_tooltip=True, width=50) self.value.editingFinished.connect(save_command) @@ -67,7 +67,7 @@ def __init__(self, parent, controller: SchedulerParamsWindowController, ui_state # delete on close so entry widgets and the field validators they register globally are freed, not leaked self.finished.connect(self.deleteLater) - self.setWindowTitle("Learning Rate Scheduler Settings") + self.setWindowTitle("学习率调度器设置") self.resize(800, 500) outer = QGridLayout(self) diff --git a/modules/ui/PySide6TimestepDistributionWindowView.py b/modules/ui/PySide6TimestepDistributionWindowView.py index 1e92fedc5..bb2c564d5 100644 --- a/modules/ui/PySide6TimestepDistributionWindowView.py +++ b/modules/ui/PySide6TimestepDistributionWindowView.py @@ -15,7 +15,7 @@ def __init__(self, parent, controller: TimestepDistributionWindowController, ui_ # delete on close so entry widgets and the field validators they register globally are freed, not leaked self.finished.connect(self.deleteLater) - self.setWindowTitle("Timestep Distribution") + self.setWindowTitle("时间步分布") self.resize(900, 600) self._controller = controller @@ -34,7 +34,7 @@ def __init__(self, parent, controller: TimestepDistributionWindowController, ui_ lo.addWidget(self._canvas, 0, 3, 8, 1) self._update_preview() - update_btn = QPushButton("Update Preview", frame) + update_btn = QPushButton("更新预览", frame) update_btn.clicked.connect(self._update_preview) lo.addWidget(update_btn, 8, 3) diff --git a/modules/ui/PySide6TopBarView.py b/modules/ui/PySide6TopBarView.py index 68037fb73..d1fa054c0 100644 --- a/modules/ui/PySide6TopBarView.py +++ b/modules/ui/PySide6TopBarView.py @@ -43,7 +43,7 @@ def _forget_dropdown(self, widget): widget.deleteLater() def _show_save_dialog(self, initial_dir: str, callback): - path, _ = QFileDialog.getSaveFileName(self, "Save config", initial_dir, "JSON (*.json)") + path, _ = QFileDialog.getSaveFileName(self, "保存配置", initial_dir, "JSON (*.json)") if path: # the native dialog doesn't reliably append the filter's extension on every platform if not path.endswith(".json"): @@ -51,6 +51,6 @@ def _show_save_dialog(self, initial_dir: str, callback): callback(path) def _show_open_dialog(self, initial_dir: str, callback): - path, _ = QFileDialog.getOpenFileName(self, "Load config", initial_dir, "JSON (*.json)") + path, _ = QFileDialog.getOpenFileName(self, "加载配置", initial_dir, "JSON (*.json)") if path: callback(path) diff --git a/modules/ui/PySide6TrainUIView.py b/modules/ui/PySide6TrainUIView.py index 4dbd6476c..11d057903 100644 --- a/modules/ui/PySide6TrainUIView.py +++ b/modules/ui/PySide6TrainUIView.py @@ -100,8 +100,8 @@ def closeEvent(self, event): if self.controller.training_thread is not None and self.controller.training_thread.is_alive(): QMessageBox.warning( self, - "Training in progress", - "A training is currently running. Stop the training before closing the window.", + "训练进行中", + "训练正在运行中,关闭窗口前请先停止训练", ) event.ignore() return @@ -151,7 +151,7 @@ def save_default(self): def show_validation_errors(self, errors: list[str]): bullet_list = "\n".join(f"• {e}" for e in errors) - QMessageBox.critical(self, "Cannot Start Training", + QMessageBox.critical(self, "无法开始训练", f"Please fix the following errors before training:\n\n{bullet_list}") def open_dataset_tool(self): @@ -247,35 +247,43 @@ def _configure_embedding_frame(self, frame): def _create_tabs(self): general_page = self._create_scrollable_tab(self._configure_general_frame) self.tabview.addTab(general_page, "general") + self.tabview.setTabText(self.tabview.indexOf(general_page), "常规") self._tab_widgets["general"] = general_page self.model_tab = PySide6ModelTabView(None, ModelTabController(self.controller.train_config), self.ui_state) self.tabview.addTab(self.model_tab, "model") + self.tabview.setTabText(self.tabview.indexOf(self.model_tab), "模型") self._tab_widgets["model"] = self.model_tab data_page = self._create_scrollable_tab(self._configure_data_frame) self.tabview.addTab(data_page, "data") + self.tabview.setTabText(self.tabview.indexOf(data_page), "数据") self._tab_widgets["data"] = data_page concepts_page = QWidget() self.concepts_tab = PySide6ConceptTabView(concepts_page, ConceptTabController(self.controller.train_config), self.ui_state) self.tabview.addTab(concepts_page, "concepts") + self.tabview.setTabText(self.tabview.indexOf(concepts_page), "数据集") self._tab_widgets["concepts"] = concepts_page self.training_tab = PySide6TrainingTabView(None, TrainingTabController(self.controller.train_config), self.ui_state) self.tabview.addTab(self.training_tab, "training") + self.tabview.setTabText(self.tabview.indexOf(self.training_tab), "训练") self._tab_widgets["training"] = self.training_tab sampling_page = self.create_sampling_tab() self.tabview.addTab(sampling_page, "sampling") + self.tabview.setTabText(self.tabview.indexOf(sampling_page), "采样") self._tab_widgets["sampling"] = sampling_page backup_page = self._create_scrollable_tab(self._configure_backup_frame) self.tabview.addTab(backup_page, "backup") + self.tabview.setTabText(self.tabview.indexOf(backup_page), "备份") self._tab_widgets["backup"] = backup_page tools_page = self._create_scrollable_tab(self._configure_tools_frame) self.tabview.addTab(tools_page, "tools") + self.tabview.setTabText(self.tabview.indexOf(tools_page), "工具") self._tab_widgets["tools"] = tools_page additional_embeddings_page = QWidget() @@ -285,10 +293,12 @@ def _create_tabs(self): self.ui_state, ) self.tabview.addTab(additional_embeddings_page, "additional embeddings") + self.tabview.setTabText(self.tabview.indexOf(additional_embeddings_page), "附加嵌入") self._tab_widgets["additional embeddings"] = additional_embeddings_page self.cloud_tab = PySide6CloudTabView(None, CloudTabController(self.controller.train_config, self), self.ui_state) self.tabview.addTab(self.cloud_tab, "cloud") + self.tabview.setTabText(self.tabview.indexOf(self.cloud_tab), "云端") self._tab_widgets["cloud"] = self.cloud_tab def create_sampling_tab(self): @@ -357,10 +367,12 @@ def change_training_method(self, training_method: TrainingMethod): if training_method == TrainingMethod.LORA and 'LoRA' not in self._tab_widgets: self.lora_tab = PySide6LoraTabView(None, LoraTabController(self.controller.train_config), self.ui_state) self.tabview.addTab(self.lora_tab, 'LoRA') + self.tabview.setTabText(self.tabview.indexOf(self.lora_tab), 'LoRA') self._tab_widgets['LoRA'] = self.lora_tab if training_method == TrainingMethod.EMBEDDING and 'embedding' not in self._tab_widgets: tab_page = self._create_scrollable_tab(self._configure_embedding_frame) self.tabview.addTab(tab_page, 'embedding') + self.tabview.setTabText(self.tabview.indexOf(tab_page), '嵌入') self._tab_widgets['embedding'] = tab_page def load_preset(self): @@ -371,11 +383,11 @@ def _set_training_button_style(self, mode: str): if not self.training_button: return styles = { - "idle": ("Start Training", True, "#198754", "white"), - "running": ("Stop Training", True, "#dc3545", "white"), + "idle": ("开始训练", True, "#198754", "white"), + "running": ("停止训练", True, "#dc3545", "white"), "stopping": ("Stopping...", False, "#dc3545", "white"), } - text, enabled, bg, fg = styles.get(mode, ("Start Training", True, "#198754", "white")) + text, enabled, bg, fg = styles.get(mode, ("开始训练", True, "#198754", "white")) self.training_button.setText(text) self.training_button.setEnabled(enabled) self.training_button.setStyleSheet( @@ -385,14 +397,14 @@ def _set_training_button_style(self, mode: str): def export_training(self): file_path, _ = QFileDialog.getSaveFileName( - self, "Export Training Config", "config.json", + self, "导出训练配置", "config.json", "JSON Files (*.json);;All Files (*.*)" ) if file_path: self.controller.export_training(file_path) def generate_debug_package(self): - dir_path = QFileDialog.getExistingDirectory(self, "Select Directory to Save Debug Package", ".") + dir_path = QFileDialog.getExistingDirectory(self, "选择调试包保存目录", ".") if not dir_path: return self.controller.generate_debug_package(Path(dir_path) / "OneTrainer_debug_report.zip") diff --git a/modules/ui/PySide6VideoToolUIView.py b/modules/ui/PySide6VideoToolUIView.py index 18772adf6..299b4c48b 100644 --- a/modules/ui/PySide6VideoToolUIView.py +++ b/modules/ui/PySide6VideoToolUIView.py @@ -33,7 +33,7 @@ def __init__(self, parent, controller: VideoToolUIController): ui_state = PySide6UIState(controller.args) - self.setWindowTitle("Video Tools") + self.setWindowTitle("视频工具") self.resize(700, 750) outer = QGridLayout(self) @@ -79,7 +79,7 @@ def _build_status_bar(self): 150, 150, Qt.KeepAspectRatio, Qt.SmoothTransformation ) ) - self._preview_caption_label = QLabel("Preview image", frame) + self._preview_caption_label = QLabel("预览图", frame) self._preview_caption_label.setWordWrap(True) preview_col = QWidget(frame) @@ -93,7 +93,7 @@ def _build_status_bar(self): self._status_box.setReadOnly(True) self._status_box.setFixedHeight(160) self._status_box.setMinimumWidth(300) - self._status_box.setPlainText("Current status") + self._status_box.setPlainText("当前状态") lo.addWidget(self._status_box, 0, 1, Qt.AlignTop) return frame diff --git a/zh_cn_map.py b/zh_cn_map.py new file mode 100644 index 000000000..c89a494ac --- /dev/null +++ b/zh_cn_map.py @@ -0,0 +1,689 @@ +# OneTrainer UI 中文翻译映射 +# 由 Hermes Agent 生成 + +TRANSLATIONS = { + # === 顶部栏 === + "Load Preset": "加载预设", + "Load config": "加载配置", + "Save config": "保存配置", + "Wiki": "Wiki", + "OneTrainer": "OneTrainer", + + # === 训练标签页 === + "Concept": "数据集", + "Training": "训练", + "Sampling": "采样", + "Backup": "备份", + "Cloud": "云端", + "Model": "模型", + "Additional Embeddings": "附加嵌入", + + # === 概念/数据集 === + "Add Concept": "添加数据集", + "Add Config": "添加配置", + "Add Sample": "添加采样", + "Name": "名称", + "Path": "路径", + "Enabled": "启用", + "Concept Type": "数据集类型", + "Prompt Source": "提示词来源", + "Include Subdirectories": "包含子目录", + "Resolution Override": "分辨率覆盖", + "Image Variations": "图像变体", + "Text Variations": "文本变体", + "Crop Jitter": "裁剪抖动", + "Crop Variation": "裁剪变化", + "Balancing": "平衡策略", + "Loss Weight": "损失权重", + "Tag Shuffling": "标签打乱", + "Tag Dropout": "标签丢弃", + "Keep Tag Count": "保留标签数", + "Tag Delimiter": "标签分隔符", + "Special Tags Regex": "特殊标签正则", + "Special Dropout Tags": "特殊丢弃标签", + "Dropout Mode": "丢弃模式", + "Captialization Mode": "大小写模式", + "Randomize Capitalization": "随机大小写", + "Force Lowercase": "强制小写", + "Probability": "概率", + "Random": "随机", + "Random Weighted": "随机加权", + "Fixed": "固定", + "Full": "全部", + "None": "无", + "Random Flip": "随机翻转", + "Random Rotation": "随机旋转", + "Random Brightness": "随机亮度", + "Random Contrast": "随机对比度", + "Random Hue": "随机色相", + "Random Saturation": "随机饱和度", + "Random Rotate and Crop": "随机旋转裁剪", + "Circular Mask Generation": "圆形遮罩生成", + "Masked Training": "遮罩训练", + "Blacklist": "黑名单", + "Whitelist": "白名单", + "Enable or disable this concept": "启用或禁用此数据集", + "Name of the concept": "数据集名称", + "Path where the training data is located": "训练数据所在路径", + "Enables random cropping of samples": "启用样本随机裁剪", + "Enables tag shuffling": "启用标签打乱", + "The delimiter between tags": "标签之间的分隔符", + "The loss multiplyer for this concept.": "此数据集的损失乘数", + "From image file name": "从图像文件名", + "From single text file": "从单个文本文件", + "From text file per sample": "从每样本文本文件", + "Includes images from subdirectories into the dataset": "将子目录中的图像包含到数据集中", + "Enable this augmentation with fixed values": "以固定值启用此增强", + "Enable this augmentation with random values": "以随机值启用此增强", + "Randomly flip the sample during training": "训练时随机翻转样本", + "Randomly rotates the sample during training": "训练时随机旋转样本", + "Randomly adjusts the brightness of the sample during training": "训练时随机调整样本亮度", + "Randomly adjusts the contrast of the sample during training": "训练时随机调整样本对比度", + "Randomly adjusts the hue of the sample during training": "训练时随机调整样本色相", + "Randomly adjusts the saturation of the sample during training": "训练时随机调整样本饱和度", + "Enables random dropout for tags in the captions.": "启用标签随机丢弃", + "Probability to drop tags, from 0 to 1.": "标签丢弃概率,0到1", + "Automatically create circular masks for masked training": "自动为遮罩训练创建圆形遮罩", + "Enables randomization of capitalization for tags in the caption.": "启用标签大小写随机化", + "If enabled, converts the caption to lowercase before any further processing.": "启用后,将标签转为小写后再处理", + "Refresh Basic": "刷新基本", + "Refresh Advanced": "刷新高级", + "Reload basic statistics for the concept directory": "重新加载数据集目录的基本统计", + "Reload advanced statistics for the concept directory": "重新加载数据集目录的高级统计", + "Abort Scan": "中止扫描", + "Stop the currently running scan if it's taking a long time - advanced scan will be slow on large folders and on HDDs": "如果扫描时间过长则中止——高级扫描对大文件夹和HDD较慢", + "Directories": "目录数", + "Total Size": "总大小", + "Token count": "Token数", + "Frames": "帧数", + "Time taken to process concept directory": "处理数据集目录耗时", + "Total number of image files with an associated caption": "有关联标签的图像文件总数", + "Total number of image files with an associated mask": "有关联遮罩的图像文件总数", + "Total size of all image, mask, and caption files in MB": "图像、遮罩和标签文件总大小(MB)", + "Average fps of videos in the concept": "数据集中视频平均帧率", + "Video in concept with highest fps": "数据集中最高帧率视频", + "Video in concept with the lowest fps": "数据集中最低帧率视频", + "Longest video in the concept by number of frames": "数据集中帧数最多的视频", + "Shortest video in the concept by number of frames": "数据集中帧数最少的视频", + + # === 训练参数 === + "Learning Rate": "学习率", + "The base learning rate": "基础学习率", + "Learning Rate Scheduler": "学习率调度器", + "Learning rate scheduler that automatically changes the learning rate during training": "训练过程中自动调整学习率的调度器", + "Learning Rate Warmup Steps": "学习率预热步数", + "Learning Rate Cycles": "学习率周期数", + "Learning Rate Min Factor": "学习率最小因子", + "Learning Rate Scaler": "学习率缩放器", + "Local Batch Size": "本地批次大小", + "The batch size of one training step. If you use multiple GPUs, this is the batch size of each GPU (local batch size).": "单步训练的批次大小。多GPU时每块GPU的批次大小", + "Accumulation Steps": "梯度累积步数", + "Number of accumulation steps. Increase this number to trade batch size for training speed": "梯度累积步数,增加此值以训练速度换取更大批次", + "Epochs": "训练轮数", + "The number of epochs for a full training run": "完整训练运行的轮数", + "Optimizer": "优化器", + "The type of optimizer": "优化器类型", + "Optimizer Settings": "优化器设置", + "Optimizer Defaults": "优化器默认值", + "Load Defaults": "加载默认值", + "Load default settings for the selected optimizer": "加载所选优化器的默认设置", + "Gradient Checkpointing": "梯度检查点", + "Enables gradient checkpointing for this component. Reduces VRAM usage at the cost of training speed": "启用梯度检查点,减少显存占用但降低训练速度", + "Clip Grad Norm": "梯度裁剪", + "Clips the gradient norm. Leave empty to disable gradient clipping.": "梯度范数裁剪,留空则禁用", + "Clip Skip": "Clip跳层", + "The number of additional clip layers to skip. 0 = the model default": "额外跳过的Clip层数,0为模型默认", + "Caption Dropout Probability": "标签丢弃概率", + "The Probability for dropping the text encoder conditioning": "丢弃文本编码器条件的概率", + "Resolution": "分辨率", + "The resolution used for training. Optionally specify multiple resolutions separated by a comma, or a single exact resolution in the format x": "训练分辨率,可用逗号分隔多个分辨率,或指定 <宽>x<高> 格式", + "Attention": "注意力机制", + "The attention mechanism used during training. Use `torch SDPA` on linux. On windows, `flash-attn` can be faster, but it has to be installed manually and does not support all models. `torch cuDNN` is an alternative backend some models require or benefit from.": "训练使用的注意力机制。Linux用torch SDPA,Windows可手动安装flash-attn", + "Train UNet": "训练UNet", + "Enables training the UNet model": "启用UNet模型训练", + "Train Text Encoder": "训练文本编码器", + "Enables training the text encoder model": "启用文本编码器训练", + "Train Transformer": "训练Transformer", + "Enables training the Transformer model": "启用Transformer模型训练", + "Train Prior": "训练Prior", + "Enables training the Prior model": "启用Prior模型训练", + "UNet Learning Rate": "UNet学习率", + "The learning rate of the UNet. Overrides the base learning rate": "UNet学习率,覆盖基础学习率", + "Text Encoder Learning Rate": "文本编码器学习率", + "The learning rate of the text encoder. Overrides the base learning rate": "文本编码器学习率,覆盖基础学习率", + "Transformer Learning Rate": "Transformer学习率", + "The learning rate of the Transformer. Overrides the base learning rate": "Transformer学习率,覆盖基础学习率", + "Prior Learning Rate": "Prior学习率", + "The learning rate of the Prior. Overrides the base learning rate": "Prior学习率,覆盖基础学习率", + "Embeddings Learning Rate": "嵌入学习率", + "The learning rate of embeddings. Overrides the base learning rate": "嵌入学习率,覆盖基础学习率", + "Text Encoder Sequence Length": "文本编码器序列长度", + "Text Encoder": "文本编码器", + "The text encoder weight data type": "文本编码器权重数据类型", + "Text Encoder Data Type": "文本编码器数据类型", + "UNet Data Type": "UNet数据类型", + "The unet weight data type": "UNet权重数据类型", + "Transformer Data Type": "Transformer数据类型", + "The transformer weight data type": "Transformer权重数据类型", + "Prior Data Type": "Prior数据类型", + "The prior weight data type": "Prior权重数据类型", + "VAE Data Type": "VAE数据类型", + "The vae weight data type": "VAE权重数据类型", + "VAE Override": "VAE覆盖", + "Train Data Type": "训练数据类型", + "The mixed precision data type used for training. This can increase training speed, but reduces precision": "训练混合精度数据类型,可提高速度但降低精度", + "Fallback Train Data Type": "回退训练数据类型", + "The mixed precision data type used for training stages that don't support float16 data types. This can increase training speed, but reduces precision": "不支持float16的训练阶段的混合精度数据类型", + "Output Data Type": "输出数据类型", + "EMA": "EMA", + "EMA Decay": "EMA衰减", + "Decay parameter of the EMA model. Higher numbers will average more steps. For datasets of hundreds or thousands of images, set this to 0.9999. For smaller datasets, set it to 0.999 or even 0.998": "EMA模型衰减参数。大数据集设0.9999,小数据集设0.999或0.998", + "EMA Update Step Interval": "EMA更新步间隔", + "Number of steps between EMA update steps": "EMA更新之间的步数", + "EMA averages the training progress over many steps, better preserving different concepts in big datasets": "EMA对多步训练取平均,更好地保留大数据集中的不同概念", + "Offset Noise Weight": "偏移噪声权重", + "The weight of offset noise added to each training step": "每步训练添加的偏移噪声权重", + "Perturbation Noise Weight": "扰动噪声权重", + "The weight of perturbation noise added to each training step": "每步训练添加的扰动噪声权重", + "Generalized Offset Noise": "广义偏移噪声", + "Per-timestep 'brightness knob' instead of a fixed offset - steadier training, better starts, and improved very dark/bright images. Compatible with V-pred and Eps-pred. Start with 0.02 and adjust as needed.": "逐时间步的亮度调节,训练更稳定。建议从0.02开始", + "Guidance Scale": "引导尺度", + "The guidance scale of guidance distilled models passed to the transformer during training.": "引导蒸馏模型传递给Transformer的引导尺度", + "Masked Prior Preservation Weight": "遮罩Prior保留权重", + "Preserves regions outside the mask using the original untrained model output as a target. Only available for LoRA training. If enabled, use a low unmasked weight.": "使用原始未训练模型输出保留遮罩外区域,仅限LoRA训练", + "Normalize Masked Area Loss": "归一化遮罩区域损失", + "When masked training is enabled, normalizes the loss for each sample based on the sizes of the masked region": "遮罩训练时按遮罩区域大小归一化损失", + "Unmasked Probability": "未遮罩概率", + "When masked training is enabled, specifies the number of training steps done on unmasked samples": "遮罩训练时未遮罩样本的训练步数", + "Unmasked Weight": "未遮罩权重", + "When masked training is enabled, specifies the loss weight of areas outside the masked region": "遮罩训练时遮罩外区域的损失权重", + "Force Attention Mask": "强制注意力遮罩", + "Force enables passing of a text embedding attention mask to the transformer. This can improve training on shorter captions.": "强制向Transformer传递文本嵌入注意力遮罩,可改善短标签训练", + "Force Circular Padding": "强制循环填充", + "Enables circular padding for all conv layers to better train seamless images": "为所有卷积层启用循环填充,更好地训练无缝图像", + "Autocast Cache": "自动转换缓存", + "Enables the autocast cache. Disabling this reduces memory usage, but increases training time": "启用自动转换缓存,禁用可减少内存但增加训练时间", + "Offload Activations": "卸载激活值", + "Offloads this component's activations to CPU during training to reduce VRAM usage": "训练时将激活值卸载到CPU以减少显存占用", + "Layer Offload Fraction": "层卸载比例", + "Fraction of this component's layers to offload to CPU to reduce VRAM usage. Increases training time and RAM usage. 0=disabled, 1=all layers": "卸载到CPU的层比例,0=禁用,1=全部", + "Latent Caching": "潜在缓存", + "Caching of intermediate training data that can be re-used between epochs": "缓存可在轮次间复用的中间训练数据", + "Clear cache before training": "训练前清除缓存", + "Clears the cache directory before starting to train. Only disable this if you want to continue using the same cached data. Disabling this can lead to errors, if other settings are changed during a restart": "训练前清除缓存目录,仅在使用相同缓存数据时禁用", + "Timestep Distribution": "时间步分布", + "Selects the function to sample timesteps during training": "选择训练时的时间步采样函数", + "Timestep Shift": "时间步偏移", + "Shift the timestep distribution. Use the preview to see more details.": "偏移时间步分布,使用预览查看详情", + "Dynamic Timestep Shifting": "动态时间步偏移", + "Dynamically shift the timestep distribution based on resolution. If enabled, the shifting parameters are taken from the model's scheduler configuration and Timestep Shift is ignored.": "根据分辨率动态偏移时间步分布,启用后忽略固定偏移", + "Noising Bias": "噪声偏差", + "Controls the bias parameter of the timestep distribution function. Use the preview to see more details.": "控制时间步分布函数的偏差参数", + "Noising Weight": "噪声权重", + "Controls the weight parameter of the timestep distribution function. Use the preview to see more details.": "控制时间步分布函数的权重参数", + "Min Noising Strength": "最小噪声强度", + "Specifies the minimum noising strength used during training. This can help to improve composition, but prevents finer details from being trained": "训练最小噪声强度,有助于构图但会阻碍细节训练", + "Max Noising Strength": "最大噪声强度", + "Specifies the maximum noising strength used during training. This can be useful to reduce overfitting, but also reduces the impact of training samples on the overall image composition": "训练最大噪声强度,可减少过拟合但降低样本对构图的影响", + "Loss Scaler": "损失缩放器", + "Selects the type of loss scaling to use during training. Functionally equated as: Loss * selection": "训练损失缩放类型,等效于: Loss * 选择值", + "Loss Weight Function": "损失权重函数", + "Choice of loss weight function. Can help the model learn details more accurately.": "损失权重函数选择,帮助模型更准确学习细节", + "Huber Delta": "Huber Delta", + "Delta parameter for huber loss": "Huber损失的delta参数", + "Huber Strength": "Huber强度", + "Huber loss strength for custom loss settings. Less sensitive to outliers than MSE. Strengths should generally sum to 1.": "Huber损失强度,比MSE对异常值更不敏感", + "MSE Strength": "MSE强度", + "Mean Squared Error strength for custom loss settings. Strengths should generally sum to 1.": "均方误差强度,强度总和应为1", + "MAE Strength": "MAE强度", + "Mean Absolute Error strength for custom loss settings. Strengths should generally sum to 1.": "平均绝对误差强度,强度总和应为1", + "VB Strength": "VB强度", + "Variational lower-bound strength for custom loss settings. Should be set to 1 for variational diffusion models": "变分下界强度,变分扩散模型应设为1", + "Gamma": "Gamma", + "Inverse strength of loss weighting. Range: 1-20, only applies to Min SNR and P2.": "损失权重逆强度,范围1-20,仅用于Min SNR和P2", + "Rescale Noise Scheduler + V-pred": "重缩放噪声调度+V预测", + "Rescales the noise scheduler to a zero terminal signal to noise ratio and switches the model to a v-prediction target": "将噪声调度器重缩放至零终端信噪比,切换模型到v预测目标", + "Custom Conditioning Image": "自定义条件图像", + "When custom conditioning image is enabled, will use png postfix with -condlabel instead of automatically generated.It's suitable for special scenarios, such as object removal, allowing the model to learn a certain behavior concept": "启用自定义条件图像,适用于对象移除等特殊场景", + "Dropout Probability": "丢弃概率", + "Dropout probability. This percentage of model nodes will be randomly ignored at each training step. Helps with overfitting. 0 disables, 1 maximum.": "丢弃概率,每步随机忽略此比例的模型节点,0=禁用", + "Dataloader Threads": "数据加载线程", + "Number of threads used for the data loader. Increase if your GPU has room during caching, decrease if it's going out of memory during caching.": "数据加载线程数,缓存时GPU有余量可增加", + "Layer Filter": "层过滤器", + "Comma-separated list of diffusion layers to train. Regular expressions (if toggled) are supported. Any model layer with a matching name will be trained": "逗号分隔的训练层列表,支持正则表达式", + "Preserve Embedding Norm": "保留嵌入范数", + "Rescales each trained embedding to the median embedding norm": "将每个训练嵌入重缩放至中位嵌入范数", + "Compile transformer blocks": "编译Transformer块", + "Uses torch.compile and Triton to significantly speed up training. Only applies to transformer/unet. Disable in case of compatibility issues.": "使用torch.compile和Triton加速训练,如有兼容问题请禁用", + "Stop Training After": "训练停止条件", + "Validate after": "验证间隔", + "The interval used when validate training": "训练验证间隔", + "Validation": "验证", + "Enable validation steps and add new graph in tensorboard": "启用验证步骤并在Tensorboard添加图表", + "Include Text Encoder {i}": "包含文本编码器{i}", + "Includes text encoder {i} in the training run": "在训练中包含文本编码器{i}", + "Text Encoder {i} Learning Rate": "文本编码器{i}学习率", + "Text Encoder {i} Clip Skip": "文本编码器{i} Clip跳层", + "Text Encoder {i} Sequence Length": "文本编码器{i}序列长度", + "Train Text Encoder {i}": "训练文本编码器{i}", + "Train Text Encoder {i} Embedding": "训练文本编码器{i}嵌入", + "Enables training the text encoder {i} model": "启用文本编码器{i}训练", + "Enables training embeddings for the text encoder {i} model": "启用文本编码器{i}嵌入训练", + "The learning rate of the text encoder {i}. Overrides the base learning rate": "文本编码器{i}学习率,覆盖基础学习率", + "The Probability for dropping the text encoder {i} conditioning": "丢弃文本编码器{i}条件的概率", + "When to stop training the text encoder {i}": "何时停止训练文本编码器{i}", + "When to stop training the UNet": "何时停止训练UNet", + "When to stop training the text encoder": "何时停止训练文本编码器", + "When to stop training the Transformer": "何时停止训练Transformer", + "When to stop training the Prior": "何时停止训练Prior", + "When to stop training the embedding": "何时停止训练嵌入", + "Include Unconditional Transformer": "包含无条件Transformer", + "Loads the dedicated unconditional transformer used for the negative branch of CFG": "加载用于CFG负分支的专用无条件Transformer", + "Unconditional Transformer Data Type": "无条件Transformer数据类型", + "The weight data type of the unconditional transformer, used for the negative branch of CFG during sampling": "无条件Transformer权重数据类型,用于CFG负分支", + "Include Config": "包含配置", + "Include the training configuration in the final model. Only supported for safetensors files.": "将训练配置包含在最终模型中,仅支持safetensors", + "Prevent Overwrites": "防止覆盖", + "When enabled, output paths that already exist on disk will be flagged as invalid to avoid accidental overwrites": "启用后,已存在的输出路径将被标记为无效以防止意外覆盖", + "Only Cache": "仅缓存", + "Only populate the cache, without any training": "仅填充缓存,不进行训练", + "Offline Mode": "离线模式", + "Skip the Hugging Face login and resolve every model from the local cache only.": "跳过Hugging Face登录,仅从本地缓存加载模型", + "Async Offloading": "异步卸载", + "Overlaps CPU<->GPU transfers with computation using CUDA streams. Applies to every offloaded component": "使用CUDA流重叠CPU<->GPU传输与计算", + "Async Gradient Reduce": "异步梯度归约", + "Multi-GPU: Asynchroniously start the gradient reduce operations during the backward pass. Can be more efficient, but requires some VRAM.": "多GPU:反向传播时异步启动梯度归约,更高效但占用显存", + "Fused Gradient Reduce": "融合梯度归约", + "Multi-GPU: Gradient synchronisation during the backward pass. Can be more efficient, especially with Async Gradient Reduce": "多GPU:反向传播时的梯度同步,配合异步梯度归约更高效", + "Gradient Reduce Precision": "梯度归约精度", + "Device Indexes": "设备索引", + "Enable multi-GPU training": "启用多GPU训练", + + # === 模型标签页 === + "Base Model": "基础模型", + "Base Model Name": "基础模型名称", + "Filename, directory or Hugging Face repository of the base model": "基础模型文件名、目录或Hugging Face仓库", + "Output": "输出", + "Model Output Destination": "模型输出目标", + "Filename or directory where the output model is saved": "输出模型保存的文件名或目录", + "Output Format": "输出格式", + "Format to use when saving the output model": "保存输出模型的格式", + "Save Filename Prefix": "保存文件名前缀", + "The prefix for filenames used when saving the model during training": "训练时保存模型的文件名前缀", + "Workspace Directory": "工作空间目录", + "The directory where all files of this training run are saved": "此训练运行所有文件保存的目录", + "Cache Directory": "缓存目录", + "The directory where cached data is saved": "缓存数据保存的目录", + "Debug Directory": "调试目录", + "The directory where debug data is saved": "调试数据保存的目录", + "Hugging Face Cache Directory": "Hugging Face缓存目录", + "Huggingface cache Directory": "Hugging Face缓存目录", + "Directory used to cache Hugging Face model downloads.": "Hugging Face模型下载缓存目录", + "Hugging Face Token": "Hugging Face令牌", + "Enter your Hugging Face access token if you have used a protected Hugging Face repository below.\nThis value is stored separately, not saved to your configuration file.": "如果使用了受保护的Hugging Face仓库,请输入访问令牌。此值单独存储,不保存到配置文件", + "Save Every": "保存间隔", + "The interval used when automatically saving the model during training": "训练时自动保存模型的间隔", + "Sample After": "采样间隔", + "The interval used when automatically sampling from the model during training": "训练时自动采样的间隔", + "Backup After": "备份间隔", + "The interval used when automatically creating model backups during training": "训练时自动创建模型备份的间隔", + "Backup Before Save": "保存前备份", + "Create a full backup before saving the final model": "保存最终模型前创建完整备份", + "Rolling Backup": "滚动备份", + "If rolling backups are enabled, older backups are deleted automatically": "启用滚动备份后自动删除旧备份", + "Rolling Backup Count": "滚动备份数量", + "Defines the number of backups to keep if rolling backups are enabled": "滚动备份保留的数量", + "Continue from last backup": "从上次备份继续", + "Automatically continues training from the last backup saved in /backup": "自动从/backup中的上次备份继续训练", + "Output embedding": "输出嵌入", + "Output embeddings are calculated at the output of the text encoder, not the input. This can improve results for larger text encoders and lower VRAM usage.": "在文本编码器输出处计算嵌入,可改善大文本编码器效果并降低显存", + "Quantization": "量化", + "Quantization Layer Filter": "量化层过滤器", + "Comma-separated list of layers to quantize. Regular expressions (if toggled) are supported. Any model layer with a matching name will be quantized": "逗号分隔的量化层列表,支持正则表达式", + "Select a preset defining which layers to quantize. Quantization of certain layers can decrease model quality. Only applies to the transformer/unet": "选择量化层预设,量化某些层可能降低模型质量", + "SVDQuant": "SVDQuant", + "SVDQuant Rank": "SVDQuant秩", + "Rank for SVDQuant weights decomposition": "SVDQuant权重分解的秩", + "What datatype to use for SVDQuant weights decomposition.": "SVDQuant权重分解的数据类型", + "Embedding": "嵌入", + "Base embedding": "基础嵌入", + "The base embedding to train on. Leave empty to create a new embedding": "训练的基础嵌入,留空创建新嵌入", + "Initial embedding text": "初始嵌入文本", + "The initial embedding text used when creating a new embedding": "创建新嵌入时的初始文本", + "Placeholder": "占位符", + "The placeholder used when using the embedding in a prompt": "在提示词中使用嵌入的占位符", + "Bundle Embeddings": "捆绑嵌入", + "Number of tokens for captions": "标签Token数", + "The token count used when creating a new embedding. Leave empty to auto detect from the initial embedding text.": "新嵌入的Token数,留空自动检测", + "Alpha": "Alpha", + "Applies a scaling factor to the learned weights. This ensures that the effective learning rate remains consistent across different block sizes. Without this, different block sizes require significantly different learning rates.": "学习权重缩放因子,确保不同块大小下有效学习率一致", + "Apply DoRA on Output Axis": "在输出轴应用DoRA", + "Apply on output axis (DoRA Only)": "在输出轴应用(仅DoRA)", + "Apply the DoRA weight decomposition on the output axis instead of the input axis.": "在输出轴而非输入轴应用DoRA权重分解", + "Decompose Both Matrices": "分解两个矩阵", + "Perform rank decomposition on both Kronecker product matrices (W1 and W2). Only effective for very small dimensions.": "对两个Kronecker积矩阵进行秩分解,仅对极小维度有效", + "Decomposition Factor": "分解因子", + "Factor for Kronecker product decomposition. -1 for auto, which is recommended. Changing this drastically affects parameter count.": "Kronecker积分解因子,-1为自动(推荐)", + "Block Share": "块共享", + "Share the OFT parameters between blocks. A single rotation matrix is shared across all blocks within a layer, drastically cutting the number of trainable parameters and yielding very compact adapter files, potentially improving generalization but at the cost of significant expressiveness, which can lead to underfitting on more complex or diverse tasks.": "块间共享OFT参数,大幅减少可训练参数,但可能降低表达能力", + "Decompose LoRA Weights (aka, DoRA).": "分解LoRA权重(即DoRA)", + "Apply weight decomposition (DoRA) on top of the LoKr update.": "在LoKr更新上应用权重分解(DoRA)", + "Apply the weight decomposition on the output axis instead of the input axis.": "在输出轴而非输入轴应用权重分解", + "Add an epsilon to the norm divison calculation in DoRA. Can aid in training stability, and also acts as regularization.": "在DoRA范数除法中添加epsilon,有助于训练稳定性", + "The dimension parameter used for the secondary decomposition. Analogous to rank in LoRA.": "二次分解的维度参数,类似于LoRA的秩", + "Forces the second Kronecker matrix (W2) to be a full matrix, ignoring the dimension setting. For expert use.": "强制第二个Kronecker矩阵为全矩阵,忽略维度设置", + "Use Tucker decomposition for convolutional layers. Can be more efficient for some architectures.": "对卷积层使用Tucker分解,某些架构更高效", + "Uses an accelerated path that bypasses the materialization of the full Kronecker product. This delivers a massive speedup to the LoKr without sacrificing precision. Highly recommended.": "使用加速路径绕过完整Kronecker积的实现,大幅加速LoKr", + "Only implemented for LoRA.": "仅对LoRA实现", + + # === 采样 === + "Sample": "采样", + "Prompt": "提示词", + "Negative Prompt": "负面提示词", + "Width": "宽度", + "Height": "高度", + "Seed": "种子", + "Steps": "步数", + "CFG Scale": "CFG尺度", + "Sampler": "采样器", + "Update Preview": "更新预览", + "Preview image": "预览图", + "The base image used when inpainting.": "修复使用的基础图像", + "The mask used when inpainting.": "修复使用的遮罩", + "Enables inpainting sampling. Only available when sampling from an inpainting model.": "启用修复采样,仅修复模型可用", + "Number of frames to generate. Only used when generating videos.": "生成帧数,仅视频生成时使用", + "Length in seconds of audio output.": "音频输出长度(秒)", + "Whether to include non-ema sampling when using ema.": "使用EMA时是否包含非EMA采样", + "Samples to Tensorboard": "采样到Tensorboard", + "Whether to include sample images in the Tensorboard output.": "是否在Tensorboard输出中包含采样图像", + "File Format used when saving samples": "保存样本的文件格式", + "Start sampling automatically after this interval has elapsed.": "经过此间隔后自动开始采样", + "Add a new sample configuration.": "添加新的采样配置", + "The number of different image versions to cache if latent caching is enabled.": "启用潜在缓存时缓存的图像版本数", + "The number of different text versions to cache if latent caching is enabled.": "启用潜在缓存时缓存的文本版本数", + "Overrides the number of tokens used for captions. If empty, the model default is used, which is 512 on Flux. Comfy samples with 256 tokens though. 77 is the default only for backwards compatibility.": "覆盖标签Token数,留空使用模型默认值", + + # === 训练控制 === + "Start Training": "开始训练", + "Stop Training": "停止训练", + "Cannot Start Training": "无法开始训练", + "Training in progress": "训练进行中", + "Current status": "当前状态", + "Current status of the training run": "训练运行当前状态", + "A training is currently running. Stop the training before closing the window.": "训练正在运行中,关闭窗口前请先停止训练", + "Stopped": "已停止", + + # === 工具 === + "Dataset Tool": "数据集工具", + "Dataset Tools": "数据集工具", + "Sampling Tool": "采样工具", + "Convert Model Tools": "模型转换工具", + "Convert models": "转换模型", + "Convert": "转换", + "Profiling Tool": "性能分析工具", + "Profiling": "性能分析", + "Start Profiling": "开始分析", + "End Profiling": "结束分析", + "Video Tools": "视频工具", + "Debug": "调试", + "Debug mode": "调试模式", + "Save debug information during the training into the debug directory": "训练时将调试信息保存到调试目录", + "Export Training Config": "导出训练配置", + "Export the current configuration as a script to run without a UI": "导出当前配置为无UI运行脚本", + "Open the captioning tool": "打开标签工具", + "Open the model conversion tool": "打开模型转换工具", + "Open the model sampling tool": "打开模型采样工具", + "Open the profiling tools.": "打开性能分析工具", + "Open the video tools": "打开视频工具", + "Generate Captions": "生成标签", + "Generate Masks": "生成遮罩", + "Batch generate captions": "批量生成标签", + "Batch generate masks": "批量生成遮罩", + "Create Captions": "创建标签", + "Create Masks": "创建遮罩", + "Replace all captions": "替换所有标签", + "Replace all masks": "替换所有遮罩", + "Add as new line": "添加为新行", + "Add to existing": "添加到现有", + "Blend with existing": "与现有混合", + "Subtract from existing": "从现有减去", + "Initial Caption": "初始标签", + "Threshold": "阈值", + "Smooth": "平滑", + "Remove Borders": "移除边框", + "Remove black borders from output image": "移除输出图像的黑色边框", + "Remove black borders from output clip": "移除输出片段的黑色边框", + "open a dialog to automatically generate captions": "打开自动生成标签对话框", + "open a dialog to automatically generate masks": "打开自动生成遮罩对话框", + "open a new directory": "打开新目录", + "open the current image in Explorer": "在资源管理器中打开当前图像", + "draw a mask using a brush": "用画笔绘制遮罩", + "draw a mask using a fill tool": "用填充工具绘制遮罩", + "Blur Removal": "模糊移除", + "Draw": "绘制", + "Fill": "填充", + "Hex Color": "十六进制颜色", + "Class Name": "类名", + "Use Regex": "使用正则", + "Interpret special tags with regex, such as 'photo.*' to match 'photo, photograph, photon' but not 'telephoto'. Includes exception for '/(' and '/)' syntax found in many booru/e6 tags.": "使用正则匹配特殊标签,如'photo.*'匹配'photo, photograph'", + "Expand": "展开", + "Clear": "清除", + "Open in Explorer": "在资源管理器中打开", + "Open": "打开", + "Export": "导出", + "Generate a zip file with config.json, debug_report.log and settings diff, use this to report bugs or issues": "生成包含配置和调试报告的zip文件,用于报告问题", + "Select Directory to Save Debug Package": "选择调试包保存目录", + "Turns on/off Scalene profiling. Only works when OneTrainer is launched with Scalene!": "开关Scalene性能分析,仅在使用Scalene启动时有效", + "Type of the model": "模型类型", + "The type of model to convert": "要转换的模型类型", + "Model Type": "模型类型", + "Type": "类型", + + # === 云端 === + "Enable cloud training": "启用云端训练", + "Hostname": "主机名", + "SSH server hostname or IP. Leave empty if you have a Cloud ID or want to automatically create a new cloud.": "SSH服务器主机名或IP,有Cloud ID时留空", + "Port": "端口", + "SSH server port. Leave empty if you have a Cloud ID or want to automatically create a new cloud.": "SSH服务器端口,有Cloud ID时留空", + "User": "用户", + "SSH keyfile path": "SSH密钥路径", + "Absolute path to the private key file used for SSH connections. Leave empty to rely on your system SSH configuration.": "SSH私钥文件绝对路径,留空使用系统SSH配置", + "SSH password": "SSH密码", + "SSH password for password-based authentication. If you try to use native SCP requires sshpass to be installed. Leave empty to use key-based authentication.": "SSH密码认证,留空使用密钥认证", + "SSH Public Keys": "SSH公钥", + "API key": "API密钥", + "Cloud service API key for RUNPOD. Leave empty for LINUX. This value is stored separately, not saved to your configuration file. ": "RUNPOD云服务API密钥,LINUX留空。单独存储不保存到配置文件", + "Cloud id": "云ID", + "Cloud name": "云名称", + "RUNPOD Cloud ID. The cloud service must have a public IP and SSH service. Leave empty if you want to automatically create a new RUNPOD cloud, or if you're connecting to another cloud provider via SSH Hostname and Port.": "RUNPOD云ID,需要有公网IP和SSH服务", + "The name of the new cloud instance.": "新云实例名称", + "Remote Directory": "远程目录", + "The directory on the cloud where files will be uploaded and downloaded.": "云端上传下载文件的目录", + "OneTrainer Directory": "OneTrainer目录", + "The directory for OneTrainer on the cloud.": "云端OneTrainer目录", + "Volume size": "卷大小", + "Set the storage volume size in GB. This volume persists only until the cloud is deleted - not a RunPod network volume": "存储卷大小(GB),云删除后不保留", + "Min download": "最小下载速度", + "Set the minimum download speed of the cloud in Mbps.": "云端最小下载速度(Mbps)", + "File sync method": "文件同步方式", + "Choose NATIVE_SCP to use scp.exe to transfer files. FABRIC_SFTP uses the Paramiko/Fabric SFTP implementation for file transfers instead.": "NATIVE_SCP使用scp.exe传输,FABRIC_SFTP使用Paramiko SFTP", + "Install command": "安装命令", + "The command for installing OneTrainer. Leave the default, unless you want to use a development branch of OneTrainer.": "OneTrainer安装命令,默认即可", + "Install OneTrainer": "安装OneTrainer", + "Automatically install OneTrainer from GitHub if the directory doesn't already exist.": "如果目录不存在,自动从GitHub安装OneTrainer", + "Update OneTrainer": "更新OneTrainer", + "Update OneTrainer if it already exists on the cloud.": "如果云端已存在则更新OneTrainer", + "Create cloud via API": "通过API创建云", + "Create cloud via website": "通过网站创建云", + "Automatically creates a new cloud instance if both Host:Port and Cloud ID are empty. Currently supported for RUNPOD.": "主机和云ID为空时自动创建云实例,目前支持RUNPOD", + "Select the GPU type. Enter an API key before pressing the button.": "选择GPU类型,请先输入API密钥", + "Select the RunPod cloud type. See RunPod's website for details.": "选择RunPod云类型,详见RunPod网站", + "Reattach id": "重连ID", + "Reattach now": "立即重连", + "An id identifying the remotely running trainer. In case you have lost connection or closed OneTrainer, it will try to reattach to this id instead of starting a new remote trainer.": "远程训练器标识ID,断连后可重新连接", + "Detach remote trainer": "断开远程训练器", + "Allows the trainer to keep running even if your connection to the cloud is lost.": "允许训练器在断连后继续运行", + "Delete remote workspace": "删除远程工作空间", + "Delete the workspace directory on the cloud after training has finished successfully and data has been downloaded.": "训练完成并下载数据后删除云端工作空间目录", + "Download backups": "下载备份", + "Download backups from the remote workspace directory to your local machine. It's usually not necessary to download them, because as long as the backups are still available on the cloud, the training can be restarted using one of the cloud's backups.": "从远程下载备份到本地", + "Download samples": "下载样本", + "Download samples from the remote workspace directory to your local machine.": "从远程下载样本到本地", + "Download saved checkpoints": "下载已保存检查点", + "Download the automatically saved training checkpoints from the remote workspace directory to your local machine.": "从远程下载训练检查点到本地", + "Download output model": "下载输出模型", + "Download the final model after training. You can disable this if you plan to use an automatically saved checkpoint instead.": "训练后下载最终模型", + "Download tensorboard logs": "下载Tensorboard日志", + "Download Link": "下载链接", + "Download List": "下载列表", + "Link List": "链接列表", + "Single Link": "单个链接", + "Single Video": "单个视频", + "Download dataset from Huggingface now, for the purpose of previewing and statistics. Otherwise, it will be downloaded when you start training. Path must be a Huggingface repository.": "从Huggingface下载数据集用于预览和统计", + "Huggingface models are downloaded to this remote directory.": "Huggingface模型下载到此远程目录", + "Action on finish": "完成时操作", + "Action on error": "错误时操作", + "Action on detached finish": "断连完成时操作", + "Action on detached error": "断连错误时操作", + "What to do when training finishes and the data has been fully downloaded: Stop or delete the cloud, or do nothing.": "训练完成且数据下载后的操作", + "What to do if training stops due to an error: Stop or delete the cloud, or do nothing. Data may be lost.": "训练出错时的操作,数据可能丢失", + "What to do when training finishes, but the client has been detached and cannot download data. Data may be lost.": "训练完成但客户端已断连时的操作", + "What to if training stops due to an error, but the client has been detached and cannot download data. Data may be lost.": "训练出错且客户端已断连时的操作", + "Delete": "删除", + "Choose LINUX to connect to a linux machine via SSH. Choose RUNPOD for additional functionality such as automatically creating and deleting pods.": "LINUX通过SSH连接Linux机器,RUNPOD自动创建和删除Pod", + "Create if absent": "不存在则创建", + + # === Tensorboard === + "Tensorboard": "Tensorboard", + "Starts the Tensorboard Web UI during training": "训练时启动Tensorboard Web UI", + "Tensorboard Port": "Tensorboard端口", + "Port to use for Tensorboard link": "Tensorboard链接端口", + "Expose Tensorboard": "暴露Tensorboard", + "Exposes Tensorboard Web UI to all network interfaces (makes it accessible from the network)": "将Tensorboard暴露到所有网络接口", + "Tensorboard TCP tunnel": "Tensorboard TCP隧道", + "Instead of starting tensorboard locally, make a TCP tunnel to a tensorboard on the cloud": "通过TCP隧道连接云端Tensorboard", + "Always-On Tensorboard": "常驻Tensorboard", + "Keep Tensorboard accessible even when not training. Useful for monitoring completed training sessions.": "非训练时也保持Tensorboard可访问", + + # === 视频工具 === + "Set FPS": "设置FPS", + "FPS to convert output videos to, set to 0 to keep original rate.": "输出视频帧率,0保持原始", + "Split at Cuts": "按剪辑分割", + "Extract Single": "提取单个", + "Extract Directory": "提取目录", + "Path to directory with multiple videos to process, including in subdirectories.": "包含子目录的多视频处理目录", + "Path to folder where downloaded videos will be saved.": "下载视频保存目录", + "Path to folder where extracted clips will be saved.": "提取片段保存目录", + "Path to folder where extracted images will be saved.": "提取图像保存目录", + "Path to txt file with list of links separated by newlines.": "链接列表txt文件路径", + "Link to single video file to process.": "单个视频文件链接", + "Link to video/playlist to download. Uses yt-dlp, supports youtube, twitch, instagram, and many other sites.": "视频/播放列表下载链接,支持YouTube等", + "Maximum length in seconds for saved clips, larger clips will be broken into multiple small clips.": "保存片段最大长度(秒),超出则分割", + + # === 其他 === + "Help": "帮助", + "Settings": "设置", + "Temp Device": "临时设备", + "The device used to temporarily offload models while they are not used. Default:": "模型不使用时的临时卸载设备", + "Train Device": "训练设备", + "The device used for training. Can be ": "训练使用的设备", + "Multi-GPU: Maximum VRAM for ": "多GPU:最大显存 ", + "The number of learning rate cycles. This is only applicable if the learning rate scheduler supports cycles": "学习率周期数,仅调度器支持时有效", + "The number of samples used during training. Use repeats to multiply the concept, or samples to specify an exact number of samples used in each epoch.": "训练使用的样本数,用repeats倍乘或samples指定精确数", + "The number of steps it takes to gradually increase the learning rate from 0 to the specified learning rate. Values >1 are interpeted as a fixed number of steps, values <=1 are intepreted as a percentage of the total training steps (ex. 0.2 = 20% of the total step count)": "学习率从0渐增到指定值的步数,>1为固定步数,<=1为总步数百分比", + "The number of tags at the start of the caption that are not shuffled or dropped": "标签开头不打乱不丢弃的标签数", + "The number of frames used for training.": "训练使用的帧数", + "Unit = float. Method = percentage. For a factor of 0.1, the final LR will be 10% of the initial LR. If the initial LR is 1e-4, the final LR will be 1e-5.": "浮点数,百分比方式。如0.1则最终学习率为初始值的10%", + "EMA decay must be between 0.5 and 1": "EMA衰减必须在0.5到1之间", + "Gamma must be between 1 and 20": "Gamma必须在1到20之间", + "Learning rate min factor must be between 0 and 0.99": "学习率最小因子必须在0到0.99之间", + "Unmasked probability must be between 0 and 1": "未遮罩概率必须在0到1之间", + "Unmasked weight must be between 0 and 1": "未遮罩权重必须在0到1之间", + "Masked prior preservation weight must be between 0 and 1": "遮罩Prior保留权重必须在0到1之间", + "Aspect Ratio Bucketing": "宽高比分桶", + "Aspect ratio bucketing enables training on images with different aspect ratios": "宽高比分桶允许在不同宽高比的图像上训练", + "Image buckets with the least nonzero total images - if 'batch size' is larger than this, these images will be ignored during training! See the wiki for more details.": "非零图像最少的桶,批次大小超过此值时这些图像将被忽略", + "Select a preset defining which layers to train, or select 'Custom' to define your own.\nA blank 'custom' field or 'Full' will train all layers.": "选择训练层预设,或选'Custom'自定义。空白或'Full'训练所有层", + "Disables/Enables all visible items in the current view": "禁用/启用当前视图中的所有可见项", + "Adds a new concept to the current config.": "向当前配置添加新数据集", + "Adds a new config, which are containers for concepts, which themselves contain your dataset": "添加新配置,配置是数据集的容器", + "All: All settings, including the samples and concepts are included.": "全部:包含所有设置、采样和数据集", + "Additional Args": "附加参数", + "Key name for an argument in your scheduler": "调度器参数键名", + "Value for an argument in your scheduler. Some special values can be used, wrapped in percent signs: LR, EPOCHS, STEPS_PER_EPOCH, TOTAL_STEPS, SCHEDULER_STEPS. Note that OneTrainer calls step() after every individual learning step, not every epoch, so what Torch calls 'epoch' you should treat as 'step'.": "调度器参数值,可用特殊值:LR, EPOCHS, TOTAL_STEPS等", + "Learning Rate Scheduler Settings": "学习率调度器设置", + "Selects the type of learning rate scaling to use during training. Functionally equated as: LR * SQRT(selection)": "学习率缩放类型,等效于: LR * SQRT(选择值)", + "Python class module and name for the custom scheduler class, in the form of ..": "自定义调度器类,格式:<模块>.<类名>", + "Configure the auxiliary AdamW_adv optimizer": "配置辅助AdamW_adv优化器", + "Method used to drop captions. 'Full' will drop the entire caption past the 'kept' tags with a certain probability, 'Random' will drop individual tags with the set probability, and 'Random Weighted' will linearly increase the probability of dropping tags, more likely to preseve tags near the front with full probability to drop at the end.": "标签丢弃方式:Full整体丢弃,Random随机丢弃,Random Weighted加权丢弃", + "List of tags which will be whitelisted/blacklisted by dropout. 'Whitelist' tags will never be dropped but all others may be, 'Blacklist' tags may be dropped but all others will never be, 'None' may drop any tags. Can specify either a delimiter-separated list in the field, or a file path to a .txt or .csv file with entries separated by newlines.": "丢弃白/黑名单标签列表,可输入分隔列表或文件路径", + "Comma-separated list of types of capitalization randomization to perform. 'capslock' for ALL CAPS, 'title' for First Letter Of Every Word, 'first' for First word only, 'random' for rAndOMiZeD lEtTERs.": "大小写随机化类型:capslock全大写,title首字母大写,first首词大写,random随机", + "If enabled, layer filter patterns are interpreted as regular expressions. Otherwise, simple substring matching is used.": "启用后层过滤器使用正则匹配,否则使用子串匹配", + "The source for prompts used during training. When selecting ": "训练提示词来源。选择", + "STANDARD: Standard finetuning with the sample as training target\n": "标准:以样本为训练目标的标准微调\n", + "VALIDATION: Use concept for validation instead of training\n": "验证:用数据集进行验证而非训练\n", + "WEIGHT_DTYPE: Reduce gradients between GPUs in your weight data type; can be imprecise, but more efficient than float32\n": "WEIGHT_DTYPE:以权重数据类型归约梯度,可能比float32不精确但更高效\n", + "Directory or Hugging Face repository of a VAE model in diffusers format. Can be used to override the VAE included in the base model. Using a safetensor VAE file will cause an error that the model cannot be loaded.": "diffusers格式的VAE模型目录或Hugging Face仓库,用于覆盖基础模型的VAE", + "Can be used to override the transformer in the base model. Safetensors and GGUF files are supported, local and on Huggingface. If a GGUF file is used, the DataType must also be set to GGUF": "覆盖基础模型的Transformer,支持safetensors和GGUF", + "Filename, directory or Hugging Face repository of the base model this LoRA/embedding was trained on": "此LoRA/嵌入训练的基础模型", + "Filename, directory or Hugging Face repository of the decoder model": "解码器模型路径", + "Filename, directory or Hugging Face repository of the effnet encoder model": "Effnet编码器模型路径", + "Filename, directory or Hugging Face repository of the prior model": "Prior模型路径", + "Filename, directory or Hugging Face repository of the text encoder 4 model": "文本编码器4模型路径", + "Decoder Data Type": "解码器数据类型", + "The decoder weight data type": "解码器权重数据类型", + "Decoder Text Encoder Data Type": "解码器文本编码器数据类型", + "The decoder text encoder weight data type": "解码器文本编码器权重数据类型", + "Decoder VQGAN Data Type": "解码器VQGAN数据类型", + "The decoder vqgan weight data type": "解码器VQGAN权重数据类型", + "Decoder Model": "解码器模型", + "Effnet Encoder Data Type": "Effnet编码器数据类型", + "The effnet encoder weight data type": "Effnet编码器权重数据类型", + "Effnet Encoder Model": "Effnet编码器模型", + "Prior Model": "Prior模型", + "The Embedding weight data type used for training. This can reduce memory consumption, but reduces precision": "嵌入权重数据类型,可减少内存但降低精度", + "Embedding Weight Data Type": "嵌入权重数据类型", + "The type of low-parameter finetuning method.": "低参数微调方法类型", + "The text encoder 1 weight data type": "文本编码器1权重数据类型", + "The text encoder 2 weight data type": "文本编码器2权重数据类型", + "The text encoder 3 weight data type": "文本编码器3权重数据类型", + "The text encoder 4 weight data type": "文本编码器4权重数据类型", + "Loading model ": "加载模型 ", + "Saving model ": "保存模型 ", + "Model converted": "模型已转换", + "Release all models from VRAM": "从显存释放所有模型", + "Show Augmentations": "显示增强", + "Show Disabled": "显示禁用项", + "Skip First": "跳过首个", + "Folder": "文件夹", + "Secure": "安全", + "Inactive": "未激活", + "Enable": "启用", + "Disable": "禁用", + "Community": "社区", + "Standard": "标准", + "Square": "方形", + "Wide": "宽图", + "Tall": "长图", + "Average length of caption in concept by character count. For token count, assume ~2 tokens/word": "标签平均长度(字符数),Token数约2/词", + "Largest caption in concept by character count. For token count, assume ~2 tokens/word": "最长标签(字符数),Token数约2/词", + "Smallest caption in concept by character count. For token count, assume ~2 tokens/word": "最短标签(字符数),Token数约2/词", + "Average size of images in the concept by number of pixels (width * height)": "图像平均尺寸(宽x高像素)", + "Largest image in the concept by number of pixels (width * height)": "最大图像尺寸(宽x高像素)", + "Smallest image in the concept by number of pixels (width * height)": "最小图像尺寸(宽x高像素)", + "Average length of videos in the concept by number of frames": "视频平均帧数", + "Total number of caption files which lack a corresponding image file - if >0, check your data set! If using 'from file name' or 'from single text file' then this can be ignored.": "缺少对应图像的标签文件数,>0请检查数据集", + "Total number of caption files, any .txt file. With advanced scan, includes the total number of captions on separate lines across all files in parentheses.": "标签文件总数(.txt文件)", + "Total number of directories including and under (if 'include subdirectories' is enabled) the main concept directory": "数据集目录及子目录总数", + "Total number of image files, any of the extensions ": "图像文件总数,扩展名:", + "Total number of mask files which lack a corresponding image file - if >0, check your data set!": "缺少对应图像的遮罩文件数,>0请检查数据集", + "Total number of mask files, any file ending in '-masklabel.png'": "遮罩文件总数(-masklabel.png结尾)", + "Total number of video files with an associated caption": "有关联标签的视频文件总数", + "Total number of video files, any of the extensions ": "视频文件总数,扩展名:", + "Number of tokens for captions": "标签Token数", + "The number of different image versions to cache if latent caching is enabled.": "潜在缓存的图像版本数", + "The number of different text versions to cache if latent caching is enabled.": "潜在缓存的文本版本数", + "Start saving automatically after this interval has elapsed.": "经过此间隔后自动开始保存", + "Download TensorBoard event logs from the remote workspace directory to your local machine. They can then be viewed locally in TensorBoard. It is recommended to disable \\": "从远程下载Tensorboard日志到本地查看", + "Multi-GPU: A comma-separated list of device indexes. If empty, all your GPUs are used. With a list such as \\": "多GPU:逗号分隔的设备索引列表,留空使用所有GPU", +}