diff --git a/demo/facechain_agent b/demo/facechain_agent deleted file mode 160000 index 1818bae2b..000000000 --- a/demo/facechain_agent +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 1818bae2b043eb1fd18644088280c510a96ac267 diff --git a/demo/facechain_agent/README.md b/demo/facechain_agent/README.md new file mode 100644 index 000000000..0124b5e19 --- /dev/null +++ b/demo/facechain_agent/README.md @@ -0,0 +1,42 @@ +--- +license: Apache License 2.0 +domain: #领域:cv/nlp/audio/multi-modal/AutoML +# - cv +tags: #自定义标签 +- +datasets: #关联数据集 + evaluation: + #- damotest/beans + test: + #- damotest/squad + train: + #- modelscope/coco_2014_caption +models: +- damo/cv_ddsar_face-detection_iclr23-damofd +- damo/cv_resnet101_image-multiple-human-parsing +- damo/cv_unet_skin-retouching +- damo/cv_resnet34_face-attribute-recognition_fairface +- damo/cv_manual_face-quality-assessment_fqa +- damo/cv_unet-image-face-fusion_damo +- damo/cv_ir_face-recognition-ood_rts +- damo/cv_manual_facial-landmark-confidence_flcm +- Cherrytest/rot_bgr +- ly261666/cv_portrait_model +- ly261666/civitai_xiapei_lora +deployspec: #部署配置,默认上限CPU4核、内存8GB、无GPU、单实例,超过此规格请联系管理员配置才能生效 +# 部署启动文件(若SDK为Gradio/Streamlit,默认为app.py, 若为Static HTML, 默认为index.html) +# entry_file: +# CPU核数 + cpu: 7 +# 内存(单位MB) + memory: 26500 +# gpu个数 + gpu: 1 +# 实例数 + instance: 1 + instance_type: ecs.gn7i-c8g1.2xlarge +--- +#### Clone with HTTP +```bash + git clone https://www.modelscope.cn/studios/CVstudio/FaceChain_Agent.git +``` \ No newline at end of file diff --git a/demo/facechain_agent/app.py b/demo/facechain_agent/app.py new file mode 100644 index 000000000..67533177d --- /dev/null +++ b/demo/facechain_agent/app.py @@ -0,0 +1,5 @@ +import os +os.chdir('./demo/facechain_agent') +#os.system('cd ./demo/facechain_agent') +os.system('python app_v1.0.py') + diff --git a/demo/facechain_agent/demo/config/cfg_model_template.json b/demo/facechain_agent/demo/config/cfg_model_template.json new file mode 100644 index 000000000..e0cf4cb7f --- /dev/null +++ b/demo/facechain_agent/demo/config/cfg_model_template.json @@ -0,0 +1,37 @@ +{ + "modelscope-agent": { + "type": "dashscope", + "model": "modelscope-agent-llm-v1", + "generate_cfg": { + "parameters":{ + "use_raw_prompt": true, + "top_p": 0.8, + "top_k": 10, + "seed": 123, + "debug": false + } + } + }, + "http_llm": { + "type":"http_llm" + }, + "openai": { + "model": "gpt-3.5-turbo-16k-0613", + "type": "openai" + }, + "modelscope-agent-qwen-7b":{ + "type": "modelscope", + "model_id": "damo/MSAgent-Qwen-7B", + "model_revision": "v1.0.2", + "use_raw_generation_config": true, + "custom_chat": true + }, + "modelscope-agent-7b":{ + "type": "modelscope", + "model_id": "damo/ModelScope-Agent-7B", + "model_revision": "v1.0.3", + "use_raw_generation_config": true, + "custom_chat": true + } + +} diff --git a/demo/facechain_agent/demo/config/cfg_tool_template.json b/demo/facechain_agent/demo/config/cfg_tool_template.json new file mode 100644 index 000000000..1aea7e18d --- /dev/null +++ b/demo/facechain_agent/demo/config/cfg_tool_template.json @@ -0,0 +1,32 @@ +{ + "modelscope_text-address": { + "url": "https://api-inference.modelscope.cn/api-inference/v1/models/damo/mgeo_geographic_elements_tagging_chinese_base" + }, + "modelscope_text-ner": { + "url": "https://api-inference.modelscope.cn/api-inference/v1/models/damo/nlp_raner_named-entity-recognition_chinese-base-cmeee" + }, + "modelscope_text-ie": { + "url": "https://api-inference.modelscope.cn/api-inference/v1/models/damo/nlp_structbert_siamese-uie_chinese-base" + }, + "modelscope_speech-generation": { + "url": "https://api-inference.modelscope.cn/api-inference/v1/models/damo/speech_sambert-hifigan_tts_zh-cn_16k" + }, + "modelscope_video-generation": { + "url": "https://api-inference.modelscope.cn/api-inference/v1/models/damo/text-to-video-synthesis" + }, + "modelscope_image-chat": { + "url": "https://api-inference.modelscope.cn/api-inference/v1/models/damo/multi-modal_mplug_owl_multimodal-dialogue_7b" + }, + "modelscope_text-translation-en2zh": { + "url": "https://api-inference.modelscope.cn/api-inference/v1/models/damo/nlp_csanmt_translation_en2zh" + }, + "modelscope_text-translation-zh2en": { + "url": "https://api-inference.modelscope.cn/api-inference/v1/models/damo/nlp_csanmt_translation_zh2en" + }, + "modelscope_image-generation": { + "url": "https://api-inference.modelscope.cn/api-inference/v1/models/AI-ModelScope/stable-diffusion-xl-base-1.0", + "pipeline_params": { + "use_safetensors": true + } + } +} diff --git a/demo/facechain_agent/demo/facechain_agent/app_v1.0.py b/demo/facechain_agent/demo/facechain_agent/app_v1.0.py new file mode 100644 index 000000000..aaa8cbfd3 --- /dev/null +++ b/demo/facechain_agent/demo/facechain_agent/app_v1.0.py @@ -0,0 +1,387 @@ +from __future__ import annotations +import os +import sys +sys.path.append('../../') +from functools import partial +import json +import shutil +import slugify +import glob +from torch import multiprocessing +import gradio as gr +from dotenv import load_dotenv +from modelscope_agent.agent import AgentExecutor +from modelscope_agent.llm import LLMFactory +from modelscope_agent.prompt import MSPromptGenerator, PromptGenerator +from modelscope_agent.retrieve import ToolRetrieval +from gradio_chatbot import ChatBot +from help_tool import StyleSearchTool, FaceChainFineTuneTool, FaceChainInferenceTool +import copy +from facechain.train_text_to_image_lora import prepare_dataset +from modelscope.utils.config import Config +import uuid +import dashscope +from dashscope.audio.tts import SpeechSynthesizer + +PROMPT_START = "你好,我是FaceChainAgent,可以帮你生成写真照片。请告诉我你需要的风格的名字。" + +SYSTEM_PROMPT = """<|system|>: 你现在扮演一个Facechain Agent,不断和用户沟通创作想法,询问用户写真照风格,最后生成搜索到的风格类型返回给用户。当前对话可以使用的插件信息如下,请自行判断是否需要调用插件来解决当前用户问题。若需要调用插件,则需要将插件调用请求按照json格式给出,必须包含api_name、parameters字段,并在其前后使用<|startofthink|>和<|endofthink|>作为标志。然后你需要根据插件API调用结果生成合理的答复。 +\n\n""" + +INSTRUCTION_TEMPLATE = """【多轮对话历史】 +<|user|>: 给我生成一个赛博朋克风的吧 + +<|assistant|>: 好的,我将为您找到这个风格类型。 +正在搜索风格类型: +<|startofthink|>```JSON\n{\n "api_name": "style_search_tool",\n "parameters": {\n "text": "我想要赛博朋克风。"\n }\n}\n```<|endofthink|> + +<|startofexec|>```JSON\n{"result": {"name": "style_search_tool", "value": "赛博朋克(Cybernetics punk)", file_path: "../../styles/leosamsMoonfilm_filmGrain20/Cybernetics_punk.json"}}\n```<|endofexec|> + +我已为你找到的风格类型名字是赛博朋克(Cybernetics punk)。 + +现在我需要你提供1-3张照片,请点击图片上传按钮上传你的照片。上传完毕后在对话框里告诉我你已经上传好照片了。\n\n + +<|user|>: 我的照片上传好了。 + +<|assistant|>: 收到,我需要几分钟时间训练你上传的照片,然后再生成您的赛博朋克风格写真照。 + +正在训练人物lora中: +<|startofthink|>```JSON\n{\n "api_name": "facechain_finetune_tool",\n "parameters": {}\n}\n```<|endofthink|> + +人物lora训练完成。正在生成你选择的赛博朋克风格写真照中: +<|startofthink|>```JSON\n{\n "api_name": "facechain_inference_tool",\n "parameters": {\n "matched_style_file_path": "../../styles/leosamsMoonfilm_filmGrain20/Cybernetics_punk.json"\n }\n}\n```<|endofthink|> + +写真照已经生成完毕!你还可以继续生成这类风格的照片或者更换一个风格\n\n + +【角色扮演要求】 +上面多轮角色对话是提供的创作一个写真照风格要和用户沟通的样例,请按照上述的询问步骤来引导用户完成风格的生成,每次只回复对应的内容,不要生成多轮对话。记住只回复用户当前的提问,不要生成多轮对话,回复不要包含<|user|>后面的内容。 +""" + + +INSTRUCTION_TEMPLATE1 = """ +<|user|>: 我想要换个古风风格。 + +<|assistant|>: 好的,我将首先搜索相关风格,然后再为您生成古风风格的写真 +<|startofthink|>```JSON\n{\n "api_name": "style_search_tool",\n "parameters": {\n "text": "换一个古风的吧"\n }\n}\n```<|endofthink|> + +我为你搜索到的风格是古风风格(Old style)。 +我现在将用前面你上传的照片和新选择的风格生成写真照。 +生成写真照中: +<|startofthink|>```JSON\n{\n "api_name": "facechain_inference_tool",\n "parameters": {\n "matched_style_file_path": "../../styles/leosamsMoonfilm_filmGrain20/Old_style.json"\n }\n}\n```<|endofthink|> + +古风写真已经生成完毕!你还可以继续生成这类风格的照片或者更换一个风格\n\n + +【角色扮演要求】 +上面多轮角色对话是提供的创作一个写真照风格要和用户沟通的样例,请按照上述的询问步骤来引导用户完成风格的生成,每次只回复对应的内容,不要生成多轮对话。记住只回复用户当前的提问,不要生成多轮对话,回复不要包含<|user|>后面的内容。 + +""" + + +KEY_TEMPLATE = " " +load_dotenv('../config/.env', override=True) +os.environ['TOOL_CONFIG_FILE'] = '../config/cfg_tool_template.json' +os.environ['MODEL_CONFIG_FILE'] = '../config/cfg_model_template.json' +os.environ['OUTPUT_FILE_DIRECTORY'] = './tmp' +#dashscope.api_key = os.environ.get('DASHSCOPE_API_KEY') +#dashscope.base_http_api_url = 'https://poc-dashscope.aliyuncs.com/api/v1' +#dashscope.base_websocket_api_url = 'https://poc-dashscope.aliyuncs.com/api-ws/v1/inference' + +style_paths = ["../../styles/leosamsMoonfilm_filmGrain20", "../../styles/MajicmixRealistic_v6"] +styles = [] +for folder_path in style_paths: + for filename in os.listdir(folder_path): + file_path = os.path.join(folder_path, filename) + with open(file_path, "r") as f: + data = json.load(f) + styles.append(data) + +with open( + os.path.join(os.path.dirname(__file__), 'main.css'), "r", + encoding="utf-8") as f: + MAIN_CSS_CODE = f.read() + +# ----------agent 对象初始化-------------------- + +tool_cfg_file = os.getenv('TOOL_CONFIG_FILE') +model_cfg_file = os.getenv('MODEL_CONFIG_FILE') + +tool_cfg = Config.from_file(tool_cfg_file) +model_cfg = Config.from_file(model_cfg_file) + +model_name = 'modelscope-agent-7b' +# model_name = 'modelscope-agent' +#model_name = 'http_llm' +llm = LLMFactory.build_llm(model_name, model_cfg) + +prompt_generator = MSPromptGenerator( + system_template=SYSTEM_PROMPT, + instruction_template=INSTRUCTION_TEMPLATE) + +prompt_generator1 = MSPromptGenerator( + system_template=SYSTEM_PROMPT, + instruction_template=INSTRUCTION_TEMPLATE1) + +def add_file(history, files, uuid_str: str): + if not uuid_str: + if os.getenv("MODELSCOPE_ENVIRONMENT") == 'studio': + raise gr.Error("请登陆后使用! (Please login first)") + else: + uuid_str = 'facechain_agent' + history = history + [((file.name,), None) for file in files] + # task_history = task_history + [((file.name,), None) for file in files] + file_paths = [] + filtered_list = [] + print(history) + file_paths = [item[0][0] for item in history if item[0] != None] + if len(file_paths) == 0: + raise ValueError("照片上传失败") + print("#####", file_paths) + filtered_list = [item for item in file_paths if '.jpg' in item or '.png' in item] + print("#####", filtered_list) + uuid = 'qw' + # shutil.rmtree(f"./{uuid}", ignore_errors=True) + base_model_path = 'cv_portrait_model' + revision = 'v2.0' + sub_path = "film/film" + uuid_str=uuid_str[:8] + print("#####切割后uuid_str",uuid_str) + output_model_name = uuid_str + output_model_name = slugify.slugify(output_model_name) + instance_data_dir = os.path.join('./', base_model_path, output_model_name) + shutil.rmtree(instance_data_dir, ignore_errors=True) + try: + prepare_dataset(filtered_list, instance_data_dir) + except Exception as e: + raise e("预处理图片数据出错") + return history + + +def reset_user_input(): + return gr.update(value="") + + +def text_to_speech(text): + result = SpeechSynthesizer.call(model='sambert-zhichu-v1', + text=text, + sample_rate=48000, + format='wav') + return result.get_audio_data() + + if result.get_audio_data() is not None: + with open('tts.wav', 'wb') as f: + f.write(result.get_audio_data()) + + +def init(uuid_str, state): + if not uuid_str: + if os.getenv("MODELSCOPE_ENVIRONMENT") == 'studio': + raise gr.Error("请登陆后使用! (Please login first)") + else: + uuid_str = 'facechain_agent' + #print('##############################', uuid_str) + uuid_str=uuid_str[:8] + #print("#####切割后uuid_str",uuid_str) + style_search_tool = StyleSearchTool(style_paths) + facechain_finetune_tool = FaceChainFineTuneTool(uuid_str) # 初始化lora_name,区分不同用户 + facechain_inference_tool = FaceChainInferenceTool(uuid_str) + additional_tool_list = { + style_search_tool.name: style_search_tool, + facechain_finetune_tool.name: facechain_finetune_tool, + facechain_inference_tool.name: facechain_inference_tool + } + agent = AgentExecutor( + llm, + tool_cfg, + prompt_generator=prompt_generator, + tool_retrieval=False, + additional_tool_list=additional_tool_list, + # knowledge_retrieval=knowledge_retrieval + ) + agent.set_available_tools(additional_tool_list.keys()) + state['agent'] = agent + state['additional_tool_list'] = additional_tool_list + + +with gr.Blocks(css=MAIN_CSS_CODE, theme=gr.themes.Soft()) as demo: + uuid_str = gr.Textbox(label="modelscope_uuid", visible=False) + state = gr.State({}) + demo.load(init, inputs=[uuid_str, state], outputs=[]) + # 生成随机的 UUID(和uuid=‘qw'不一样) + + with gr.Row(): + gr.Markdown( + "#
\N{fire} FaceChain Potrait Generation ([Github star it here](https://github.com/modelscope/facechain/tree/main) \N{whale}, [Paper cite it here](https://arxiv.org/abs/2308.14256) \N{whale})
") + with gr.Row(): + gr.Markdown( + "#####
本项目仅供学习交流,请勿将模型及其制作内容用于非法活动或违反他人隐私的场景。(This project is intended solely for the purpose of technological discussion, and should not be used for illegal activities and violating privacy of individuals.)
") + with gr.Row(): + gr.Markdown( + """ """) + with gr.Row(): + with gr.Column(): + gr.Markdown(""" 🌈 🌈 🌈 + + ## 你好,我是FaceChain Agent,可以帮你生成写真照片。 + + ## 下图是各类风格的展示图,你可以在这先挑选你喜欢的风格。 + + ## 然后在下方的聊天框里与我交流吧,一起来生成美妙的写真照! + + """) + with gr.Row(): + gallery = gr.Gallery(value=[(os.path.join("../../", item["img"]), item["name"]) for item in styles], + elem_id='gallery', show_label=False + ).style(object_fit='contain', preview=True, columns=6) + with gr.Row(elem_id="container_row").style(equal_height=True): + with gr.Column(scale=8, elem_classes=["chatInterface", "chatDialog", "chatContent"]): + with gr.Row(elem_id='chat-container'): + chatbot = ChatBot(value=[[None, PROMPT_START]], + elem_id="chatbot", + elem_classes=["markdown-body"], + show_label=False, + ) + + with gr.Row(elem_id="chat-bottom-container"): + with gr.Column(min_width=70, scale=1): + clear_session_button = gr.Button( + "清除", elem_id='clear_session_button', default_value=True) + with gr.Column(scale=12): + user_input = gr.Textbox( + show_label=False, + placeholder="一起来自由生成写真照吧~", + elem_id="chat-input").style(container=False) + with gr.Column(min_width=70, scale=1): + submitBtn = gr.Button("发送", variant="primary") + with gr.Column(min_width=110, scale=1): + upload_button = gr.UploadButton("上传照片", file_types=["image"], file_count="multiple") + with gr.Column(min_width=110, scale=1): + regenerate_button = gr.Button( + "重新生成", elem_id='regenerate_button') + gr.Examples( + examples=['我想要牛仔风', '我想要凤冠霞帔风', '我的照片上传好了', '我现在想换个风格,我想要工作风'], + inputs=[user_input], + label="示例", + elem_id="chat-examples") + + + def facechain_agent(*inputs): + + user_input = inputs[0] + chatbot = inputs[1] + state = inputs[2] + agent = state['agent'] + + chatbot.append((user_input, None)) + yield chatbot + history_image = [] + + def update_component(exec_result, history): + exec_result = exec_result['result'] + name = exec_result.pop('name') + if name == 'facechain_inference_tool': + single_path = exec_result['single_path'] + #print("########_______single_path", single_path) + + image_files = glob.glob(os.path.join(single_path, '*.jpg')) + image_files += glob.glob(os.path.join(single_path, '*.png')) + #print("########_______image_files", image_files) + + history = [(None, (file,)) for file in image_files] + # task_history = task_history + [(None,(file,)) for file in image_files] + else: + history = [] + # task_history = task_history + return history + + response = '' + for frame in agent.stream_run(user_input + KEY_TEMPLATE, remote=True): + is_final = frame.get("frame_is_final") + llm_result = frame.get("llm_text", "") + exec_result = frame.get('exec_result', '') + # print(frame) + history = [] + llm_result = llm_result.split("<|user|>")[0].strip() + if len(exec_result) != 0: + history = update_component(exec_result, chatbot) + print("#########________history", history) + frame_text = " " + else: + # action_exec_result + frame_text = llm_result + response = f'{response}\n{frame_text}' + chatbot[-1] = (user_input, response) + if history != []: + history_image = history + + yield chatbot + try: + if history_image != []: + try: + agent = AgentExecutor( + llm, + tool_cfg, + prompt_generator=prompt_generator1, + tool_retrieval=False, + additional_tool_list=state["additional_tool_list"], + # knowledge_retrieval=knowledge_retrieval + ) + agent.set_available_tools(state["additional_tool_list"].keys()) + inputs[2]['agent'] = agent + except Exception as e: + import traceback + print(f'error {e} with detail {traceback.format_exc()}') + + for item in history_image: + chatbot.append(item) + yield chatbot + + except: + pass + + + # ---------- 事件 --------------------- + + stream_predict_input = [user_input, chatbot, state] + stream_predict_output = [chatbot] + + clean_outputs_start = ['', gr.update(value=[(None, PROMPT_START)])] + clean_outputs = ['', gr.update(value=[])] + clean_outputs_target = [user_input, chatbot] + user_input.submit( + facechain_agent, + inputs=stream_predict_input, + outputs=stream_predict_output, + show_progress=True) + user_input.submit( + fn=lambda: clean_outputs, inputs=[], outputs=clean_outputs_target) + submitBtn.click( + facechain_agent, + stream_predict_input, + stream_predict_output, + show_progress=True + ) + submitBtn.click(reset_user_input, [], [user_input]) + regenerate_button.click( + fn=lambda: clean_outputs, inputs=[], outputs=clean_outputs_target) + regenerate_button.click( + facechain_agent, + stream_predict_input, + stream_predict_output, + show_progress=True) + + + def clear_session(state): + agent = state['agent'] + agent.reset() + + + clear_session_button.click(fn=clear_session, inputs=[state], outputs=[]) + clear_session_button.click( + fn=lambda: clean_outputs_start, inputs=[], outputs=clean_outputs_target) + upload_button.upload(add_file, inputs=[chatbot, upload_button, uuid_str], outputs=[chatbot], show_progress=True) + # chatbot[-1] = ((None, PROMPT_START)) +demo.title = "Facechian Agent 🎁" +if __name__ == "__main__": + # print(multiprocessing.get_start_method()) + multiprocessing.set_start_method('spawn') + demo.queue(status_update_rate=1).launch(share=True) diff --git a/demo/facechain_agent/demo/facechain_agent/gradio_chatbot.py b/demo/facechain_agent/demo/facechain_agent/gradio_chatbot.py new file mode 100644 index 000000000..6bf23d005 --- /dev/null +++ b/demo/facechain_agent/demo/facechain_agent/gradio_chatbot.py @@ -0,0 +1,205 @@ +from __future__ import annotations +import html +import re +import traceback +from typing import List, Tuple + +import json +import markdown +from gradio.components import Chatbot as ChatBotBase +ALREADY_CONVERTED_MARK = "" + +class ChatBot(ChatBotBase): + + def normalize_markdown(self, bot_message): + lines = bot_message.split("\n") + normalized_lines = [] + inside_list = False + + for i, line in enumerate(lines): + if re.match(r"^(\d+\.|-|\*|\+)\s", line.strip()): + if not inside_list and i > 0 and lines[i - 1].strip() != "": + normalized_lines.append("") + inside_list = True + normalized_lines.append(line) + elif inside_list and line.strip() == "": + if i < len(lines) - 1 and not re.match(r"^(\d+\.|-|\*|\+)\s", + lines[i + 1].strip()): + normalized_lines.append(line) + continue + else: + inside_list = False + normalized_lines.append(line) + + return "\n".join(normalized_lines) + + def convert_markdown(self, bot_message): + if bot_message.count('```') % 2 != 0: + bot_message += '\n```' + + bot_message = self.normalize_markdown(bot_message) + + result = markdown.markdown( + bot_message, + extensions=[ + 'toc', 'extra', 'tables', 'markdown_katex', 'codehilite', + 'mdx_truly_sane_lists', 'markdown_cjk_spacing.cjk_spacing', + 'pymdownx.magiclink' + ], + extension_configs={ + 'markdown_katex': { + 'no_inline_svg': True, # fix for WeasyPrint + 'insert_fonts_css': True, + }, + 'codehilite': { + 'linenums': False, + 'guess_lang': True + }, + 'mdx_truly_sane_lists': { + 'nested_indent': 2, + 'truly_sane': True, + } + }) + result = "".join(result) + return result + + def convert_bot_message(self, bot_message): + + # 兼容老格式 + chunks = bot_message.split('') + if len(chunks) > 1: + new_bot_message = '' + for idx, chunk in enumerate(chunks): + new_bot_message += chunk + if idx % 2 == 0: + if idx != len(chunks) - 1: + new_bot_message += '<|startofthink|>' + else: + new_bot_message += '<|endofthink|>' + + bot_message = new_bot_message + + start_pos = 0 + result = '' + find_json_pattern = re.compile(r'{[\s\S]+}') + START_OF_THINK_TAG, END_OF_THINK_TAG = '<|startofthink|>', '<|endofthink|>' + START_OF_EXEC_TAG, END_OF_EXEC_TAG = '<|startofexec|>', '<|endofexec|>' + while start_pos < len(bot_message): + try: + start_of_think_pos = bot_message.index(START_OF_THINK_TAG, + start_pos) + end_of_think_pos = bot_message.index(END_OF_THINK_TAG, + start_pos) + if start_pos < start_of_think_pos: + result += self.convert_markdown( + bot_message[start_pos:start_of_think_pos]) + think_content = bot_message[start_of_think_pos + + len(START_OF_THINK_TAG + ):end_of_think_pos].strip() + json_content = find_json_pattern.search(think_content) + think_content = json_content.group( + ) if json_content else think_content + try: + think_node = json.loads(think_content) + plugin_name = think_node.get( + 'plugin_name', + think_node.get('plugin', + think_node.get('api_name', 'unknown'))) + summary = f'选择插件【{plugin_name}】,调用处理中...' + del think_node['url'] + #think_node.pop('url', None) + + detail = f'```json\n\n{json.dumps(think_node,indent=3,ensure_ascii=False)}\n\n```' + except Exception: + summary = f'思考中...' + detail = think_content + # traceback.print_exc() + # detail += traceback.format_exc() + result += '
' + summary + '' + self.convert_markdown( + detail) + '
' + #print(f'detail:{detail}') + start_pos = end_of_think_pos + len(END_OF_THINK_TAG) + except Exception: + # result += traceback.format_exc() + break + # continue + + try: + start_of_exec_pos = bot_message.index(START_OF_EXEC_TAG, + start_pos) + end_of_exec_pos = bot_message.index(END_OF_EXEC_TAG, start_pos) + # print(start_of_exec_pos) + # print(end_of_exec_pos) + # print(bot_message[start_of_exec_pos:end_of_exec_pos]) + # print('------------------------') + if start_pos < start_of_exec_pos: + result += self.convert_markdown( + bot_message[start_pos:start_of_think_pos]) + exec_content = bot_message[start_of_exec_pos + + len(START_OF_EXEC_TAG + ):end_of_exec_pos].strip() + try: + summary = f'完成插件调用.' + detail = f'```json\n\n{exec_content}\n\n```' + except Exception: + pass + + result += '
' + summary + '' + self.convert_markdown( + detail) + '
' + + start_pos = end_of_exec_pos + len(END_OF_EXEC_TAG) + except Exception: + # result += traceback.format_exc() + continue + if start_pos < len(bot_message): + result += self.convert_markdown(bot_message[start_pos:]) + result += ALREADY_CONVERTED_MARK + return result + + + def postprocess( + self, + message_pairs: list[list[str | tuple[str] | tuple[str, str] | None] | tuple], + ) -> list[list[str | dict | None]]: + """ + Parameters: + message_pairs: List of lists representing the message and response pairs. Each message and response should be a string, which may be in Markdown format. It can also be a tuple whose first element is a string or pathlib.Path filepath or URL to an image/video/audio, and second (optional) element is the alt text, in which case the media file is displayed. It can also be None, in which case that message is not displayed. + Returns: + List of lists representing the message and response. Each message and response will be a string of HTML, or a dictionary with media information. Or None if the message is not to be displayed. + """ + if message_pairs is None: + return [] + processed_messages = [] + for message_pair in message_pairs: + assert isinstance( + message_pair, (tuple, list) + ), f"Expected a list of lists or list of tuples. Received: {message_pair}" + assert ( + len(message_pair) == 2 + ), f"Expected a list of lists of length 2 or list of tuples of length 2. Received: {message_pair}" + if isinstance(message_pair[0], tuple) or isinstance(message_pair[1], tuple): + processed_messages.append( + [ + self._postprocess_chat_messages(message_pair[0]), + self._postprocess_chat_messages(message_pair[1]), + ] + ) + else: + # 处理不是元组的情况 + user_message, bot_message = message_pair + + if user_message and not user_message.endswith( + ALREADY_CONVERTED_MARK): + convert_md = self.convert_markdown(html.escape(user_message)) + user_message = f"

{convert_md}

" + ALREADY_CONVERTED_MARK + if bot_message and not bot_message.endswith( + ALREADY_CONVERTED_MARK): + bot_message = self.convert_bot_message(bot_message) + processed_messages.append( + [ + user_message, + bot_message, + ] + ) + + return processed_messages diff --git a/demo/facechain_agent/demo/facechain_agent/help_tool.py b/demo/facechain_agent/demo/facechain_agent/help_tool.py new file mode 100644 index 000000000..4dc2ee96f --- /dev/null +++ b/demo/facechain_agent/demo/facechain_agent/help_tool.py @@ -0,0 +1,444 @@ +import os +import sys +from modelscope_agent.tools import Tool, TextToImageTool +from langchain.embeddings import ModelScopeEmbeddings +from langchain.vectorstores import FAISS +from langchain.text_splitter import CharacterTextSplitter +from langchain.document_loaders import TextLoader +from langchain.schema import Document +import gradio as gr +from difflib import SequenceMatcher +from typing import List +from pathlib import Path +import json +import platform +import random +import shutil +import slugify +import subprocess +import time +import torch +import cv2 +import numpy as np + +from facechain.inference import data_process_fn +from facechain.utils import snapshot_download +from concurrent.futures import ProcessPoolExecutor +from facechain.inference import GenPortrait + +class StyleSearchTool(Tool): + description = '' + name = 'style_search_tool' + parameters: list = [{ + 'name': 'text', + 'description': '用户输入的想要的风格文本', + 'required': True + }, + ] + def __init__(self, style_path: List[str]): + self.style_path = style_path + super().__init__() + def _remote_call(self, text): + + best_match = None # 用于存储最佳匹配风格 + best_similarity = 0 # 用于存储最佳匹配的相似性度量值 + best_file_path = None # 用于存储最佳匹配的文件路径 + for style_folder in self.style_path: + + # 列出风格文件夹下的所有文件 + files = os.listdir(style_folder) + files.sort() + for file in files: + file_path = os.path.join(style_folder, file) + with open(file_path, "r") as f: + data = json.load(f) + style_name = data.get('name', '') # 获取风格文件中的名称字段 + + # 计算文本与风格名称之间的相似性 + similarity = SequenceMatcher(None, text, style_name).ratio() + + # 如果相似性高于当前最佳匹配,更新最佳匹配 + if similarity > best_similarity: + best_similarity = similarity + best_match = style_name + best_file_path = file_path # 更新最佳匹配的文件路径 + + result = { + 'name': self.name, + 'value': best_match , + 'file_path':best_file_path # 返回最相似的风格名称 + } + + return {'result': result} + def _remote_call(self, text): + best_match = None # 用于存储最佳匹配风格 + best_similarity = 0 # 用于存储最佳匹配的相似性度量值 + best_file_path = None # 用于存储最佳匹配的文件路径 + + for style_folder in self.style_path: + # 列出风格文件夹下的所有文件 + files = os.listdir(style_folder) + files.sort() + for file in files: + file_path = os.path.join(style_folder, file) + with open(file_path, "r") as f: + data = json.load(f) + style_name = data.get('name', '') # 获取风格文件中的名称字段 + + # 计算文本与风格名称之间的相似性 + similarity = SequenceMatcher(None, text, style_name).ratio() + + # 如果相似性高于当前最佳匹配,更新最佳匹配 + if similarity > best_similarity: + best_similarity = similarity + best_match = style_name + best_file_path = file_path # 更新最佳匹配的文件路径 + + result = { + 'name': self.name, + 'value': best_match , + 'file_path':best_file_path # 返回最相似的风格名称 + } + + return {'result': result} + +class FaceChainFineTuneTool(Tool): + description = "模型微调工具,根据用户提供的图片训练出Lora" + name = "facechain_finetune_tool" + parameters: list = [] + + def __init__(self,lora_name:str): + super().__init__() + self.base_model_path = 'ly261666/cv_portrait_model' + self.revision = 'v2.0' + self.sub_path = "film/film" + # 这里固定了Lora的名字,重新训练会覆盖原来的 + self.lora_name = lora_name + + + def _remote_call(self): + uuid = 'qw' + # train lora + _train_lora(uuid, self.lora_name, self.base_model_path, self.revision, self.sub_path) + + result = {'name':self.name,'lora_name': self.lora_name, 'uuid': uuid, 'msg': "训练完成"} + return {'result': result} + + def _local_call(self): + uuid = 'qw' + + # train lora + _train_lora(uuid, self.lora_name,self.base_model_path, self.revision, self.sub_path) + + result = {'name':self.name,'lora_name': self.lora_name, 'uuid': uuid, 'msg': "训练完成"} + return {'result': result} + +def train_lora_fn(base_model_path=None, revision=None, sub_path=None, output_img_dir=None, work_dir=None, photo_num=0): + torch.cuda.empty_cache() + + lora_r = 4 + lora_alpha = 32 + #max_train_steps = min(photo_num * 200, 800) + + if platform.system() == 'Windows': + command = [ + 'accelerate', 'launch', '../../facechain/train_text_to_image_lora.py', + f'--pretrained_model_name_or_path={base_model_path}', + f'--revision={revision}', + f'--sub_path={sub_path}', + f'--output_dataset_name={output_img_dir}', + '--caption_column=text', + '--resolution=512', + '--random_flip', + '--train_batch_size=1', + '--num_train_epochs=200', + '--checkpointing_steps=5000', + '--learning_rate=1.5e-04', + '--lr_scheduler=cosine', + '--lr_warmup_steps=0', + '--seed=42', + f'--output_dir={work_dir}', + f'--lora_r={lora_r}', + f'--lora_alpha={lora_alpha}', + '--lora_text_encoder_r=32', + '--lora_text_encoder_alpha=32', + '--resume_from_checkpoint="fromfacecommon"' + ] + + try: + subprocess.run(command, check=True) + except subprocess.CalledProcessError as e: + print(f"Error executing the command: {e}") + raise RuntimeError("训练失败 (Training failed)") + else: + res = os.system( + f'PYTHONPATH=. accelerate launch ../../facechain/train_text_to_image_lora.py ' + f'--pretrained_model_name_or_path={base_model_path} ' + f'--revision={revision} ' + f'--sub_path={sub_path} ' + f'--output_dataset_name={output_img_dir} ' + f'--caption_column="text" ' + f'--resolution=512 ' + f'--random_flip ' + f'--train_batch_size=1 ' + f'--num_train_epochs=200 ' + f'--checkpointing_steps=5000 ' + f'--learning_rate=1.5e-04 ' + f'--lr_scheduler="cosine" ' + f'--lr_warmup_steps=0 ' + f'--seed=42 ' + f'--output_dir={work_dir} ' + f'--lora_r={lora_r} ' + f'--lora_alpha={lora_alpha} ' + f'--lora_text_encoder_r=32 ' + f'--lora_text_encoder_alpha=32 ' + f'--resume_from_checkpoint="fromfacecommon"') + if res != 0: + raise RuntimeError("训练失败 (Training failed)") + + +def _train_lora(uuid, output_model_name, base_model_path, revision, sub_path): + output_model_name = slugify.slugify(output_model_name) + + # mv user upload data to target dir + instance_data_dir = os.path.join('./', base_model_path.split('/')[-1], output_model_name) + print('################################instance_data_dir', instance_data_dir) + if not os.path.exists(f"./{uuid}"): + os.makedirs(f"./{uuid}") + work_dir = f"./{uuid}/{base_model_path}/{output_model_name}" + print('################################work_dir', work_dir) + + shutil.rmtree(work_dir, ignore_errors=True) + try: + data_process_fn(instance_data_dir, True) + except Exception as e: + raise e("提取图片label错误") from e + + train_lora_fn( + base_model_path=base_model_path, + revision=revision, + sub_path=sub_path, + output_img_dir=instance_data_dir, + work_dir=work_dir, + photo_num=len(instance_data_dir) + ) + + return base_model_path, revision, sub_path, instance_data_dir, work_dir + +#-------------------------------------- +training_done_count = 0 +inference_done_count = 0 +base_models = [ + {'name': 'leosamsMoonfilm_filmGrain20', + 'model_id': 'ly261666/cv_portrait_model', + 'revision': 'v2.0', + 'sub_path': "film/film"}, + {'name': 'MajicmixRealistic_v6', + 'model_id': 'YorickHe/majicmixRealistic_v6', + 'revision': 'v1.0.0', + 'sub_path': "realistic"}, +] +neg_prompt = '(nsfw:2), paintings, sketches, (worst quality:2), (low quality:2), ' \ + 'lowers, normal quality, ((monochrome)), ((grayscale)), logo, word, character, bad hand, tattoo, (username, watermark, signature, time signature, timestamp, artist name, copyright name, copyright),'\ + 'low res, ((monochrome)), ((grayscale)), skin spots, acnes, skin blemishes, age spot, glans, extra fingers, fewer fingers, strange fingers, bad hand, mole, ((extra legs)), ((extra hands))' +pos_prompt_with_cloth = 'raw photo, masterpiece, chinese, {}, solo, medium shot, high detail face, looking straight into the camera with shoulders parallel to the frame, photorealistic, best quality' +pos_prompt_with_style = '{}, upper_body, raw photo, masterpiece, solo, medium shot, high detail face, photorealistic, best quality' + +def concatenate_images(images): + heights = [img.shape[0] for img in images] + max_width = sum([img.shape[1] for img in images]) + + concatenated_image = np.zeros((max(heights), max_width, 3), dtype=np.uint8) + x_offset = 0 + for img in images: + concatenated_image[0:img.shape[0], x_offset:x_offset + img.shape[1], :] = img + x_offset += img.shape[1] + return concatenated_image +def launch_pipeline(uuid, + pos_prompt, + matched, + num_images, + neg_prompt=None, + base_model_index=0, + user_model=None, + lora_choice=None, + multiplier_style=0.35, + multiplier_human=0.95, + pose_model=None, + pose_image=None, + ): + uuid = 'qw' + character_model='ly261666/cv_portrait_model'# + # Check character LoRA + folder_path = f"./{uuid}/{character_model}" + folder_list = [] + if os.path.exists(folder_path): + files = os.listdir(folder_path) + for file in files: + file_path = os.path.join(folder_path, file) + if os.path.isdir(folder_path): + file_lora_path = f"{file_path}/pytorch_lora_weights.bin" + if os.path.exists(file_lora_path): + folder_list.append(file) + if len(folder_list) == 0: + raise '没有人物LoRA,请先训练(There is no character LoRA, please train first)!' + # Check output model + if user_model is None: + raise '请选择人物LoRA(Please select the character LoRA)!' + base_model = base_models[base_model_index]['model_id'] + revision = base_models[base_model_index]['revision'] + sub_path = base_models[base_model_index]['sub_path'] + before_queue_size = 0 + before_done_count = inference_done_count + style_model = matched['name'] + if matched['model_id'] is None: + style_model_path = None + else: + model_dir = snapshot_download(matched['model_id'], revision=matched['revision']) + style_model_path = os.path.join(model_dir, matched['bin_file']) + + if pose_image is None or pose_model == 0: + pose_model_path = None + use_depth_control = False + pose_image = None + else: + model_dir = snapshot_download('damo/face_chain_control_model', revision='v1.0.1') + pose_model_path = os.path.join(model_dir, 'model_controlnet/control_v11p_sd15_openpose') + if pose_model == 1: + use_depth_control = True + else: + use_depth_control = False + + print("-------user_model(也就是人物lora name): ", user_model) + + use_main_model = True + use_face_swap = True + use_post_process = True + use_stylization = False +#user_model就是人物lora的name + instance_data_dir = os.path.join('./', character_model.split('/')[-1], user_model) + lora_model_path = f'./{uuid}/{character_model}/{user_model}' + print('################################instance_data_dir', instance_data_dir) + print('################################lora_model_path', lora_model_path) + + gen_portrait = GenPortrait(pose_model_path, pose_image, use_depth_control, pos_prompt, neg_prompt, style_model_path, + multiplier_style, multiplier_human, use_main_model, + use_face_swap, use_post_process, + use_stylization) + + num_images = min(6, num_images) + + with ProcessPoolExecutor(max_workers=1) as executor: + future = executor.submit(gen_portrait, instance_data_dir, + num_images, base_model, lora_model_path, sub_path, revision) + while not future.done(): + is_processing = future.running() + if not is_processing: + cur_done_count = inference_done_count + to_wait = before_queue_size - (cur_done_count - before_done_count) + print("排队等待资源中, 前方还有{}个生成任务, 预计需要等待{}分钟...".format(to_wait, to_wait * 2.5), + None) + else: + print("生成中, 请耐心等待(Generating)...", None) + time.sleep(1) + + outputs = future.result() + outputs_RGB = [] + for out_tmp in outputs: + outputs_RGB.append(cv2.cvtColor(out_tmp, cv2.COLOR_BGR2RGB)) + + save_dir = os.path.join('./', base_model, user_model) + if lora_choice == 'preset': + save_dir = os.path.join(save_dir, 'style_' + style_model[:2]) + else: + save_dir = os.path.join(save_dir, 'lora_' + os.path.basename(lora_choice).split('.')[0]) + + if not os.path.exists(save_dir): + os.makedirs(save_dir) + # use single to save outputs + if not os.path.exists(os.path.join(save_dir, 'single')): + os.makedirs(os.path.join(save_dir, 'single')) + single_path=os.path.join(save_dir, 'single') + for img in outputs: + # count the number of images in the folder + num = len(os.listdir(os.path.join(save_dir, 'single'))) + cv2.imwrite(os.path.join(save_dir, 'single', str(num) + '.png'), img) + + if len(outputs) > 0: + result = concatenate_images(outputs) + if not os.path.exists(os.path.join(save_dir, 'concat')): + os.makedirs(os.path.join(save_dir, 'concat')) + num = len(os.listdir(os.path.join(save_dir, 'concat'))) + image_path = os.path.join(save_dir, 'concat', str(num) + '.png') + cv2.imwrite(image_path, result)#整体图像 + + return ("生成完毕(Generation done)!", outputs_RGB,single_path) + else: + return ("生成失败, 请重试(Generation failed, please retry)!", outputs_RGB,single_path) + +def generate_pos_prompt(matched_style_file, prompt_cloth): + if matched_style_file is not None: + # matched = list(filter(lambda style: style_model == style['name'], styles)) + # if len(matched) == 0: + # raise ValueError(f'styles not found: {style_model}') + + if matched_style_file['model_id'] is None: + pos_prompt = pos_prompt_with_cloth.format(prompt_cloth) + else: + pos_prompt = pos_prompt_with_style.format(matched_style_file['add_prompt_style']) + else: + pos_prompt = pos_prompt_with_cloth.format(prompt_cloth) + return pos_prompt +class FaceChainInferenceTool(Tool): + description = "根据用户人脸lora和风格lora生成写真" + name = 'facechain_inference_tool' + parameters: list = [{ + 'name': 'matched_style_file_path', + 'description': '风格文件的位置', + 'required': True + }] +#user_model 也就是 lora_name + def __init__(self,user_model:str): + self.user_model = user_model + super().__init__() + + def _remote_call(self, matched_style_file_path:str): + with open (matched_style_file_path,'r') as f: + matched_style_file = json.load(f) + pos_prompt = generate_pos_prompt(matched_style_file, matched_style_file['add_prompt_style']) + print(os.path.dirname(matched_style_file_path)) + if "leosamsMoonfilm_filmGrain20" in matched_style_file_path: + base_model_index = 0 + elif "MajicmixRealistic_v6" in matched_style_file_path: + base_model_index = 1 + (infer_progress,output_images,single_path)=launch_pipeline(uuid='qw',matched=matched_style_file,pos_prompt=pos_prompt, + neg_prompt=neg_prompt, base_model_index=base_model_index, + user_model=self.user_model, num_images=3, + multiplier_style=0.35, + multiplier_human=0.95, pose_model=None, + pose_image=None, lora_choice='preset' + ) + result = {'name':self.name, 'infer_progress':infer_progress, 'output_images':output_images, 'single_path':single_path} + return {'result': result} + + def _local_call(self, matched_style_file_path:str): + with open (matched_style_file_path,'r') as f: + matched_style_file = json.load(f) + pos_prompt = generate_pos_prompt(matched_style_file, matched_style_file['add_prompt_style']) + if "leosamsMoonfilm_filmGrain20" in matched_style_file_path: + base_model_index = 0 + elif "MajicmixRealistic_v6" in matched_style_file_path: + base_model_index = 1 + (infer_progress,output_images,single_path)=launch_pipeline(uuid='qw',matched=matched_style_file,pos_prompt=pos_prompt, + neg_prompt=neg_prompt, base_model_index=base_model_index, + user_model=self.user_model, num_images=3, + multiplier_style=0.35, + multiplier_human=0.95, pose_model=None, + pose_image=None, lora_choice='preset' + ) + result = {'name':self.name, + 'infer_progress':infer_progress, + 'single_path':single_path + } + return {'result': result} + \ No newline at end of file diff --git a/demo/facechain_agent/demo/facechain_agent/main.css b/demo/facechain_agent/demo/facechain_agent/main.css new file mode 100644 index 000000000..e173cd53a --- /dev/null +++ b/demo/facechain_agent/demo/facechain_agent/main.css @@ -0,0 +1,340 @@ +/* 屏幕宽度大于等于500px的设备 */ +@media screen and (min-width: 500px) { + #chatbot, #chatbot_classic, #chatbot_classic textarea{ + height: 100%; + max-height: calc(58vw - 200px); + min-height: calc(58vw - 400px); + } + + #chatbot .wrap, #chatbot_classic, #chatbot_classic textarea{ + max-height: 100%; + } + + #container_row { + flex-direction: row-reverse; + } +} + +/* 屏幕宽度小于500px的设备 */ +@media screen and (max-width: 499px) { + #chatbot , #chatbot_classic, #chatbot_classic textarea{ + height: 300px; + } + + #chatbot .wrap ,#chatbot_classic, #chatbot_classic textarea{ + max-height: 100%; + } + + #container_row { + flex-direction: column; + } + + #chatbot { + max-width: 91vw; + } +} + +body, .gradio-container { + background-color: #fff; +} + +.gradio-container.app { + max-width: none !important; +} + +/* status_display */ +#status_display > .wrap { + display: none; +} + +#status_display { + display: flex; + min-height: 2.5em; + align-items: flex-end; + justify-content: flex-end; + color: rgba(98,74,255,.8); +} +#status_display p { + font-size: .85em; + font-family: monospace; + color: var(--body-text-color-subdued); +} + +#container_row button { + border-radius: 0; + box-shadow: none; +} + +#container_row button.primary { + border: 1px solid #624aff; + background: #624aff; + color: #fff; +} + +#container_row button.secondary { + border: 1px solid rgba(98,74,255,.8); + color: rgba(98,74,255,.8); +} + +#container_row .form { + border-radius: 0; +} + +#chat-input textarea { + border: 1px solid #e5e7eb; + border-radius: 0; +} + +#chat-examples .gallery { + text-align: left; + font-size: 12px; +} + +#chat-container { + flex: 1; +} + +#chat-bottom-container button.secondary { + font-weight: 600; + font-size: 16px; +} + +.robot-info { + display: flex; + justify-content: center; + align-items: center; +} + +.robot-info > img { + width: 20%; +} + +.robot-info .robot-info-text { + padding: 10px; + color: #624aff; +} + +.uploaded-image-box > img { + width: 100px; +} + +#settings .tab-nav button { + border: none; +} +#settings .tab-nav { + border: none; +} +#settings .tabitem { + border: none; + padding: 0px; +} + +#clear_session_button , #refresh_settings_button, #regenerate_button, #classic_button{ + font-size: 1em; + font-weight: normal; +} +#chatbot_classic{ + height: 100%; +} + +#chatbot { + border-radius: 0; + border: 1px solid #e5e7eb; + box-shadow: var(--shadow-drop); +} + +/* 对话气泡 */ +#chatbot [class *= "message"] { + border-radius: var(--radius-md) !important; + border: none; + padding: var(--spacing-xl) !important; + min-height: calc(var(--text-md) * var(--line-lg) + 2 * var(--spacing-xl)); + min-width: calc(var(--text-md) * var(--line-lg) + 2 * var(--spacing-xl)); + white-space: pre-line; + word-wrap: break-word; + font-size: 1rem; + line-height: 1.5rem; +} + +#chatbot .bot { + max-width: 85%; + border-bottom-left-radius: 0 !important; + margin-left: 38px; +} + +#chatbot .bot::before { + content: ''; + display: block; + width: 30px; + height: 30px; + background-image: url(//img.alicdn.com/imgextra/i4/O1CN01PRJFWt1PU8nZDGIKZ_!!6000000001843-0-tps-128-128.jpg); + background-size: cover; + background-repeat: no-repeat; + position: absolute; + top: 5px; + left: -38px; +} + +#chatbot .bot img{ + max-height: 400px !important; +} + +#chatbot .user { + max-width: 85%; + width: auto !important; + border-bottom-right-radius: 0 !important; +} + +#chatbot .bot > ol { + padding-left: 30px; +} +#chatbot .bot > ul { + padding-left: 30px; +} + +#chatbot summary { + font-size: 0.9em; + font-style: italic; + background-color: var(--secondary-400); + padding-left: 8px; +} + +#chatbot .bot details:not(:last-child) { + border-bottom: 1px solid #f7f8f9; +} + +/* 表格 */ +table { + border-radius: var(--radius-xl) !important; + margin: 1em 0; + border-collapse: collapse; + empty-cells: show; + font-size: 14px; +} + +td,th { + font-weight: var(--base-text-weight-semibold, 600); + padding: 6px 13px; + border: 1px solid #d0d7de; +} +thead { + background-color: rgba(175,184,193,0.2); +} +thead { + padding: 6px 13px; +} + +table tr:nth-child(2n) { + background-color: var(--color-canvas-subtle) +} + +table img { + background-color: transparent +} + +.codehilite .copy-button { + display: none; +} + +.codehilite { + background: #1d1d1dfc; + color: #666; + page-break-inside: avoid; + max-width: 100%; + display: block; + word-wrap: break-word; + overflow: auto; + overflow-x: auto; + counter-reset: line; + padding-left: 5px; +} + +.codehilitetable .codehilite { + border: 0px solid #3e3e3ed6; + box-shadow: inset 0 0 0px #000; +} + + +pre { line-height: 125%; } +td.linenos .normal { color: #37474F; background-color: #263238; padding-left: 5px; padding-right: 5px; } +span.linenos { color: #37474F; background-color: #263238; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #607A86; background-color: #263238; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #607A86; background-color: #263238; padding-left: 5px; padding-right: 5px; } +.codehilite .hll { background-color: #2C3B41 } +.codehilite { background: #263238; color: #EEFFFF } +.codehilite .c { color: #546E7A; font-style: italic } /* Comment */ +.codehilite .err { color: #FF5370 } /* Error */ +.codehilite .esc { color: #89DDFF } /* Escape */ +.codehilite .g { color: #EEFFFF } /* Generic */ +.codehilite .k { color: #BB80B3 } /* Keyword */ +.codehilite .l { color: #C3E88D } /* Literal */ +.codehilite .n { color: #EEFFFF } /* Name */ +.codehilite .o { color: #89DDFF } /* Operator */ +.codehilite .p { color: #89DDFF } /* Punctuation */ +.codehilite .ch { color: #546E7A; font-style: italic } /* Comment.Hashbang */ +.codehilite .cm { color: #546E7A; font-style: italic } /* Comment.Multiline */ +.codehilite .cp { color: #546E7A; font-style: italic } /* Comment.Preproc */ +.codehilite .cpf { color: #546E7A; font-style: italic } /* Comment.PreprocFile */ +.codehilite .c1 { color: #546E7A; font-style: italic } /* Comment.Single */ +.codehilite .cs { color: #546E7A; font-style: italic } /* Comment.Special */ +.codehilite .gd { color: #FF5370 } /* Generic.Deleted */ +.codehilite .ge { color: #89DDFF } /* Generic.Emph */ +.codehilite .gr { color: #FF5370 } /* Generic.Error */ +.codehilite .gh { color: #C3E88D } /* Generic.Heading */ +.codehilite .gi { color: #C3E88D } /* Generic.Inserted */ +.codehilite .go { color: #546E7A } /* Generic.Output */ +.codehilite .gp { color: #FFCB6B } /* Generic.Prompt */ +.codehilite .gs { color: #FF5370 } /* Generic.Strong */ +.codehilite .gu { color: #89DDFF } /* Generic.Subheading */ +.codehilite .gt { color: #FF5370 } /* Generic.Traceback */ +.codehilite .kc { color: #89DDFF } /* Keyword.Constant */ +.codehilite .kd { color: #BB80B3 } /* Keyword.Declaration */ +.codehilite .kn { color: #89DDFF; font-style: italic } /* Keyword.Namespace */ +.codehilite .kp { color: #89DDFF } /* Keyword.Pseudo */ +.codehilite .kr { color: #BB80B3 } /* Keyword.Reserved */ +.codehilite .kt { color: #BB80B3 } /* Keyword.Type */ +.codehilite .ld { color: #C3E88D } /* Literal.Date */ +.codehilite .m { color: #F78C6C } /* Literal.Number */ +.codehilite .s { color: #C3E88D } /* Literal.String */ +.codehilite .na { color: #BB80B3 } /* Name.Attribute */ +.codehilite .nb { color: #82AAFF } /* Name.Builtin */ +.codehilite .nc { color: #FFCB6B } /* Name.Class */ +.codehilite .no { color: #EEFFFF } /* Name.Constant */ +.codehilite .nd { color: #82AAFF } /* Name.Decorator */ +.codehilite .ni { color: #89DDFF } /* Name.Entity */ +.codehilite .ne { color: #FFCB6B } /* Name.Exception */ +.codehilite .nf { color: #82AAFF } /* Name.Function */ +.codehilite .nl { color: #82AAFF } /* Name.Label */ +.codehilite .nn { color: #FFCB6B } /* Name.Namespace */ +.codehilite .nx { color: #EEFFFF } /* Name.Other */ +.codehilite .py { color: #FFCB6B } /* Name.Property */ +.codehilite .nt { color: #FF5370 } /* Name.Tag */ +.codehilite .nv { color: #89DDFF } /* Name.Variable */ +.codehilite .ow { color: #89DDFF; font-style: italic } /* Operator.Word */ +.codehilite .pm { color: #89DDFF } /* Punctuation.Marker */ +.codehilite .w { color: #EEFFFF } /* Text.Whitespace */ +.codehilite .mb { color: #F78C6C } /* Literal.Number.Bin */ +.codehilite .mf { color: #F78C6C } /* Literal.Number.Float */ +.codehilite .mh { color: #F78C6C } /* Literal.Number.Hex */ +.codehilite .mi { color: #F78C6C } /* Literal.Number.Integer */ +.codehilite .mo { color: #F78C6C } /* Literal.Number.Oct */ +.codehilite .sa { color: #BB80B3 } /* Literal.String.Affix */ +.codehilite .sb { color: #C3E88D } /* Literal.String.Backtick */ +.codehilite .sc { color: #C3E88D } /* Literal.String.Char */ +.codehilite .dl { color: #EEFFFF } /* Literal.String.Delimiter */ +.codehilite .sd { color: #546E7A; font-style: italic } /* Literal.String.Doc */ +.codehilite .s2 { color: #C3E88D } /* Literal.String.Double */ +.codehilite .se { color: #EEFFFF } /* Literal.String.Escape */ +.codehilite .sh { color: #C3E88D } /* Literal.String.Heredoc */ +.codehilite .si { color: #89DDFF } /* Literal.String.Interpol */ +.codehilite .sx { color: #C3E88D } /* Literal.String.Other */ +.codehilite .sr { color: #89DDFF } /* Literal.String.Regex */ +.codehilite .s1 { color: #C3E88D } /* Literal.String.Single */ +.codehilite .ss { color: #89DDFF } /* Literal.String.Symbol */ +.codehilite .bp { color: #89DDFF } /* Name.Builtin.Pseudo */ +.codehilite .fm { color: #82AAFF } /* Name.Function.Magic */ +.codehilite .vc { color: #89DDFF } /* Name.Variable.Class */ +.codehilite .vg { color: #89DDFF } /* Name.Variable.Global */ +.codehilite .vi { color: #89DDFF } /* Name.Variable.Instance */ +.codehilite .vm { color: #82AAFF } /* Name.Variable.Magic */ +.codehilite .il { color: #F78C6C } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/demo/facechain_agent/demo/facechain_agent/requirements.txt b/demo/facechain_agent/demo/facechain_agent/requirements.txt new file mode 100644 index 000000000..46c370e46 --- /dev/null +++ b/demo/facechain_agent/demo/facechain_agent/requirements.txt @@ -0,0 +1,38 @@ +accelerate +transformers +diffusers +onnxruntime +modelscope +Pillow +opencv-python +torchvision +mmdet==2.26.0 +mmengine +numpy==1.22.0 +protobuf==3.20.1 +timm +scikit-image +gradio==3.29.0 +controlnet_aux==0.0.6 +mediapipe +python-slugify +dashscope +datasets>=2.8.0 +ipython +langchain +modelscope>=1.7.0 +moviepy +ms-swift +openai +opencv-python +Pillow +pydantic==1.10.8 +pytest +python-dotenv +soundfile +transformers>=4.29.0 +transformers_stream_generator +markdown_katex +mdx_truly_sane_lists +markdown-cjk-spacing +pymdown-extensions diff --git a/demo/facechain_agent/facechain/__init__.py b/demo/facechain_agent/facechain/__init__.py new file mode 100644 index 000000000..b937315b6 --- /dev/null +++ b/demo/facechain_agent/facechain/__init__.py @@ -0,0 +1 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. diff --git a/demo/facechain_agent/facechain/constants.py b/demo/facechain_agent/facechain/constants.py new file mode 100644 index 000000000..29ade6214 --- /dev/null +++ b/demo/facechain_agent/facechain/constants.py @@ -0,0 +1,37 @@ +neg_prompt = '(nsfw:2), paintings, sketches, (worst quality:2), (low quality:2), ' \ + 'lowers, normal quality, ((monochrome)), ((grayscale)), logo, word, character, bad hand, tattoo, (username, watermark, signature, time signature, timestamp, artist name, copyright name, copyright),'\ + 'low res, ((monochrome)), ((grayscale)), skin spots, acnes, skin blemishes, age spot, glans, extra fingers, fewer fingers, strange fingers, bad hand, mole, ((extra legs)), ((extra hands))' +pos_prompt_with_cloth = 'raw photo, masterpiece, chinese, {}, solo, medium shot, high detail face, looking straight into the camera with shoulders parallel to the frame, photorealistic, best quality' +pos_prompt_with_style = '{}, upper_body, raw photo, masterpiece, solo, medium shot, high detail face, photorealistic, best quality' + +base_models = [ + {'name': 'leosamsMoonfilm_filmGrain20', + 'model_id': 'ly261666/cv_portrait_model', + 'revision': 'v2.0', + 'sub_path': "film/film"}, + {'name': 'MajicmixRealistic_v6', + 'model_id': 'YorickHe/majicmixRealistic_v6', + 'revision': 'v1.0.0', + 'sub_path': "realistic"}, +] + +pose_models = [ + {'name': '无姿态控制(No pose control)'}, + {'name': 'pose-v1.1-with-depth'}, + {'name': 'pose-v1.1'} +] + +pose_examples = { + 'man': [ + ['./poses/man/pose1.png'], + ['./poses/man/pose2.png'], + ['./poses/man/pose3.png'], + ['./poses/man/pose4.png'] + ], + 'woman': [ + ['./poses/woman/pose1.png'], + ['./poses/woman/pose2.png'], + ['./poses/woman/pose3.png'], + ['./poses/woman/pose4.png'], + ] +} diff --git a/demo/facechain_agent/facechain/data_process/__init__.py b/demo/facechain_agent/facechain/data_process/__init__.py new file mode 100644 index 000000000..b937315b6 --- /dev/null +++ b/demo/facechain_agent/facechain/data_process/__init__.py @@ -0,0 +1 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. diff --git a/demo/facechain_agent/facechain/data_process/deepbooru.py b/demo/facechain_agent/facechain/data_process/deepbooru.py new file mode 100644 index 000000000..96799dea8 --- /dev/null +++ b/demo/facechain_agent/facechain/data_process/deepbooru.py @@ -0,0 +1,796 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. + +import os +import re + +from PIL import Image +import numpy as np + +re_special = re.compile(r'([\\()])') + +import torch +import torch.nn as nn +import torch.nn.functional as F +from modelscope.hub.snapshot_download import snapshot_download + +# see https://github.com/AUTOMATIC1111/TorchDeepDanbooru for more +LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS) + + +class DeepDanbooruModel(nn.Module): + def __init__(self): + super(DeepDanbooruModel, self).__init__() + + self.tags = [] + + self.n_Conv_0 = nn.Conv2d(kernel_size=(7, 7), in_channels=3, out_channels=64, stride=(2, 2)) + self.n_MaxPool_0 = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2)) + self.n_Conv_1 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=256) + self.n_Conv_2 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=64) + self.n_Conv_3 = nn.Conv2d(kernel_size=(3, 3), in_channels=64, out_channels=64) + self.n_Conv_4 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=256) + self.n_Conv_5 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=64) + self.n_Conv_6 = nn.Conv2d(kernel_size=(3, 3), in_channels=64, out_channels=64) + self.n_Conv_7 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=256) + self.n_Conv_8 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=64) + self.n_Conv_9 = nn.Conv2d(kernel_size=(3, 3), in_channels=64, out_channels=64) + self.n_Conv_10 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=256) + self.n_Conv_11 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=512, stride=(2, 2)) + self.n_Conv_12 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=128) + self.n_Conv_13 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128, stride=(2, 2)) + self.n_Conv_14 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512) + self.n_Conv_15 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128) + self.n_Conv_16 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128) + self.n_Conv_17 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512) + self.n_Conv_18 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128) + self.n_Conv_19 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128) + self.n_Conv_20 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512) + self.n_Conv_21 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128) + self.n_Conv_22 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128) + self.n_Conv_23 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512) + self.n_Conv_24 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128) + self.n_Conv_25 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128) + self.n_Conv_26 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512) + self.n_Conv_27 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128) + self.n_Conv_28 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128) + self.n_Conv_29 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512) + self.n_Conv_30 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128) + self.n_Conv_31 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128) + self.n_Conv_32 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512) + self.n_Conv_33 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128) + self.n_Conv_34 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128) + self.n_Conv_35 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512) + self.n_Conv_36 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=1024, stride=(2, 2)) + self.n_Conv_37 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=256) + self.n_Conv_38 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256, stride=(2, 2)) + self.n_Conv_39 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_40 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_41 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_42 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_43 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_44 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_45 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_46 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_47 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_48 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_49 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_50 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_51 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_52 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_53 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_54 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_55 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_56 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_57 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_58 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_59 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_60 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_61 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_62 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_63 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_64 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_65 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_66 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_67 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_68 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_69 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_70 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_71 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_72 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_73 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_74 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_75 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_76 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_77 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_78 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_79 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_80 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_81 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_82 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_83 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_84 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_85 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_86 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_87 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_88 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_89 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_90 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_91 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_92 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_93 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_94 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_95 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_96 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_97 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_98 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256, stride=(2, 2)) + self.n_Conv_99 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_100 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=1024, stride=(2, 2)) + self.n_Conv_101 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_102 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_103 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_104 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_105 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_106 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_107 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_108 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_109 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_110 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_111 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_112 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_113 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_114 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_115 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_116 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_117 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_118 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_119 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_120 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_121 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_122 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_123 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_124 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_125 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_126 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_127 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_128 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_129 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_130 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_131 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_132 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_133 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_134 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_135 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_136 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_137 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_138 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_139 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_140 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_141 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_142 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_143 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_144 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_145 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_146 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_147 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_148 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_149 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_150 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_151 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_152 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_153 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_154 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_155 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256) + self.n_Conv_156 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256) + self.n_Conv_157 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024) + self.n_Conv_158 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=2048, stride=(2, 2)) + self.n_Conv_159 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=512) + self.n_Conv_160 = nn.Conv2d(kernel_size=(3, 3), in_channels=512, out_channels=512, stride=(2, 2)) + self.n_Conv_161 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=2048) + self.n_Conv_162 = nn.Conv2d(kernel_size=(1, 1), in_channels=2048, out_channels=512) + self.n_Conv_163 = nn.Conv2d(kernel_size=(3, 3), in_channels=512, out_channels=512) + self.n_Conv_164 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=2048) + self.n_Conv_165 = nn.Conv2d(kernel_size=(1, 1), in_channels=2048, out_channels=512) + self.n_Conv_166 = nn.Conv2d(kernel_size=(3, 3), in_channels=512, out_channels=512) + self.n_Conv_167 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=2048) + self.n_Conv_168 = nn.Conv2d(kernel_size=(1, 1), in_channels=2048, out_channels=4096, stride=(2, 2)) + self.n_Conv_169 = nn.Conv2d(kernel_size=(1, 1), in_channels=2048, out_channels=1024) + self.n_Conv_170 = nn.Conv2d(kernel_size=(3, 3), in_channels=1024, out_channels=1024, stride=(2, 2)) + self.n_Conv_171 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=4096) + self.n_Conv_172 = nn.Conv2d(kernel_size=(1, 1), in_channels=4096, out_channels=1024) + self.n_Conv_173 = nn.Conv2d(kernel_size=(3, 3), in_channels=1024, out_channels=1024) + self.n_Conv_174 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=4096) + self.n_Conv_175 = nn.Conv2d(kernel_size=(1, 1), in_channels=4096, out_channels=1024) + self.n_Conv_176 = nn.Conv2d(kernel_size=(3, 3), in_channels=1024, out_channels=1024) + self.n_Conv_177 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=4096) + self.n_Conv_178 = nn.Conv2d(kernel_size=(1, 1), in_channels=4096, out_channels=9176, bias=False) + + def forward(self, *inputs): + t_358, = inputs + t_359 = t_358.permute(*[0, 3, 1, 2]) + t_359_padded = F.pad(t_359, [2, 3, 2, 3], value=0) + # t_360 = self.n_Conv_0(t_359_padded.to(self.n_Conv_0.bias.dtype) if devices.unet_needs_upcast else t_359_padded) + t_360 = self.n_Conv_0(t_359_padded.to(self.n_Conv_0.bias.dtype)) + t_361 = F.relu(t_360) + t_361 = F.pad(t_361, [0, 1, 0, 1], value=float('-inf')) + t_362 = self.n_MaxPool_0(t_361) + t_363 = self.n_Conv_1(t_362) + t_364 = self.n_Conv_2(t_362) + t_365 = F.relu(t_364) + t_365_padded = F.pad(t_365, [1, 1, 1, 1], value=0) + t_366 = self.n_Conv_3(t_365_padded) + t_367 = F.relu(t_366) + t_368 = self.n_Conv_4(t_367) + t_369 = torch.add(t_368, t_363) + t_370 = F.relu(t_369) + t_371 = self.n_Conv_5(t_370) + t_372 = F.relu(t_371) + t_372_padded = F.pad(t_372, [1, 1, 1, 1], value=0) + t_373 = self.n_Conv_6(t_372_padded) + t_374 = F.relu(t_373) + t_375 = self.n_Conv_7(t_374) + t_376 = torch.add(t_375, t_370) + t_377 = F.relu(t_376) + t_378 = self.n_Conv_8(t_377) + t_379 = F.relu(t_378) + t_379_padded = F.pad(t_379, [1, 1, 1, 1], value=0) + t_380 = self.n_Conv_9(t_379_padded) + t_381 = F.relu(t_380) + t_382 = self.n_Conv_10(t_381) + t_383 = torch.add(t_382, t_377) + t_384 = F.relu(t_383) + t_385 = self.n_Conv_11(t_384) + t_386 = self.n_Conv_12(t_384) + t_387 = F.relu(t_386) + t_387_padded = F.pad(t_387, [0, 1, 0, 1], value=0) + t_388 = self.n_Conv_13(t_387_padded) + t_389 = F.relu(t_388) + t_390 = self.n_Conv_14(t_389) + t_391 = torch.add(t_390, t_385) + t_392 = F.relu(t_391) + t_393 = self.n_Conv_15(t_392) + t_394 = F.relu(t_393) + t_394_padded = F.pad(t_394, [1, 1, 1, 1], value=0) + t_395 = self.n_Conv_16(t_394_padded) + t_396 = F.relu(t_395) + t_397 = self.n_Conv_17(t_396) + t_398 = torch.add(t_397, t_392) + t_399 = F.relu(t_398) + t_400 = self.n_Conv_18(t_399) + t_401 = F.relu(t_400) + t_401_padded = F.pad(t_401, [1, 1, 1, 1], value=0) + t_402 = self.n_Conv_19(t_401_padded) + t_403 = F.relu(t_402) + t_404 = self.n_Conv_20(t_403) + t_405 = torch.add(t_404, t_399) + t_406 = F.relu(t_405) + t_407 = self.n_Conv_21(t_406) + t_408 = F.relu(t_407) + t_408_padded = F.pad(t_408, [1, 1, 1, 1], value=0) + t_409 = self.n_Conv_22(t_408_padded) + t_410 = F.relu(t_409) + t_411 = self.n_Conv_23(t_410) + t_412 = torch.add(t_411, t_406) + t_413 = F.relu(t_412) + t_414 = self.n_Conv_24(t_413) + t_415 = F.relu(t_414) + t_415_padded = F.pad(t_415, [1, 1, 1, 1], value=0) + t_416 = self.n_Conv_25(t_415_padded) + t_417 = F.relu(t_416) + t_418 = self.n_Conv_26(t_417) + t_419 = torch.add(t_418, t_413) + t_420 = F.relu(t_419) + t_421 = self.n_Conv_27(t_420) + t_422 = F.relu(t_421) + t_422_padded = F.pad(t_422, [1, 1, 1, 1], value=0) + t_423 = self.n_Conv_28(t_422_padded) + t_424 = F.relu(t_423) + t_425 = self.n_Conv_29(t_424) + t_426 = torch.add(t_425, t_420) + t_427 = F.relu(t_426) + t_428 = self.n_Conv_30(t_427) + t_429 = F.relu(t_428) + t_429_padded = F.pad(t_429, [1, 1, 1, 1], value=0) + t_430 = self.n_Conv_31(t_429_padded) + t_431 = F.relu(t_430) + t_432 = self.n_Conv_32(t_431) + t_433 = torch.add(t_432, t_427) + t_434 = F.relu(t_433) + t_435 = self.n_Conv_33(t_434) + t_436 = F.relu(t_435) + t_436_padded = F.pad(t_436, [1, 1, 1, 1], value=0) + t_437 = self.n_Conv_34(t_436_padded) + t_438 = F.relu(t_437) + t_439 = self.n_Conv_35(t_438) + t_440 = torch.add(t_439, t_434) + t_441 = F.relu(t_440) + t_442 = self.n_Conv_36(t_441) + t_443 = self.n_Conv_37(t_441) + t_444 = F.relu(t_443) + t_444_padded = F.pad(t_444, [0, 1, 0, 1], value=0) + t_445 = self.n_Conv_38(t_444_padded) + t_446 = F.relu(t_445) + t_447 = self.n_Conv_39(t_446) + t_448 = torch.add(t_447, t_442) + t_449 = F.relu(t_448) + t_450 = self.n_Conv_40(t_449) + t_451 = F.relu(t_450) + t_451_padded = F.pad(t_451, [1, 1, 1, 1], value=0) + t_452 = self.n_Conv_41(t_451_padded) + t_453 = F.relu(t_452) + t_454 = self.n_Conv_42(t_453) + t_455 = torch.add(t_454, t_449) + t_456 = F.relu(t_455) + t_457 = self.n_Conv_43(t_456) + t_458 = F.relu(t_457) + t_458_padded = F.pad(t_458, [1, 1, 1, 1], value=0) + t_459 = self.n_Conv_44(t_458_padded) + t_460 = F.relu(t_459) + t_461 = self.n_Conv_45(t_460) + t_462 = torch.add(t_461, t_456) + t_463 = F.relu(t_462) + t_464 = self.n_Conv_46(t_463) + t_465 = F.relu(t_464) + t_465_padded = F.pad(t_465, [1, 1, 1, 1], value=0) + t_466 = self.n_Conv_47(t_465_padded) + t_467 = F.relu(t_466) + t_468 = self.n_Conv_48(t_467) + t_469 = torch.add(t_468, t_463) + t_470 = F.relu(t_469) + t_471 = self.n_Conv_49(t_470) + t_472 = F.relu(t_471) + t_472_padded = F.pad(t_472, [1, 1, 1, 1], value=0) + t_473 = self.n_Conv_50(t_472_padded) + t_474 = F.relu(t_473) + t_475 = self.n_Conv_51(t_474) + t_476 = torch.add(t_475, t_470) + t_477 = F.relu(t_476) + t_478 = self.n_Conv_52(t_477) + t_479 = F.relu(t_478) + t_479_padded = F.pad(t_479, [1, 1, 1, 1], value=0) + t_480 = self.n_Conv_53(t_479_padded) + t_481 = F.relu(t_480) + t_482 = self.n_Conv_54(t_481) + t_483 = torch.add(t_482, t_477) + t_484 = F.relu(t_483) + t_485 = self.n_Conv_55(t_484) + t_486 = F.relu(t_485) + t_486_padded = F.pad(t_486, [1, 1, 1, 1], value=0) + t_487 = self.n_Conv_56(t_486_padded) + t_488 = F.relu(t_487) + t_489 = self.n_Conv_57(t_488) + t_490 = torch.add(t_489, t_484) + t_491 = F.relu(t_490) + t_492 = self.n_Conv_58(t_491) + t_493 = F.relu(t_492) + t_493_padded = F.pad(t_493, [1, 1, 1, 1], value=0) + t_494 = self.n_Conv_59(t_493_padded) + t_495 = F.relu(t_494) + t_496 = self.n_Conv_60(t_495) + t_497 = torch.add(t_496, t_491) + t_498 = F.relu(t_497) + t_499 = self.n_Conv_61(t_498) + t_500 = F.relu(t_499) + t_500_padded = F.pad(t_500, [1, 1, 1, 1], value=0) + t_501 = self.n_Conv_62(t_500_padded) + t_502 = F.relu(t_501) + t_503 = self.n_Conv_63(t_502) + t_504 = torch.add(t_503, t_498) + t_505 = F.relu(t_504) + t_506 = self.n_Conv_64(t_505) + t_507 = F.relu(t_506) + t_507_padded = F.pad(t_507, [1, 1, 1, 1], value=0) + t_508 = self.n_Conv_65(t_507_padded) + t_509 = F.relu(t_508) + t_510 = self.n_Conv_66(t_509) + t_511 = torch.add(t_510, t_505) + t_512 = F.relu(t_511) + t_513 = self.n_Conv_67(t_512) + t_514 = F.relu(t_513) + t_514_padded = F.pad(t_514, [1, 1, 1, 1], value=0) + t_515 = self.n_Conv_68(t_514_padded) + t_516 = F.relu(t_515) + t_517 = self.n_Conv_69(t_516) + t_518 = torch.add(t_517, t_512) + t_519 = F.relu(t_518) + t_520 = self.n_Conv_70(t_519) + t_521 = F.relu(t_520) + t_521_padded = F.pad(t_521, [1, 1, 1, 1], value=0) + t_522 = self.n_Conv_71(t_521_padded) + t_523 = F.relu(t_522) + t_524 = self.n_Conv_72(t_523) + t_525 = torch.add(t_524, t_519) + t_526 = F.relu(t_525) + t_527 = self.n_Conv_73(t_526) + t_528 = F.relu(t_527) + t_528_padded = F.pad(t_528, [1, 1, 1, 1], value=0) + t_529 = self.n_Conv_74(t_528_padded) + t_530 = F.relu(t_529) + t_531 = self.n_Conv_75(t_530) + t_532 = torch.add(t_531, t_526) + t_533 = F.relu(t_532) + t_534 = self.n_Conv_76(t_533) + t_535 = F.relu(t_534) + t_535_padded = F.pad(t_535, [1, 1, 1, 1], value=0) + t_536 = self.n_Conv_77(t_535_padded) + t_537 = F.relu(t_536) + t_538 = self.n_Conv_78(t_537) + t_539 = torch.add(t_538, t_533) + t_540 = F.relu(t_539) + t_541 = self.n_Conv_79(t_540) + t_542 = F.relu(t_541) + t_542_padded = F.pad(t_542, [1, 1, 1, 1], value=0) + t_543 = self.n_Conv_80(t_542_padded) + t_544 = F.relu(t_543) + t_545 = self.n_Conv_81(t_544) + t_546 = torch.add(t_545, t_540) + t_547 = F.relu(t_546) + t_548 = self.n_Conv_82(t_547) + t_549 = F.relu(t_548) + t_549_padded = F.pad(t_549, [1, 1, 1, 1], value=0) + t_550 = self.n_Conv_83(t_549_padded) + t_551 = F.relu(t_550) + t_552 = self.n_Conv_84(t_551) + t_553 = torch.add(t_552, t_547) + t_554 = F.relu(t_553) + t_555 = self.n_Conv_85(t_554) + t_556 = F.relu(t_555) + t_556_padded = F.pad(t_556, [1, 1, 1, 1], value=0) + t_557 = self.n_Conv_86(t_556_padded) + t_558 = F.relu(t_557) + t_559 = self.n_Conv_87(t_558) + t_560 = torch.add(t_559, t_554) + t_561 = F.relu(t_560) + t_562 = self.n_Conv_88(t_561) + t_563 = F.relu(t_562) + t_563_padded = F.pad(t_563, [1, 1, 1, 1], value=0) + t_564 = self.n_Conv_89(t_563_padded) + t_565 = F.relu(t_564) + t_566 = self.n_Conv_90(t_565) + t_567 = torch.add(t_566, t_561) + t_568 = F.relu(t_567) + t_569 = self.n_Conv_91(t_568) + t_570 = F.relu(t_569) + t_570_padded = F.pad(t_570, [1, 1, 1, 1], value=0) + t_571 = self.n_Conv_92(t_570_padded) + t_572 = F.relu(t_571) + t_573 = self.n_Conv_93(t_572) + t_574 = torch.add(t_573, t_568) + t_575 = F.relu(t_574) + t_576 = self.n_Conv_94(t_575) + t_577 = F.relu(t_576) + t_577_padded = F.pad(t_577, [1, 1, 1, 1], value=0) + t_578 = self.n_Conv_95(t_577_padded) + t_579 = F.relu(t_578) + t_580 = self.n_Conv_96(t_579) + t_581 = torch.add(t_580, t_575) + t_582 = F.relu(t_581) + t_583 = self.n_Conv_97(t_582) + t_584 = F.relu(t_583) + t_584_padded = F.pad(t_584, [0, 1, 0, 1], value=0) + t_585 = self.n_Conv_98(t_584_padded) + t_586 = F.relu(t_585) + t_587 = self.n_Conv_99(t_586) + t_588 = self.n_Conv_100(t_582) + t_589 = torch.add(t_587, t_588) + t_590 = F.relu(t_589) + t_591 = self.n_Conv_101(t_590) + t_592 = F.relu(t_591) + t_592_padded = F.pad(t_592, [1, 1, 1, 1], value=0) + t_593 = self.n_Conv_102(t_592_padded) + t_594 = F.relu(t_593) + t_595 = self.n_Conv_103(t_594) + t_596 = torch.add(t_595, t_590) + t_597 = F.relu(t_596) + t_598 = self.n_Conv_104(t_597) + t_599 = F.relu(t_598) + t_599_padded = F.pad(t_599, [1, 1, 1, 1], value=0) + t_600 = self.n_Conv_105(t_599_padded) + t_601 = F.relu(t_600) + t_602 = self.n_Conv_106(t_601) + t_603 = torch.add(t_602, t_597) + t_604 = F.relu(t_603) + t_605 = self.n_Conv_107(t_604) + t_606 = F.relu(t_605) + t_606_padded = F.pad(t_606, [1, 1, 1, 1], value=0) + t_607 = self.n_Conv_108(t_606_padded) + t_608 = F.relu(t_607) + t_609 = self.n_Conv_109(t_608) + t_610 = torch.add(t_609, t_604) + t_611 = F.relu(t_610) + t_612 = self.n_Conv_110(t_611) + t_613 = F.relu(t_612) + t_613_padded = F.pad(t_613, [1, 1, 1, 1], value=0) + t_614 = self.n_Conv_111(t_613_padded) + t_615 = F.relu(t_614) + t_616 = self.n_Conv_112(t_615) + t_617 = torch.add(t_616, t_611) + t_618 = F.relu(t_617) + t_619 = self.n_Conv_113(t_618) + t_620 = F.relu(t_619) + t_620_padded = F.pad(t_620, [1, 1, 1, 1], value=0) + t_621 = self.n_Conv_114(t_620_padded) + t_622 = F.relu(t_621) + t_623 = self.n_Conv_115(t_622) + t_624 = torch.add(t_623, t_618) + t_625 = F.relu(t_624) + t_626 = self.n_Conv_116(t_625) + t_627 = F.relu(t_626) + t_627_padded = F.pad(t_627, [1, 1, 1, 1], value=0) + t_628 = self.n_Conv_117(t_627_padded) + t_629 = F.relu(t_628) + t_630 = self.n_Conv_118(t_629) + t_631 = torch.add(t_630, t_625) + t_632 = F.relu(t_631) + t_633 = self.n_Conv_119(t_632) + t_634 = F.relu(t_633) + t_634_padded = F.pad(t_634, [1, 1, 1, 1], value=0) + t_635 = self.n_Conv_120(t_634_padded) + t_636 = F.relu(t_635) + t_637 = self.n_Conv_121(t_636) + t_638 = torch.add(t_637, t_632) + t_639 = F.relu(t_638) + t_640 = self.n_Conv_122(t_639) + t_641 = F.relu(t_640) + t_641_padded = F.pad(t_641, [1, 1, 1, 1], value=0) + t_642 = self.n_Conv_123(t_641_padded) + t_643 = F.relu(t_642) + t_644 = self.n_Conv_124(t_643) + t_645 = torch.add(t_644, t_639) + t_646 = F.relu(t_645) + t_647 = self.n_Conv_125(t_646) + t_648 = F.relu(t_647) + t_648_padded = F.pad(t_648, [1, 1, 1, 1], value=0) + t_649 = self.n_Conv_126(t_648_padded) + t_650 = F.relu(t_649) + t_651 = self.n_Conv_127(t_650) + t_652 = torch.add(t_651, t_646) + t_653 = F.relu(t_652) + t_654 = self.n_Conv_128(t_653) + t_655 = F.relu(t_654) + t_655_padded = F.pad(t_655, [1, 1, 1, 1], value=0) + t_656 = self.n_Conv_129(t_655_padded) + t_657 = F.relu(t_656) + t_658 = self.n_Conv_130(t_657) + t_659 = torch.add(t_658, t_653) + t_660 = F.relu(t_659) + t_661 = self.n_Conv_131(t_660) + t_662 = F.relu(t_661) + t_662_padded = F.pad(t_662, [1, 1, 1, 1], value=0) + t_663 = self.n_Conv_132(t_662_padded) + t_664 = F.relu(t_663) + t_665 = self.n_Conv_133(t_664) + t_666 = torch.add(t_665, t_660) + t_667 = F.relu(t_666) + t_668 = self.n_Conv_134(t_667) + t_669 = F.relu(t_668) + t_669_padded = F.pad(t_669, [1, 1, 1, 1], value=0) + t_670 = self.n_Conv_135(t_669_padded) + t_671 = F.relu(t_670) + t_672 = self.n_Conv_136(t_671) + t_673 = torch.add(t_672, t_667) + t_674 = F.relu(t_673) + t_675 = self.n_Conv_137(t_674) + t_676 = F.relu(t_675) + t_676_padded = F.pad(t_676, [1, 1, 1, 1], value=0) + t_677 = self.n_Conv_138(t_676_padded) + t_678 = F.relu(t_677) + t_679 = self.n_Conv_139(t_678) + t_680 = torch.add(t_679, t_674) + t_681 = F.relu(t_680) + t_682 = self.n_Conv_140(t_681) + t_683 = F.relu(t_682) + t_683_padded = F.pad(t_683, [1, 1, 1, 1], value=0) + t_684 = self.n_Conv_141(t_683_padded) + t_685 = F.relu(t_684) + t_686 = self.n_Conv_142(t_685) + t_687 = torch.add(t_686, t_681) + t_688 = F.relu(t_687) + t_689 = self.n_Conv_143(t_688) + t_690 = F.relu(t_689) + t_690_padded = F.pad(t_690, [1, 1, 1, 1], value=0) + t_691 = self.n_Conv_144(t_690_padded) + t_692 = F.relu(t_691) + t_693 = self.n_Conv_145(t_692) + t_694 = torch.add(t_693, t_688) + t_695 = F.relu(t_694) + t_696 = self.n_Conv_146(t_695) + t_697 = F.relu(t_696) + t_697_padded = F.pad(t_697, [1, 1, 1, 1], value=0) + t_698 = self.n_Conv_147(t_697_padded) + t_699 = F.relu(t_698) + t_700 = self.n_Conv_148(t_699) + t_701 = torch.add(t_700, t_695) + t_702 = F.relu(t_701) + t_703 = self.n_Conv_149(t_702) + t_704 = F.relu(t_703) + t_704_padded = F.pad(t_704, [1, 1, 1, 1], value=0) + t_705 = self.n_Conv_150(t_704_padded) + t_706 = F.relu(t_705) + t_707 = self.n_Conv_151(t_706) + t_708 = torch.add(t_707, t_702) + t_709 = F.relu(t_708) + t_710 = self.n_Conv_152(t_709) + t_711 = F.relu(t_710) + t_711_padded = F.pad(t_711, [1, 1, 1, 1], value=0) + t_712 = self.n_Conv_153(t_711_padded) + t_713 = F.relu(t_712) + t_714 = self.n_Conv_154(t_713) + t_715 = torch.add(t_714, t_709) + t_716 = F.relu(t_715) + t_717 = self.n_Conv_155(t_716) + t_718 = F.relu(t_717) + t_718_padded = F.pad(t_718, [1, 1, 1, 1], value=0) + t_719 = self.n_Conv_156(t_718_padded) + t_720 = F.relu(t_719) + t_721 = self.n_Conv_157(t_720) + t_722 = torch.add(t_721, t_716) + t_723 = F.relu(t_722) + t_724 = self.n_Conv_158(t_723) + t_725 = self.n_Conv_159(t_723) + t_726 = F.relu(t_725) + t_726_padded = F.pad(t_726, [0, 1, 0, 1], value=0) + t_727 = self.n_Conv_160(t_726_padded) + t_728 = F.relu(t_727) + t_729 = self.n_Conv_161(t_728) + t_730 = torch.add(t_729, t_724) + t_731 = F.relu(t_730) + t_732 = self.n_Conv_162(t_731) + t_733 = F.relu(t_732) + t_733_padded = F.pad(t_733, [1, 1, 1, 1], value=0) + t_734 = self.n_Conv_163(t_733_padded) + t_735 = F.relu(t_734) + t_736 = self.n_Conv_164(t_735) + t_737 = torch.add(t_736, t_731) + t_738 = F.relu(t_737) + t_739 = self.n_Conv_165(t_738) + t_740 = F.relu(t_739) + t_740_padded = F.pad(t_740, [1, 1, 1, 1], value=0) + t_741 = self.n_Conv_166(t_740_padded) + t_742 = F.relu(t_741) + t_743 = self.n_Conv_167(t_742) + t_744 = torch.add(t_743, t_738) + t_745 = F.relu(t_744) + t_746 = self.n_Conv_168(t_745) + t_747 = self.n_Conv_169(t_745) + t_748 = F.relu(t_747) + t_748_padded = F.pad(t_748, [0, 1, 0, 1], value=0) + t_749 = self.n_Conv_170(t_748_padded) + t_750 = F.relu(t_749) + t_751 = self.n_Conv_171(t_750) + t_752 = torch.add(t_751, t_746) + t_753 = F.relu(t_752) + t_754 = self.n_Conv_172(t_753) + t_755 = F.relu(t_754) + t_755_padded = F.pad(t_755, [1, 1, 1, 1], value=0) + t_756 = self.n_Conv_173(t_755_padded) + t_757 = F.relu(t_756) + t_758 = self.n_Conv_174(t_757) + t_759 = torch.add(t_758, t_753) + t_760 = F.relu(t_759) + t_761 = self.n_Conv_175(t_760) + t_762 = F.relu(t_761) + t_762_padded = F.pad(t_762, [1, 1, 1, 1], value=0) + t_763 = self.n_Conv_176(t_762_padded) + t_764 = F.relu(t_763) + t_765 = self.n_Conv_177(t_764) + t_766 = torch.add(t_765, t_760) + t_767 = F.relu(t_766) + t_768 = self.n_Conv_178(t_767) + t_769 = F.avg_pool2d(t_768, kernel_size=t_768.shape[-2:]) + t_770 = torch.squeeze(t_769, 3) + t_770 = torch.squeeze(t_770, 2) + t_771 = torch.sigmoid(t_770) + return t_771 + + def load_state_dict(self, state_dict, **kwargs): + self.tags = state_dict.get('tags', []) + + super(DeepDanbooruModel, self).load_state_dict({k: v for k, v in state_dict.items() if k != 'tags'}) + + +def resize_image(im, width, height): + ratio = width / height + src_ratio = im.width / im.height + + src_w = width if ratio < src_ratio else im.width * height // im.height + src_h = height if ratio >= src_ratio else im.height * width // im.width + + resized = im.resize((src_w, src_h), resample=LANCZOS) + res = Image.new("RGB", (width, height)) + res.paste(resized, box=(width // 2 - src_w // 2, height // 2 - src_h // 2)) + + if ratio < src_ratio: + fill_height = height // 2 - src_h // 2 + res.paste(resized.resize((width, fill_height), box=(0, 0, width, 0)), box=(0, 0)) + res.paste(resized.resize((width, fill_height), box=(0, resized.height, width, resized.height)), + box=(0, fill_height + src_h)) + elif ratio > src_ratio: + fill_width = width // 2 - src_w // 2 + res.paste(resized.resize((fill_width, height), box=(0, 0, 0, height)), box=(0, 0)) + res.paste(resized.resize((fill_width, height), box=(resized.width, 0, resized.width, height)), + box=(fill_width + src_w, 0)) + + return res + + +class DeepDanbooru: + def __init__(self): + self.model = DeepDanbooruModel() + + foundation_model_id = 'ly261666/cv_portrait_model' + snapshot_path = snapshot_download(foundation_model_id, revision='v4.0') + pretrain_model_path = os.path.join(snapshot_path, 'model-resnet_custom_v3.pt') + + self.model.load_state_dict(torch.load(pretrain_model_path, map_location="cpu")) + self.model.eval() + self.model.to(torch.float16) + + def start(self): + self.model.cuda() + + def stop(self): + self.model.cpu() + torch.cuda.empty_cache() + torch.cuda.ipc_collect() + + def tag(self, pil_image): + threshold = 0.5 + use_spaces = False + use_escape = True + alpha_sort = True + include_ranks = False + + pic = resize_image(pil_image.convert("RGB"), 512, 512) + a = np.expand_dims(np.array(pic, dtype=np.float32), 0) / 255 + + with torch.no_grad(), torch.autocast("cuda"): + x = torch.from_numpy(a).cuda() + y = self.model(x)[0].detach().cpu().numpy() + + probability_dict = {} + + for tag, probability in zip(self.model.tags, y): + if probability < threshold: + continue + + if tag.startswith("rating:"): + continue + + probability_dict[tag] = probability + + if alpha_sort: + tags = sorted(probability_dict) + else: + tags = [tag for tag, _ in sorted(probability_dict.items(), key=lambda x: -x[1])] + + res = [] + + for tag in [x for x in tags]: + probability = probability_dict[tag] + tag_outformat = tag + if use_spaces: + tag_outformat = tag_outformat.replace('_', ' ') + if use_escape: + tag_outformat = re.sub(re_special, r'\\\1', tag_outformat) + if include_ranks: + tag_outformat = f"({tag_outformat}:{probability:.3f})" + + res.append(tag_outformat) + + return ", ".join(res) + + +''' +model = DeepDanbooru() +impath = 'lyf' +imlist = os.listdir(impath) +result_list = [] +for im in imlist: + if im[-4:]=='.png': + print(im) + img = Image.open(os.path.join(impath, im)) + result = model.tag(img) + print(result) + result_list.append(result) +model.stop() +''' diff --git a/demo/facechain_agent/facechain/data_process/preprocessing.py b/demo/facechain_agent/facechain/data_process/preprocessing.py new file mode 100644 index 000000000..a9666abd7 --- /dev/null +++ b/demo/facechain_agent/facechain/data_process/preprocessing.py @@ -0,0 +1,355 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. + +import json +import math +import os +import shutil + +import cv2 +import numpy as np +from modelscope.outputs import OutputKeys +from modelscope.pipelines import pipeline +from modelscope.utils.constant import Tasks +from PIL import Image +from tqdm import tqdm + +from .deepbooru import DeepDanbooru + + + +def crop_and_resize(im, bbox): + h, w, _ = im.shape + thre = 0.35/1.15 + maxf = max(bbox[2] - bbox[0], bbox[3] - bbox[1]) + cx = (bbox[2] + bbox[0]) / 2 + cy = (bbox[3] + bbox[1]) / 2 + lenp = int(maxf / thre) + yc = 0.5/1.15 + xc = 0.5 + xmin = int(cx - xc * lenp) + xmax = xmin + lenp + ymin = int(cy - yc * lenp) + ymax = ymin + lenp + x1 = 0 + x2 = lenp + y1 = 0 + y2 = lenp + if xmin < 0: + x1 = -xmin + xmin = 0 + if xmax > w: + x2 = w - (xmax - lenp) + xmax = w + if ymin < 0: + y1 = -ymin + ymin = 0 + if ymax > h: + y2 = h - (ymax - lenp) + ymax = h + imc = (np.ones((lenp, lenp, 3)) * 255).astype(np.uint8) + imc[y1:y2, x1:x2, :] = im[ymin:ymax, xmin:xmax, :] + imr = cv2.resize(imc, (512, 512)) + return imr + + +def pad_to_square(im): + h, w, _ = im.shape + ns = int(max(h, w) * 1.5) + im = cv2.copyMakeBorder(im, int((ns - h) / 2), (ns - h) - int((ns - h) / 2), int((ns - w) / 2), + (ns - w) - int((ns - w) / 2), cv2.BORDER_CONSTANT, 255) + return im + + +def post_process_naive(result_list, score_gender, score_age): + # determine trigger word + gender = np.argmax(score_gender) + age = np.argmax(score_age) + if age < 2: + if gender == 0: + tag_a_g = ['a boy', 'children'] + else: + tag_a_g = ['a girl', 'children'] + elif age > 4: + if gender == 0: + tag_a_g = ['a mature man'] + else: + tag_a_g = ['a mature woman'] + else: + if gender == 0: + tag_a_g = ['a handsome man'] + else: + tag_a_g = ['a beautiful woman'] + num_images = len(result_list) + cnt_girl = 0 + cnt_boy = 0 + result_list_new = [] + for result in result_list: + result_new = [] + result_new.extend(tag_a_g) + ## don't include other infos for lora training + #for tag in result: + # if tag == '1girl' or tag == '1boy': + # continue + # if tag[-4:] == '_man': + # continue + # if tag[-6:] == '_woman': + # continue + # if tag[-5:] == '_male': + # continue + # elif tag[-7:] == '_female': + # continue + # elif ( + # tag == 'ears' or tag == 'head' or tag == 'face' or tag == 'lips' or tag == 'mouth' or tag == '3d' or tag == 'asian' or tag == 'teeth'): + # continue + # elif ('eye' in tag and not 'eyewear' in tag): + # continue + # elif ('nose' in tag or 'body' in tag): + # continue + # elif tag[-5:] == '_lips': + # continue + # else: + # result_new.append(tag) + # # import pdb;pdb.set_trace() + ## result_new.append('slim body') + result_list_new.append(result_new) + + return result_list_new + + +def transformation_from_points(points1, points2): + points1 = points1.astype(np.float64) + points2 = points2.astype(np.float64) + c1 = np.mean(points1, axis=0) + c2 = np.mean(points2, axis=0) + points1 -= c1 + points2 -= c2 + s1 = np.std(points1) + s2 = np.std(points2) + if s1 < 1.0e-4: + s1 = 1.0e-4 + points1 /= s1 + points2 /= s2 + U, S, Vt = np.linalg.svd(points1.T * points2) + R = (U * Vt).T + return np.vstack([np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T)), np.matrix([0., 0., 1.])]) + + +def rotate(im, keypoints): + h, w, _ = im.shape + points_array = np.zeros((5, 2)) + dst_mean_face_size = 160 + dst_mean_face = np.asarray([0.31074522411511746, 0.2798131190011913, + 0.6892073313037804, 0.2797830232679366, + 0.49997367716346774, 0.5099309118810921, + 0.35811903020866753, 0.7233174007629063, + 0.6418878095835022, 0.7232890570786875]) + dst_mean_face = np.reshape(dst_mean_face, (5, 2)) * dst_mean_face_size + + for k in range(5): + points_array[k, 0] = keypoints[2 * k] + points_array[k, 1] = keypoints[2 * k + 1] + + pts1 = np.float64(np.matrix([[point[0], point[1]] for point in points_array])) + pts2 = np.float64(np.matrix([[point[0], point[1]] for point in dst_mean_face])) + trans_mat = transformation_from_points(pts1, pts2) + if trans_mat[1, 1] > 1.0e-4: + angle = math.atan(trans_mat[1, 0] / trans_mat[1, 1]) + else: + angle = math.atan(trans_mat[0, 1] / trans_mat[0, 2]) + im = pad_to_square(im) + ns = int(1.5 * max(h, w)) + M = cv2.getRotationMatrix2D((ns / 2, ns / 2), angle=-angle / np.pi * 180, scale=1.0) + im = cv2.warpAffine(im, M=M, dsize=(ns, ns)) + return im + + +def get_mask_head(result): + masks = result['masks'] + scores = result['scores'] + labels = result['labels'] + mask_hair = np.zeros((512, 512)) + mask_face = np.zeros((512, 512)) + mask_human = np.zeros((512, 512)) + for i in range(len(labels)): + if scores[i] > 0.8: + if labels[i] == 'Face': + if np.sum(masks[i]) > np.sum(mask_face): + mask_face = masks[i] + elif labels[i] == 'Human': + if np.sum(masks[i]) > np.sum(mask_human): + mask_human = masks[i] + elif labels[i] == 'Hair': + if np.sum(masks[i]) > np.sum(mask_hair): + mask_hair = masks[i] + mask_head = np.clip(mask_hair + mask_face, 0, 1) + ksize = max(int(np.sqrt(np.sum(mask_face)) / 20), 1) + kernel = np.ones((ksize, ksize)) + mask_head = cv2.dilate(mask_head, kernel, iterations=1) * mask_human + _, mask_head = cv2.threshold((mask_head * 255).astype(np.uint8), 127, 255, cv2.THRESH_BINARY) + contours, hierarchy = cv2.findContours(mask_head, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) + area = [] + for j in range(len(contours)): + area.append(cv2.contourArea(contours[j])) + max_idx = np.argmax(area) + mask_head = np.zeros((512, 512)).astype(np.uint8) + cv2.fillPoly(mask_head, [contours[max_idx]], 255) + mask_head = mask_head.astype(np.float32) / 255 + mask_head = np.clip(mask_head + mask_face, 0, 1) + mask_head = np.expand_dims(mask_head, 2) + return mask_head + + +class Blipv2(): + def __init__(self): + self.model = DeepDanbooru() + self.skin_retouching = pipeline('skin-retouching-torch', model='damo/cv_unet_skin_retouching_torch', model_revision='v1.0.4') + self.face_detection = pipeline(task=Tasks.face_detection, model='damo/cv_ddsar_face-detection_iclr23-damofd', model_revision='v1.1') + # self.mog_face_detection_func = pipeline(Tasks.face_detection, 'damo/cv_resnet101_face-detection_cvpr22papermogface') + self.segmentation_pipeline = pipeline(Tasks.image_segmentation, + 'damo/cv_resnet101_image-multiple-human-parsing', model_revision='v1.0.1') + self.fair_face_attribute_func = pipeline(Tasks.face_attribute_recognition, + 'damo/cv_resnet34_face-attribute-recognition_fairface', model_revision='v2.0.2') + self.facial_landmark_confidence_func = pipeline(Tasks.face_2d_keypoints, + 'damo/cv_manual_facial-landmark-confidence_flcm', model_revision='v2.5') + + def __call__(self, imdir): + self.model.start() + savedir = str(imdir) + '_labeled' + shutil.rmtree(savedir, ignore_errors=True) + os.makedirs(savedir, exist_ok=True) + + imlist = os.listdir(imdir) + result_list = [] + imgs_list = [] + + cnt = 0 + tmp_path = os.path.join(savedir, 'tmp.png') + for imname in imlist: + try: + # if 1: + if imname.startswith('.'): + continue + img_path = os.path.join(imdir, imname) + im = cv2.imread(img_path) + h, w, _ = im.shape + max_size = max(w, h) + ratio = 1024 / max_size + new_w = round(w * ratio) + new_h = round(h * ratio) + imt = cv2.resize(im, (new_w, new_h)) + cv2.imwrite(tmp_path, imt) + result_det = self.face_detection(tmp_path) + bboxes = result_det['boxes'] + if len(bboxes) > 1: + areas = [] + for i in range(len(bboxes)): + bbox = bboxes[i] + areas.append((bbox[2] - bbox[0]) * (bbox[3] - bbox[1])) + areas = np.array(areas) + areas_new = np.sort(areas)[::-1] + idxs = np.argsort(areas)[::-1] + if areas_new[0] < 4 * areas_new[1]: + print('Detecting multiple faces, do not use image {}.'.format(imname)) + continue + else: + keypoints = result_det['keypoints'][idxs[0]] + elif len(bboxes) == 0: + print('Detecting no face, do not use image {}.'.format(imname)) + continue + else: + keypoints = result_det['keypoints'][0] + + im = rotate(im, keypoints) + ns = im.shape[0] + imt = cv2.resize(im, (1024, 1024)) + cv2.imwrite(tmp_path, imt) + result_det = self.face_detection(tmp_path) + bboxes = result_det['boxes'] + + if len(bboxes) > 1: + areas = [] + for i in range(len(bboxes)): + bbox = bboxes[i] + areas.append((bbox[2] - bbox[0]) * (bbox[3] - bbox[1])) + areas = np.array(areas) + areas_new = np.sort(areas)[::-1] + idxs = np.argsort(areas)[::-1] + if areas_new[0] < 4 * areas_new[1]: + print('Detecting multiple faces after rotation, do not use image {}.'.format(imname)) + continue + else: + bbox = bboxes[idxs[0]] + elif len(bboxes) == 0: + print('Detecting no face after rotation, do not use this image {}'.format(imname)) + continue + else: + bbox = bboxes[0] + + for idx in range(4): + bbox[idx] = bbox[idx] * ns / 1024 + imr = crop_and_resize(im, bbox) + cv2.imwrite(tmp_path, imr) + + result = self.skin_retouching(tmp_path) + if (result is None or (result[OutputKeys.OUTPUT_IMG] is None)): + print('Cannot do skin retouching, do not use this image.') + continue + cv2.imwrite(tmp_path, result[OutputKeys.OUTPUT_IMG]) + + result = self.segmentation_pipeline(tmp_path) + mask_head = get_mask_head(result) + im = cv2.imread(tmp_path) + im = im * mask_head + 255 * (1 - mask_head) + # print(im.shape) + + raw_result = self.facial_landmark_confidence_func(im) + if raw_result is None: + print('landmark quality fail...') + continue + + print(imname, raw_result['scores'][0]) + if float(raw_result['scores'][0]) < (1 - 0.145): + print('landmark quality fail...') + continue + + cv2.imwrite(os.path.join(savedir, '{}.png'.format(cnt)), im) + imgs_list.append('{}.png'.format(cnt)) + img = Image.open(os.path.join(savedir, '{}.png'.format(cnt))) + result = self.model.tag(img) + print(result) + attribute_result = self.fair_face_attribute_func(tmp_path) + if cnt == 0: + score_gender = np.array(attribute_result['scores'][0]) + score_age = np.array(attribute_result['scores'][1]) + else: + score_gender += np.array(attribute_result['scores'][0]) + score_age += np.array(attribute_result['scores'][1]) + + result_list.append(result.split(', ')) + cnt += 1 + except Exception as e: + print('cathed for image process of ' + imname) + print(f'Error: {e}') + + print(result_list) + if len(result_list) == 0: + print('Error: result is empty.') + exit() + # return os.path.join(savedir, "metadata.jsonl") + + result_list = post_process_naive(result_list, score_gender, score_age) + self.model.stop() + try: + os.remove(tmp_path) + except OSError as e: + print(f"Failed to remove path {tmp_path}: {e}") + + out_json_name = os.path.join(savedir, "metadata.jsonl") + fo = open(out_json_name, 'w') + for i in range(len(result_list)): + generated_text = ", ".join(result_list[i]) + print(imgs_list[i], generated_text) + info_dict = {"file_name": imgs_list[i], "text": ", " + generated_text} + fo.write(json.dumps(info_dict) + '\n') + fo.close() + return out_json_name diff --git a/demo/facechain_agent/facechain/inference.py b/demo/facechain_agent/facechain/inference.py new file mode 100644 index 000000000..82fe914fc --- /dev/null +++ b/demo/facechain_agent/facechain/inference.py @@ -0,0 +1,530 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. +import json +import os + +import cv2 +import numpy as np +import torch +from PIL import Image +from controlnet_aux import OpenposeDetector +from diffusers import StableDiffusionPipeline, StableDiffusionControlNetPipeline, ControlNetModel, \ + UniPCMultistepScheduler +from facechain.utils import snapshot_download +from modelscope.outputs import OutputKeys +from modelscope.pipelines import pipeline +from modelscope.utils.constant import Tasks +from torch import multiprocessing +from transformers import pipeline as tpipeline + +from facechain.data_process.preprocessing import Blipv2 +from facechain.merge_lora import merge_lora + + +def _data_process_fn_process(input_img_dir): + Blipv2()(input_img_dir) + + +def data_process_fn(input_img_dir, use_data_process): + ## TODO add face quality filter + if use_data_process: + ## TODO + #_data_process_fn_process(input_img_dir) + _process = multiprocessing.Process(target=_data_process_fn_process, args=(input_img_dir,)) + _process.start() + _process.join() + + return os.path.join(str(input_img_dir) + '_labeled', "metadata.jsonl") + +def txt2img(pipe, pos_prompt, neg_prompt, num_images=10): + batch_size = 5 + images_out = [] + for i in range(int(num_images / batch_size)): + images_style = pipe(prompt=pos_prompt, height=512, width=512, guidance_scale=7, negative_prompt=neg_prompt, + num_inference_steps=40, num_images_per_prompt=batch_size).images + images_out.extend(images_style) + return images_out + +def img_pad(pil_file, fixed_height=512, fixed_width=512): + w, h = pil_file.size + + if h / float(fixed_height) >= w / float(fixed_width): + factor = h / float(fixed_height) + new_w = int(w / factor) + pil_file.thumbnail(size=(new_w, fixed_height)) + pad_w = int((fixed_width - new_w) / 2) + pad_w1 = (fixed_width - new_w) - pad_w + array_file = np.array(pil_file) + array_file = np.pad(array_file, ((0, 0), (pad_w, pad_w1), (0, 0)), 'constant') + else: + factor = w / float(fixed_width) + new_h = int(h / factor) + pil_file.thumbnail(size=(fixed_width, new_h)) + pad_h = fixed_height - new_h + pad_h1 = 0 + array_file = np.array(pil_file) + array_file = np.pad(array_file, ((pad_h, pad_h1), (0, 0), (0, 0)), 'constant') + + output_file = Image.fromarray(array_file) + return output_file + +def preprocess_pose(origin_img) -> Image: + img = Image.open(origin_img) + img = img_pad(img) + model_dir = snapshot_download('damo/face_chain_control_model',revision='v1.0.1') + openpose = OpenposeDetector.from_pretrained(os.path.join(model_dir, 'model_controlnet/ControlNet')) + result = openpose(img, include_hand=True, output_type='np') + # resize to original size + h, w = img.size + result = cv2.resize(result, (w, h)) + return result + +def txt2img_pose(pipe, pose_im, pos_prompt, neg_prompt, num_images=10): + batch_size = 2 + images_out = [] + for i in range(int(num_images / batch_size)): + images_style = pipe(prompt=pos_prompt, image=pose_im, height=512, width=512, guidance_scale=7, negative_prompt=neg_prompt, + num_inference_steps=40, num_images_per_prompt=batch_size).images + images_out.extend(images_style) + return images_out + +def txt2img_multi(pipe, images, pos_prompt, neg_prompt, num_images=10): + batch_size = 2 + images_out = [] + for i in range(int(num_images / batch_size)): + images_style = pipe(pos_prompt, images, height=512, width=512, guidance_scale=7, negative_prompt=neg_prompt, controlnet_conditioning_scale=[1.0, 0.5], + num_inference_steps=40, num_images_per_prompt=batch_size).images + images_out.extend(images_style) + return images_out + +def get_mask(result): + masks = result['masks'] + scores = result['scores'] + labels = result['labels'] + h, w = masks[0].shape + mask_hair = np.zeros((h, w)) + mask_face = np.zeros((h, w)) + mask_human = np.zeros((h, w)) + for i in range(len(labels)): + if scores[i] > 0.8: + if labels[i] == 'Face': + if np.sum(masks[i]) > np.sum(mask_face): + mask_face = masks[i] + elif labels[i] == 'Human': + if np.sum(masks[i]) > np.sum(mask_human): + mask_human = masks[i] + elif labels[i] == 'Hair': + if np.sum(masks[i]) > np.sum(mask_hair): + mask_hair = masks[i] + mask_rst = np.clip(mask_human - mask_hair - mask_face, 0, 1) + mask_rst = np.expand_dims(mask_rst, 2) + mask_rst = np.concatenate([mask_rst, mask_rst, mask_rst], axis=2) + return mask_rst + +def main_diffusion_inference(pos_prompt, neg_prompt, + input_img_dir, base_model_path, style_model_path, lora_model_path, + multiplier_style=0.25, + multiplier_human=0.85): + if style_model_path is None: + model_dir = snapshot_download('Cherrytest/zjz_mj_jiyi_small_addtxt_fromleo', revision='v1.0.0') + style_model_path = os.path.join(model_dir, 'zjz_mj_jiyi_small_addtxt_fromleo.safetensors') + + pipe = StableDiffusionPipeline.from_pretrained(base_model_path, safety_checker=None, torch_dtype=torch.float32) + lora_style_path = style_model_path + lora_human_path = lora_model_path + pipe = merge_lora(pipe, lora_style_path, multiplier_style, from_safetensor=True) + pipe = merge_lora(pipe, lora_human_path, multiplier_human, from_safetensor=lora_human_path.endswith('safetensors')) + print(f'multiplier_style:{multiplier_style}, multiplier_human:{multiplier_human}') + + train_dir = str(input_img_dir) + '_labeled' + add_prompt_style = [] + f = open(os.path.join(train_dir, 'metadata.jsonl'), 'r') + tags_all = [] + cnt = 0 + cnts_trigger = np.zeros(6) + for line in f: + cnt += 1 + data = json.loads(line)['text'].split(', ') + tags_all.extend(data) + if data[1] == 'a boy': + cnts_trigger[0] += 1 + elif data[1] == 'a girl': + cnts_trigger[1] += 1 + elif data[1] == 'a handsome man': + cnts_trigger[2] += 1 + elif data[1] == 'a beautiful woman': + cnts_trigger[3] += 1 + elif data[1] == 'a mature man': + cnts_trigger[4] += 1 + elif data[1] == 'a mature woman': + cnts_trigger[5] += 1 + else: + print('Error.') + f.close() + + attr_idx = np.argmax(cnts_trigger) + trigger_styles = ['a boy, children, ', 'a girl, children, ', 'a handsome man, ', 'a beautiful woman, ', + 'a mature man, ', 'a mature woman, '] + trigger_style = '(:10), ' + trigger_styles[attr_idx] + if attr_idx == 2 or attr_idx == 4: + neg_prompt += ', children' + + for tag in tags_all: + if tags_all.count(tag) > 0.5 * cnt: + if ('hair' in tag or 'face' in tag or 'mouth' in tag or 'skin' in tag or 'smile' in tag): + if not tag in add_prompt_style: + add_prompt_style.append(tag) + + + + if len(add_prompt_style) > 0: + add_prompt_style = ", ".join(add_prompt_style) + ', ' + else: + add_prompt_style = '' + + pipe = pipe.to("cuda") + images_style = txt2img(pipe, trigger_style + add_prompt_style + pos_prompt, neg_prompt, num_images=10) + return images_style + +def main_diffusion_inference_pose(pose_model_path, pose_image, + pos_prompt, neg_prompt, + input_img_dir, base_model_path, style_model_path, lora_model_path, + multiplier_style=0.25, + multiplier_human=0.85): + if style_model_path is None: + model_dir = snapshot_download('Cherrytest/zjz_mj_jiyi_small_addtxt_fromleo', revision='v1.0.0') + style_model_path = os.path.join(model_dir, 'zjz_mj_jiyi_small_addtxt_fromleo.safetensors') + + controlnet = ControlNetModel.from_pretrained(pose_model_path, torch_dtype=torch.float32) + pipe = StableDiffusionControlNetPipeline.from_pretrained(base_model_path, safety_checker=None, controlnet=controlnet, torch_dtype=torch.float32) + pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config) + pose_im = Image.open(pose_image) + pose_im = img_pad(pose_im) + model_dir = snapshot_download('damo/face_chain_control_model',revision='v1.0.1') + openpose = OpenposeDetector.from_pretrained(os.path.join(model_dir, 'model_controlnet/ControlNet')) + pose_im = openpose(pose_im, include_hand=True) + + lora_style_path = style_model_path + lora_human_path = lora_model_path + pipe = merge_lora(pipe, lora_style_path, multiplier_style, from_safetensor=True) + pipe = merge_lora(pipe, lora_human_path, multiplier_human, from_safetensor=False) + print(f'multiplier_style:{multiplier_style}, multiplier_human:{multiplier_human}') + + train_dir = str(input_img_dir) + '_labeled' + add_prompt_style = [] + f = open(os.path.join(train_dir, 'metadata.jsonl'), 'r') + tags_all = [] + cnt = 0 + cnts_trigger = np.zeros(6) + for line in f: + cnt += 1 + data = json.loads(line)['text'].split(', ') + tags_all.extend(data) + if data[1] == 'a boy': + cnts_trigger[0] += 1 + elif data[1] == 'a girl': + cnts_trigger[1] += 1 + elif data[1] == 'a handsome man': + cnts_trigger[2] += 1 + elif data[1] == 'a beautiful woman': + cnts_trigger[3] += 1 + elif data[1] == 'a mature man': + cnts_trigger[4] += 1 + elif data[1] == 'a mature woman': + cnts_trigger[5] += 1 + else: + print('Error.') + f.close() + + attr_idx = np.argmax(cnts_trigger) + trigger_styles = ['a boy, children, ', 'a girl, children, ', 'a handsome man, ', 'a beautiful woman, ', + 'a mature man, ', 'a mature woman, '] + trigger_style = '(:10), ' + trigger_styles[attr_idx] + if attr_idx == 2 or attr_idx == 4: + neg_prompt += ', children' + + for tag in tags_all: + if tags_all.count(tag) > 0.5 * cnt: + if ('hair' in tag or 'face' in tag or 'mouth' in tag or 'skin' in tag or 'smile' in tag): + if not tag in add_prompt_style: + add_prompt_style.append(tag) + + if len(add_prompt_style) > 0: + add_prompt_style = ", ".join(add_prompt_style) + ', ' + else: + add_prompt_style = '' + # trigger_style = trigger_style + 'with face, ' + # pos_prompt = 'Generate a standard ID photo of a chinese {}, solo, wearing high-class business/working suit, beautiful smooth face, with high-class/simple pure color background, looking straight into the camera with shoulders parallel to the frame, smile, high detail face, best quality, photorealistic'.format(gender) + pipe = pipe.to("cuda") + # print(trigger_style + add_prompt_style + pos_prompt) + images_style = txt2img_pose(pipe, pose_im, trigger_style + add_prompt_style + pos_prompt, neg_prompt, num_images=10) + return images_style + + +def main_diffusion_inference_multi(pose_model_path, pose_image, + pos_prompt, neg_prompt, + input_img_dir, base_model_path, style_model_path, lora_model_path, + multiplier_style=0.25, + multiplier_human=0.85): + if style_model_path is None: + model_dir = snapshot_download('Cherrytest/zjz_mj_jiyi_small_addtxt_fromleo', revision='v1.0.0') + style_model_path = os.path.join(model_dir, 'zjz_mj_jiyi_small_addtxt_fromleo.safetensors') + + model_dir = snapshot_download('damo/face_chain_control_model', revision='v1.0.1') + controlnet = [ + ControlNetModel.from_pretrained(pose_model_path, torch_dtype=torch.float32), + ControlNetModel.from_pretrained(os.path.join(model_dir, 'model_controlnet/control_v11p_sd15_depth'), torch_dtype=torch.float32) + ] + pipe = StableDiffusionControlNetPipeline.from_pretrained(base_model_path, safety_checker=None, controlnet=controlnet, torch_dtype=torch.float32) + pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config) + pose_image = Image.open(pose_image) + pose_image = img_pad(pose_image) + openpose = OpenposeDetector.from_pretrained(os.path.join(model_dir, 'model_controlnet/ControlNet')) + pose_im = openpose(pose_image, include_hand=True) + segmentation_pipeline = pipeline(Tasks.image_segmentation, + 'damo/cv_resnet101_image-multiple-human-parsing') + result = segmentation_pipeline(pose_image) + mask_rst = get_mask(result) + pose_image = np.array(pose_image) + pose_image = (pose_image * mask_rst).astype(np.uint8) + pose_image = Image.fromarray(pose_image) + depth_estimator = tpipeline('depth-estimation', os.path.join(model_dir, 'model_controlnet/dpt-large')) + depth_im = depth_estimator(pose_image)['depth'] + depth_im = np.array(depth_im) + depth_im = depth_im[:, :, None] + depth_im = np.concatenate([depth_im, depth_im, depth_im], axis=2) + depth_im = Image.fromarray(depth_im) + control_im = [pose_im, depth_im] + + lora_style_path = style_model_path + lora_human_path = lora_model_path + pipe = merge_lora(pipe, lora_style_path, multiplier_style, from_safetensor=True) + pipe = merge_lora(pipe, lora_human_path, multiplier_human, from_safetensor=False) + print(f'multiplier_style:{multiplier_style}, multiplier_human:{multiplier_human}') + + train_dir = str(input_img_dir) + '_labeled' + add_prompt_style = [] + f = open(os.path.join(train_dir, 'metadata.jsonl'), 'r') + tags_all = [] + cnt = 0 + cnts_trigger = np.zeros(6) + for line in f: + cnt += 1 + data = json.loads(line)['text'].split(', ') + tags_all.extend(data) + if data[1] == 'a boy': + cnts_trigger[0] += 1 + elif data[1] == 'a girl': + cnts_trigger[1] += 1 + elif data[1] == 'a handsome man': + cnts_trigger[2] += 1 + elif data[1] == 'a beautiful woman': + cnts_trigger[3] += 1 + elif data[1] == 'a mature man': + cnts_trigger[4] += 1 + elif data[1] == 'a mature woman': + cnts_trigger[5] += 1 + else: + print('Error.') + f.close() + + attr_idx = np.argmax(cnts_trigger) + trigger_styles = ['a boy, children, ', 'a girl, children, ', 'a handsome man, ', 'a beautiful woman, ', + 'a mature man, ', 'a mature woman, '] + trigger_style = '(:10), ' + trigger_styles[attr_idx] + if attr_idx == 2 or attr_idx == 4: + neg_prompt += ', children' + + for tag in tags_all: + if tags_all.count(tag) > 0.5 * cnt: + if ('hair' in tag or 'face' in tag or 'mouth' in tag or 'skin' in tag or 'smile' in tag): + if not tag in add_prompt_style: + add_prompt_style.append(tag) + + if len(add_prompt_style) > 0: + add_prompt_style = ", ".join(add_prompt_style) + ', ' + else: + add_prompt_style = '' + # trigger_style = trigger_style + 'with face, ' + # pos_prompt = 'Generate a standard ID photo of a chinese {}, solo, wearing high-class business/working suit, beautiful smooth face, with high-class/simple pure color background, looking straight into the camera with shoulders parallel to the frame, smile, high detail face, best quality, photorealistic'.format(gender) + pipe = pipe.to("cuda") + # print(trigger_style + add_prompt_style + pos_prompt) + images_style = txt2img_multi(pipe, control_im, trigger_style + add_prompt_style + pos_prompt, neg_prompt, num_images=10) + return images_style + +def stylization_fn(use_stylization, rank_results): + if use_stylization: + ## TODO + pass + else: + return rank_results + + +def main_model_inference(pose_model_path, pose_image, use_depth_control, pos_prompt, neg_prompt, style_model_path, multiplier_style, multiplier_human, use_main_model, + input_img_dir=None, base_model_path=None, lora_model_path=None): + if use_main_model: + multiplier_style_kwargs = {'multiplier_style': multiplier_style} if multiplier_style is not None else {} + multiplier_human_kwargs = {'multiplier_human': multiplier_human} if multiplier_human is not None else {} + if pose_image is None: + return main_diffusion_inference(pos_prompt, neg_prompt, input_img_dir, base_model_path, + style_model_path, lora_model_path, + **multiplier_style_kwargs, **multiplier_human_kwargs) + else: + pose_image = compress_image(pose_image, 1024 * 1024) + if use_depth_control: + return main_diffusion_inference_multi(pose_model_path, pose_image, pos_prompt, + neg_prompt, input_img_dir, base_model_path, style_model_path, + lora_model_path, + **multiplier_style_kwargs, **multiplier_human_kwargs) + else: + return main_diffusion_inference_pose(pose_model_path, pose_image, pos_prompt, neg_prompt, + input_img_dir, base_model_path, style_model_path, lora_model_path, + **multiplier_style_kwargs, **multiplier_human_kwargs) + + +def select_high_quality_face(input_img_dir): + input_img_dir = str(input_img_dir) + '_labeled' + quality_score_list = [] + abs_img_path_list = [] + ## TODO + face_quality_func = pipeline(Tasks.face_quality_assessment, 'damo/cv_manual_face-quality-assessment_fqa', model_revision='v2.0') + + for img_name in os.listdir(input_img_dir): + if img_name.endswith('jsonl') or img_name.startswith('.ipynb') or img_name.startswith('.safetensors'): + continue + + if img_name.endswith('jpg') or img_name.endswith('png'): + abs_img_name = os.path.join(input_img_dir, img_name) + face_quality_score = face_quality_func(abs_img_name)[OutputKeys.SCORES] + if face_quality_score is None: + quality_score_list.append(0) + else: + quality_score_list.append(face_quality_score[0]) + abs_img_path_list.append(abs_img_name) + + sort_idx = np.argsort(quality_score_list)[::-1] + print('Selected face: ' + abs_img_path_list[sort_idx[0]]) + + return Image.open(abs_img_path_list[sort_idx[0]]) + + +def face_swap_fn(use_face_swap, gen_results, template_face): + if use_face_swap: + ## TODO + out_img_list = [] + image_face_fusion = pipeline('face_fusion_torch', + model='damo/cv_unet_face_fusion_torch', model_revision='v1.0.3') + for img in gen_results: + result = image_face_fusion(dict(template=img, user=template_face))[OutputKeys.OUTPUT_IMG] + out_img_list.append(result) + + return out_img_list + else: + ret_results = [] + for img in gen_results: + ret_results.append(cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)) + return ret_results + + +def post_process_fn(use_post_process, swap_results_ori, selected_face, num_gen_images): + if use_post_process: + sim_list = [] + ## TODO + face_recognition_func = pipeline(Tasks.face_recognition, 'damo/cv_ir_face-recognition-ood_rts', model_revision='v2.5') + face_det_func = pipeline(task=Tasks.face_detection, model='damo/cv_ddsar_face-detection_iclr23-damofd', model_revision='v1.1') + swap_results = [] + for img in swap_results_ori: + result_det = face_det_func(img) + bboxes = result_det['boxes'] + if len(bboxes) == 1: + bbox = bboxes[0] + lenface = max(bbox[2] - bbox[0], bbox[3] - bbox[1]) + if 120 < lenface < 300: + swap_results.append(img) + + select_face_emb = face_recognition_func(selected_face)[OutputKeys.IMG_EMBEDDING][0] + + for img in swap_results: + emb = face_recognition_func(img)[OutputKeys.IMG_EMBEDDING] + if emb is None or select_face_emb is None: + sim_list.append(0) + else: + sim = np.dot(emb, select_face_emb) + sim_list.append(sim.item()) + sort_idx = np.argsort(sim_list)[::-1] + + return np.array(swap_results)[sort_idx[:min(int(num_gen_images), len(swap_results))]] + else: + return np.array(swap_results_ori) + + +class GenPortrait: + def __init__(self, pose_model_path, pose_image, use_depth_control, pos_prompt, neg_prompt, style_model_path, multiplier_style, multiplier_human, + use_main_model=True, use_face_swap=True, + use_post_process=True, use_stylization=True): + self.use_main_model = use_main_model + self.use_face_swap = use_face_swap + self.use_post_process = use_post_process + self.use_stylization = use_stylization + self.multiplier_style = multiplier_style + self.multiplier_human = multiplier_human + self.style_model_path = style_model_path + self.pos_prompt = pos_prompt + self.neg_prompt = neg_prompt + self.pose_model_path = pose_model_path + self.pose_image = pose_image + self.use_depth_control = use_depth_control + + def __call__(self, input_img_dir, num_gen_images=6, base_model_path=None, + lora_model_path=None, sub_path=None, revision=None): + base_model_path = snapshot_download(base_model_path, revision=revision) + if sub_path is not None and len(sub_path) > 0: + base_model_path = os.path.join(base_model_path, sub_path) + + # main_model_inference PIL + gen_results = main_model_inference(self.pose_model_path, self.pose_image, self.use_depth_control, + self.pos_prompt, self.neg_prompt, + self.style_model_path, self.multiplier_style, self.multiplier_human, + self.use_main_model, input_img_dir=input_img_dir, + lora_model_path=lora_model_path, base_model_path=base_model_path) + + # select_high_quality_face PIL + selected_face = select_high_quality_face(input_img_dir) + # face_swap cv2 + swap_results = face_swap_fn(self.use_face_swap, gen_results, selected_face) + # pose_process + rank_results = post_process_fn(self.use_post_process, swap_results, selected_face, + num_gen_images=num_gen_images) + # stylization + final_gen_results = stylization_fn(self.use_stylization, rank_results) + + + return final_gen_results + +def compress_image(input_path, target_size): + output_path = change_extension_to_jpg(input_path) + + image = cv2.imread(input_path) + + quality = 95 + try: + while cv2.imencode('.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, quality])[1].size > target_size: + quality -= 5 + except: + import pdb;pdb.set_trace() + + compressed_image = cv2.imencode('.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, quality])[1].tostring() + + with open(output_path, 'wb') as f: + f.write(compressed_image) + return output_path + + +def change_extension_to_jpg(image_path): + + base_name = os.path.basename(image_path) + new_base_name = os.path.splitext(base_name)[0] + ".jpg" + + directory = os.path.dirname(image_path) + + new_image_path = os.path.join(directory, new_base_name) + return new_image_path diff --git a/demo/facechain_agent/facechain/inference_inpaint.py b/demo/facechain_agent/facechain/inference_inpaint.py new file mode 100644 index 000000000..7bffbfef5 --- /dev/null +++ b/demo/facechain_agent/facechain/inference_inpaint.py @@ -0,0 +1,890 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. +# Modified from the original implementation at https://github.com/modelscope/facechain/pull/104. +import json +import os +import sys + +import cv2 +import numpy as np +import torch +from PIL import Image +from skimage import transform +from controlnet_aux import OpenposeDetector +from diffusers import StableDiffusionPipeline, StableDiffusionControlNetPipeline, \ + StableDiffusionControlNetInpaintPipeline, ControlNetModel, UniPCMultistepScheduler +from facechain.utils import snapshot_download +from modelscope.outputs import OutputKeys +from modelscope.pipelines import pipeline +from modelscope.utils.constant import Tasks +from torch import multiprocessing +from transformers import pipeline as tpipeline + +from facechain.data_process.preprocessing import Blipv2 +from facechain.merge_lora import merge_lora + + +def _data_process_fn_process(input_img_dir): + Blipv2()(input_img_dir) + + +def concatenate_images(images): + heights = [img.shape[0] for img in images] + max_width = sum([img.shape[1] for img in images]) + + concatenated_image = np.zeros((max(heights), max_width, 3), dtype=np.uint8) + x_offset = 0 + for img in images: + concatenated_image[0:img.shape[0], x_offset:x_offset + img.shape[1], :] = img + x_offset += img.shape[1] + return concatenated_image + + +def data_process_fn(input_img_dir, use_data_process): + ## TODO add face quality filter + if use_data_process: + ## TODO + + _process = multiprocessing.Process(target=_data_process_fn_process, args=(input_img_dir,)) + _process.start() + _process.join() + + return os.path.join(str(input_img_dir) + '_labeled', "metadata.jsonl") + + +def call_face_crop(det_pipeline, image, crop_ratio): + det_result = det_pipeline(image) + bboxes = det_result['boxes'] + keypoints = det_result['keypoints'] + area = 0 + idx = 0 + for i in range(len(bboxes)): + bbox = bboxes[i] + area_tmp = (bbox[2] - bbox[0]) * (bbox[3] - bbox[1]) + if area_tmp > area: + area = area_tmp + idx = i + bbox = bboxes[idx] + keypoint = keypoints[idx] + points_array = np.zeros((5, 2)) + for k in range(5): + points_array[k, 0] = keypoint[2 * k] + points_array[k, 1] = keypoint[2 * k + 1] + w, h = image.size + face_w = bbox[2] - bbox[0] + face_h = bbox[3] - bbox[1] + bbox[0] = np.clip(np.array(bbox[0], np.int32) - face_w * (crop_ratio - 1) / 2, 0, w - 1) + bbox[1] = np.clip(np.array(bbox[1], np.int32) - face_h * (crop_ratio - 1) / 2, 0, h - 1) + bbox[2] = np.clip(np.array(bbox[2], np.int32) + face_w * (crop_ratio - 1) / 2, 0, w - 1) + bbox[3] = np.clip(np.array(bbox[3], np.int32) + face_h * (crop_ratio - 1) / 2, 0, h - 1) + bbox = np.array(bbox, np.int32) + return bbox, points_array + + +def crop_and_paste(Source_image, Source_image_mask, Target_image, Source_Five_Point, Target_Five_Point, Source_box, use_warp=True): + if use_warp: + Source_Five_Point = np.reshape(Source_Five_Point, [5, 2]) - np.array(Source_box[:2]) + Target_Five_Point = np.reshape(Target_Five_Point, [5, 2]) + + Crop_Source_image = Source_image.crop(np.int32(Source_box)) + Crop_Source_image_mask = Source_image_mask.crop(np.int32(Source_box)) + Source_Five_Point, Target_Five_Point = np.array(Source_Five_Point), np.array(Target_Five_Point) + + tform = transform.SimilarityTransform() + tform.estimate(Source_Five_Point, Target_Five_Point) + M = tform.params[0:2, :] + + warped = cv2.warpAffine(np.array(Crop_Source_image), M, np.shape(Target_image)[:2][::-1], borderValue=0.0) + warped_mask = cv2.warpAffine(np.array(Crop_Source_image_mask), M, np.shape(Target_image)[:2][::-1], borderValue=0.0) + + mask = np.float32(warped_mask == 0) + output = mask * np.float32(Target_image) + (1 - mask) * np.float32(warped) + else: + mask = np.float32(np.array(Source_image_mask) == 0) + output = mask * np.float32(Target_image) + (1 - mask) * np.float32(Source_image) + return output, mask + + +def segment(segmentation_pipeline, img, ksize=0, eyeh=0, ksize1=0, include_neck=False, warp_mask=None, return_human=False): + if True: + result = segmentation_pipeline(img) + masks = result['masks'] + scores = result['scores'] + labels = result['labels'] + if len(masks) == 0: + return + h, w = masks[0].shape + mask_face = np.zeros((h, w)) + mask_hair = np.zeros((h, w)) + mask_neck = np.zeros((h, w)) + mask_cloth = np.zeros((h, w)) + mask_human = np.zeros((h, w)) + for i in range(len(labels)): + if scores[i] > 0.8: + if labels[i] == 'Torso-skin': + mask_neck += masks[i] + elif labels[i] == 'Face': + mask_face += masks[i] + elif labels[i] == 'Human': + mask_human += masks[i] + elif labels[i] == 'Hair': + mask_hair += masks[i] + elif labels[i] == 'UpperClothes' or labels[i] == 'Coat': + mask_cloth += masks[i] + mask_face = np.clip(mask_face, 0, 1) + mask_hair = np.clip(mask_hair, 0, 1) + mask_neck = np.clip(mask_neck, 0, 1) + mask_cloth = np.clip(mask_cloth, 0, 1) + mask_human = np.clip(mask_human, 0, 1) + if np.sum(mask_face) > 0: + soft_mask = np.clip(mask_face, 0, 1) + if ksize1 > 0: + kernel_size1 = int(np.sqrt(np.sum(soft_mask)) * ksize1) + kernel1 = np.ones((kernel_size1, kernel_size1)) + soft_mask = cv2.dilate(soft_mask, kernel1, iterations=1) + if ksize > 0: + kernel_size = int(np.sqrt(np.sum(soft_mask)) * ksize) + kernel = np.ones((kernel_size, kernel_size)) + soft_mask_dilate = cv2.dilate(soft_mask, kernel, iterations=1) + if warp_mask is not None: + soft_mask_dilate = soft_mask_dilate * (np.clip(soft_mask + warp_mask[:, :, 0], 0, 1)) + if eyeh > 0: + soft_mask = np.concatenate((soft_mask[:eyeh], soft_mask_dilate[eyeh:]), axis=0) + else: + soft_mask = soft_mask_dilate + else: + if ksize1 > 0: + kernel_size1 = int(np.sqrt(np.sum(soft_mask)) * ksize1) + kernel1 = np.ones((kernel_size1, kernel_size1)) + soft_mask = cv2.dilate(mask_face, kernel1, iterations=1) + else: + soft_mask = mask_face + if include_neck: + soft_mask = np.clip(soft_mask + mask_neck, 0, 1) + + if return_human: + mask_human = cv2.GaussianBlur(mask_human, (21, 21), 0) * mask_human + return soft_mask, mask_human + else: + return soft_mask + + +def crop_bottom(pil_file, width): + if width == 512: + height = 768 + else: + height = 1152 + w, h = pil_file.size + factor = w / width + new_h = int(h / factor) + pil_file = pil_file.resize((width, new_h)) + crop_h = min(int(new_h / 32) * 32, height) + array_file = np.array(pil_file) + array_file = array_file[:crop_h, :, :] + output_file = Image.fromarray(array_file) + return output_file + + +def img2img_multicontrol(img, control_image, controlnet_conditioning_scale, pipe, mask, pos_prompt, neg_prompt, + strength, num=1, use_ori=False): + image_mask = Image.fromarray(np.uint8(mask * 255)) + image_human = [] + for i in range(num): + image_human.append(pipe(image=img, mask_image=image_mask, control_image=control_image, prompt=pos_prompt, + negative_prompt=neg_prompt, guidance_scale=7, strength=strength, num_inference_steps=40, + controlnet_conditioning_scale=controlnet_conditioning_scale, + num_images_per_prompt=1).images[0]) + if use_ori: + image_human[i] = Image.fromarray((np.array(image_human[i]) * mask[:,:,None] + np.array(img) * (1 - mask[:,:,None])).astype(np.uint8)) + return image_human + + +def get_mask(result): + masks = result['masks'] + scores = result['scores'] + labels = result['labels'] + h, w = masks[0].shape + mask_hair = np.zeros((h, w)) + mask_face = np.zeros((h, w)) + mask_human = np.zeros((h, w)) + for i in range(len(labels)): + if scores[i] > 0.8: + if labels[i] == 'Face': + if np.sum(masks[i]) > np.sum(mask_face): + mask_face = masks[i] + elif labels[i] == 'Human': + if np.sum(masks[i]) > np.sum(mask_human): + mask_human = masks[i] + elif labels[i] == 'Hair': + if np.sum(masks[i]) > np.sum(mask_hair): + mask_hair = masks[i] + mask_rst = np.clip(mask_human - mask_hair - mask_face, 0, 1) + mask_rst = np.expand_dims(mask_rst, 2) + mask_rst = np.concatenate([mask_rst, mask_rst, mask_rst], axis=2) + return mask_rst + + +def main_diffusion_inference_inpaint(inpaint_image, strength, output_img_size, pos_prompt, neg_prompt, + input_img_dir, base_model_path, style_model_path, lora_model_path, + multiplier_style=0.05, + multiplier_human=1.0): + if style_model_path is None: + model_dir = snapshot_download('Cherrytest/zjz_mj_jiyi_small_addtxt_fromleo', revision='v1.0.0') + style_model_path = os.path.join(model_dir, 'zjz_mj_jiyi_small_addtxt_fromleo.safetensors') + + segmentation_pipeline = pipeline(Tasks.image_segmentation, 'damo/cv_resnet101_image-multiple-human-parsing') + det_pipeline = pipeline(Tasks.face_detection, 'damo/cv_ddsar_face-detection_iclr23-damofd') + model_dir = snapshot_download('damo/face_chain_control_model', revision='v1.0.1') + model_dir1 = snapshot_download('ly261666/cv_wanx_style_model',revision='v1.0.3') + + if output_img_size == 512: + dtype = torch.float32 + else: + dtype = torch.float16 + + train_dir = str(input_img_dir) + '_labeled' + add_prompt_style = [] + f = open(os.path.join(train_dir, 'metadata.jsonl'), 'r') + tags_all = [] + cnt = 0 + cnts_trigger = np.zeros(6) + is_old = False + for line in f: + cnt += 1 + data = json.loads(line)['text'].split(', ') + tags_all.extend(data) + if data[1] == 'a boy': + cnts_trigger[0] += 1 + elif data[1] == 'a girl': + cnts_trigger[1] += 1 + elif data[1] == 'a handsome man': + cnts_trigger[2] += 1 + elif data[1] == 'a beautiful woman': + cnts_trigger[3] += 1 + elif data[1] == 'a mature man': + cnts_trigger[4] += 1 + is_old = True + elif data[1] == 'a mature woman': + cnts_trigger[5] += 1 + is_old = True + else: + print('Error.') + f.close() + + attr_idx = np.argmax(cnts_trigger) + trigger_styles = ['a boy, children, ', 'a girl, children, ', 'a handsome man, ', 'a beautiful woman, ', + 'a mature man, ', 'a mature woman, '] + trigger_style = '(:10), ' + trigger_styles[attr_idx] + if attr_idx == 2 or attr_idx == 4: + neg_prompt += ', children' + + for tag in tags_all: + if tags_all.count(tag) > 0.5 * cnt: + if ('glasses' in tag or 'smile' in tag): + if not tag in add_prompt_style: + add_prompt_style.append(tag) + + if len(add_prompt_style) > 0: + add_prompt_style = ", ".join(add_prompt_style) + ', ' + else: + add_prompt_style = '' + + if isinstance(inpaint_image, str): + inpaint_im = Image.open(inpaint_image) + else: + inpaint_im = inpaint_image + inpaint_im = crop_bottom(inpaint_im, output_img_size) + # return [inpaint_im, inpaint_im, inpaint_im] + openpose = OpenposeDetector.from_pretrained(os.path.join(model_dir, "model_controlnet/ControlNet")) + controlnet = ControlNetModel.from_pretrained(os.path.join(model_dir, "model_controlnet/control_v11p_sd15_openpose"), torch_dtype=dtype) + openpose_image = openpose(np.array(inpaint_im, np.uint8), include_hand=True, include_face=False) + w, h = inpaint_im.size + + pipe = StableDiffusionControlNetPipeline.from_pretrained(base_model_path, controlnet=controlnet, torch_dtype=dtype) + lora_style_path = style_model_path + lora_human_path = lora_model_path + pipe = merge_lora(pipe, lora_style_path, multiplier_style, from_safetensor=True) + pipe = merge_lora(pipe, lora_human_path, multiplier_human, from_safetensor=False) + pipe = pipe.to("cuda") + image_faces = [] + for i in range(1): + image_face = pipe(prompt=trigger_style + add_prompt_style + pos_prompt, image=openpose_image, height=h, width=w, + guidance_scale=7, negative_prompt=neg_prompt, + num_inference_steps=40, num_images_per_prompt=1).images[0] + image_faces.append(image_face) + selected_face = select_high_quality_face(input_img_dir) + swap_results = face_swap_fn(True, image_faces, selected_face) + + controlnet = [ + ControlNetModel.from_pretrained(os.path.join(model_dir, "model_controlnet/control_v11p_sd15_openpose"), torch_dtype=dtype), + ControlNetModel.from_pretrained(os.path.join(model_dir1, "contronet-canny"), torch_dtype=dtype) + ] + pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(base_model_path, controlnet=controlnet, + torch_dtype=dtype) + pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config) + pipe = merge_lora(pipe, style_model_path, multiplier_style, from_safetensor=True) + pipe = merge_lora(pipe, lora_model_path, multiplier_human, from_safetensor=False) + pipe = pipe.to("cuda") + + images_human = [] + images_auto = [] + inpaint_bbox, inpaint_keypoints = call_face_crop(det_pipeline, inpaint_im, 1.1) + eye_height = int((inpaint_keypoints[0, 1] + inpaint_keypoints[1, 1]) / 2) + canny_image = cv2.Canny(np.array(inpaint_im, np.uint8), 100, 200)[:, :, None] + mask = segment(segmentation_pipeline, inpaint_im, ksize=0.05, eyeh=eye_height) + canny_image = (canny_image * (1.0 - mask[:, :, None])).astype(np.uint8) + canny_image = Image.fromarray(np.concatenate([canny_image, canny_image, canny_image], axis=2)) + # canny_image.save('canny.png') + for i in range(1): + image_face = swap_results[i] + image_face = Image.fromarray(image_face[:, :, ::-1]) + + face_bbox, face_keypoints = call_face_crop(det_pipeline, image_face, 1.5) + face_mask = segment(segmentation_pipeline, image_face) + face_mask = np.expand_dims((face_mask * 255).astype(np.uint8), axis=2) + face_mask = np.concatenate([face_mask, face_mask, face_mask], axis=2) + face_mask = Image.fromarray(face_mask) + replaced_input_image, warp_mask = crop_and_paste(image_face, face_mask, inpaint_im, face_keypoints, + inpaint_keypoints, face_bbox) + warp_mask = 1.0 - warp_mask + # cv2.imwrite('tmp_{}.png'.format(i), replaced_input_image[:, :, ::-1]) + + openpose_image = openpose(np.array(replaced_input_image * warp_mask, np.uint8), include_hand=True, + include_body=False, include_face=True) + # openpose_image.save('openpose_{}.png'.format(i)) + read_control = [openpose_image, canny_image] + inpaint_mask, human_mask = segment(segmentation_pipeline, inpaint_im, ksize=0.1, ksize1=0.06, eyeh=eye_height, include_neck=False, + warp_mask=warp_mask, return_human=True) + inpaint_with_mask = ((1.0 - inpaint_mask[:,:,None]) * np.array(inpaint_im))[:,:,::-1] + # cv2.imwrite('inpaint_with_mask_{}.png'.format(i), inpaint_with_mask) + print('Finishing segmenting images.') + images_human.extend(img2img_multicontrol(inpaint_im, read_control, [1.0, 0.2], pipe, inpaint_mask, + trigger_style + add_prompt_style + pos_prompt, neg_prompt, + strength=strength)) + images_auto.extend(img2img_multicontrol(inpaint_im, read_control, [1.0, 0.2], pipe, np.zeros_like(inpaint_mask), + trigger_style + add_prompt_style + pos_prompt, neg_prompt, + strength=0.025)) + + edge_add = np.array(inpaint_im).astype(np.int16) - np.array(images_auto[i]).astype(np.int16) + edge_add = edge_add * (1 - human_mask[:,:,None]) + images_human[i] = Image.fromarray((np.clip(np.array(images_human[i]).astype(np.int16) + edge_add.astype(np.int16), 0, 255)).astype(np.uint8)) + + images_rst = [] + + for i in range(len(images_human)): + im = images_human[i] + canny_image = cv2.Canny(np.array(im, np.uint8), 100, 200)[:, :, None] + canny_image = Image.fromarray(np.concatenate([canny_image, canny_image, canny_image], axis=2)) + openpose_image = openpose(np.array(im, np.uint8), include_hand=True, include_face=True) + read_control = [openpose_image, canny_image] + inpaint_mask, human_mask = segment(segmentation_pipeline, images_human[i], ksize=0.02, return_human=True) + print('Finishing segmenting images.') + image_rst = img2img_multicontrol(im, read_control, [0.8, 0.8], pipe, inpaint_mask, + trigger_style + add_prompt_style + pos_prompt, neg_prompt, strength=0.1, + num=1)[0] + image_auto = img2img_multicontrol(im, read_control, [0.8, 0.8], pipe, np.zeros_like(inpaint_mask), + trigger_style + add_prompt_style + pos_prompt, neg_prompt, strength=0.025, + num=1)[0] + edge_add = np.array(im).astype(np.int16) - np.array(image_auto).astype(np.int16) + edge_add = edge_add * (1 - human_mask[:,:,None]) + image_rst = Image.fromarray((np.clip(np.array(image_rst).astype(np.int16) + edge_add.astype(np.int16), 0, 255)).astype(np.uint8)) + + images_rst.append(image_rst) + + for i in range(1): + images_rst[i].save('inference_{}.png'.format(i)) + + return images_rst + +def main_diffusion_inference_inpaint_multi(inpaint_images, strength, output_img_size, pos_prompt, neg_prompt, + input_img_dir, base_model_path, style_model_path, lora_model_path, + multiplier_style=0.05, + multiplier_human=1.0): + if style_model_path is None: + model_dir = snapshot_download('Cherrytest/zjz_mj_jiyi_small_addtxt_fromleo', revision='v1.0.0') + style_model_path = os.path.join(model_dir, 'zjz_mj_jiyi_small_addtxt_fromleo.safetensors') + + segmentation_pipeline = pipeline(Tasks.image_segmentation, 'damo/cv_resnet101_image-multiple-human-parsing') + det_pipeline = pipeline(Tasks.face_detection, 'damo/cv_ddsar_face-detection_iclr23-damofd') + model_dir = snapshot_download('damo/face_chain_control_model', revision='v1.0.1') + model_dir1 = snapshot_download('ly261666/cv_wanx_style_model',revision='v1.0.3') + + if output_img_size == 512: + dtype = torch.float32 + else: + dtype = torch.float16 + + train_dir = str(input_img_dir) + '_labeled' + add_prompt_style = [] + f = open(os.path.join(train_dir, 'metadata.jsonl'), 'r') + tags_all = [] + cnt = 0 + cnts_trigger = np.zeros(6) + is_old = False + for line in f: + cnt += 1 + data = json.loads(line)['text'].split(', ') + tags_all.extend(data) + if data[1] == 'a boy': + cnts_trigger[0] += 1 + elif data[1] == 'a girl': + cnts_trigger[1] += 1 + elif data[1] == 'a handsome man': + cnts_trigger[2] += 1 + elif data[1] == 'a beautiful woman': + cnts_trigger[3] += 1 + elif data[1] == 'a mature man': + cnts_trigger[4] += 1 + is_old = True + elif data[1] == 'a mature woman': + cnts_trigger[5] += 1 + is_old = True + else: + print('Error.') + f.close() + + attr_idx = np.argmax(cnts_trigger) + trigger_styles = ['a boy, children, ', 'a girl, children, ', 'a handsome man, ', 'a beautiful woman, ', + 'a mature man, ', 'a mature woman, '] + trigger_style = '(:10), ' + trigger_styles[attr_idx] + if attr_idx == 2 or attr_idx == 4: + neg_prompt += ', children' + + for tag in tags_all: + if tags_all.count(tag) > 0.5 * cnt: + if ('glasses' in tag or 'smile' in tag): + if not tag in add_prompt_style: + add_prompt_style.append(tag) + + if len(add_prompt_style) > 0: + add_prompt_style = ", ".join(add_prompt_style) + ', ' + else: + add_prompt_style = '' + + openpose = OpenposeDetector.from_pretrained(os.path.join(model_dir, "model_controlnet/ControlNet")) + controlnet = ControlNetModel.from_pretrained(os.path.join(model_dir, "model_controlnet/control_v11p_sd15_openpose"), torch_dtype=dtype) + pipe = StableDiffusionControlNetPipeline.from_pretrained(base_model_path, controlnet=controlnet, torch_dtype=dtype) + lora_style_path = style_model_path + lora_human_path = lora_model_path + pipe = merge_lora(pipe, lora_style_path, multiplier_style, from_safetensor=True) + pipe = merge_lora(pipe, lora_human_path, multiplier_human, from_safetensor=False) + pipe = pipe.to("cuda") + image_faces = [] + + for i in range(1): + inpaint_im = inpaint_images[i] + inpaint_im = crop_bottom(inpaint_im, output_img_size) + + openpose_image = openpose(np.array(inpaint_im, np.uint8), include_hand=True, include_face=False) + w, h = inpaint_im.size + image_face = pipe(prompt=trigger_style + add_prompt_style + pos_prompt, image=openpose_image, height=h, width=w, + guidance_scale=7, negative_prompt=neg_prompt, + num_inference_steps=40, num_images_per_prompt=1).images[0] + image_faces.append(image_face) + + selected_face = select_high_quality_face(input_img_dir) + swap_results = face_swap_fn(True, image_faces, selected_face) + + controlnet = [ + ControlNetModel.from_pretrained(os.path.join(model_dir, "model_controlnet/control_v11p_sd15_openpose"), torch_dtype=dtype), + ControlNetModel.from_pretrained(os.path.join(model_dir1, "contronet-canny"), torch_dtype=dtype) + ] + pipe = StableDiffusionControlNetInpaintPipeline.from_pretrained(base_model_path, controlnet=controlnet, + torch_dtype=dtype) + pipe.scheduler = UniPCMultistepScheduler.from_config(pipe.scheduler.config) + pipe = merge_lora(pipe, style_model_path, multiplier_style, from_safetensor=True) + pipe = merge_lora(pipe, lora_model_path, multiplier_human, from_safetensor=False) + pipe = pipe.to("cuda") + + images_human = [] + images_auto = [] + for i in range(1): + inpaint_im = inpaint_images[i] + inpaint_bbox, inpaint_keypoints = call_face_crop(det_pipeline, inpaint_im, 1.1) + eye_height = int((inpaint_keypoints[0, 1] + inpaint_keypoints[1, 1]) / 2) + canny_image = cv2.Canny(np.array(inpaint_im, np.uint8), 100, 200)[:, :, None] + mask = segment(segmentation_pipeline, inpaint_im, ksize=0.05, eyeh=eye_height) + canny_image = (canny_image * (1.0 - mask[:, :, None])).astype(np.uint8) + canny_image = Image.fromarray(np.concatenate([canny_image, canny_image, canny_image], axis=2)) + + image_face = swap_results[i] + image_face = Image.fromarray(image_face[:, :, ::-1]) + + face_bbox, face_keypoints = call_face_crop(det_pipeline, image_face, 1.5) + face_mask = segment(segmentation_pipeline, image_face) + face_mask = np.expand_dims((face_mask * 255).astype(np.uint8), axis=2) + face_mask = np.concatenate([face_mask, face_mask, face_mask], axis=2) + face_mask = Image.fromarray(face_mask) + replaced_input_image, warp_mask = crop_and_paste(image_face, face_mask, inpaint_im, face_keypoints, + inpaint_keypoints, face_bbox) + warp_mask = 1.0 - warp_mask + # cv2.imwrite('tmp_{}.png'.format(i), replaced_input_image[:, :, ::-1]) + + openpose_image = openpose(np.array(replaced_input_image * warp_mask, np.uint8), include_hand=True, + include_body=False, include_face=True) + # openpose_image.save('openpose_{}.png'.format(i)) + read_control = [openpose_image, canny_image] + inpaint_mask, human_mask = segment(segmentation_pipeline, inpaint_im, ksize=0.1, ksize1=0.06, eyeh=eye_height, include_neck=False, + warp_mask=warp_mask, return_human=True) + inpaint_with_mask = ((1.0 - inpaint_mask[:,:,None]) * np.array(inpaint_im))[:,:,::-1] + # cv2.imwrite('inpaint_with_mask_{}.png'.format(i), inpaint_with_mask) + print('Finishing segmenting images.') + images_human.extend(img2img_multicontrol(inpaint_im, read_control, [1.0, 0.2], pipe, inpaint_mask, + trigger_style + add_prompt_style + pos_prompt, neg_prompt, + strength=strength)) + images_auto.extend(img2img_multicontrol(inpaint_im, read_control, [1.0, 0.2], pipe, np.zeros_like(inpaint_mask), + trigger_style + add_prompt_style + pos_prompt, neg_prompt, + strength=0.025)) + + edge_add = np.array(inpaint_im).astype(np.int16) - np.array(images_auto[i]).astype(np.int16) + edge_add = edge_add * (1 - human_mask[:,:,None]) + images_human[i] = Image.fromarray((np.clip(np.array(images_human[i]).astype(np.int16) + edge_add.astype(np.int16), 0, 255)).astype(np.uint8)) + + + images_rst = [] + for i in range(len(images_human)): + im = images_human[i] + canny_image = cv2.Canny(np.array(im, np.uint8), 100, 200)[:, :, None] + canny_image = Image.fromarray(np.concatenate([canny_image, canny_image, canny_image], axis=2)) + openpose_image = openpose(np.array(im, np.uint8), include_hand=True, include_face=True) + read_control = [openpose_image, canny_image] + inpaint_mask, human_mask = segment(segmentation_pipeline, images_human[i], ksize=0.02, return_human=True) + print('Finishing segmenting images.') + image_rst = img2img_multicontrol(im, read_control, [0.8, 0.8], pipe, np.zeros_like(inpaint_mask), + trigger_style + add_prompt_style + pos_prompt, neg_prompt, strength=0.1, + num=1)[0] + image_auto = img2img_multicontrol(im, read_control, [0.8, 0.8], pipe, np.zeros_like(inpaint_mask), + trigger_style + add_prompt_style + pos_prompt, neg_prompt, strength=0.025, + num=1)[0] + edge_add = np.array(im).astype(np.int16) - np.array(image_auto).astype(np.int16) + edge_add = edge_add * (1 - human_mask[:,:,None]) + image_rst = Image.fromarray((np.clip(np.array(image_rst).astype(np.int16) + edge_add.astype(np.int16), 0, 255)).astype(np.uint8)) + + images_rst.append(image_rst) + + for i in range(1): + images_rst[i].save('inference_{}.png'.format(i)) + + return images_rst + +def stylization_fn(use_stylization, rank_results): + if use_stylization: + ## TODO + pass + else: + return rank_results + + +def main_model_inference(inpaint_image, strength, output_img_size, + pos_prompt, neg_prompt, style_model_path, multiplier_style, multiplier_human, use_main_model, + input_img_dir=None, base_model_path=None, lora_model_path=None): + + if use_main_model: + multiplier_style_kwargs = {'multiplier_style': multiplier_style} if multiplier_style is not None else {} + multiplier_human_kwargs = {'multiplier_human': multiplier_human} if multiplier_human is not None else {} + return main_diffusion_inference_inpaint(inpaint_image, strength, output_img_size, pos_prompt, neg_prompt, + input_img_dir, base_model_path, style_model_path, lora_model_path, + **multiplier_style_kwargs, **multiplier_human_kwargs) + +def main_model_inference_multi(inpaint_image, strength, output_img_size, + pos_prompt, neg_prompt, style_model_path, multiplier_style, multiplier_human, use_main_model, + input_img_dir=None, base_model_path=None, lora_model_path=None): + + if use_main_model: + multiplier_style_kwargs = {'multiplier_style': multiplier_style} if multiplier_style is not None else {} + multiplier_human_kwargs = {'multiplier_human': multiplier_human} if multiplier_human is not None else {} + return main_diffusion_inference_inpaint_multi(inpaint_image, strength, output_img_size, pos_prompt, neg_prompt, + input_img_dir, base_model_path, style_model_path, lora_model_path, + **multiplier_style_kwargs, **multiplier_human_kwargs) + + +def select_high_quality_face(input_img_dir): + input_img_dir = str(input_img_dir) + '_labeled' + quality_score_list = [] + abs_img_path_list = [] + ## TODO + face_quality_func = pipeline(Tasks.face_quality_assessment, 'damo/cv_manual_face-quality-assessment_fqa', + model_revision='v2.0') + + for img_name in os.listdir(input_img_dir): + if img_name.endswith('jsonl') or img_name.startswith('.ipynb') or img_name.startswith('.safetensors'): + continue + + if img_name.endswith('jpg') or img_name.endswith('png'): + abs_img_name = os.path.join(input_img_dir, img_name) + face_quality_score = face_quality_func(abs_img_name)[OutputKeys.SCORES] + if face_quality_score is None: + quality_score_list.append(0) + else: + quality_score_list.append(face_quality_score[0]) + abs_img_path_list.append(abs_img_name) + + sort_idx = np.argsort(quality_score_list)[::-1] + print('Selected face: ' + abs_img_path_list[sort_idx[0]]) + + return Image.open(abs_img_path_list[sort_idx[0]]) + + +def face_swap_fn(use_face_swap, gen_results, template_face): + if use_face_swap: + ## TODO + out_img_list = [] + image_face_fusion = pipeline('face_fusion_torch', + model='damo/cv_unet_face_fusion_torch', model_revision='v1.0.5') + segmentation_pipeline = pipeline(Tasks.image_segmentation, 'damo/cv_resnet101_image-multiple-human-parsing') + for img in gen_results: + result = image_face_fusion(dict(template=img, user=template_face))[OutputKeys.OUTPUT_IMG] + face_mask = segment(segmentation_pipeline, img, ksize=0.1) + result = (result * face_mask[:,:,None] + np.array(img)[:,:,::-1] * (1 - face_mask[:,:,None])).astype(np.uint8) + out_img_list.append(result) + return out_img_list + else: + ret_results = [] + for img in gen_results: + ret_results.append(cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)) + return ret_results + + +def post_process_fn(use_post_process, swap_results_ori, selected_face, num_gen_images): + if use_post_process: + sim_list = [] + ## TODO + face_recognition_func = pipeline(Tasks.face_recognition, 'damo/cv_ir_face-recognition-ood_rts', + model_revision='v2.5') + face_det_func = pipeline(task=Tasks.face_detection, model='damo/cv_ddsar_face-detection_iclr23-damofd', + model_revision='v1.1') + swap_results = swap_results_ori + + select_face_emb = face_recognition_func(selected_face)[OutputKeys.IMG_EMBEDDING][0] + + for img in swap_results: + emb = face_recognition_func(img)[OutputKeys.IMG_EMBEDDING] + if emb is None or select_face_emb is None: + sim_list.append(0) + else: + sim = np.dot(emb, select_face_emb) + sim_list.append(sim.item()) + sort_idx = np.argsort(sim_list)[::-1] + + return np.array(swap_results)[sort_idx[:min(int(num_gen_images), len(swap_results))]] + else: + return np.array(swap_results_ori) + + +class GenPortrait_inpaint: + def __init__(self, inpaint_img, strength, num_faces, + pos_prompt, neg_prompt, style_model_path, multiplier_style, multiplier_human, + use_main_model=True, use_face_swap=True, + use_post_process=True, use_stylization=True): + self.use_main_model = use_main_model + self.use_face_swap = use_face_swap + self.use_post_process = use_post_process + self.use_stylization = use_stylization + self.multiplier_style = multiplier_style + self.multiplier_human = multiplier_human + self.style_model_path = style_model_path + self.pos_prompt = pos_prompt + self.neg_prompt = neg_prompt + self.inpaint_img = inpaint_img + self.strength = strength + self.num_faces = num_faces + + def __call__(self, input_img_dir1=None, input_img_dir2=None, base_model_path=None, + lora_model_path1=None, lora_model_path2=None, sub_path=None, revision=None): + base_model_path = snapshot_download(base_model_path, revision=revision) + if sub_path is not None and len(sub_path) > 0: + base_model_path = os.path.join(base_model_path, sub_path) + + face_detection = pipeline(task=Tasks.face_detection, model='damo/cv_ddsar_face-detection_iclr23-damofd', + model_revision='v1.1') + result_det = face_detection(self.inpaint_img) + bboxes = result_det['boxes'] + assert(len(bboxes)) == self.num_faces + bboxes = np.array(bboxes).astype(np.int16) + lefts = [] + for bbox in bboxes: + lefts.append(bbox[0]) + idxs = np.argsort(lefts) + + if lora_model_path1 != None: + face_box = bboxes[idxs[0]] + inpaint_img_large = cv2.imread(self.inpaint_img) + mask_large = np.ones_like(inpaint_img_large) + mask_large1 = np.zeros_like(inpaint_img_large) + h,w,_ = inpaint_img_large.shape + for i in range(len(bboxes)): + if i != idxs[0]: + bbox = bboxes[i] + inpaint_img_large[bbox[1]:bbox[3], bbox[0]:bbox[2]] = 0 + mask_large[bbox[1]:bbox[3], bbox[0]:bbox[2]] = 0 + + face_ratio = 0.45 + cropl = int(max(face_box[3] - face_box[1], face_box[2] - face_box[0]) / face_ratio / 2) + cx = int((face_box[2] + face_box[0])/2) + cy = int((face_box[1] + face_box[3])/2) + cropup = min(cy, cropl) + cropbo = min(h-cy, cropl) + crople = min(cx, cropl) + cropri = min(w-cx, cropl) + inpaint_img = np.pad(inpaint_img_large[cy-cropup:cy+cropbo, cx-crople:cx+cropri], ((cropl-cropup, cropl-cropbo), (cropl-crople, cropl-cropri), (0, 0)), 'constant') + inpaint_img = cv2.resize(inpaint_img, (512, 512)) + inpaint_img = Image.fromarray(inpaint_img[:,:,::-1]) + mask_large1[cy-cropup:cy+cropbo, cx-crople:cx+cropri] = 1 + mask_large = mask_large * mask_large1 + + gen_results = main_model_inference(inpaint_img, self.strength, 512, + self.pos_prompt, self.neg_prompt, + self.style_model_path, self.multiplier_style, self.multiplier_human, + self.use_main_model, input_img_dir=input_img_dir1, + lora_model_path=lora_model_path1, base_model_path=base_model_path) + + # select_high_quality_face PIL + selected_face = select_high_quality_face(input_img_dir1) + # face_swap cv2 + swap_results = face_swap_fn(self.use_face_swap, gen_results, selected_face) + # stylization + final_gen_results = swap_results + + print(len(final_gen_results)) + + final_gen_results_new = [] + inpaint_img_large = cv2.imread(self.inpaint_img) + ksize = int(10 * cropl / 256) + for i in range(len(final_gen_results)): + print('Start cropping.') + rst_gen = cv2.resize(final_gen_results[i], (cropl * 2, cropl * 2)) + rst_crop = rst_gen[cropl-cropup:cropl+cropbo, cropl-crople:cropl+cropri] + print(rst_crop.shape) + inpaint_img_rst = np.zeros_like(inpaint_img_large) + print('Start pasting.') + inpaint_img_rst[cy-cropup:cy+cropbo, cx-crople:cx+cropri] = rst_crop + print('Fininsh pasting.') + print(inpaint_img_rst.shape, mask_large.shape, inpaint_img_large.shape) + mask_large = mask_large.astype(np.float32) + kernel = np.ones((ksize * 2, ksize * 2)) + mask_large1 = cv2.erode(mask_large, kernel, iterations=1) + mask_large1 = cv2.GaussianBlur(mask_large1, (int(ksize * 1.8) * 2 + 1, int(ksize * 1.8) * 2 + 1), 0) + mask_large1[face_box[1]:face_box[3], face_box[0]:face_box[2]] = 1 + mask_large = mask_large * mask_large1 + final_inpaint_rst = (inpaint_img_rst.astype(np.float32) * mask_large.astype(np.float32) + inpaint_img_large.astype(np.float32) * (1.0 - mask_large.astype(np.float32))).astype(np.uint8) + print('Finish masking.') + final_gen_results_new.append(final_inpaint_rst) + print('Finish generating.') + else: + inpaint_img_large = cv2.imread(self.inpaint_img) + inpaint_img_le = cv2.imread(self.inpaint_img) + final_gen_results_new = [inpaint_img_le, inpaint_img_le, inpaint_img_le] + + for i in range(1): + cv2.imwrite('tmp_inpaint_left_{}.png'.format(i), final_gen_results_new[i]) + + if lora_model_path2 != None and self.num_faces == 2: + face_box = bboxes[idxs[1]] + mask_large = np.ones_like(inpaint_img_large) + mask_large1 = np.zeros_like(inpaint_img_large) + h,w,_ = inpaint_img_large.shape + for i in range(len(bboxes)): + if i != idxs[1]: + bbox = bboxes[i] + inpaint_img_large[bbox[1]:bbox[3], bbox[0]:bbox[2]] = 0 + mask_large[bbox[1]:bbox[3], bbox[0]:bbox[2]] = 0 + + face_ratio = 0.45 + cropl = int(max(face_box[3] - face_box[1], face_box[2] - face_box[0]) / face_ratio / 2) + cx = int((face_box[2] + face_box[0])/2) + cy = int((face_box[1] + face_box[3])/2) + cropup = min(cy, cropl) + cropbo = min(h-cy, cropl) + crople = min(cx, cropl) + cropri = min(w-cx, cropl) + mask_large1[cy-cropup:cy+cropbo, cx-crople:cx+cropri] = 1 + mask_large = mask_large * mask_large1 + + inpaint_imgs = [] + for i in range(1): + inpaint_img_large = final_gen_results_new[i] * mask_large + inpaint_img = np.pad(inpaint_img_large[cy-cropup:cy+cropbo, cx-crople:cx+cropri], ((cropl-cropup, cropl-cropbo), (cropl-crople, cropl-cropri), (0, 0)), 'constant') + inpaint_img = cv2.resize(inpaint_img, (512, 512)) + inpaint_img = Image.fromarray(inpaint_img[:,:,::-1]) + inpaint_imgs.append(inpaint_img) + + + gen_results = main_model_inference_multi(inpaint_imgs, self.strength, 512, + self.pos_prompt, self.neg_prompt, + self.style_model_path, self.multiplier_style, self.multiplier_human, + self.use_main_model, input_img_dir=input_img_dir2, + lora_model_path=lora_model_path2, base_model_path=base_model_path) + + # select_high_quality_face PIL + selected_face = select_high_quality_face(input_img_dir2) + # face_swap cv2 + swap_results = face_swap_fn(self.use_face_swap, gen_results, selected_face) + # stylization + final_gen_results = swap_results + + print(len(final_gen_results)) + + final_gen_results_final = [] + inpaint_img_large = cv2.imread(self.inpaint_img) + ksize = int(10 * cropl / 256) + for i in range(len(final_gen_results)): + print('Start cropping.') + rst_gen = cv2.resize(final_gen_results[i], (cropl * 2, cropl * 2)) + rst_crop = rst_gen[cropl-cropup:cropl+cropbo, cropl-crople:cropl+cropri] + print(rst_crop.shape) + inpaint_img_rst = np.zeros_like(inpaint_img_large) + print('Start pasting.') + inpaint_img_rst[cy-cropup:cy+cropbo, cx-crople:cx+cropri] = rst_crop + print('Fininsh pasting.') + print(inpaint_img_rst.shape, mask_large.shape, inpaint_img_large.shape) + mask_large = mask_large.astype(np.float32) + kernel = np.ones((ksize * 2, ksize * 2)) + mask_large1 = cv2.erode(mask_large, kernel, iterations=1) + mask_large1 = cv2.GaussianBlur(mask_large1, (int(ksize * 1.8) * 2 + 1, int(ksize * 1.8) * 2 + 1), 0) + mask_large1[face_box[1]:face_box[3], face_box[0]:face_box[2]] = 1 + mask_large = mask_large * mask_large1 + final_inpaint_rst = (inpaint_img_rst.astype(np.float32) * mask_large.astype(np.float32) + final_gen_results_new[i].astype(np.float32) * (1.0 - mask_large.astype(np.float32))).astype(np.uint8) + print('Finish masking.') + final_gen_results_final.append(final_inpaint_rst) + print('Finish generating.') + else: + final_gen_results_final = final_gen_results_new + + outputs = final_gen_results_final + outputs_RGB = [] + for out_tmp in outputs: + outputs_RGB.append(cv2.cvtColor(out_tmp, cv2.COLOR_BGR2RGB)) + image_path = './lora_result.png' + if len(outputs) > 0: + result = concatenate_images(outputs) + cv2.imwrite(image_path, result) + + return final_gen_results_final + +def compress_image(input_path, target_size): + output_path = change_extension_to_jpg(input_path) + + image = cv2.imread(input_path) + + quality = 95 + try: + while cv2.imencode('.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, quality])[1].size > target_size: + quality -= 5 + except: + import pdb;pdb.set_trace() + + compressed_image = cv2.imencode('.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, quality])[1].tostring() + + with open(output_path, 'wb') as f: + f.write(compressed_image) + return output_path + + +def change_extension_to_jpg(image_path): + + base_name = os.path.basename(image_path) + new_base_name = os.path.splitext(base_name)[0] + ".jpg" + + directory = os.path.dirname(image_path) + + new_image_path = os.path.join(directory, new_base_name) + return new_image_path diff --git a/demo/facechain_agent/facechain/merge_lora.py b/demo/facechain_agent/facechain/merge_lora.py new file mode 100644 index 000000000..bdc1baeea --- /dev/null +++ b/demo/facechain_agent/facechain/merge_lora.py @@ -0,0 +1,75 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. +import torch +import os +import re +from collections import defaultdict +from safetensors.torch import load_file + + +def merge_lora(pipeline, lora_path, multiplier, from_safetensor=False, device='cpu', dtype=torch.float32): + LORA_PREFIX_UNET = "lora_unet" + LORA_PREFIX_TEXT_ENCODER = "lora_te" + if from_safetensor: + state_dict = load_file(lora_path, device=device) + else: + if os.path.exists(os.path.join(lora_path, 'pytorch_lora_weights.bin')): + checkpoint = torch.load(os.path.join(lora_path, 'pytorch_lora_weights.bin'), map_location=torch.device(device)) + elif os.path.exists(os.path.join(lora_path, 'pytorch_lora_weights.safetensors')): + checkpoint= load_file(os.path.join(lora_path,'pytorch_lora_weights.safetensors'), device=device) + new_dict = dict() + for idx, key in enumerate(checkpoint): + new_key = re.sub(r'\.processor\.', '_', key) + new_key = re.sub(r'mid_block\.', 'mid_block_', new_key) + new_key = re.sub('_lora.up.', '.lora_up.', new_key) + new_key = re.sub('_lora.down.', '.lora_down.', new_key) + new_key = re.sub(r'\.(\d+)\.', '_\\1_', new_key) + new_key = re.sub('to_out', 'to_out_0', new_key) + new_key = 'lora_unet_' + new_key + new_dict[new_key] = checkpoint[key] + state_dict = new_dict + updates = defaultdict(dict) + for key, value in state_dict.items(): + layer, elem = key.split('.', 1) + updates[layer][elem] = value + + for layer, elems in updates.items(): + + if "text" in layer: + layer_infos = layer.split(LORA_PREFIX_TEXT_ENCODER + "_")[-1].split("_") + curr_layer = pipeline.text_encoder + else: + layer_infos = layer.split(LORA_PREFIX_UNET + "_")[-1].split("_") + curr_layer = pipeline.unet + + temp_name = layer_infos.pop(0) + while len(layer_infos) > -1: + try: + curr_layer = curr_layer.__getattr__(temp_name) + if len(layer_infos) > 0: + temp_name = layer_infos.pop(0) + elif len(layer_infos) == 0: + break + except Exception: + if len(layer_infos) == 0: + print('Error loading layer') + if len(temp_name) > 0: + temp_name += "_" + layer_infos.pop(0) + else: + temp_name = layer_infos.pop(0) + + weight_up = elems['lora_up.weight'].to(dtype) + weight_down = elems['lora_down.weight'].to(dtype) + if 'alpha' in elems.keys(): + alpha = elems['alpha'].item() / weight_up.shape[1] + else: + alpha = 1.0 + + curr_layer.weight.data = curr_layer.weight.data.to(device) + if len(weight_up.shape) == 4: + curr_layer.weight.data += multiplier * alpha * torch.mm(weight_up.squeeze(3).squeeze(2), + weight_down.squeeze(3).squeeze(2)).unsqueeze( + 2).unsqueeze(3) + else: + curr_layer.weight.data += multiplier * alpha * torch.mm(weight_up, weight_down) + + return pipeline diff --git a/demo/facechain_agent/facechain/train_text_to_image_lora.py b/demo/facechain_agent/facechain/train_text_to_image_lora.py new file mode 100644 index 000000000..456de1de6 --- /dev/null +++ b/demo/facechain_agent/facechain/train_text_to_image_lora.py @@ -0,0 +1,1166 @@ +# coding=utf-8 +# Copyright (c) Alibaba, Inc. and its affiliates. +# Copyright 2023 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Fine-tuning script for Stable Diffusion for text2image with support for LoRA.""" + +import argparse +import base64 +import itertools +import json +import logging +import math +import os +import sys +sys.path.append('../../') +import random +import shutil +from glob import glob +from pathlib import Path + +import cv2 +import datasets +import diffusers +import numpy as np +import onnxruntime +import PIL.Image +import torch +import torch.nn.functional as F +import torch.utils.checkpoint +from torch import Tensor +from typing import List, Optional, Tuple, Union +import torchvision.transforms.functional as Ft +import transformers +from accelerate import Accelerator +from accelerate.logging import get_logger +from accelerate.utils import ProjectConfiguration, set_seed +from datasets import load_dataset +from diffusers import (AutoencoderKL, DDPMScheduler, DiffusionPipeline, + DPMSolverMultistepScheduler, + StableDiffusionInpaintPipeline, UNet2DConditionModel) +from diffusers.loaders import AttnProcsLayers +from diffusers.models.attention_processor import LoRAAttnProcessor +from diffusers.optimization import get_scheduler +from diffusers.utils import check_min_version, is_wandb_available +from diffusers.utils.import_utils import is_xformers_available +from huggingface_hub import create_repo, upload_folder +from facechain.utils import snapshot_download + +from packaging import version +from PIL import Image +from torchvision import transforms +from tqdm.auto import tqdm +from torch import multiprocessing +from transformers import CLIPTextModel, CLIPTokenizer + +from facechain.inference import data_process_fn + +# Will error if the minimal version of diffusers is not installed. Remove at your own risks. +check_min_version("0.14.0.dev0") + +logger = get_logger(__name__, log_level="INFO") + + +class FaceCrop(torch.nn.Module): + + @staticmethod + def get_params(img: Tensor) -> Tuple[int, int, int, int]: + _, h, w = Ft.get_dimensions(img) + if h != w: + raise ValueError(f"The input image is not square.") + ratio = torch.rand(size=(1,)).item() * 0.1 + 0.35 + yc = torch.rand(size=(1,)).item() * 0.15 + 0.35 + + th = int(h / 1.15 * 0.35 / ratio) + tw = th + + cx = int(0.5 * w) + cy = int(0.5 / 1.15 * h) + + i = min(max(int(cy - yc * th), 0), h - th) + j = int(cx - 0.5 * tw) + + return i, j, th, tw + + def __init__(self): + super().__init__() + + def forward(self, img): + i, j, h, w = self.get_params(img) + + return Ft.crop(img, i, j, h, w) + + def __repr__(self) -> str: + return f"{self.__class__.__name__}" + + +def save_model_card(repo_id: str, images=None, base_model=str, dataset_name=str, repo_folder=None): + img_str = "" + for i, image in enumerate(images): + image.save(os.path.join(repo_folder, f"image_{i}.png")) + img_str += f"![img_{i}](./image_{i}.png)\n" + + yaml = f""" +--- +license: creativeml-openrail-m +base_model: {base_model} +tags: +- stable-diffusion +- stable-diffusion-diffusers +- text-to-image +- diffusers +- lora +inference: true +--- + """ + model_card = f""" +# LoRA text2image fine-tuning - {repo_id} +These are LoRA adaption weights for {base_model}. The weights were fine-tuned on the {dataset_name} dataset. You can find some example images in the following. \n +{img_str} +""" + with open(os.path.join(repo_folder, "README.md"), "w") as f: + f.write(yaml + model_card) + + +def softmax(x): + x -= np.max(x, axis=0, keepdims=True) + x = np.exp(x) / np.sum(np.exp(x), axis=0, keepdims=True) + return x + + +def get_rot(image): + model_dir = snapshot_download('Cherrytest/rot_bgr', + revision='v1.0.0') + model_path = os.path.join(model_dir, 'rot_bgr.onnx') + providers = ['CPUExecutionProvider'] + if torch.cuda.is_available(): + providers.insert(0, 'CUDAExecutionProvider') + ort_session = onnxruntime.InferenceSession(model_path,providers=providers) + + img_cv = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR) + img_clone = img_cv.copy() + img_np = cv2.resize(img_cv, (224, 224)) + img_np = img_np.astype(np.float32) + mean = np.array([103.53, 116.28, 123.675], dtype=np.float32).reshape((1, 1, 3)) + norm = np.array([0.01742919, 0.017507, 0.01712475], dtype=np.float32).reshape((1, 1, 3)) + img_np = (img_np - mean) * norm + img_tensor = torch.from_numpy(img_np) + img_tensor = img_tensor.unsqueeze(0) + img_nchw = img_tensor.permute(0, 3, 1, 2) + ort_inputs = {ort_session.get_inputs()[0].name: img_nchw.numpy()} + outputs = ort_session.run(None, ort_inputs) + logits = outputs[0].reshape((-1,)) + probs = softmax(logits) + rot_idx = np.argmax(probs) + if rot_idx == 1: + print('rot 90') + img_clone = cv2.transpose(img_clone) + img_clone = np.flip(img_clone, 1) + return Image.fromarray(cv2.cvtColor(img_clone, cv2.COLOR_BGR2RGB)) + elif rot_idx == 2: + print('rot 180') + img_clone = cv2.flip(img_clone, -1) + return Image.fromarray(cv2.cvtColor(img_clone, cv2.COLOR_BGR2RGB)) + elif rot_idx == 3: + print('rot 270') + img_clone = cv2.transpose(img_clone) + img_clone = np.flip(img_clone, 0) + return Image.fromarray(cv2.cvtColor(img_clone, cv2.COLOR_BGR2RGB)) + else: + return image + + +def prepare_dataset(instance_images: list, output_dataset_dir): + if not os.path.exists(output_dataset_dir): + os.makedirs(output_dataset_dir) + for i, temp_path in enumerate(instance_images): + image = PIL.Image.open(temp_path) + # image = PIL.Image.open(temp_path.name) + ''' + w, h = image.size + max_size = max(w, h) + ratio = 1024 / max_size + new_w = round(w * ratio) + new_h = round(h * ratio) + ''' + image = image.convert('RGB') + image = get_rot(image) + # image = image.resize((new_w, new_h)) + # image = image.resize((new_w, new_h), PIL.Image.ANTIALIAS) + out_path = f'{output_dataset_dir}/{i:03d}.jpg' + image.save(out_path, format='JPEG', quality=100) + + +def parse_args(): + parser = argparse.ArgumentParser(description="Simple example of a training script.") + parser.add_argument( + "--pretrained_model_name_or_path", + type=str, + default=None, + required=True, + help="Path to pretrained model or model identifier.", + ) + parser.add_argument( + "--revision", + type=str, + default=None, + required=False, + help="Revision of pretrained model identifier.", + ) + parser.add_argument( + "--sub_path", + type=str, + default=None, + required=False, + help="The sub model path of the `pretrained_model_name_or_path`", + ) + parser.add_argument( + "--dataset_name", + type=str, + default=None, + help=( + "The data images dir" + ), + ) + parser.add_argument( + "--dataset_config_name", + type=str, + default=None, + help="The config of the Dataset, leave as None if there's only one config.", + ) + parser.add_argument( + "--train_data_dir", + type=str, + default=None, + help=( + "A folder containing the training data. Folder contents must follow the structure described in" + " https://huggingface.co/docs/datasets/image_dataset#imagefolder. In particular, a `metadata.jsonl` file" + " must exist to provide the captions for the images. Ignored if `dataset_name` is specified." + ), + ) + parser.add_argument( + "--output_dataset_name", + type=str, + default=None, + help=( + "The dataset dir after processing" + ), + ) + parser.add_argument( + "--image_column", type=str, default="image", help="The column of the dataset containing an image." + ) + parser.add_argument( + "--caption_column", + type=str, + default="text", + help="The column of the dataset containing a caption or a list of captions.", + ) + parser.add_argument( + "--validation_prompt", type=str, default=None, help="A prompt that is sampled during training for inference." + ) + parser.add_argument( + "--num_validation_images", + type=int, + default=1, + help="Number of images that should be generated during validation with `validation_prompt`.", + ) + parser.add_argument( + "--validation_epochs", + type=int, + default=1, + help=( + "Run fine-tuning validation every X epochs. The validation process consists of running the prompt" + " `args.validation_prompt` multiple times: `args.num_validation_images`." + ), + ) + parser.add_argument( + "--max_train_samples", + type=int, + default=None, + help=( + "For debugging purposes or quicker training, truncate the number of training examples to this " + "value if set." + ), + ) + parser.add_argument( + "--output_dir", + type=str, + default="sd-model-finetuned-lora", + help="The output directory where the model predictions and checkpoints will be written.", + ) + parser.add_argument( + "--cache_dir", + type=str, + default=None, + help="The directory where the downloaded models and datasets will be stored.", + ) + parser.add_argument("--seed", type=int, default=None, help="A seed for reproducible training.") + parser.add_argument( + "--resolution", + type=int, + default=512, + help=( + "The resolution for input images, all the images in the train/validation dataset will be resized to this" + " resolution" + ), + ) + parser.add_argument( + "--center_crop", + default=False, + action="store_true", + help=( + "Whether to center crop the input images to the resolution. If not set, the images will be randomly" + " cropped. The images will be resized to the resolution first before cropping." + ), + ) + parser.add_argument( + "--random_flip", + action="store_true", + help="whether to randomly flip images horizontally", + ) + parser.add_argument("--train_text_encoder", action="store_true", help="Whether to train the text encoder") + + # lora args + parser.add_argument("--use_peft", action="store_true", help="Whether to use peft to support lora") + parser.add_argument("--lora_r", type=int, default=4, help="Lora rank, only used if use_lora is True") + parser.add_argument("--lora_alpha", type=int, default=32, help="Lora alpha, only used if lora is True") + parser.add_argument("--lora_dropout", type=float, default=0.0, help="Lora dropout, only used if use_lora is True") + parser.add_argument( + "--lora_bias", + type=str, + default="none", + help="Bias type for Lora. Can be 'none', 'all' or 'lora_only', only used if use_lora is True", + ) + parser.add_argument( + "--lora_text_encoder_r", + type=int, + default=4, + help="Lora rank for text encoder, only used if `use_lora` and `train_text_encoder` are True", + ) + parser.add_argument( + "--lora_text_encoder_alpha", + type=int, + default=32, + help="Lora alpha for text encoder, only used if `use_lora` and `train_text_encoder` are True", + ) + parser.add_argument( + "--lora_text_encoder_dropout", + type=float, + default=0.0, + help="Lora dropout for text encoder, only used if `use_lora` and `train_text_encoder` are True", + ) + parser.add_argument( + "--lora_text_encoder_bias", + type=str, + default="none", + help="Bias type for Lora. Can be 'none', 'all' or 'lora_only', only used if use_lora and `train_text_encoder` are True", + ) + + parser.add_argument( + "--train_batch_size", type=int, default=16, help="Batch size (per device) for the training dataloader." + ) + parser.add_argument("--num_train_epochs", type=int, default=100) + parser.add_argument( + "--max_train_steps", + type=int, + default=None, + help="Total number of training steps to perform. If provided, overrides num_train_epochs.", + ) + parser.add_argument( + "--gradient_accumulation_steps", + type=int, + default=1, + help="Number of updates steps to accumulate before performing a backward/update pass.", + ) + parser.add_argument( + "--gradient_checkpointing", + action="store_true", + help="Whether or not to use gradient checkpointing to save memory at the expense of slower backward pass.", + ) + parser.add_argument( + "--learning_rate", + type=float, + default=1e-4, + help="Initial learning rate (after the potential warmup period) to use.", + ) + parser.add_argument( + "--scale_lr", + action="store_true", + default=False, + help="Scale the learning rate by the number of GPUs, gradient accumulation steps, and batch size.", + ) + parser.add_argument( + "--lr_scheduler", + type=str, + default="constant", + help=( + 'The scheduler type to use. Choose between ["linear", "cosine", "cosine_with_restarts", "polynomial",' + ' "constant", "constant_with_warmup"]' + ), + ) + parser.add_argument( + "--lr_warmup_steps", type=int, default=500, help="Number of steps for the warmup in the lr scheduler." + ) + parser.add_argument( + "--use_8bit_adam", action="store_true", help="Whether or not to use 8-bit Adam from bitsandbytes." + ) + parser.add_argument( + "--allow_tf32", + action="store_true", + help=( + "Whether or not to allow TF32 on Ampere GPUs. Can be used to speed up training. For more information, see" + " https://pytorch.org/docs/stable/notes/cuda.html#tensorfloat-32-tf32-on-ampere-devices" + ), + ) + parser.add_argument( + "--dataloader_num_workers", + type=int, + default=0, + help=( + "Number of subprocesses to use for data loading. 0 means that the data will be loaded in the main process." + ), + ) + parser.add_argument("--adam_beta1", type=float, default=0.9, help="The beta1 parameter for the Adam optimizer.") + parser.add_argument("--adam_beta2", type=float, default=0.999, help="The beta2 parameter for the Adam optimizer.") + parser.add_argument("--adam_weight_decay", type=float, default=1e-2, help="Weight decay to use.") + parser.add_argument("--adam_epsilon", type=float, default=1e-08, help="Epsilon value for the Adam optimizer") + parser.add_argument("--max_grad_norm", default=1.0, type=float, help="Max gradient norm.") + parser.add_argument("--push_to_hub", action="store_true", help="Whether or not to push the model to the Hub.") + parser.add_argument("--hub_token", type=str, default=None, help="The token to use to push to the Model Hub.") + parser.add_argument( + "--hub_model_id", + type=str, + default=None, + help="The name of the repository to keep in sync with the local `output_dir`.", + ) + parser.add_argument( + "--logging_dir", + type=str, + default="logs", + help=( + "[TensorBoard](https://www.tensorflow.org/tensorboard) log directory. Will default to" + " *output_dir/runs/**CURRENT_DATETIME_HOSTNAME***." + ), + ) + parser.add_argument( + "--mixed_precision", + type=str, + default=None, + choices=["no", "fp16", "bf16"], + help=( + "Whether to use mixed precision. Choose between fp16 and bf16 (bfloat16). Bf16 requires PyTorch >=" + " 1.10.and an Nvidia Ampere GPU. Default to the value of accelerate config of the current system or the" + " flag passed with the `accelerate.launch` command. Use this argument to override the accelerate config." + ), + ) + parser.add_argument( + "--report_to", + type=str, + default="tensorboard", + help=( + 'The integration to report the results and logs to. Supported platforms are `"tensorboard"`' + ' (default), `"wandb"` and `"comet_ml"`. Use `"all"` to report to all integrations.' + ), + ) + parser.add_argument("--local_rank", type=int, default=-1, help="For distributed training: local_rank") + parser.add_argument( + "--checkpointing_steps", + type=int, + default=500, + help=( + "Save a checkpoint of the training state every X updates. These checkpoints are only suitable for resuming" + " training using `--resume_from_checkpoint`." + ), + ) + parser.add_argument( + "--checkpoints_total_limit", + type=int, + default=None, + help=( + "Max number of checkpoints to store. Passed as `total_limit` to the `Accelerator` `ProjectConfiguration`." + " See Accelerator::save_state https://huggingface.co/docs/accelerate/package_reference/accelerator#accelerate.Accelerator.save_state" + " for more docs" + ), + ) + parser.add_argument( + "--resume_from_checkpoint", + type=str, + default=None, + help=( + "Whether training should be resumed from a previous checkpoint. Use a path saved by" + ' `--checkpointing_steps`, or `"latest"` to automatically select the last available checkpoint.' + ), + ) + parser.add_argument( + "--enable_xformers_memory_efficient_attention", action="store_true", help="Whether or not to use xformers." + ) + + args = parser.parse_args() + env_local_rank = int(os.environ.get("LOCAL_RANK", -1)) + if env_local_rank != -1 and env_local_rank != args.local_rank: + args.local_rank = env_local_rank + + # Sanity checks + if args.dataset_name is None and args.train_data_dir is None and args.output_dataset_name is None: + raise ValueError("Need either a dataset name or a training folder.") + + return args + + +DATASET_NAME_MAPPING = { + "lambdalabs/pokemon-blip-captions": ("image", "text"), +} + + +def main(): + + args = parse_args() + logging_dir = os.path.join(args.output_dir, args.logging_dir) + shutil.rmtree(args.output_dir, ignore_errors=True) + os.makedirs(args.output_dir) + + if args.dataset_name is not None: + # if dataset_name is None, then it's called from the gradio + # the data processing will be executed in the app.py to save the gpu memory. + print('All input images:', args.dataset_name) + args.dataset_name = [os.path.join(args.dataset_name, x) for x in os.listdir(args.dataset_name)] + shutil.rmtree(args.output_dataset_name, ignore_errors=True) + prepare_dataset(args.dataset_name, args.output_dataset_name) + ## Our data process fn + data_process_fn(input_img_dir=args.output_dataset_name, use_data_process=True) + + args.dataset_name = args.output_dataset_name + '_labeled' + + accelerator_project_config = ProjectConfiguration( + total_limit=args.checkpoints_total_limit, project_dir=args.output_dir, logging_dir=logging_dir + ) + + accelerator = Accelerator( + gradient_accumulation_steps=args.gradient_accumulation_steps, + mixed_precision=args.mixed_precision, + log_with=args.report_to, + project_config=accelerator_project_config, + ) + if args.report_to == "wandb": + if not is_wandb_available(): + raise ImportError("Make sure to install wandb if you want to use it for logging during training.") + import wandb + + # Make one log on every process with the configuration for debugging. + logging.basicConfig( + format="%(asctime)s - %(levelname)s - %(name)s - %(message)s", + datefmt="%m/%d/%Y %H:%M:%S", + level=logging.INFO, + ) + logger.info(accelerator.state, main_process_only=False) + if accelerator.is_local_main_process: + datasets.utils.logging.set_verbosity_warning() + transformers.utils.logging.set_verbosity_warning() + diffusers.utils.logging.set_verbosity_info() + else: + datasets.utils.logging.set_verbosity_error() + transformers.utils.logging.set_verbosity_error() + diffusers.utils.logging.set_verbosity_error() + + # If passed along, set the training seed now. + if args.seed is not None: + set_seed(args.seed) + + # Handle the repository creation + if accelerator.is_main_process: + if args.output_dir is not None: + os.makedirs(args.output_dir, exist_ok=True) + + if args.push_to_hub: + repo_id = create_repo( + repo_id=args.hub_model_id or Path(args.output_dir).name, exist_ok=True, token=args.hub_token + ).repo_id + + ## Download foundation Model + model_dir = snapshot_download(args.pretrained_model_name_or_path, + revision=args.revision, + user_agent={'invoked_by': 'trainer', 'third_party': 'facechain'}) + + if args.sub_path is not None and len(args.sub_path) > 0: + model_dir = os.path.join(model_dir, args.sub_path) + + # Load scheduler, tokenizer and models. + noise_scheduler = DDPMScheduler.from_pretrained(model_dir, subfolder="scheduler") + tokenizer = CLIPTokenizer.from_pretrained( + model_dir, subfolder="tokenizer" + ) + text_encoder = CLIPTextModel.from_pretrained( + model_dir, subfolder="text_encoder" + ) + vae = AutoencoderKL.from_pretrained(model_dir, subfolder="vae") + unet = UNet2DConditionModel.from_pretrained( + model_dir, subfolder="unet" + ) + + # For mixed precision training we cast the text_encoder and vae weights to half-precision + # as these models are only used for inference, keeping weights in full precision is not required. + weight_dtype = torch.float32 + if accelerator.mixed_precision == "fp16": + weight_dtype = torch.float16 + elif accelerator.mixed_precision == "bf16": + weight_dtype = torch.bfloat16 + + if args.use_peft: + from peft import LoraConfig, LoraModel, get_peft_model_state_dict, set_peft_model_state_dict + + UNET_TARGET_MODULES = ["to_q", "to_v", "query", "value"] + TEXT_ENCODER_TARGET_MODULES = ["q_proj", "v_proj"] + + config = LoraConfig( + r=args.lora_r, + lora_alpha=args.lora_alpha, + target_modules=UNET_TARGET_MODULES, + lora_dropout=args.lora_dropout, + bias=args.lora_bias, + ) + unet = LoraModel(config, unet) + + vae.requires_grad_(False) + if args.train_text_encoder: + config = LoraConfig( + r=args.lora_text_encoder_r, + lora_alpha=args.lora_text_encoder_alpha, + target_modules=TEXT_ENCODER_TARGET_MODULES, + lora_dropout=args.lora_text_encoder_dropout, + bias=args.lora_text_encoder_bias, + ) + text_encoder = LoraModel(config, text_encoder) + else: + # freeze parameters of models to save more memory + unet.requires_grad_(False) + vae.requires_grad_(False) + + text_encoder.requires_grad_(False) + + # now we will add new LoRA weights to the attention layers + # It's important to realize here how many attention weights will be added and of which sizes + # The sizes of the attention layers consist only of two different variables: + # 1) - the "hidden_size", which is increased according to `unet.config.block_out_channels`. + # 2) - the "cross attention size", which is set to `unet.config.cross_attention_dim`. + + # Let's first see how many attention processors we will have to set. + # For Stable Diffusion, it should be equal to: + # - down blocks (2x attention layers) * (2x transformer layers) * (3x down blocks) = 12 + # - mid blocks (2x attention layers) * (1x transformer layers) * (1x mid blocks) = 2 + # - up blocks (2x attention layers) * (3x transformer layers) * (3x down blocks) = 18 + # => 32 layers + + # Set correct lora layers + lora_attn_procs = {} + for name in unet.attn_processors.keys(): + cross_attention_dim = None if name.endswith("attn1.processor") else unet.config.cross_attention_dim + if name.startswith("mid_block"): + hidden_size = unet.config.block_out_channels[-1] + elif name.startswith("up_blocks"): + block_id = int(name[len("up_blocks.")]) + hidden_size = list(reversed(unet.config.block_out_channels))[block_id] + elif name.startswith("down_blocks"): + block_id = int(name[len("down_blocks.")]) + hidden_size = unet.config.block_out_channels[block_id] + + lora_attn_procs[name] = LoRAAttnProcessor(hidden_size=hidden_size, cross_attention_dim=cross_attention_dim, rank=args.lora_r) + + unet.set_attn_processor(lora_attn_procs) + + # Move unet, vae and text_encoder to device and cast to weight_dtype + vae.to(accelerator.device, dtype=weight_dtype) + if not args.train_text_encoder: + text_encoder.to(accelerator.device, dtype=weight_dtype) + + if args.enable_xformers_memory_efficient_attention: + if is_xformers_available(): + import xformers + + xformers_version = version.parse(xformers.__version__) + if xformers_version == version.parse("0.0.16"): + logger.warn( + "xFormers 0.0.16 cannot be used for training in some GPUs. If you observe problems during training, please update xFormers to at least 0.0.17. See https://huggingface.co/docs/diffusers/main/en/optimization/xformers for more details." + ) + unet.enable_xformers_memory_efficient_attention() + else: + raise ValueError("xformers is not available. Make sure it is installed correctly") + + # Enable TF32 for faster training on Ampere GPUs, + # cf https://pytorch.org/docs/stable/notes/cuda.html#tensorfloat-32-tf32-on-ampere-devices + if args.allow_tf32: + torch.backends.cuda.matmul.allow_tf32 = True + + if args.scale_lr: + args.learning_rate = ( + args.learning_rate * args.gradient_accumulation_steps * args.train_batch_size * accelerator.num_processes + ) + + # Initialize the optimizer + if args.use_8bit_adam: + try: + import bitsandbytes as bnb + except ImportError: + raise ImportError( + "Please install bitsandbytes to use 8-bit Adam. You can do so by running `pip install bitsandbytes`" + ) + + optimizer_cls = bnb.optim.AdamW8bit + else: + optimizer_cls = torch.optim.AdamW + + if args.use_peft: + # Optimizer creation + params_to_optimize = ( + itertools.chain(unet.parameters(), text_encoder.parameters()) + if args.train_text_encoder + else unet.parameters() + ) + optimizer = optimizer_cls( + params_to_optimize, + lr=args.learning_rate, + betas=(args.adam_beta1, args.adam_beta2), + weight_decay=args.adam_weight_decay, + eps=args.adam_epsilon, + ) + else: + lora_layers = AttnProcsLayers(unet.attn_processors) + optimizer = optimizer_cls( + lora_layers.parameters(), + lr=args.learning_rate, + betas=(args.adam_beta1, args.adam_beta2), + weight_decay=args.adam_weight_decay, + eps=args.adam_epsilon, + ) + + # Get the datasets: you can either provide your own training and evaluation files (see below) + # or specify a Dataset from the hub (the dataset will be downloaded automatically from the datasets Hub). + + # In distributed training, the load_dataset function guarantees that only one local process can concurrently + # download the dataset. + if args.dataset_name is not None: + # Downloading and loading a dataset from the hub. + dataset = load_dataset( + args.dataset_name, + args.dataset_config_name, + cache_dir=args.cache_dir, + ) + else: + # This branch will not be called + data_files = {} + if args.train_data_dir is not None: + data_files["train"] = os.path.join(args.train_data_dir, "**") + dataset = load_dataset( + "imagefolder", + data_files=data_files, + cache_dir=args.cache_dir, + ) + # See more about loading custom images at + # https://huggingface.co/docs/datasets/v2.4.0/en/image_load#imagefolder + + # Preprocessing the datasets. + # We need to tokenize inputs and targets. + column_names = dataset["train"].column_names + + # 6. Get the column names for input/target. + dataset_columns = DATASET_NAME_MAPPING.get(args.dataset_name, None) + if args.image_column is None: + image_column = dataset_columns[0] if dataset_columns is not None else column_names[0] + else: + image_column = args.image_column + if image_column not in column_names: + raise ValueError( + f"--image_column' value '{args.image_column}' needs to be one of: {', '.join(column_names)}" + ) + if args.caption_column is None: + caption_column = dataset_columns[1] if dataset_columns is not None else column_names[1] + else: + caption_column = args.caption_column + if caption_column not in column_names: + raise ValueError( + f"--caption_column' value '{args.caption_column}' needs to be one of: {', '.join(column_names)}" + ) + + # Preprocessing the datasets. + # We need to tokenize input captions and transform the images. + def tokenize_captions(examples, is_train=True): + captions = [] + for caption in examples[caption_column]: + if isinstance(caption, str): + captions.append(caption) + elif isinstance(caption, (list, np.ndarray)): + # take a random caption if there are multiple + captions.append(random.choice(caption) if is_train else caption[0]) + else: + raise ValueError( + f"Caption column `{caption_column}` should contain either strings or lists of strings." + ) + inputs = tokenizer( + captions, max_length=tokenizer.model_max_length, padding="max_length", truncation=True, return_tensors="pt" + ) + return inputs.input_ids + + # Preprocessing the datasets. + train_transforms = transforms.Compose( + [ + #transforms.Resize(args.resolution, interpolation=transforms.InterpolationMode.BILINEAR), + #transforms.CenterCrop(args.resolution) if args.center_crop else transforms.RandomCrop(args.resolution), + FaceCrop(), + transforms.Resize(args.resolution, interpolation=transforms.InterpolationMode.BILINEAR), + transforms.RandomHorizontalFlip() if args.random_flip else transforms.Lambda(lambda x: x), + transforms.ToTensor(), + transforms.Normalize([0.5], [0.5]), + ] + ) + + def preprocess_train(examples): + images = [image.convert("RGB") for image in examples[image_column]] + examples["pixel_values"] = [train_transforms(image) for image in images] + examples["input_ids"] = tokenize_captions(examples) + return examples + + with accelerator.main_process_first(): + if args.max_train_samples is not None: + dataset["train"] = dataset["train"].shuffle(seed=args.seed).select(range(args.max_train_samples)) + # Set the training transforms + train_dataset = dataset["train"].with_transform(preprocess_train) + + def collate_fn(examples): + pixel_values = torch.stack([example["pixel_values"] for example in examples]) + pixel_values = pixel_values.to(memory_format=torch.contiguous_format).float() + input_ids = torch.stack([example["input_ids"] for example in examples]) + return {"pixel_values": pixel_values, "input_ids": input_ids} + + # DataLoaders creation: + train_dataloader = torch.utils.data.DataLoader( + train_dataset, + shuffle=True, + collate_fn=collate_fn, + batch_size=args.train_batch_size, + num_workers=args.dataloader_num_workers, + ) + + # Scheduler and math around the number of training steps. + overrode_max_train_steps = False + num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) + if args.max_train_steps is None: + args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch + overrode_max_train_steps = True + + lr_scheduler = get_scheduler( + args.lr_scheduler, + optimizer=optimizer, + num_warmup_steps=args.lr_warmup_steps * accelerator.num_processes, + num_training_steps=args.max_train_steps * accelerator.num_processes, + ) + + # Prepare everything with our `accelerator`. + if args.use_peft: + if args.train_text_encoder: + unet, text_encoder, optimizer, train_dataloader, lr_scheduler = accelerator.prepare( + unet, text_encoder, optimizer, train_dataloader, lr_scheduler + ) + else: + unet, optimizer, train_dataloader, lr_scheduler = accelerator.prepare( + unet, optimizer, train_dataloader, lr_scheduler + ) + else: + lora_layers, optimizer, train_dataloader, lr_scheduler = accelerator.prepare( + lora_layers, optimizer, train_dataloader, lr_scheduler + ) + unet = unet.cuda() + # We need to recalculate our total training steps as the size of the training dataloader may have changed. + num_update_steps_per_epoch = math.ceil(len(train_dataloader) / args.gradient_accumulation_steps) + if overrode_max_train_steps: + args.max_train_steps = args.num_train_epochs * num_update_steps_per_epoch + # Afterwards we recalculate our number of training epochs + args.num_train_epochs = math.ceil(args.max_train_steps / num_update_steps_per_epoch) + + # We need to initialize the trackers we use, and also store our configuration. + # The trackers initializes automatically on the main process. + if accelerator.is_main_process: + accelerator.init_trackers("text2image-fine-tune", config=vars(args)) + + # Train! + total_batch_size = args.train_batch_size * accelerator.num_processes * args.gradient_accumulation_steps + + logger.info("***** Running training *****") + logger.info(f" Num examples = {len(train_dataset)}") + logger.info(f" Num Epochs = {args.num_train_epochs}") + logger.info(f" Instantaneous batch size per device = {args.train_batch_size}") + logger.info(f" Total train batch size (w. parallel, distributed & accumulation) = {total_batch_size}") + logger.info(f" Gradient Accumulation steps = {args.gradient_accumulation_steps}") + logger.info(f" Total optimization steps = {args.max_train_steps}") + global_step = 0 + first_epoch = 0 + + # Potentially load in the weights and states from a previous save + if args.resume_from_checkpoint: + if args.resume_from_checkpoint == 'fromfacecommon': + weight_model_dir = snapshot_download('damo/face_frombase_c4', + revision='v1.0.0', + user_agent={'invoked_by': 'trainer', 'third_party': 'facechain'}) + path = os.path.join(weight_model_dir, 'face_frombase_c4.bin') + elif args.resume_from_checkpoint != "latest": + path = os.path.basename(args.resume_from_checkpoint) + else: + # Get the most recent checkpoint + dirs = os.listdir(args.output_dir) + dirs = [d for d in dirs if d.startswith("checkpoint")] + dirs = sorted(dirs, key=lambda x: int(x.split("-")[1])) + path = dirs[-1] if len(dirs) > 0 else None + + if path is None: + accelerator.print( + f"Checkpoint '{args.resume_from_checkpoint}' does not exist. Starting a new training run." + ) + args.resume_from_checkpoint = None + else: + if args.resume_from_checkpoint == 'fromfacecommon': + accelerator.print(f"Resuming from checkpoint {path}") + unet_state_dict = torch.load(path, map_location='cpu') + accelerator._models[-1].load_state_dict(unet_state_dict) + global_step = 0 + else: + accelerator.print(f"Resuming from checkpoint {path}") + accelerator.load_state(os.path.join(args.output_dir, path)) + global_step = int(path.split("-")[1]) + + resume_global_step = global_step * args.gradient_accumulation_steps + first_epoch = global_step // num_update_steps_per_epoch + resume_step = resume_global_step % (num_update_steps_per_epoch * args.gradient_accumulation_steps) + + # Only show the progress bar once on each machine. + progress_bar = tqdm(range(global_step, args.max_train_steps), disable=not accelerator.is_local_main_process) + progress_bar.set_description("Steps") + + for epoch in range(first_epoch, args.num_train_epochs): + unet.train() + if args.train_text_encoder: + text_encoder.train() + train_loss = 0.0 + for step, batch in enumerate(train_dataloader): + # Skip steps until we reach the resumed step + if args.resume_from_checkpoint and epoch == first_epoch and step < resume_step: + if step % args.gradient_accumulation_steps == 0: + progress_bar.update(1) + continue + + with accelerator.accumulate(unet): + # Convert images to latent space + latents = vae.encode(batch["pixel_values"].to(dtype=weight_dtype)).latent_dist.sample() + latents = latents * vae.config.scaling_factor + + # Sample noise that we'll add to the latents + noise = torch.randn_like(latents) + bsz = latents.shape[0] + # Sample a random timestep for each image + timesteps = torch.randint(0, noise_scheduler.config.num_train_timesteps, (bsz,), device=latents.device) + timesteps = timesteps.long() + + # Add noise to the latents according to the noise magnitude at each timestep + # (this is the forward diffusion process) + noisy_latents = noise_scheduler.add_noise(latents, noise, timesteps) + + # Get the text embedding for conditioning + encoder_hidden_states = text_encoder(batch["input_ids"])[0] + + # Get the target for loss depending on the prediction type + if noise_scheduler.config.prediction_type == "epsilon": + target = noise + elif noise_scheduler.config.prediction_type == "v_prediction": + target = noise_scheduler.get_velocity(latents, noise, timesteps) + else: + raise ValueError(f"Unknown prediction type {noise_scheduler.config.prediction_type}") + + # Predict the noise residual and compute loss + model_pred = unet(noisy_latents, timesteps, encoder_hidden_states).sample + loss = F.mse_loss(model_pred.float(), target.float(), reduction="mean") + + # Gather the losses across all processes for logging (if we use distributed training). + avg_loss = accelerator.gather(loss.repeat(args.train_batch_size)).mean() + train_loss += avg_loss.item() / args.gradient_accumulation_steps + + # Backpropagate + accelerator.backward(loss) + if accelerator.sync_gradients: + if args.use_peft: + params_to_clip = ( + itertools.chain(unet.parameters(), text_encoder.parameters()) + if args.train_text_encoder + else unet.parameters() + ) + else: + params_to_clip = lora_layers.parameters() + accelerator.clip_grad_norm_(params_to_clip, args.max_grad_norm) + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + + # Checks if the accelerator has performed an optimization step behind the scenes + if accelerator.sync_gradients: + progress_bar.update(1) + global_step += 1 + accelerator.log({"train_loss": train_loss}, step=global_step) + train_loss = 0.0 + + if global_step % args.checkpointing_steps == 0: + if accelerator.is_main_process: + save_path = os.path.join(args.output_dir, f"checkpoint-{global_step}") + accelerator.save_state(save_path) + logger.info(f"Saved state to {save_path}") + + logs = {"step_loss": loss.detach().item(), "lr": lr_scheduler.get_last_lr()[0]} + progress_bar.set_postfix(**logs) + + if global_step >= args.max_train_steps: + break + + + if accelerator.is_main_process: + if args.validation_prompt is not None and epoch % args.validation_epochs == 0: + logger.info( + f"Running validation... \n Generating {args.num_validation_images} images with prompt:" + f" {args.validation_prompt}." + ) + pipeline = DiffusionPipeline.from_pretrained( + model_dir, + unet=accelerator.unwrap_model(unet), + text_encoder=accelerator.unwrap_model(text_encoder), + torch_dtype=weight_dtype, + ) + pipeline = pipeline.to(accelerator.device) + pipeline.set_progress_bar_config(disable=True) + + # run inference + generator = torch.Generator(device=accelerator.device).manual_seed(args.seed) + images = [] + for _ in range(args.num_validation_images): + images.append( + pipeline(args.validation_prompt, num_inference_steps=30, generator=generator).images[0] + ) + + if accelerator.is_main_process: + for tracker in accelerator.trackers: + if tracker.name == "tensorboard": + np_images = np.stack([np.asarray(img) for img in images]) + tracker.writer.add_images("validation", np_images, epoch, dataformats="NHWC") + if tracker.name == "wandb": + tracker.log( + { + "validation": [ + wandb.Image(image, caption=f"{i}: {args.validation_prompt}") + for i, image in enumerate(images) + ] + } + ) + + del pipeline + torch.cuda.empty_cache() + + # Save the lora layers + accelerator.wait_for_everyone() + if accelerator.is_main_process: + if args.use_peft: + lora_config = {} + unwarpped_unet = accelerator.unwrap_model(unet) + state_dict = get_peft_model_state_dict(unwarpped_unet, state_dict=accelerator.get_state_dict(unet)) + lora_config["peft_config"] = unwarpped_unet.get_peft_config_as_dict(inference=True) + if args.train_text_encoder: + unwarpped_text_encoder = accelerator.unwrap_model(text_encoder) + text_encoder_state_dict = get_peft_model_state_dict( + unwarpped_text_encoder, state_dict=accelerator.get_state_dict(text_encoder) + ) + text_encoder_state_dict = {f"text_encoder_{k}": v for k, v in text_encoder_state_dict.items()} + state_dict.update(text_encoder_state_dict) + lora_config["text_encoder_peft_config"] = unwarpped_text_encoder.get_peft_config_as_dict( + inference=True + ) + + accelerator.save(state_dict, os.path.join(args.output_dir, f"{global_step}_lora.pt")) + with open(os.path.join(args.output_dir, f"{global_step}_lora_config.json"), "w") as f: + json.dump(lora_config, f) + else: + unet = unet.to(torch.float32) + unet.save_attn_procs(args.output_dir, safe_serialization=False) + + if args.push_to_hub: + save_model_card( + repo_id, + images=images, + base_model=model_dir, + dataset_name=args.dataset_name, + repo_folder=args.output_dir, + ) + upload_folder( + repo_id=repo_id, + folder_path=args.output_dir, + commit_message="End of training", + ignore_patterns=["step_*", "epoch_*"], + ) + + # Final inference + # Load previous pipeline + pipeline = DiffusionPipeline.from_pretrained( + model_dir, torch_dtype=weight_dtype + ) + + if args.use_peft: + def load_and_set_lora_ckpt(pipe, ckpt_dir, global_step, device, dtype): + with open(os.path.join(args.output_dir, f"{global_step}_lora_config.json"), "r") as f: + lora_config = json.load(f) + print(lora_config) + + checkpoint = os.path.join(args.output_dir, f"{global_step}_lora.pt") + lora_checkpoint_sd = torch.load(checkpoint) + unet_lora_ds = {k: v for k, v in lora_checkpoint_sd.items() if "text_encoder_" not in k} + text_encoder_lora_ds = { + k.replace("text_encoder_", ""): v for k, v in lora_checkpoint_sd.items() if "text_encoder_" in k + } + + unet_config = LoraConfig(**lora_config["peft_config"]) + pipe.unet = LoraModel(unet_config, pipe.unet) + set_peft_model_state_dict(pipe.unet, unet_lora_ds) + + if "text_encoder_peft_config" in lora_config: + text_encoder_config = LoraConfig(**lora_config["text_encoder_peft_config"]) + pipe.text_encoder = LoraModel(text_encoder_config, pipe.text_encoder) + set_peft_model_state_dict(pipe.text_encoder, text_encoder_lora_ds) + + if dtype in (torch.float16, torch.bfloat16): + pipe.unet.half() + pipe.text_encoder.half() + + pipe.to(device) + return pipe + + pipeline = load_and_set_lora_ckpt(pipeline, args.output_dir, global_step, accelerator.device, weight_dtype) + + else: + pipeline = pipeline.to(accelerator.device) + # load attention processors + pipeline.unet.load_attn_procs(args.output_dir) + + # run inference + if args.seed is not None: + generator = torch.Generator(device=accelerator.device).manual_seed(args.seed) + else: + generator = None + images = [] + + accelerator.end_training() + + +if __name__ == "__main__": + multiprocessing.set_start_method('spawn') + main() diff --git a/demo/facechain_agent/facechain/utils.py b/demo/facechain_agent/facechain/utils.py new file mode 100644 index 000000000..f2ba1fc37 --- /dev/null +++ b/demo/facechain_agent/facechain/utils.py @@ -0,0 +1,37 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. + +import time +from modelscope import snapshot_download as ms_snapshot_download + + +def max_retries(max_attempts): + def decorator(func): + def wrapper(*args, **kwargs): + attempts = 0 + while attempts < max_attempts: + try: + return func(*args, **kwargs) + except Exception as e: + attempts += 1 + print(f"Retry {attempts}/{max_attempts}: {e}") + # wait 1 sec + time.sleep(1) + raise Exception(f"Max retries ({max_attempts}) exceeded.") + return wrapper + return decorator + + +@max_retries(3) +def snapshot_download(*args, **kwargs): + return ms_snapshot_download(*args, **kwargs) + + +def pre_download_models(): + snapshot_download('ly261666/cv_portrait_model', revision='v4.0') + snapshot_download('YorickHe/majicmixRealistic_v6', revision='v1.0.0') + snapshot_download('damo/face_chain_control_model', revision='v1.0.1') + snapshot_download('ly261666/cv_wanx_style_model', revision='v1.0.3') + snapshot_download('damo/face_chain_control_model', revision='v1.0.1') + snapshot_download('Cherrytest/zjz_mj_jiyi_small_addtxt_fromleo', revision='v1.0.0') + snapshot_download('Cherrytest/rot_bgr', revision='v1.0.0') + snapshot_download('damo/face_frombase_c4', revision='v1.0.0') diff --git a/demo/facechain_agent/requirements.txt b/demo/facechain_agent/requirements.txt new file mode 100644 index 000000000..46c370e46 --- /dev/null +++ b/demo/facechain_agent/requirements.txt @@ -0,0 +1,38 @@ +accelerate +transformers +diffusers +onnxruntime +modelscope +Pillow +opencv-python +torchvision +mmdet==2.26.0 +mmengine +numpy==1.22.0 +protobuf==3.20.1 +timm +scikit-image +gradio==3.29.0 +controlnet_aux==0.0.6 +mediapipe +python-slugify +dashscope +datasets>=2.8.0 +ipython +langchain +modelscope>=1.7.0 +moviepy +ms-swift +openai +opencv-python +Pillow +pydantic==1.10.8 +pytest +python-dotenv +soundfile +transformers>=4.29.0 +transformers_stream_generator +markdown_katex +mdx_truly_sane_lists +markdown-cjk-spacing +pymdown-extensions diff --git a/demo/facechain_agent/style_image/Armor.jpg b/demo/facechain_agent/style_image/Armor.jpg new file mode 100644 index 000000000..8ab929bf3 Binary files /dev/null and b/demo/facechain_agent/style_image/Armor.jpg differ diff --git a/demo/facechain_agent/style_image/Autumn_populus.jpg b/demo/facechain_agent/style_image/Autumn_populus.jpg new file mode 100644 index 000000000..b7c18ef35 Binary files /dev/null and b/demo/facechain_agent/style_image/Autumn_populus.jpg differ diff --git a/demo/facechain_agent/style_image/Barbie_Doll.jpg b/demo/facechain_agent/style_image/Barbie_Doll.jpg new file mode 100644 index 000000000..fa0edbfab Binary files /dev/null and b/demo/facechain_agent/style_image/Barbie_Doll.jpg differ diff --git a/demo/facechain_agent/style_image/Bleak_autumn.jpg b/demo/facechain_agent/style_image/Bleak_autumn.jpg new file mode 100644 index 000000000..7ecea4014 Binary files /dev/null and b/demo/facechain_agent/style_image/Bleak_autumn.jpg differ diff --git a/demo/facechain_agent/style_image/Cartoon.jpg b/demo/facechain_agent/style_image/Cartoon.jpg new file mode 100644 index 000000000..55630b241 Binary files /dev/null and b/demo/facechain_agent/style_image/Cartoon.jpg differ diff --git a/demo/facechain_agent/style_image/Casual_Lifestyle.jpg b/demo/facechain_agent/style_image/Casual_Lifestyle.jpg new file mode 100644 index 000000000..663a1303a Binary files /dev/null and b/demo/facechain_agent/style_image/Casual_Lifestyle.jpg differ diff --git a/demo/facechain_agent/style_image/Cheongsam.jpg b/demo/facechain_agent/style_image/Cheongsam.jpg new file mode 100644 index 000000000..14d52e341 Binary files /dev/null and b/demo/facechain_agent/style_image/Cheongsam.jpg differ diff --git a/demo/facechain_agent/style_image/Chinese_Girl_among_Plum_Blossoms.jpg b/demo/facechain_agent/style_image/Chinese_Girl_among_Plum_Blossoms.jpg new file mode 100644 index 000000000..2ca786b4d Binary files /dev/null and b/demo/facechain_agent/style_image/Chinese_Girl_among_Plum_Blossoms.jpg differ diff --git a/demo/facechain_agent/style_image/Chinese_New_Year.jpg b/demo/facechain_agent/style_image/Chinese_New_Year.jpg new file mode 100644 index 000000000..3a7027caa Binary files /dev/null and b/demo/facechain_agent/style_image/Chinese_New_Year.jpg differ diff --git a/demo/facechain_agent/style_image/Chinese_traditional.jpg b/demo/facechain_agent/style_image/Chinese_traditional.jpg new file mode 100644 index 000000000..21fe97218 Binary files /dev/null and b/demo/facechain_agent/style_image/Chinese_traditional.jpg differ diff --git a/demo/facechain_agent/style_image/Chinese_traditional_gorgeous_suit.jpg b/demo/facechain_agent/style_image/Chinese_traditional_gorgeous_suit.jpg new file mode 100644 index 000000000..d7073bbdc Binary files /dev/null and b/demo/facechain_agent/style_image/Chinese_traditional_gorgeous_suit.jpg differ diff --git a/demo/facechain_agent/style_image/Chinese_winter_hanfu.jpg b/demo/facechain_agent/style_image/Chinese_winter_hanfu.jpg new file mode 100644 index 000000000..b35837f51 Binary files /dev/null and b/demo/facechain_agent/style_image/Chinese_winter_hanfu.jpg differ diff --git a/demo/facechain_agent/style_image/Christmas.jpg b/demo/facechain_agent/style_image/Christmas.jpg new file mode 100644 index 000000000..0266bf8bf Binary files /dev/null and b/demo/facechain_agent/style_image/Christmas.jpg differ diff --git a/demo/facechain_agent/style_image/Colorful_rainbow.jpg b/demo/facechain_agent/style_image/Colorful_rainbow.jpg new file mode 100644 index 000000000..a6d631237 Binary files /dev/null and b/demo/facechain_agent/style_image/Colorful_rainbow.jpg differ diff --git a/demo/facechain_agent/style_image/Cool_tones.jpg b/demo/facechain_agent/style_image/Cool_tones.jpg new file mode 100644 index 000000000..2237cea38 Binary files /dev/null and b/demo/facechain_agent/style_image/Cool_tones.jpg differ diff --git a/demo/facechain_agent/style_image/Cowboy.jpg b/demo/facechain_agent/style_image/Cowboy.jpg new file mode 100644 index 000000000..a24a74802 Binary files /dev/null and b/demo/facechain_agent/style_image/Cowboy.jpg differ diff --git a/demo/facechain_agent/style_image/Cybernetics_punk.jpg b/demo/facechain_agent/style_image/Cybernetics_punk.jpg new file mode 100644 index 000000000..98dc93800 Binary files /dev/null and b/demo/facechain_agent/style_image/Cybernetics_punk.jpg differ diff --git a/demo/facechain_agent/style_image/Deer_girl.jpg b/demo/facechain_agent/style_image/Deer_girl.jpg new file mode 100644 index 000000000..7b4c79535 Binary files /dev/null and b/demo/facechain_agent/style_image/Deer_girl.jpg differ diff --git a/demo/facechain_agent/style_image/Disneyland.jpg b/demo/facechain_agent/style_image/Disneyland.jpg new file mode 100644 index 000000000..a0899af6b Binary files /dev/null and b/demo/facechain_agent/style_image/Disneyland.jpg differ diff --git a/demo/facechain_agent/style_image/DreamyOcean.jpg b/demo/facechain_agent/style_image/DreamyOcean.jpg new file mode 100644 index 000000000..6772d8c41 Binary files /dev/null and b/demo/facechain_agent/style_image/DreamyOcean.jpg differ diff --git a/demo/facechain_agent/style_image/Dunhuang.jpg b/demo/facechain_agent/style_image/Dunhuang.jpg new file mode 100644 index 000000000..02f90c9ad Binary files /dev/null and b/demo/facechain_agent/style_image/Dunhuang.jpg differ diff --git a/demo/facechain_agent/style_image/Duobaan.jpg b/demo/facechain_agent/style_image/Duobaan.jpg new file mode 100644 index 000000000..c03a05e56 Binary files /dev/null and b/demo/facechain_agent/style_image/Duobaan.jpg differ diff --git a/demo/facechain_agent/style_image/Elegant_Princess.jpg b/demo/facechain_agent/style_image/Elegant_Princess.jpg new file mode 100644 index 000000000..a0e9e85c3 Binary files /dev/null and b/demo/facechain_agent/style_image/Elegant_Princess.jpg differ diff --git a/demo/facechain_agent/style_image/Embroidery.jpg b/demo/facechain_agent/style_image/Embroidery.jpg new file mode 100644 index 000000000..ce0d7e4bf Binary files /dev/null and b/demo/facechain_agent/style_image/Embroidery.jpg differ diff --git a/demo/facechain_agent/style_image/European_fields.jpg b/demo/facechain_agent/style_image/European_fields.jpg new file mode 100644 index 000000000..2016f8a13 Binary files /dev/null and b/demo/facechain_agent/style_image/European_fields.jpg differ diff --git a/demo/facechain_agent/style_image/Fairy_style.jpg b/demo/facechain_agent/style_image/Fairy_style.jpg new file mode 100644 index 000000000..a4f43df7e Binary files /dev/null and b/demo/facechain_agent/style_image/Fairy_style.jpg differ diff --git a/demo/facechain_agent/style_image/Fashion_glasses.jpg b/demo/facechain_agent/style_image/Fashion_glasses.jpg new file mode 100644 index 000000000..833160d25 Binary files /dev/null and b/demo/facechain_agent/style_image/Fashion_glasses.jpg differ diff --git a/demo/facechain_agent/style_image/Flame_red_style.jpg b/demo/facechain_agent/style_image/Flame_red_style.jpg new file mode 100644 index 000000000..35770b7cc Binary files /dev/null and b/demo/facechain_agent/style_image/Flame_red_style.jpg differ diff --git a/demo/facechain_agent/style_image/Flowers.jpg b/demo/facechain_agent/style_image/Flowers.jpg new file mode 100644 index 000000000..04be174b8 Binary files /dev/null and b/demo/facechain_agent/style_image/Flowers.jpg differ diff --git a/demo/facechain_agent/style_image/Gentleman.jpg b/demo/facechain_agent/style_image/Gentleman.jpg new file mode 100644 index 000000000..6743596f6 Binary files /dev/null and b/demo/facechain_agent/style_image/Gentleman.jpg differ diff --git a/demo/facechain_agent/style_image/Gown.jpg b/demo/facechain_agent/style_image/Gown.jpg new file mode 100644 index 000000000..ae628994d Binary files /dev/null and b/demo/facechain_agent/style_image/Gown.jpg differ diff --git a/demo/facechain_agent/style_image/GuoFeng.jpg b/demo/facechain_agent/style_image/GuoFeng.jpg new file mode 100644 index 000000000..706688936 Binary files /dev/null and b/demo/facechain_agent/style_image/GuoFeng.jpg differ diff --git a/demo/facechain_agent/style_image/Hanfu.jpg b/demo/facechain_agent/style_image/Hanfu.jpg new file mode 100644 index 000000000..b1ca69895 Binary files /dev/null and b/demo/facechain_agent/style_image/Hanfu.jpg differ diff --git a/demo/facechain_agent/style_image/Hiphop.jpg b/demo/facechain_agent/style_image/Hiphop.jpg new file mode 100644 index 000000000..560715b57 Binary files /dev/null and b/demo/facechain_agent/style_image/Hiphop.jpg differ diff --git a/demo/facechain_agent/style_image/Hong_Kong_night_style.jpg b/demo/facechain_agent/style_image/Hong_Kong_night_style.jpg new file mode 100644 index 000000000..56dd43d25 Binary files /dev/null and b/demo/facechain_agent/style_image/Hong_Kong_night_style.jpg differ diff --git a/demo/facechain_agent/style_image/India.jpg b/demo/facechain_agent/style_image/India.jpg new file mode 100644 index 000000000..cf0111e11 Binary files /dev/null and b/demo/facechain_agent/style_image/India.jpg differ diff --git a/demo/facechain_agent/style_image/Innocent_Girl_in_White_Dress.jpg b/demo/facechain_agent/style_image/Innocent_Girl_in_White_Dress.jpg new file mode 100644 index 000000000..bb0a56cf2 Binary files /dev/null and b/demo/facechain_agent/style_image/Innocent_Girl_in_White_Dress.jpg differ diff --git a/demo/facechain_agent/style_image/Jacket_in_Snow_Mountain.jpg b/demo/facechain_agent/style_image/Jacket_in_Snow_Mountain.jpg new file mode 100644 index 000000000..a4cb69f43 Binary files /dev/null and b/demo/facechain_agent/style_image/Jacket_in_Snow_Mountain.jpg differ diff --git a/demo/facechain_agent/style_image/Kimono.jpg b/demo/facechain_agent/style_image/Kimono.jpg new file mode 100644 index 000000000..0eef70cf9 Binary files /dev/null and b/demo/facechain_agent/style_image/Kimono.jpg differ diff --git a/demo/facechain_agent/style_image/Li.jpg b/demo/facechain_agent/style_image/Li.jpg new file mode 100644 index 000000000..d4077e172 Binary files /dev/null and b/demo/facechain_agent/style_image/Li.jpg differ diff --git a/demo/facechain_agent/style_image/Lolita.jpg b/demo/facechain_agent/style_image/Lolita.jpg new file mode 100644 index 000000000..185a48fb7 Binary files /dev/null and b/demo/facechain_agent/style_image/Lolita.jpg differ diff --git a/demo/facechain_agent/style_image/Luolita.jpg b/demo/facechain_agent/style_image/Luolita.jpg new file mode 100644 index 000000000..9ae912cef Binary files /dev/null and b/demo/facechain_agent/style_image/Luolita.jpg differ diff --git a/demo/facechain_agent/style_image/Maid.jpg b/demo/facechain_agent/style_image/Maid.jpg new file mode 100644 index 000000000..847e92a80 Binary files /dev/null and b/demo/facechain_agent/style_image/Maid.jpg differ diff --git a/demo/facechain_agent/style_image/Mechnical.jpg b/demo/facechain_agent/style_image/Mechnical.jpg new file mode 100644 index 000000000..5f37e6db9 Binary files /dev/null and b/demo/facechain_agent/style_image/Mechnical.jpg differ diff --git a/demo/facechain_agent/style_image/Men_suit.jpg b/demo/facechain_agent/style_image/Men_suit.jpg new file mode 100644 index 000000000..648eef04c Binary files /dev/null and b/demo/facechain_agent/style_image/Men_suit.jpg differ diff --git a/demo/facechain_agent/style_image/Miaozu.jpg b/demo/facechain_agent/style_image/Miaozu.jpg new file mode 100644 index 000000000..b78c0530c Binary files /dev/null and b/demo/facechain_agent/style_image/Miaozu.jpg differ diff --git a/demo/facechain_agent/style_image/Model_style.jpg b/demo/facechain_agent/style_image/Model_style.jpg new file mode 100644 index 000000000..b9e66a4fa Binary files /dev/null and b/demo/facechain_agent/style_image/Model_style.jpg differ diff --git a/demo/facechain_agent/style_image/Mongolian.jpg b/demo/facechain_agent/style_image/Mongolian.jpg new file mode 100644 index 000000000..00da98686 Binary files /dev/null and b/demo/facechain_agent/style_image/Mongolian.jpg differ diff --git a/demo/facechain_agent/style_image/Motorcycle_race_style.jpg b/demo/facechain_agent/style_image/Motorcycle_race_style.jpg new file mode 100644 index 000000000..9e3facba9 Binary files /dev/null and b/demo/facechain_agent/style_image/Motorcycle_race_style.jpg differ diff --git a/demo/facechain_agent/style_image/Ocean_Summer_vibe.jpg b/demo/facechain_agent/style_image/Ocean_Summer_vibe.jpg new file mode 100644 index 000000000..afa04651e Binary files /dev/null and b/demo/facechain_agent/style_image/Ocean_Summer_vibe.jpg differ diff --git a/demo/facechain_agent/style_image/PekingOpera_female_role.jpg b/demo/facechain_agent/style_image/PekingOpera_female_role.jpg new file mode 100644 index 000000000..6c105b9e2 Binary files /dev/null and b/demo/facechain_agent/style_image/PekingOpera_female_role.jpg differ diff --git a/demo/facechain_agent/style_image/Pixy_Girl.jpg b/demo/facechain_agent/style_image/Pixy_Girl.jpg new file mode 100644 index 000000000..b269e1d2a Binary files /dev/null and b/demo/facechain_agent/style_image/Pixy_Girl.jpg differ diff --git a/demo/facechain_agent/style_image/Polaroid_style.jpg b/demo/facechain_agent/style_image/Polaroid_style.jpg new file mode 100644 index 000000000..bc1b53f85 Binary files /dev/null and b/demo/facechain_agent/style_image/Polaroid_style.jpg differ diff --git a/demo/facechain_agent/style_image/Princess_style.jpg b/demo/facechain_agent/style_image/Princess_style.jpg new file mode 100644 index 000000000..af004facf Binary files /dev/null and b/demo/facechain_agent/style_image/Princess_style.jpg differ diff --git a/demo/facechain_agent/style_image/Rainy_night.jpg b/demo/facechain_agent/style_image/Rainy_night.jpg new file mode 100644 index 000000000..f7f9d595b Binary files /dev/null and b/demo/facechain_agent/style_image/Rainy_night.jpg differ diff --git a/demo/facechain_agent/style_image/Redstyle.jpg b/demo/facechain_agent/style_image/Redstyle.jpg new file mode 100644 index 000000000..d3c5c19c1 Binary files /dev/null and b/demo/facechain_agent/style_image/Redstyle.jpg differ diff --git a/demo/facechain_agent/style_image/Retro_style.jpg b/demo/facechain_agent/style_image/Retro_style.jpg new file mode 100644 index 000000000..2ef274ccd Binary files /dev/null and b/demo/facechain_agent/style_image/Retro_style.jpg differ diff --git a/demo/facechain_agent/style_image/Roaming_Astronaut.jpg b/demo/facechain_agent/style_image/Roaming_Astronaut.jpg new file mode 100644 index 000000000..e2d87b5eb Binary files /dev/null and b/demo/facechain_agent/style_image/Roaming_Astronaut.jpg differ diff --git a/demo/facechain_agent/style_image/School_uniform.jpg b/demo/facechain_agent/style_image/School_uniform.jpg new file mode 100644 index 000000000..a278fd8df Binary files /dev/null and b/demo/facechain_agent/style_image/School_uniform.jpg differ diff --git a/demo/facechain_agent/style_image/Science_fiction.jpg b/demo/facechain_agent/style_image/Science_fiction.jpg new file mode 100644 index 000000000..57d9b134a Binary files /dev/null and b/demo/facechain_agent/style_image/Science_fiction.jpg differ diff --git a/demo/facechain_agent/style_image/Snow_white.jpg b/demo/facechain_agent/style_image/Snow_white.jpg new file mode 100644 index 000000000..9c929ff3e Binary files /dev/null and b/demo/facechain_agent/style_image/Snow_white.jpg differ diff --git a/demo/facechain_agent/style_image/Soccer.jpg b/demo/facechain_agent/style_image/Soccer.jpg new file mode 100644 index 000000000..8ec53d5ca Binary files /dev/null and b/demo/facechain_agent/style_image/Soccer.jpg differ diff --git a/demo/facechain_agent/style_image/Street_style.jpg b/demo/facechain_agent/style_image/Street_style.jpg new file mode 100644 index 000000000..330ab73e0 Binary files /dev/null and b/demo/facechain_agent/style_image/Street_style.jpg differ diff --git a/demo/facechain_agent/style_image/T-shirt.jpg b/demo/facechain_agent/style_image/T-shirt.jpg new file mode 100644 index 000000000..16346c782 Binary files /dev/null and b/demo/facechain_agent/style_image/T-shirt.jpg differ diff --git a/demo/facechain_agent/style_image/Tibetan_clothing.jpg b/demo/facechain_agent/style_image/Tibetan_clothing.jpg new file mode 100644 index 000000000..d9f5c796b Binary files /dev/null and b/demo/facechain_agent/style_image/Tibetan_clothing.jpg differ diff --git a/demo/facechain_agent/style_image/Traditional_chinese_style.jpg b/demo/facechain_agent/style_image/Traditional_chinese_style.jpg new file mode 100644 index 000000000..96610e05e Binary files /dev/null and b/demo/facechain_agent/style_image/Traditional_chinese_style.jpg differ diff --git a/demo/facechain_agent/style_image/Tyndall.jpg b/demo/facechain_agent/style_image/Tyndall.jpg new file mode 100644 index 000000000..58cb3d696 Binary files /dev/null and b/demo/facechain_agent/style_image/Tyndall.jpg differ diff --git a/demo/facechain_agent/style_image/Underwater.jpg b/demo/facechain_agent/style_image/Underwater.jpg new file mode 100644 index 000000000..5d7c9550b Binary files /dev/null and b/demo/facechain_agent/style_image/Underwater.jpg differ diff --git a/demo/facechain_agent/style_image/Wedding_dress.jpg b/demo/facechain_agent/style_image/Wedding_dress.jpg new file mode 100644 index 000000000..3d04400ef Binary files /dev/null and b/demo/facechain_agent/style_image/Wedding_dress.jpg differ diff --git a/demo/facechain_agent/style_image/Wedding_dress_2.jpg b/demo/facechain_agent/style_image/Wedding_dress_2.jpg new file mode 100644 index 000000000..15001292a Binary files /dev/null and b/demo/facechain_agent/style_image/Wedding_dress_2.jpg differ diff --git a/demo/facechain_agent/style_image/West_cowboy.jpg b/demo/facechain_agent/style_image/West_cowboy.jpg new file mode 100644 index 000000000..df3b8d5ff Binary files /dev/null and b/demo/facechain_agent/style_image/West_cowboy.jpg differ diff --git a/demo/facechain_agent/style_image/Wild_west.jpg b/demo/facechain_agent/style_image/Wild_west.jpg new file mode 100644 index 000000000..da14f790f Binary files /dev/null and b/demo/facechain_agent/style_image/Wild_west.jpg differ diff --git a/demo/facechain_agent/style_image/Witch.jpg b/demo/facechain_agent/style_image/Witch.jpg new file mode 100644 index 000000000..b41c31339 Binary files /dev/null and b/demo/facechain_agent/style_image/Witch.jpg differ diff --git a/demo/facechain_agent/style_image/Wizard_of_Oz.jpg b/demo/facechain_agent/style_image/Wizard_of_Oz.jpg new file mode 100644 index 000000000..df20edf90 Binary files /dev/null and b/demo/facechain_agent/style_image/Wizard_of_Oz.jpg differ diff --git a/demo/facechain_agent/style_image/Working_suit.jpg b/demo/facechain_agent/style_image/Working_suit.jpg new file mode 100644 index 000000000..213dd6a0f Binary files /dev/null and b/demo/facechain_agent/style_image/Working_suit.jpg differ diff --git a/demo/facechain_agent/style_image/ZangZu.jpg b/demo/facechain_agent/style_image/ZangZu.jpg new file mode 100644 index 000000000..5eaec6e62 Binary files /dev/null and b/demo/facechain_agent/style_image/ZangZu.jpg differ diff --git a/demo/facechain_agent/style_image/Zhuang_style.jpg b/demo/facechain_agent/style_image/Zhuang_style.jpg new file mode 100644 index 000000000..98b0465c1 Binary files /dev/null and b/demo/facechain_agent/style_image/Zhuang_style.jpg differ diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Autumn_populus.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Autumn_populus.json new file mode 100644 index 000000000..68ea280ec --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Autumn_populus.json @@ -0,0 +1,10 @@ +{ + "name": "秋日胡杨风(Autumn populus euphratica style)", + "img": "./style_image/Autumn_populus.jpg", + "model_id": "PeiPeiY/style_lora", + "revision": "v1", + "bin_file": "autumn_populus.safetensors", + "multiplier_style": 0.55, + "multiplier_human": 0.9, + "add_prompt_style": "extremely delicate and beautiful girls, (autumn populus euphratica scenary, 1girl)" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Bleak_autumn.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Bleak_autumn.json new file mode 100644 index 000000000..e6bb4b933 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Bleak_autumn.json @@ -0,0 +1,10 @@ +{ + "name": "萧瑟秋天风(Bleak autumn style)", + "img": "./style_image/Bleak_autumn.jpg", + "model_id": "PeiPeiY/style_lora", + "revision": "v1", + "bin_file": "bleak_autumn.safetensors", + "multiplier_style": 0.55, + "multiplier_human": 0.95, + "add_prompt_style": "extremely delicate and beautiful girls, (bleak autumn scenary), asia, brown hair, close-up" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Cartoon.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Cartoon.json new file mode 100644 index 000000000..0e1662302 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Cartoon.json @@ -0,0 +1,10 @@ +{ + "name": "漫画风(Cartoon)", + "img": "./style_image/Cartoon.jpg", + "model_id": "rewfueranro/cartoon_lora", + "revision": "v1.0.0", + "bin_file": "cartoon.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "Manhuanan, jewelry, half body photo,white hair, at the coffee shop, blurred background, CG, UE5" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Cheongsam.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Cheongsam.json new file mode 100644 index 000000000..641ea4fe2 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Cheongsam.json @@ -0,0 +1,10 @@ +{ + "name": "旗袍风(Cheongsam)", + "img": "./style_image/Cheongsam.jpg", + "model_id": "PaperCloud/zju19_minguo_style_lora", + "revision": "v1.0.0", + "bin_file": "qipao2.safetensors", + "multiplier_style": 0.45, + "multiplier_human": 0.95, + "add_prompt_style": "white_cheongsam, photography, warm light, Chinese classical indoor scene, close-up, front view, earrings, hairpin, serenity, elegant, facing the camera with a smile, beautiful chinese embroidery, symmetrical short sleeves" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Chinese_New_Year.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Chinese_New_Year.json new file mode 100644 index 000000000..a1ba3b59b --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Chinese_New_Year.json @@ -0,0 +1,10 @@ +{ + "name": "中国新年风(Chinese New Year Style)", + "img": "./style_image/Chinese_New_Year.jpg", + "model_id": "houpeiran/mymodel", + "revision": "v2", + "bin_file": "aki.safetensors", + "multiplier_style": 0.2, + "multiplier_human": 0.95, + "add_prompt_style": "Chinese New Year, close-up, perfect red hanfu, long sleeves, standing, intricat bright red background, many Chinese laterns in background, red flowers, casual, clear lines" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Chinese_winter_hanfu.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Chinese_winter_hanfu.json new file mode 100644 index 000000000..6cb0f3170 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Chinese_winter_hanfu.json @@ -0,0 +1,10 @@ +{ + "name": "冬季汉服(Chinese winter hanfu)", + "img": "./style_image/Chinese_winter_hanfu.jpg", + "model_id": "YorickHe/Winter_hanfu_lora", + "revision": "v1.0.0", + "bin_file": "Winter_Hanfu.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "red hanfu, winter hanfu, cloak, photography, warm light, sunlight, majestic snow scene, close-up, front view, soft falling snowflakes, jewelry, enchanted winter wonderland" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Christmas.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Christmas.json new file mode 100644 index 000000000..e71606842 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Christmas.json @@ -0,0 +1,10 @@ +{ + "name": "圣诞风(Christmas)", + "img": "./style_image/Christmas.jpg", + "model_id": "mowunian/christmas", + "revision": "v1.0.0", + "bin_file": "christmas.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, close-up, face shot, standing, drooping arm, christmas, christmas tree, dress, sweater, snowing, bell" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Colorful_rainbow.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Colorful_rainbow.json new file mode 100644 index 000000000..b1b2b7403 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Colorful_rainbow.json @@ -0,0 +1,10 @@ +{ + "name": "炫彩少女风(Colorful rainbow style)", + "img": "./style_image/Colorful_rainbow.jpg", + "model_id": "houpeiran/mymodel", + "revision": "v1.0.0", + "bin_file": "liuli2.safetensors", + "multiplier_style": 0.25, + "multiplier_human": 0.95, + "add_prompt_style": "standing, coloured glaze, Polychromatic prism effect, rainbowcore, iridescence/opalescence, glowing colors, aluminum foil, Glowing ambiance, (portrait:1.5), black starry night background, close-up to head, wearing camisole" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Cool_tones.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Cool_tones.json new file mode 100644 index 000000000..11016a399 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Cool_tones.json @@ -0,0 +1,10 @@ +{ + "name": "自然清冷风(Cool tones)", + "img": "./style_image/Cool_tones.jpg", + "model_id": "houpeiran/mymodel", + "revision": "v1.0.0", + "bin_file": "cool_tones.safetensors", + "multiplier_style": 0.6, + "multiplier_human": 0.95, + "add_prompt_style": "photorealisitc face, close-up, hyper realistic, ultra high res, 1girl, high def, beautiful, cleavage, intricate full color portrait, sharp focus, natural lighting, subsurface scattering" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Cowboy.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Cowboy.json new file mode 100644 index 000000000..570f97161 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Cowboy.json @@ -0,0 +1,10 @@ +{ + "name": "西部牛仔风(Cowboy style)", + "img": "./style_image/Cowboy.jpg", + "model_id": "houpeiran/mymodel", + "revision": "v1.0.0", + "bin_file": "style_niuzai768.safetensors", + "multiplier_style": 0.7, + "multiplier_human": 0.95, + "add_prompt_style": "western cowboy style,photography,best quality, realistic, photorealistic, intricate details, cinematic light, clear line, ultra high res, short hair" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Deer_girl.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Deer_girl.json new file mode 100644 index 000000000..bbceca734 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Deer_girl.json @@ -0,0 +1,10 @@ +{ + "name": "林中鹿女风(Deer girl)", + "img": "./style_image/Deer_girl.jpg", + "model_id": "EnlZhao/deer_lora", + "revision": "v3.2.0", + "bin_file": "deer.safetensors", + "multiplier_style": 0.4, + "multiplier_human": 0.95, + "add_prompt_style": "bust shot, an elk girl in pink forest, sweet smile, detailed little antlers, white dress, long hair, natural lighting, warm sunlight, light pink atmosphere, outdoor photo, field of pink maple leaves, flowers, realistic" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Disneyland.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Disneyland.json new file mode 100644 index 000000000..b40dd86c2 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Disneyland.json @@ -0,0 +1,10 @@ +{ + "name": "主题乐园风(Disneyland)", + "img": "./style_image/Disneyland.jpg", + "model_id": "rtxxxx/zju_05", + "revision": "v1.0.0", + "bin_file": "disneyland.safetensors", + "multiplier_style": 0.45, + "multiplier_human": 0.9, + "add_prompt_style": "1girl, close-up, happy smile, Minnie Mouse headband, disneyland, cute dress, short depth of field, black hair, ears, looking at viewer, bokeh, sunshine, warm light, Blurred background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/DreamyOcean.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/DreamyOcean.json new file mode 100644 index 000000000..bb8ae27da --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/DreamyOcean.json @@ -0,0 +1,10 @@ +{ + "name": "海洋风(Ocean)", + "img": "./style_image/DreamyOcean.jpg", + "model_id": "MushroomLyn/artist", + "revision": "v2.0.0", + "bin_file": "mine.safetensors", + "multiplier_style": 0.5, + "multiplier_human": 0.95, + "add_prompt_style": "delicate, gentle eye, ocean, white shirt, sunlit" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Dunhuang.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Dunhuang.json new file mode 100644 index 000000000..0d872a5ca --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Dunhuang.json @@ -0,0 +1,10 @@ +{ + "name": "敦煌风(Dunhuang)", + "img": "./style_image/Dunhuang.jpg", + "model_id": "PaperCloud/zju19_dunhuang_style_lora", + "revision": "v2", + "bin_file": "dunhuangV3.safetensors", + "multiplier_style": 0.45, + "multiplier_human": 0.95, + "add_prompt_style": "1 girl, close-up, waist shot, black long hair, clean face, dunhuang, Chinese ancient style, clean skin, organza_lace, Dunhuang wind, Art deco, Necklace, jewelry, Bracelet, Earrings, dunhuang_style, see-through_dress, Expressionism, looking towards the camera" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Duobaan.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Duobaan.json new file mode 100644 index 000000000..a2de2c950 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Duobaan.json @@ -0,0 +1,10 @@ +{ + "name": "多巴胺风格(Colourful Style)", + "img": "./style_image/Duobaan.jpg", + "model_id": "Tekhne/dubaan", + "revision": "v1.0.0", + "bin_file": "colorfashionstyle_v1.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "colorfashionstyle,light smile, orange and blue and red theme" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Embroidery.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Embroidery.json new file mode 100644 index 000000000..ccc8489ef --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Embroidery.json @@ -0,0 +1,10 @@ +{ + "name": "中华刺绣风(Embroidery)", + "img": "./style_image/Embroidery.jpg", + "model_id": "rtxxxx/zju_05", + "revision": "v1.0.0", + "bin_file": "embroidery.safetensors", + "multiplier_style": 0.6, + "multiplier_human": 0.9, + "add_prompt_style": "DMajic, 1girl, close-up, face shot, Chinese embroidery, embroidery patterns in background, rich colors, silk robe, ultra resolutions, rich details, the art of light and shadow, gorgeous" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/European_fields.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/European_fields.json new file mode 100644 index 000000000..25dea892e --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/European_fields.json @@ -0,0 +1,10 @@ +{ + "name": "欧式田野风(European fields)", + "img": "./style_image/European_fields.jpg", + "model_id": "iotang/lora_testing", + "revision": "v5", + "bin_file": "edgEuropean_Vintage.safetensors", + "multiplier_style": 0.55, + "multiplier_human": 0.95, + "add_prompt_style": "focused, (edgEV, wearing edgEV_vintage dress), (field, natural lighting, detailed background, cinematic lighting), (gentle hair:1.1), windy hair, perfect eyes, perfect face" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Fairy_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Fairy_style.json new file mode 100644 index 000000000..e2e415f73 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Fairy_style.json @@ -0,0 +1,10 @@ +{ + "name": "仙女风(Fairy style)", + "img": "./style_image/Fairy_style.jpg", + "model_id": "YorickHe/fairy_lora", + "revision": "v1.0.0", + "bin_file": "fairy.safetensors", + "multiplier_style": 0.25, + "multiplier_human": 0.95, + "add_prompt_style": "a beautiful fairy standing in the middle of a flower field, petals, close-up, warm light, light green atmosphere, white atmosphere, in the style of celebrity photography, soft, romantic scenes, flowing fabrics, light white and light orange, high resolution" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Fashion_glasses.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Fashion_glasses.json new file mode 100644 index 000000000..a977b7f3d --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Fashion_glasses.json @@ -0,0 +1,10 @@ +{ + "name": "时尚墨镜风(Fashion glasses)", + "img": "./style_image/Fashion_glasses.jpg", + "model_id": "SoulNut/facechain_LoRA", + "revision": "v1.1", + "bin_file": "fashion_glasses.safetensors", + "multiplier_style": 0.6, + "multiplier_human": 0.95, + "add_prompt_style": "(masterpiece, ultra high res face, face ultra zoom, highres, best quality, ultra detailed, cinematic lighting, portrait:1.2), sfw, short hair, black glasses, black lens, sunglasses, close-up, red lips, facing aside, cityscape, detailed background, blonde Leather clothing" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Flame_red_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Flame_red_style.json new file mode 100644 index 000000000..56bcf50c7 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Flame_red_style.json @@ -0,0 +1,10 @@ +{ + "name": "火红少女风(Flame Red Style)", + "img": "./style_image/Flame_red_style.jpg", + "model_id": "Hswich/wlop_offset", + "revision": "v1.0.0", + "bin_file": "wlop_offset.safetensors", + "multiplier_style": 0.4, + "multiplier_human": 0.95, + "add_prompt_style": "wlop, 1girl, close-up, black jacket, character request, commentary, earrings, jacket, jewelry, long hair, looking down, fire background, red hair, ruthlessness, golden ACC, locomotive" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Flowers.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Flowers.json new file mode 100644 index 000000000..b72a1c0ec --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Flowers.json @@ -0,0 +1,10 @@ +{ + "name": "花园风(Flowers)", + "img": "./style_image/Flowers.jpg", + "model_id": "lljjcc/outdoor", + "revision": "v1.0.0", + "bin_file": "outdoor photo_v2.0.safetensors", + "multiplier_style": 0.65, + "multiplier_human": 0.95, + "add_prompt_style": "1 girl, flower, close-up, beautiful face, outdoor, sunlight, warm light" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Gentleman.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Gentleman.json new file mode 100644 index 000000000..e1b16cf65 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Gentleman.json @@ -0,0 +1,10 @@ +{ + "name": "绅士风(Gentleman style)", + "img": "./style_image/Gentleman.jpg", + "model_id": "Licht000/gentleman", + "revision": "v1.0.0", + "bin_file": "trkshgntlmn10.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "1male, black classic suit, ties, bowties, bar background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/GuoFeng.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/GuoFeng.json new file mode 100644 index 000000000..6d87ff878 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/GuoFeng.json @@ -0,0 +1,10 @@ +{ + "name": "国风(GuoFeng Style)", + "img": "./style_image/GuoFeng.jpg", + "model_id": "Tekhne/GuoFengchill", + "revision": "v1.0.0", + "bin_file": "GuoFeng_sd-000006.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "(masterpiece, best quality, hires:1.2), GuoFeng, 1girl, close-up, face shot, linen cloth, red_lips, solo_focus, standing, looking at viewer, ethereal background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Hiphop.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Hiphop.json new file mode 100644 index 000000000..b542c51ab --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Hiphop.json @@ -0,0 +1,10 @@ +{ + "name": "嘻哈风(Hiphop style)", + "img": "./style_image/Hiphop.jpg", + "model_id": "Licht000/hiphop", + "revision": "v1.0.1", + "bin_file": "edg90hh.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "1male, hiphop style, baggy hoodies, sweatshirts, jeans, baseball caps, chunky gold chains, sunglasses, hoop earrings, braids, dreadlocks, graffiti wall background, street" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Hong_Kong_night_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Hong_Kong_night_style.json new file mode 100644 index 000000000..7e91e2e22 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Hong_Kong_night_style.json @@ -0,0 +1,10 @@ +{ + "name": "夜景港风(Hong Kong night)", + "img": "./style_image/Hong_Kong_night_style.jpg", + "model_id": "YorickHe/polaroid_lora", + "revision": "v1.0.0", + "bin_file": "InstantPhotoX3.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, close-up, face shot, stylish outfit, fitted jeans, oversized jacket, fashionable accessories, cityscape backdrop, rooftop or high-rise balcony, dynamic composition, engaging pose, soft yet striking lighting, shallow depth of field, bokeh from city lights, naturally blurred background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/India.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/India.json new file mode 100644 index 000000000..8748ec786 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/India.json @@ -0,0 +1,10 @@ +{ + "name": "印度风(India)", + "img": "./style_image/India.jpg", + "model_id": "lljjcc/IndianSarres", + "revision": "v1.0.0", + "bin_file": "Indian saree.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "wear indian style costume, gold ornament, gorgeous background, dynamic, Indian clothes, Indian Palace, jewelry, Indian style background, clean face" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Jacket_in_Snow_Mountain.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Jacket_in_Snow_Mountain.json new file mode 100644 index 000000000..6bea45646 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Jacket_in_Snow_Mountain.json @@ -0,0 +1,10 @@ +{ + "name": "雪山羽绒服风(Jacket in Snow Mountain)", + "img": "./style_image/Jacket_in_Snow_Mountain.jpg", + "model_id": "iotang/lora_testing", + "revision": "v7", + "bin_file": "puffy_jacket-1.0.safetensors", + "multiplier_style": 0.6, + "multiplier_human": 0.9, + "add_prompt_style": "close-up, fur collar, ((jacket)), shirt, pants, winter, (bright sunny day, snow mountain, alpine slopes, snow), gyaru, fashion, trendy, gentle hair" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Kimono.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Kimono.json new file mode 100644 index 000000000..f0e0e7246 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Kimono.json @@ -0,0 +1,10 @@ +{ + "name": "日系和服风(Kimono Style)", + "img": "./style_image/Kimono.jpg", + "model_id": "ZackWang123/filmvelvia_lora", + "revision": "v1.0.0", + "bin_file": "FilmVelvia3.safetensors", + "multiplier_style": 0.45, + "multiplier_human": 0.95, + "add_prompt_style": "outdoor, (linen:1.4), cute japanese model girl, kimono, floral print, hair ornament, looking at viewer, hair flower, brown eyes, bangs, realistic" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Li.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Li.json new file mode 100644 index 000000000..b6e4c082e --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Li.json @@ -0,0 +1,10 @@ +{ + "name": "哥特洛丽塔(Gothic Lolita)", + "img": "./style_image/Li.jpg", + "model_id": "Cleaner/lo_dress_gothic_style2_v2", + "revision": "v1.0.0", + "bin_file": "lo_dress_gothic_style2_v2.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "Lolita dress, Gothic Lolita style, Clothes in black or burgundy tones, 1 girl, indoor, looking at viewer, standing, natural lighting, depth of field, Gothic castle, Medieval painting, Medieval murals, long hair, dynamic pose, detailed background, lace-trimmed, with bowknot, Large glass windows, European monumental architecture" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Lolita.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Lolita.json new file mode 100644 index 000000000..b510f1cd2 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Lolita.json @@ -0,0 +1,10 @@ +{ + "name": "洛丽塔(Lolita)", + "img": "./style_image/Lolita.jpg", + "model_id": "Licht000/lolita", + "revision": "v1.0.0", + "bin_file": "lolitaV1.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, puffy dresses, lace edges, high-waist skirts, lace gloves, brooches, curled hair, braids, adorned with bows, rosy blush, pink lipsticks, reserved, sweet, girlish, garden background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Luolita.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Luolita.json new file mode 100644 index 000000000..50c29298e --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Luolita.json @@ -0,0 +1,10 @@ +{ + "name": "花环洛丽塔(Flora Lolita)", + "img": "./style_image/Luolita.jpg", + "model_id": "idlepiggy/zju_16FC", + "revision": "v3.0.1", + "bin_file": "lolitaV1.safetensors", + "multiplier_style": 0.6, + "multiplier_human": 0.95, + "add_prompt_style": "lolita, warm sunlight, front view, jewelry,summer,purple eyes,long hair, white dress,backgound is sun and rainbow,faceing camera with a smile,beautiful flower on the head" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Maid.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Maid.json new file mode 100644 index 000000000..9d143bbc7 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Maid.json @@ -0,0 +1,10 @@ +{ + "name": "女仆风(Maid style)", + "img": "./style_image/Maid.jpg", + "model_id": "Licht000/maid", + "revision": "v1.0.0", + "bin_file": "maid_attire_v2.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, black or white short dresses, lace edges, aprons, bows, lace gloves, neckties, cuffs, twin-tails, light makeup, pink blush, pink lipsticks, gentle, considerate, cafe background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Mechnical.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Mechnical.json new file mode 100644 index 000000000..1f0e81314 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Mechnical.json @@ -0,0 +1,10 @@ +{ + "name": "机械风(Mechanical)", + "img": "./style_image/Mechnical.jpg", + "model_id": "rewfueranro/Mechanical_lora", + "revision": "v1.0.0", + "bin_file": "reelmech1v2.safetensors", + "multiplier_style": 0.8, + "multiplier_human": 0.95, + "add_prompt_style": "looking to the camera, clean face, top quality, official art, beautiful and aesthetic, a futuristic dystopian city, scrapper, intricate, elegant, highly detailed, cyberpunk, luminescence, transparency, 8K, stunning art, hyper-realistic art, mechanical woman, art by Genevieve Valentine, Nikon D850, F/8, reelmech, demonic, expressive, delicate, perfect shading, HDR" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Men_suit.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Men_suit.json new file mode 100644 index 000000000..97c1942f6 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Men_suit.json @@ -0,0 +1,10 @@ +{ + "name": "男士西装风(Men's Suit)", + "img": "./style_image/Men_suit.jpg", + "model_id": "potazinc/suit", + "revision": "v2", + "bin_file": "businessman-AIX.safetensors", + "multiplier_style": 0.7, + "multiplier_human": 0.95, + "add_prompt_style": "(realistic:1.2), HDR, UHD, 8K, face ultra zoom, portrait, male, (1boy, office man, adult, asian, black hair, suit, hand in pocket, close-up)" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Miaozu.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Miaozu.json new file mode 100644 index 000000000..87ef1ff07 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Miaozu.json @@ -0,0 +1,10 @@ +{ + "name": "苗族服装风(Miao style)", + "img": "./style_image/Miaozu.jpg", + "model_id": "SoulNut/facechain_model", + "revision": "v3.0", + "bin_file": "miaozu.safetensors", + "multiplier_style": 0.45, + "multiplier_human": 0.9, + "add_prompt_style": "(masterpiece, ultra high res face, face ultra zoom, highres, best quality, ultra detailed, portrait:1.2), sfw, Miao nationality, smaller head, beautiful face, smaller face, ((intricate embroideries on clothes)), silver ornaments, ((intricate detailed headdresses)), (((extremely elaborate silver detailing))), exquisite and ornate headpiece featuring intricate filigree designs and delicate engravings, leaning against a stone archway, hands clasped behind, wear gloves, detailed fingers, Miao Village background, flat chest, realistic" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Model_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Model_style.json new file mode 100644 index 000000000..169920c4e --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Model_style.json @@ -0,0 +1,10 @@ +{ + "name": "模特风(Model style)", + "img": "./style_image/Model_style.jpg", + "model_id": "YorickHe/polaroid_lora", + "revision": "v1.0.0", + "bin_file": "InstantPhotoX3.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, balenciaga, close-up, fashion, streets of new york, new york, modeling for Balenciaga, natural skin texture, dynamic pose, rouge, film grain" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Mongolian.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Mongolian.json new file mode 100644 index 000000000..582abdba5 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Mongolian.json @@ -0,0 +1,10 @@ +{ + "name": "蒙古草原风(Mongolian)", + "img": "./style_image/Mongolian.jpg", + "model_id": "rtxxxx/zju_05", + "revision": "v1.0.0", + "bin_file": "mongolian.safetensors", + "multiplier_style": 0.6, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, mongolian style, mongolian traditional clothes, close-up, smile, linen, mongolian hair ornament, grass, prairie background, hills, sunlight, warm light, front view" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Motorcycle_race_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Motorcycle_race_style.json new file mode 100644 index 000000000..82b4ca9cb --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Motorcycle_race_style.json @@ -0,0 +1,10 @@ +{ + "name": "机车风(Motorcycle race style)", + "img": "./style_image/Motorcycle_race_style.jpg", + "model_id": "YorickHe/polaroid_lora", + "revision": "v1.0.0", + "bin_file": "InstantPhotoX3.safetensors", + "multiplier_style": 0.4, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, close-up, wearing racing clothes, motorbike clothes, modeling, playful, futuristic, city street background, at night, cool atmospheric, realistic" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Ocean_Summer_vibe.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Ocean_Summer_vibe.json new file mode 100644 index 000000000..656610fba --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Ocean_Summer_vibe.json @@ -0,0 +1,10 @@ +{ + "name": "夏日海滩风(Summer Ocean Vibe)", + "img": "./style_image/Ocean_Summer_vibe.jpg", + "model_id": "JeffVan/Oil_Paint_Style_LORA", + "revision": "v1.0.0", + "bin_file": "OilPaint.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "summer vibe, ocean, rock, sea wave, palm tree, sunshine, rim lighting, two tone light, professional photo portrait, beautiful eyes, beautiful face, ocean background, Style by NTY" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/PekingOpera_female_role.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/PekingOpera_female_role.json new file mode 100644 index 000000000..08018b355 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/PekingOpera_female_role.json @@ -0,0 +1,10 @@ +{ + "name": "京剧名旦风(Female role in Peking opera)", + "img": "./style_image/PekingOpera_female_role.jpg", + "model_id": "houpeiran/mymodel", + "revision": "v1.0.0", + "bin_file": "PekingOperaR.safetensors", + "multiplier_style": 0.45, + "multiplier_human": 0.95, + "add_prompt_style": "portraits,standing, (photorealistic:1.4), official art, unity 8k wallpaper, ultra detailed, beautiful and aesthetic, masterpiece, (fractal art), 1girl, bust, wide aperture, Peking Opera, light makeup, Close-up of the face, the face is clear, no headdress, standing, black hair, each hand has five fingers" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Polaroid_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Polaroid_style.json new file mode 100644 index 000000000..7b2a9d305 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Polaroid_style.json @@ -0,0 +1,10 @@ +{ + "name": "拍立得风(Polaroid style)", + "img": "./style_image/Polaroid_style.jpg", + "model_id": "YorickHe/polaroid_lora", + "revision": "v1.0.0", + "bin_file": "InstantPhotoX3.safetensors", + "multiplier_style": 0.4, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, close-up, simple clothes, front view, looking straight into the camera, film grain, flash, enhanced flash, dark background, polaroid, instant photo, realistic face" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Princess_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Princess_style.json new file mode 100644 index 000000000..6d6c5aca6 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Princess_style.json @@ -0,0 +1,10 @@ +{ + "name": "贵族公主风(Princess costum)", + "img": "./style_image/Princess_style.jpg", + "model_id": "AzilyModelScope/facechain_lora", + "revision": "v1.0.0", + "bin_file": "foreign_princess_costum.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "fantasy girl, close-up, Waist shot, long hair, jewelry, earrings, looking at viewer, white dress, cathedral background, crown, (detailed face, perfect face, perfect eyes, realistic eyes), (clear face), high detail, sharp focus, dramatic, beautiful girl" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Rainy_night.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Rainy_night.json new file mode 100644 index 000000000..4a11b7cf1 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Rainy_night.json @@ -0,0 +1,10 @@ +{ + "name": "雨夜(Rainy night)", + "img": "./style_image/Rainy_night.jpg", + "model_id": "YorickHe/polaroid_lora", + "revision": "v1.0.0", + "bin_file": "InstantPhotoX3.safetensors", + "multiplier_style": 0.45, + "multiplier_human": 0.95, + "add_prompt_style": "standing in the rain, wet, wet clothes, wet hair, face Shot, front view, close-up, cityscape, cold lighting, realistic, cinematic lighting, photon mapping, radiosity, physically-based rendering" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Redstyle.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Redstyle.json new file mode 100644 index 000000000..abc1d7279 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Redstyle.json @@ -0,0 +1,10 @@ +{ + "name": "红发礼服风(Red Style)", + "img": "./style_image/Redstyle.jpg", + "model_id": "Tekhne/red", + "revision": "v1.0.0", + "bin_file": "edgAyre_AC6.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "Masterpiece, best quality,edgQuality,smirk,smug, edgAyre, red hair,red eyes,dress,Haute_Couture, feathered top,woman wearing a Haute_Couture dress" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Retro_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Retro_style.json new file mode 100644 index 000000000..0637c558e --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Retro_style.json @@ -0,0 +1,10 @@ +{ + "name": "复古风(Retro Style)", + "img": "./style_image/Retro_style.jpg", + "model_id": "HanYixuan1/Retro_style", + "revision": "v1.0.0", + "bin_file": "Retro_style.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.8, + "add_prompt_style": "1990s, 1girl, close-up, waist shot, instant camera, woman looking out window, against glass, clothes, gray white and black ,black hair, misty beauty, glimmer, warm-toned, soft, sense of depth, Gauze texture, Solid fabric, face focusing, fit, Slight yellowing, autochrome photography, light and shade contrast, dim, pale, color fading, old city background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Roaming_Astronaut.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Roaming_Astronaut.json new file mode 100644 index 000000000..292e9ebdd --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Roaming_Astronaut.json @@ -0,0 +1,10 @@ +{ + "name": "漫游宇航员(Roaming Astronaut)", + "img": "./style_image/Roaming_Astronaut.jpg", + "model_id": "idlepiggy/zju_16FC", + "revision": "v3.0.1", + "bin_file": "firmamentV2.1.safetensors", + "multiplier_style": 0.7, + "multiplier_human": 0.9, + "add_prompt_style": "firmament, space_helmet, background is universe with stars, moon, looking at viewer" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/School_uniform.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/School_uniform.json new file mode 100644 index 000000000..0133d06bf --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/School_uniform.json @@ -0,0 +1,10 @@ +{ + "name": "校服风(School uniform)", + "img": "./style_image/School_uniform.jpg", + "model_id": "YorickHe/JK_uniform_lora", + "revision": "v1.0.0", + "bin_file": "jk_uniform.safetensors", + "multiplier_style": 0.2, + "multiplier_human": 0.95, + "add_prompt_style": "JK_style, white short-sleeved JK_shirt, dark blue JK_skirt, bow JK_tie, close-up, looking at viewer, sweet smile, night, Tokyo street, night city scape" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Science_fiction.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Science_fiction.json new file mode 100644 index 000000000..ace7d5bad --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Science_fiction.json @@ -0,0 +1,10 @@ +{ + "name": "科幻风(Science fiction style)", + "img": "./style_image/Science_fiction.jpg", + "model_id": "StigXI/zju_01_LoRA", + "revision": "v1.0.0", + "bin_file": "scific.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "science fiction style suit,tidy face, photography, clean, vivid colors, (clean face:1.5), highly detailed, UHD, professional, cyber punk street background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Soccer.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Soccer.json new file mode 100644 index 000000000..5303c978d --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Soccer.json @@ -0,0 +1,10 @@ +{ + "name": "绿茵球场风(Soccer Field)", + "img": "./style_image/Soccer.jpg", + "model_id": "rtxxxx/zju_05", + "revision": "v1.0.0", + "bin_file": "soccer_field.safetensors", + "multiplier_style": 0.15, + "multiplier_human": 0.9, + "add_prompt_style": "1 girl, close-up, sport uniform, no brand, no logo, warm light, sunlight, outdoor, dynamic, inside soccer field background, blue sky, happy smile, clean clothes, brilliant clothes" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Street_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Street_style.json new file mode 100644 index 000000000..5ddbaa284 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Street_style.json @@ -0,0 +1,10 @@ +{ + "name": "街拍风(Street style)", + "img": "./style_image/Street_style.jpg", + "model_id": "Licht000/retro_style_lora", + "revision": "v1.0.0", + "bin_file": "lijiaxin.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, close-up, face shot, broad-shouldered blue jackets, high-waisted pants, black curly hair, dim yellow light, old movie filters, shallow depth of field, playful smiles, (naturally blurred background, shabby street:2), Yellowed photos, blurry figure" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Tibetan_clothing.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Tibetan_clothing.json new file mode 100644 index 000000000..0f9dce44d --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Tibetan_clothing.json @@ -0,0 +1,10 @@ +{ + "name": "藏族服饰风(Tibetan clothing style)", + "img": "./style_image/Tibetan_clothing.jpg", + "model_id": "PeiPeiY/style_lora", + "revision": "v1", + "bin_file": "tibetan.safetensors", + "multiplier_style": 0.55, + "multiplier_human": 0.9, + "add_prompt_style": "extremely delicate and beautiful girls, (tibetan clothing style), ((fur hat)), long hair, colorful makeup, outdoor, delicate headwear" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Traditional_chinese_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Traditional_chinese_style.json new file mode 100644 index 000000000..a333b7444 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Traditional_chinese_style.json @@ -0,0 +1,10 @@ +{ + "name": "古风(Traditional chinese style)", + "img": "./style_image/Traditional_chinese_style.jpg", + "model_id": "iotang/lora_testing", + "revision": "v5", + "bin_file": "MoXinV1.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "(best quality, hanfu, Chinese traditional ink painting:1.8), close-up, song, anxiang, chinese_clothes, ornaments, topknot, perfect eyes, perfect face, soft smile" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Tyndall.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Tyndall.json new file mode 100644 index 000000000..af819ed7d --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Tyndall.json @@ -0,0 +1,10 @@ +{ + "name": "丁达尔风(Tyndall Light)", + "img": "./style_image/Tyndall.jpg", + "model_id": "Cleaner/Tyndalleffect_Light", + "revision": "v1.0.0", + "bin_file": "Tyndall effect_Light v1.1.safetensors", + "multiplier_style": 0.7, + "multiplier_human": 0.95, + "add_prompt_style": "Best Quality,Masterpiece,Ultra High Resolution,(Realisticity:1.4),Original Photo,Cinematic Lighting,1Girl,light rays,Tyndall effect,,masterpiece, best quality, highly detailed,outdoor,soft light" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Underwater.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Underwater.json new file mode 100644 index 000000000..4bd3e12c3 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Underwater.json @@ -0,0 +1,10 @@ +{ + "name": "梦幻深海风(Sea World)", + "img": "./style_image/Underwater.jpg", + "model_id": "rtxxxx/zju_05", + "revision": "v1.0.0", + "bin_file": "underwater.safetensors", + "multiplier_style": 0.4, + "multiplier_human": 0.9, + "add_prompt_style": "underwater, sea life, aquatic, photography, upper body, masterpiece, cinematic angle, looking at viewer, coral" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Wedding_dress.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Wedding_dress.json new file mode 100644 index 000000000..4f38e1894 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Wedding_dress.json @@ -0,0 +1,10 @@ +{ + "name": "婚纱风(Wedding dress)", + "img": "./style_image/Wedding_dress.jpg", + "model_id": "YorickHe/outdoor_photo_lora", + "revision": "v1.0.0", + "bin_file": "outdoor_photo_v2.0.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "white wedding dress, 1girl, summer, flower, happy atmosphere, sunlight, Waist Shot" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Wedding_dress_2.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Wedding_dress_2.json new file mode 100644 index 000000000..262efe254 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Wedding_dress_2.json @@ -0,0 +1,10 @@ +{ + "name": "婚纱风-2(Wedding dress 2)", + "img": "./style_image/Wedding_dress_2.jpg", + "model_id": "YorickHe/polaroid_lora", + "revision": "v1.0.0", + "bin_file": "InstantPhotoX3.safetensors", + "multiplier_style": 0.4, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, close-up, wearing wedding dress, white, film grain, sunlight, sun flare, lens flare, field of white roses, high fashion, top model" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/West_cowboy.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/West_cowboy.json new file mode 100644 index 000000000..d3aa63e71 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/West_cowboy.json @@ -0,0 +1,10 @@ +{ + "name": "西部牛仔风(West cowboy)", + "img": "./style_image/West_cowboy.jpg", + "model_id": "Licht000/cowboy", + "revision": "v1.0.0", + "bin_file": "James West-000196.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "1male, face shot, Denim jackets, West style, checkered shirts, leather vests, yellow wide-brimmed hats, bandanas, leather belts with silver buckles, short hair, tough, desert background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Wild_west.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Wild_west.json new file mode 100644 index 000000000..a8d77334d --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Wild_west.json @@ -0,0 +1,10 @@ +{ + "name": "西部风(Wild west style)", + "img": "./style_image/Wild_west.jpg", + "model_id": "StigXI/zju_01_LoRA", + "revision": "v1.0.0", + "bin_file": "west.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "wild west style clothing, vivid colors, west countryside, front view, grassland, HDR, studio lighting, highly detailed, trending on artstation" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Witch.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Witch.json new file mode 100644 index 000000000..120e8ed3c --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Witch.json @@ -0,0 +1,10 @@ +{ + "name": "女巫风(Witch style)", + "img": "./style_image/Witch.jpg", + "model_id": "Licht000/witch", + "revision": "v1.0.0", + "bin_file": "Moon Witch.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "1girl, close-up, front view, black robes, lace clothing, long skirts, capes, jewelry, black hats, dark wavy hair, dark eyeshadows, dark blush, forest background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Wizard_of_Oz.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Wizard_of_Oz.json new file mode 100644 index 000000000..ef965c16b --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Wizard_of_Oz.json @@ -0,0 +1,10 @@ +{ + "name": "绿野仙踪(Wizard of Oz)", + "img": "./style_image/Wizard_of_Oz.jpg", + "model_id": "Rechycs/Wizard_lora", + "revision": "v1.0.0", + "bin_file": "Wizard_of_Oz.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.8, + "add_prompt_style": "OIL PAINTING, IMPRESSIONISM, medium full view, amidst the ancient woodland, the image captures the ethereal beauty of a young dryad. her long, braided red hair cascades like flames, entwining with vines and flowers that form her ornate dress, the air is filled with colorful petals, and dappled sunlight paints a mesmerizing tapestry on the forest floor, dense foliage, gnarled roots and branches, beams of sunlight, ethereal, mysterious, wondrous, chiaroscuro" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/ZangZu.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/ZangZu.json new file mode 100644 index 000000000..f7962a6a6 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/ZangZu.json @@ -0,0 +1,10 @@ +{ + "name": "藏族风(ZangZu Style)", + "img": "./style_image/ZangZu.jpg", + "model_id": "fffff1123/zangzu", + "revision": "v1.0.0", + "bin_file": "ZangZu_chillout-000004.safetensors", + "multiplier_style": 0.55, + "multiplier_human": 0.95, + "add_prompt_style": "(masterpiece, best quality, hires:1.2),Zangzu,1girl,solo,sitting,lips,upper_body,beads necklace,snow,looking at viewer, blurry background, blurry hair edge, outdoors, ultra-detailed," +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/MajicmixRealistic_v6/Zhuang_style.json b/demo/facechain_agent/styles/MajicmixRealistic_v6/Zhuang_style.json new file mode 100644 index 000000000..13cb3dcb3 --- /dev/null +++ b/demo/facechain_agent/styles/MajicmixRealistic_v6/Zhuang_style.json @@ -0,0 +1,10 @@ +{ + "name": "壮族服装风(Zhuang style)", + "img": "./style_image/Zhuang_style.jpg", + "model_id": "iotang/lora_testing", + "revision": "v5", + "bin_file": "zhuangnv.safetensors", + "multiplier_style": 0.75, + "multiplier_human": 0.95, + "add_prompt_style": "((best quality)), close-up, portrait, ((zhuangzunv)), ornaments, jewelry, headwear, ((beautiful embroidery, floral print, marvelous design)), perfect eyes, perfect face, gentle black hair, smile" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Armor.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Armor.json new file mode 100644 index 000000000..d56b067bf --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Armor.json @@ -0,0 +1,10 @@ +{ + "name": "盔甲风(Armor)", + "img": "./style_image/Armor.jpg", + "model_id": null, + "revision": null, + "bin_file": null, + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "wearing silver armor, simple background, high-class pure color background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Barbie_Doll.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Barbie_Doll.json new file mode 100644 index 000000000..b82d50715 --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Barbie_Doll.json @@ -0,0 +1,10 @@ +{ + "name": "芭比娃娃(Barbie Doll)", + "img": "./style_image/Barbie_Doll.jpg", + "model_id": "theRealSlimShady/AI_portraits", + "revision": "v2", + "bin_file": "PinkBarbie.safetensors", + "multiplier_style": 0.25, + "multiplier_human": 0.95, + "add_prompt_style": "golden blond hair, wearing frilly dress, bow and ponytail, exquisite background, pure color background, delicate earrings and necklace, solo, happy expression" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Casual_Lifestyle.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Casual_Lifestyle.json new file mode 100644 index 000000000..238145f88 --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Casual_Lifestyle.json @@ -0,0 +1,10 @@ +{ + "name": "休闲生活风(Casual Lifestyle)", + "img": "./style_image/Casual_Lifestyle.jpg", + "model_id": "theRealSlimShady/AI_portraits", + "revision": "v2", + "bin_file": "PortraitMasterV1.safetensors", + "multiplier_style": 0.25, + "multiplier_human": 0.95, + "add_prompt_style": "smile, lips, put on makeup, wearing casual clothes, simple background, blurred background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Chinese_traditional_gorgeous_suit.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Chinese_traditional_gorgeous_suit.json new file mode 100644 index 000000000..c09d54061 --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Chinese_traditional_gorgeous_suit.json @@ -0,0 +1,10 @@ +{ + "name": "凤冠霞帔(Chinese traditional gorgeous suit)", + "img": "./style_image/Chinese_traditional_gorgeous_suit.jpg", + "model_id": "ly261666/civitai_xiapei_lora", + "revision": "v1.0.0", + "bin_file": "xiapei.safetensors", + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "red, hanfu, tiara, crown" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Cybernetics_punk.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Cybernetics_punk.json new file mode 100644 index 000000000..b89473b3a --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Cybernetics_punk.json @@ -0,0 +1,10 @@ +{ + "name": "赛博朋克(Cybernetics punk)", + "img": "./style_image/Cybernetics_punk.jpg", + "model_id": null, + "revision": null, + "bin_file": null, + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "white hair, neon glowing glasses, cybernetics, punks, robotic, AI, NFT art, Fluorescent color, ustration" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Elegant_Princess.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Elegant_Princess.json new file mode 100644 index 000000000..f5ee7184b --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Elegant_Princess.json @@ -0,0 +1,10 @@ +{ + "name": "优雅公主(Elegant Princess)", + "img": "./style_image/Elegant_Princess.jpg", + "model_id": "theRealSlimShady/AI_portraits", + "revision": "v2", + "bin_file": "blancanievesV2.safetensors", + "multiplier_style": 0.25, + "multiplier_human": 0.95, + "add_prompt_style": "short black wavy hair, pale complexion, white lace, sky-blue dress, puff sleeves, earings, necklace, happy expression, simple pure color background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Gown.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Gown.json new file mode 100644 index 000000000..79da34dfa --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Gown.json @@ -0,0 +1,10 @@ +{ + "name": "女士晚礼服(Gown)", + "img": "./style_image/Gown.jpg", + "model_id": null, + "revision": null, + "bin_file": null, + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "wearing an elegant evening gown, simple background, high-class pure color background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Hanfu.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Hanfu.json new file mode 100644 index 000000000..3a14e4b30 --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Hanfu.json @@ -0,0 +1,10 @@ +{ + "name": "汉服风(Hanfu)", + "img": "./style_image/Hanfu.jpg", + "model_id": null, + "revision": null, + "bin_file": null, + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "wearing beautiful traditional hanfu, upper_body, simple background, high-class pure color background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Innocent_Girl_in_White_Dress.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Innocent_Girl_in_White_Dress.json new file mode 100644 index 000000000..92e00d495 --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Innocent_Girl_in_White_Dress.json @@ -0,0 +1,10 @@ +{ + "name": "白月光(Innocent Girl in White Dress)", + "img": "./style_image/Innocent_Girl_in_White_Dress.jpg", + "model_id": null, + "revision": null, + "bin_file": null, + "multiplier_style": 0.25, + "multiplier_human": 0.95, + "add_prompt_style": "wearing elegant white dress, simple pure color background, face located in the center of the picture, long black hair, inquisitive eyes, innocent expression, lips" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Pixy_Girl.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Pixy_Girl.json new file mode 100644 index 000000000..d7ef0cc47 --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Pixy_Girl.json @@ -0,0 +1,10 @@ +{ + "name": "鬼马少女(Pixy Girl)", + "img": "./style_image/Pixy_Girl.jpg", + "model_id": "theRealSlimShady/AI_portraits", + "revision": "v2", + "bin_file": "VidiaTinkerbellDisney-08.safetensors", + "multiplier_style": 0.25, + "multiplier_human": 0.95, + "add_prompt_style": "purple hair, ponytail, wearing slip skirt,looking straight into the camera with shoulders parallel to the frame, light purple background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Snow_white.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Snow_white.json new file mode 100644 index 000000000..10f7d850e --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Snow_white.json @@ -0,0 +1,10 @@ +{ + "name": "白雪公主(Snow White)", + "img": "./style_image/Snow_white.jpg", + "model_id": "houpeiran/mymodel", + "revision": "v1.0.0", + "bin_file": "blancanievesV2.safetensors", + "multiplier_style": 0.3, + "multiplier_human": 0.95, + "add_prompt_style": "snow white, princess, blue skirt, 1girl, medium breast, looking at viewer, close-up to head, smile, short hair, black hair, standing, brown eyes, hair bow, hairband, red bow, forest background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/T-shirt.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/T-shirt.json new file mode 100644 index 000000000..5558196e3 --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/T-shirt.json @@ -0,0 +1,10 @@ +{ + "name": "T恤衫(T-shirt)", + "img": "./style_image/T-shirt.jpg", + "model_id": null, + "revision": null, + "bin_file": null, + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "wearing T-shirt, simple background, high-class pure color background" +} \ No newline at end of file diff --git a/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Working_suit.json b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Working_suit.json new file mode 100644 index 000000000..44a7a8c65 --- /dev/null +++ b/demo/facechain_agent/styles/leosamsMoonfilm_filmGrain20/Working_suit.json @@ -0,0 +1,10 @@ +{ + "name": "工作服(Working suit)", + "img": "./style_image/Working_suit.jpg", + "model_id": null, + "revision": null, + "bin_file": null, + "multiplier_style": 0.35, + "multiplier_human": 0.95, + "add_prompt_style": "wearing high-class business/working suit, simple background, high-class pure color background" +} \ No newline at end of file