Team Ai
Apppublic

UAI-Software/PhotoMaker

sourceHugging Faceapache-2.0updated 3y agoView on Hugging Face
0likes
app.py289 linesDownload Raw Back to root
1import torch2import numpy as np3import random4import os5 6from diffusers.utils import load_image7from diffusers import DDIMScheduler8 9from huggingface_hub import hf_hub_download10import spaces11import gradio as gr12 13from pipeline import PhotoMakerStableDiffusionXLPipeline14from style_template import styles15 16# global variable17base_model_path = 'SG161222/RealVisXL_V3.0'18device = "cuda" if torch.cuda.is_available() else "cpu"19MAX_SEED = np.iinfo(np.int32).max20STYLE_NAMES = list(styles.keys())21DEFAULT_STYLE_NAME = "Photographic (Default)"22 23# download PhotoMaker checkpoint to cache24photomaker_ckpt = hf_hub_download(repo_id="TencentARC/PhotoMaker", filename="photomaker-v1.bin", repo_type="model")25 26pipe = PhotoMakerStableDiffusionXLPipeline.from_pretrained(27    base_model_path, 28    torch_dtype=torch.bfloat16, 29    use_safetensors=True, 30    variant="fp16",31).to(device)32 33pipe.load_photomaker_adapter(34    os.path.dirname(photomaker_ckpt),35    subfolder="",36    weight_name=os.path.basename(photomaker_ckpt),37    trigger_word="img"38)     39pipe.id_encoder.to(device)40 41pipe.scheduler = DDIMScheduler.from_config(pipe.scheduler.config)42# pipe.set_adapters(["photomaker"], adapter_weights=[1.0])43pipe.fuse_lora()44 45@spaces.GPU46def generate_image(upload_images, prompt, negative_prompt, style_name, num_steps, style_strength_ratio, num_outputs, guidance_scale, seed, progress=gr.Progress(track_tqdm=True)):47    # check the trigger word48    image_token_id = pipe.tokenizer.convert_tokens_to_ids(pipe.trigger_word)49    input_ids = pipe.tokenizer.encode(prompt)50    if image_token_id not in input_ids:51        raise gr.Error(f"Cannot find the trigger word '{pipe.trigger_word}' in text prompt! Please refer to step 2️⃣")52 53    if input_ids.count(image_token_id) > 1:54        raise gr.Error(f"Cannot use multiple trigger words '{pipe.trigger_word}' in text prompt!")55 56    # apply the style template57    prompt, negative_prompt = apply_style(style_name, prompt, negative_prompt)58 59    # Update nsfw negative prompt60    negative_prompt = f"nsfw, naked, {negative_prompt}"61    if upload_images is None:62        raise gr.Error(f"Cannot find any input face image! Please refer to step 1️⃣")63 64    input_id_images = []65    for img in upload_images:66        input_id_images.append(load_image(img))67    68    generator = torch.Generator(device=device).manual_seed(seed)69 70    print("Start inference...")71    print(f"[Debug] Prompt: {prompt}, \n[Debug] Neg Prompt: {negative_prompt}")72    start_merge_step = int(float(style_strength_ratio) / 100 * num_steps)73    if start_merge_step > 30:74        start_merge_step = 3075    print(start_merge_step)76    images = pipe(77        prompt=prompt,78        input_id_images=input_id_images,79        negative_prompt=negative_prompt,80        num_images_per_prompt=num_outputs,81        num_inference_steps=num_steps,82        start_merge_step=start_merge_step,83        generator=generator,84        guidance_scale=guidance_scale,85    ).images86    return images, gr.update(visible=True)87 88def swap_to_gallery(images):89    return gr.update(value=images, visible=True), gr.update(visible=True), gr.update(visible=False)90 91def upload_example_to_gallery(images, prompt, style, negative_prompt):92    return gr.update(value=images, visible=True), gr.update(visible=True), gr.update(visible=False)93 94def remove_back_to_files():95    return gr.update(visible=False), gr.update(visible=False), gr.update(visible=True)96    97def remove_tips():98    return gr.update(visible=False)99 100def randomize_seed_fn(seed: int, randomize_seed: bool) -> int:101    if randomize_seed:102        seed = random.randint(0, MAX_SEED)103    return seed104 105def apply_style(style_name: str, positive: str, negative: str = "") -> tuple[str, str]:106    p, n = styles.get(style_name, styles[DEFAULT_STYLE_NAME])107    return p.replace("{prompt}", positive), n + ' ' + negative108 109def get_image_path_list(folder_name):110    image_basename_list = os.listdir(folder_name)111    image_path_list = sorted([os.path.join(folder_name, basename) for basename in image_basename_list])112    return image_path_list113 114def get_example():115    case = [116        [117            get_image_path_list('./examples/scarletthead_woman'),118            "instagram photo, portrait photo of a woman img, colorful, perfect face, natural skin, hard shadows, film grain",119            "(No style)",120            "(asymmetry, worst quality, low quality, illustration, 3d, 2d, painting, cartoons, sketch), open mouth",121        ],122        [123            get_image_path_list('./examples/newton_man'),124            "sci-fi, closeup portrait photo of a man img wearing the sunglasses in Iron man suit, face, slim body, high quality, film grain",125            "(No style)",126            "(asymmetry, worst quality, low quality, illustration, 3d, 2d, painting, cartoons, sketch), open mouth",127        ],128    ]129    return case130 131### Description and style132logo = r"""133<center><img src='https://photo-maker.github.io/assets/logo.png' alt='PhotoMaker logo' style="width:80px; margin-bottom:10px"></center>134"""135title = r"""136<h1 align="center">PhotoMaker: Customizing Realistic Human Photos via Stacked ID Embedding</h1>137"""138 139description = r"""140<b>Official 🤗 Gradio demo</b> for <a href='https://github.com/TencentARC/PhotoMaker' target='_blank'><b>PhotoMaker: Customizing Realistic Human Photos via Stacked ID Embedding</b></a>.<br>141<br>142For stylization, you could use our other gradio demo [PhotoMaker-Style](https://huggingface.co/spaces/TencentARC/PhotoMaker-Style).143<br>144❗️❗️❗️[<b>Important</b>] Personalization steps:<br>1451️⃣ Upload images of someone you want to customize. One image is ok, but more is better.  Although we do not perform face detection, the face in the uploaded image should <b>occupy the majority of the image</b>.<br>1462️⃣ Enter a text prompt, making sure to <b>follow the class word</b> you want to customize with the <b>trigger word</b>: `img`, such as: `man img` or `woman img` or `girl img`.<br>1473️⃣ Choose your preferred style template.<br>1484️⃣ Click the <b>Submit</b> button to start customizing.149"""150 151article = r"""152 153If PhotoMaker is helpful, please help to ⭐ the <a href='https://github.com/TencentARC/PhotoMaker' target='_blank'>Github Repo</a>. Thanks! 154[![GitHub Stars](https://img.shields.io/github/stars/TencentARC/PhotoMaker?style=social)](https://github.com/TencentARC/PhotoMaker)155---156📝 **Citation**157<br>158If our work is useful for your research, please consider citing:159 160```bibtex161@inproceedings{li2023photomaker,162  title={PhotoMaker: Customizing Realistic Human Photos via Stacked ID Embedding},163  author={Li, Zhen and Cao, Mingdeng and Wang, Xintao and Qi, Zhongang and Cheng, Ming-Ming and Shan, Ying},164  booktitle={IEEE Conference on Computer Vision and Pattern Recognition (CVPR)},165  year={2024}166}167```168📋 **License**169<br>170Apache-2.0 LICENSE. Please refer to the [LICENSE file](https://huggingface.co/TencentARC/PhotoMaker/blob/main/LICENSE) for details.171 172📧 **Contact**173<br>174If you have any questions, please feel free to reach me out at <b>zhenli1031@gmail.com</b>.175"""176 177tips = r"""178### Usage tips of PhotoMaker1791. Upload more photos of the person to be customized to **improve ID fidelty**. If the input is Asian face(s), maybe consider adding 'asian' before the class word, e.g., `asian woman img`1802. When stylizing, does the generated face look too realistic? Try switching to our **other gradio demo** [PhotoMaker-Style](https://huggingface.co/spaces/TencentARC/PhotoMaker-Style). Adjust the **Style strength** to 30-50, the larger the number, the less ID fidelty, but the stylization ability will be better.1813. For **faster** speed, reduce the number of generated images and sampling steps. However, please note that reducing the sampling steps may compromise the ID fidelity.182"""183# We have provided some generate examples and comparisons at: [this website]().184# 3. Don't make the prompt too long, as we will trim it if it exceeds 77 tokens. 185# 4. When generating realistic photos, if it's not real enough, try switching to our other gradio application [PhotoMaker-Realistic]().186 187css = '''188.gradio-container {width: 85% !important}189'''190with gr.Blocks(css=css) as demo:191    gr.Markdown(logo)192    gr.Markdown(title)193    gr.Markdown(description)194    # gr.DuplicateButton(195    #     value="Duplicate Space for private use ",196    #     elem_id="duplicate-button",197    #     visible=os.getenv("SHOW_DUPLICATE_BUTTON") == "1",198    # )199    with gr.Row():200        with gr.Column():201            files = gr.File(202                        label="Drag (Select) 1 or more photos of your face",203                        file_types=["image"],204                        file_count="multiple"205                    )206            uploaded_files = gr.Gallery(label="Your images", visible=False, columns=5, rows=1, height=200)207            with gr.Column(visible=False) as clear_button:208                remove_and_reupload = gr.ClearButton(value="Remove and upload new ones", components=files, size="sm")209            prompt = gr.Textbox(label="Prompt",210                       info="Try something like 'a photo of a man/woman img', 'img' is the trigger word.",211                       placeholder="A photo of a [man/woman img]...")212            style = gr.Dropdown(label="Style template", choices=STYLE_NAMES, value=DEFAULT_STYLE_NAME)213            submit = gr.Button("Submit")214 215            with gr.Accordion(open=False, label="Advanced Options"):216                negative_prompt = gr.Textbox(217                    label="Negative Prompt", 218                    placeholder="low quality",219                    value="nsfw, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry",220                )221                num_steps = gr.Slider( 222                    label="Number of sample steps",223                    minimum=20,224                    maximum=100,225                    step=1,226                    value=50,227                )228                style_strength_ratio = gr.Slider(229                    label="Style strength (%)",230                    minimum=15,231                    maximum=50,232                    step=1,233                    value=20,234                )235                num_outputs = gr.Slider(236                    label="Number of output images",237                    minimum=1,238                    maximum=4,239                    step=1,240                    value=2,241                )242                guidance_scale = gr.Slider(243                    label="Guidance scale",244                    minimum=0.1,245                    maximum=10.0,246                    step=0.1,247                    value=5,248                )249                seed = gr.Slider(250                    label="Seed",251                    minimum=0,252                    maximum=MAX_SEED,253                    step=1,254                    value=0,255                )256                randomize_seed = gr.Checkbox(label="Randomize seed", value=True)257        with gr.Column():258            gallery = gr.Gallery(label="Generated Images")259            usage_tips = gr.Markdown(label="Usage tips of PhotoMaker", value=tips ,visible=False)260 261        files.upload(fn=swap_to_gallery, inputs=files, outputs=[uploaded_files, clear_button, files])262        remove_and_reupload.click(fn=remove_back_to_files, outputs=[uploaded_files, clear_button, files])263 264        submit.click(265            fn=remove_tips,266            outputs=usage_tips,            267        ).then(268            fn=randomize_seed_fn,269            inputs=[seed, randomize_seed],270            outputs=seed,271            queue=False,272            api_name=False,273        ).then(274            fn=generate_image,275            inputs=[files, prompt, negative_prompt, style, num_steps, style_strength_ratio, num_outputs, guidance_scale, seed],276            outputs=[gallery, usage_tips]277        )278 279    gr.Examples(280        examples=get_example(),281        inputs=[files, prompt, style, negative_prompt],282        run_on_click=True,283        fn=upload_example_to_gallery,284        outputs=[uploaded_files, clear_button, files],285    )286    287    gr.Markdown(article)288    289demo.launch()