图片生成,快到离谱!Qwen-Image-2.1-Turbo 官方无审查版 本地部署教程 + 实测|最强图片生成 AI 模型!

大家好,我是超哥。今天给大家分享 Qwen-Image-2.1-Turbo 图片 AI 模型的本地部署教程,相较于 Qwen-Image-2.1 原版,Turbo 版将生成步数从 40 步缩减至 8 步,大幅提升了图片生成速度。它集文生图和图像编辑于一体,除了高质量图片生成,还支持多图编辑、涂抹编辑、圈选编辑、Mask 编辑、透明 PNG 生成以及主体提取等功能。接下来我会带大家一步步完成模型的本地部署,并搭建网页操作界面,让我们可以直接在电脑本地使用 Qwen-Image-2.1-Turbo。下面我们开始教程。

提示:官方版就是无审查版,经过测试,可以生成任何图片,完全无审查、无限制!

博主电脑环境

显卡:NVIDIA RTX 4080 SUPER(16GB)

CPU:AMD R9 7900X 12-Core Processor(12核)

内存:64GB DDR5(3600 MHz)

Qwen-Image-2.1-Turbo 模型介绍:https://huggingface.co/Qwen/Qwen-Image-2.1-Turbo

一、安装基础环境

1. 安装python

下载地址:https://www.python.org/downloads/release/python-31210/

直达下载:https://www.python.org/ftp/python/3.12.10/python-3.12.10-amd64.exe

验证python是否安装成功,cmd里执行下面代码:

python --version

2. 安装git

下载地址:https://git-scm.com/install/windows

直达下载:https://github.com/git-for-windows/git/releases/download/v2.56.0.windows.2/Git-2.56.0.2-64-bit.exe

验证git是否安装成功,cmd里执行下面代码:

git --version

二、安装虚拟环境

1. 创建模型目录

在D盘创建目录:ImageAITurbo,创建后路径 D:\ImageAITurbo

2. 创建虚拟空间

cmd进入 D:\ImageAITurbo,执行下面命令,创建虚拟空间:

python -m venv qwen-env

输入下面命令,激活虚拟空间:

qwen-env\Scripts\activate

3. 升级 pip

升级 pip 命令:

python -m pip install --upgrade pip -i https://pypi.org/simple

或者(如果超时不成功):

python -m pip install --upgrade pip

4. 安装 CUDA 版 PyTorch

安装命令:

python -m pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128

检测命令:

python -c "import torch; print('CUDA:', torch.cuda.is_available()); print('CUDA版本:', torch.version.cuda); print('GPU:', torch.cuda.get_device_name(0) if torch.cuda.is_available() else '未检测到GPU')"

检测需要出现类似下面文字(一个人一个样):

CUDA: True

CUDA版本: 12.8

GPU: NVIDIA GeForce RTX 4080 SUPER

5. 安装DiffSynth-Studio

下载DiffSynth-Studio命令:

git clone https://github.com/modelscope/DiffSynth-Studio.git

进入DiffSynth-Studio命令:

cd DiffSynth-Studio

安装DiffSynth-Studio命令:

python -m pip install setuptools==81.0.0 -i https://pypi.org/simple

或者(如果超时不成功):

python -m pip install setuptools==81.0.0

然后执行命令:

python -m pip install -e . -i https://pypi.org/simple

或者(如果超时不成功):

python -m pip install -e .

三、下载 Qwen-Image-2.1-Turbo 模型

方法一、网盘下载地址

夸克网盘下载地址:https://pan.quark.cn/s/34d643165bef?pwd=vpJH

迅雷网盘下载地址:https://pan.xunlei.com/s/VP3a7i9wN-3nzqSWikPu7SAaA1?pwd=brnd

方法二、命令下载

Hugging Face 模型下载地址::https://huggingface.co/Qwen/Qwen-Image-2.1-Turbo/tree/main

1. cmd 进入 D:\ImageAITurbo 目录

2. 执行激活虚拟空间命令

qwen-env\Scripts\activate

3. 创建模型目录

执行命令:

mkdir Qwen-Image-2.1-Turbo

4. 安装 Hugging Face

安装命令:

python -m pip install -U huggingface_hub

5. Qwen-Image-2.1-Turbo 模型下载

下载命令:

hf download Qwen/Qwen-Image-2.1-Turbo --local-dir D:\ImageAITurbo\Qwen-Image-2.1-Turbo

四、DiffSynth-Studio 根目录配置启动文件

网盘下载文件

夸克网盘下载地址:https://pan.quark.cn/s/34d643165bef?pwd=vpJH

迅雷网盘下载地址:https://pan.xunlei.com/s/VP3a7i9wN-3nzqSWikPu7SAaA1?pwd=brnd

把2个启动文件放到 DiffSynth-Studio 文件夹里:

五. 安装 Windows 版 Triton

安装命令:

python -m pip install -U "triton-windows<3.7" -i https://pypi.org/simple

或者(如果超时不成功):

python -m pip install -U "triton-windows<3.7"

启动程序

双击 D:\ImageAITurbo\DiffSynth-Studio 目录下的 启动.bat ,启动程序

控制面板 URL:http://127.0.0.1:7860/

启动程序代码版(如果网盘无法下载)

1. 启动.bat 代码


@echo off
title Qwen-Image-2.1 XCHAOGE
cd /d "%~dp0"
call ..\qwen-env\Scripts\activate.bat
set "DIFFSYNTH_DISK_MAP_BUFFER_SIZE=1000000000000"
python web_ui.py
pause

2. web_ui.py 代码

import os

# Work around DiffSynth-Studio DiskMap mmap-handle invalidation on Windows.
# Must be set before importing diffsynth.
os.environ["DIFFSYNTH_DISK_MAP_BUFFER_SIZE"] = "1000000000000"

import glob
import json
import random
import threading
import webbrowser
import base64
import io
import traceback
import gc

from PIL import Image
from datetime import datetime
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import urlparse

import torch

os.environ["DIFFSYNTH_SKIP_DOWNLOAD"] = "True"

from diffsynth.pipelines.qwen_image_21 import QwenImage21Pipeline, ModelConfig


# ========================================
# 基本设置
# ========================================

MODEL_PATH = r"..\Qwen-Image-2.1-Turbo"
OUTPUT_DIR = os.path.join(MODEL_PATH, "output")

# Qwen-Image-2.1-Turbo 推荐采样配置(DiffSynth-Studio 文档)
# Turbo 使用 8 步采样、CFG=1.0,并显式传入专用 sigmas。
TURBO_STEPS = 8
TURBO_CFG_SCALE = 1.0
TURBO_SIGMAS = [
    1.0,
    0.978453,
    0.95418,
    0.926626,
    0.89508,
    0.845148,
    0.704534,
    0.414568,
]

HOST = "127.0.0.1"
PORT = 7860

os.makedirs(OUTPUT_DIR, exist_ok=True)


# ========================================
# 网页进度状态
# ========================================

last_generated_filename = ""

progress_state = {
    "active": False,
    "step": 0,
    "total": 0,
    "status": "等待生成",
    "error": ""
}


def web_progress_bar(iterable):
    total = len(iterable)
    progress_state["active"] = True
    progress_state["step"] = 0
    progress_state["total"] = total
    progress_state["status"] = "正在生成图片……"
    progress_state["error"] = ""

    for index, item in enumerate(iterable, 1):
        progress_state["step"] = index
        yield item


# ========================================
# 加载模型
# ========================================

# 使用 CPU 作为权重卸载位置,避免磁盘映射权重在第二次推理时出现
# "Attempted to access the data pointer on an invalid python storage"。
# 64GB 系统内存足以承载 CPU 卸载;计算仍在 CUDA 上进行。
vram_config = {
    # 恢复原版 DiffSynth-Studio 的磁盘卸载配置,避免启动阶段因设备配置不兼容而退出
    "offload_dtype": "disk",
    "offload_device": "disk",
    "onload_dtype": "disk",
    "onload_device": "disk",
    "preparing_dtype": torch.bfloat16,
    "preparing_device": "cuda",
    "computation_dtype": torch.bfloat16,
    "computation_device": "cuda",
}


print()
print("========================================")
print("      Qwen-Image-2.1-Turbo Web UI")
print("========================================")
print()
print("正在加载 Qwen-Image-2.1-Turbo,请稍候...")
print()


pipe = QwenImage21Pipeline.from_pretrained(
    torch_dtype=torch.bfloat16,
    device="cuda",

    model_configs=[
        ModelConfig(
            path=glob.glob(
                os.path.join(
                    MODEL_PATH,
                    "transformer",
                    "diffusion_pytorch_model*.safetensors"
                )
            ),
            **vram_config
        ),

        ModelConfig(
            path=glob.glob(
                os.path.join(
                    MODEL_PATH,
                    "text_encoder",
                    "model*.safetensors"
                )
            ),
            **vram_config
        ),

        ModelConfig(
            path=glob.glob(
                os.path.join(
                    MODEL_PATH,
                    "vae",
                    "diffusion_pytorch_model*.safetensors"
                )
            ),
            **vram_config
        ),
    ],

    processor_config=ModelConfig(
        path=os.path.join(MODEL_PATH, "processor")
    ),

    vram_limit=torch.cuda.mem_get_info("cuda")[1] / (1024 ** 3) - 0.5,
)


print()
print("Qwen-Image-2.1-Turbo 加载完成!")
print()


# 如果服务器重启,自动把最近一次 PNG 作为“继续创作”的上一张图片
try:
    _existing_outputs = sorted(
        [x for x in os.listdir(OUTPUT_DIR) if x.lower().endswith(".png")],
        reverse=True
    )
    if _existing_outputs:
        last_generated_filename = _existing_outputs[0]
except Exception:
    pass


# ========================================
# HTML 页面
# ========================================

HTML = r"""









Qwen-Image-2.1-Turbo








Qwen-Image-2.1-Turbo

本地 AI 文生图 · 图像编辑 · BY X超哥博客
普通文生图模式。
Qwen-Image-2.1-Turbo 原生支持从普通 RGB 图片提取主体并生成透明 RGBA 图层。
已选择 0 / 10 张
Mask 中白色区域表示需要编辑,黑色区域表示保留。网页会自动将 Mask 调整到原图尺寸。
会保留输入 PNG 的 Alpha 透明度,并将编辑结果重新套回原 Alpha。当前 DiffSynth 接口本身返回普通图像,因此这里采用“编辑后保留原透明层”的方式。
准备中……

生成结果

""" # ======================================== # HTTP Server # ======================================== class WebHandler(BaseHTTPRequestHandler): def send_text(self, content, status=200, content_type="text/html; charset=utf-8"): data = content.encode("utf-8") self.send_response(status) self.send_header( "Content-Type", content_type ) self.send_header( "Content-Length", str(len(data)) ) self.end_headers() self.wfile.write(data) def do_GET(self): path = urlparse(self.path).path if path == "/": self.send_text(HTML) return if path == "/progress": self.send_text( json.dumps( progress_state, ensure_ascii=False ), 200, "application/json; charset=utf-8" ) return if path == "/history": files = [] try: files = sorted( [x for x in os.listdir(OUTPUT_DIR) if x.lower().endswith(".png")], reverse=True )[:24] except Exception: files = [] self.send_text( json.dumps({"items": files}, ensure_ascii=False), 200, "application/json; charset=utf-8" ) return if path.startswith("/output/"): filename = os.path.basename(path) filepath = os.path.join( OUTPUT_DIR, filename ) if not os.path.isfile(filepath): self.send_response(404) self.end_headers() return with open(filepath, "rb") as f: data = f.read() self.send_response(200) self.send_header( "Content-Type", "image/png" ) self.send_header( "Content-Length", str(len(data)) ) self.end_headers() self.wfile.write(data) return self.send_response(404) self.end_headers() def do_POST(self): global last_generated_filename path = urlparse(self.path).path if path == "/open_folder": try: length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(length) data = json.loads(body.decode("utf-8")) filename = os.path.basename( str(data.get("filename", "")) ) if not filename: raise ValueError("图片文件名不能为空") filepath = os.path.join( OUTPUT_DIR, filename ) if not os.path.isfile(filepath): raise FileNotFoundError("图片文件不存在") os.startfile(os.path.dirname(filepath)) self.send_text( json.dumps( {"success": True}, ensure_ascii=False ), 200, "application/json; charset=utf-8" ) except Exception as e: self.send_text( json.dumps( { "success": False, "error": str(e) }, ensure_ascii=False ), 500, "application/json; charset=utf-8" ) return if path != "/generate": self.send_response(404) self.end_headers() return try: length = int(self.headers.get("Content-Length", 0)) body = self.rfile.read(length) data = json.loads(body.decode("utf-8")) # 每次新的生成请求到达后,立即重置服务器端进度状态。 # 这样第二次、第三次生成时,前端轮询不会先显示上一张的 100%。 progress_state["active"] = True progress_state["step"] = 0 progress_state["total"] = TURBO_STEPS progress_state["status"] = "正在准备模型……" progress_state["error"] = "" prompt = str(data.get("prompt", "")).strip() negative_prompt = str(data.get("negativePrompt", "")).strip() cfg_scale = TURBO_CFG_SCALE tiled_vae = bool(data.get("tiledVae", False)) width = int(data.get("width", 1024)) height = int(data.get("height", 1024)) steps = TURBO_STEPS seed = int(data.get("seed", -1)) mode = str(data.get("mode", "text")) edit_type = str(data.get("editType", "multi")) task_type = str(data.get("taskType", "normal")) image_data = data.get("images", []) continue_from_last = bool(data.get("continueFromLast", False)) output_transparent = bool(data.get("outputTransparent", False)) if not isinstance(image_data, list): image_data = [] if not prompt: raise ValueError("提示词不能为空") if mode == "text" and task_type == "extract" and len(image_data) != 1: raise ValueError("抠图模式需要 1 张原图") if mode == "text" and task_type == "fidelity" and not 1 <= len(image_data) <= 10: raise ValueError("高保真模式需要 1~10 张参考图片") if mode == "edit" and edit_type == "multi" and not 1 <= len(image_data) <= 10: raise ValueError("多图编辑需要 1~10 张参考图片") if mode == "edit" and edit_type in ("paint", "mask") and len(image_data) != 2: raise ValueError("局部编辑需要原图和 Mask 两张图片") if mode == "edit" and edit_type == "circle" and len(image_data) != 1: raise ValueError("圈选编辑需要 1 张标注图片") if mode == "edit" and edit_type == "alpha" and len(image_data) != 1: raise ValueError("透明图编辑需要 1 张 RGBA 图片") edit_images = [] for item in image_data: if not isinstance(item, str) or "," not in item: raise ValueError("参考图片数据无效") encoded = item.split(",", 1)[1] try: image_bytes = base64.b64decode(encoded) image = Image.open(io.BytesIO(image_bytes)) image.load() edit_images.append(image.convert("RGBA")) except Exception as e: raise ValueError("参考图片无法读取") from e if mode == "text" and task_type == "continue": if not last_generated_filename or not os.path.isfile(os.path.join(OUTPUT_DIR, last_generated_filename)): raise ValueError("没有可继续创作的上一张图片") previous = Image.open(os.path.join(OUTPUT_DIR, last_generated_filename)).convert("RGBA") edit_images = [previous] if mode == "edit" and edit_type == "mask": if edit_images[0].size != edit_images[1].size: edit_images[1] = edit_images[1].resize(edit_images[0].size, Image.Resampling.NEAREST) mask_gray = edit_images[1].convert("L") mask_gray = mask_gray.point(lambda p: 255 if p >= 128 else 0) edit_images[1] = Image.merge("RGBA", (mask_gray, mask_gray, mask_gray, Image.new("L", mask_gray.size, 255))) if mode == "edit" and edit_type in ("paint", "mask") and output_transparent: transparent_alpha = edit_images[1].getchannel("R") else: transparent_alpha = None original_alpha = edit_images[0].getchannel("A") if mode == "edit" and edit_type == "alpha" else None if seed < 0: seed = random.randint(0, 2147483647) width = max(256, round(width / 32) * 32) height = max(256, round(height / 32) * 32) print() print("========================================") print("开始生成图片") print(f"提示词:{prompt}") print(f"尺寸:{width} × {height}") print(f"Steps:{steps}") print(f"Seed:{seed}") print(f"模式:{'图像编辑' if mode == 'edit' else '文生图'}") if mode == "edit": print(f"编辑方式:{edit_type}") print(f"参考图片:{len(edit_images)} 张") print("========================================") final_prompt = prompt if mode == "text": task_prefix = { "transparent": "这是一个需要原生 Alpha 通道的透明 PNG 素材。请直接生成 RGBA 图像,背景必须是真正透明,不要生成棋盘格、白色背景或纯色背景。", "extract": "请从输入照片中提取指定主体,生成真正带 Alpha 通道的 RGBA 透明图层。删除背景,不要用白色或棋盘格代替透明。", "panorama": "请以宽幅全景构图生成,保证左右空间连续、透视自然、细节完整。", "infographic": "请按照信息图/海报设计进行构图,重视信息层级、排版、图形和中文文字清晰度。", "storyboard": "请按照故事板/连续分镜方式组织画面,保持角色、服装和视觉风格连续。", "fidelity": "请高度保持参考图中人物或产品的身份特征、外观、材质和关键细节。", "continue": "请基于上一张图片继续创作,只按照下面的新要求修改,尽可能保持未要求修改的内容一致。" } if task_type in task_prefix: final_prompt = task_prefix[task_type] + "\n" + prompt if mode == "edit": image = pipe(prompt=final_prompt, negative_prompt=negative_prompt, cfg_scale=cfg_scale, edit_image=edit_images, width=width, height=height, seed=seed, num_inference_steps=TURBO_STEPS, sigmas=TURBO_SIGMAS, tiled=tiled_vae, progress_bar_cmd=web_progress_bar) elif task_type in ("extract", "fidelity", "continue"): image = pipe(prompt=final_prompt, negative_prompt=negative_prompt, cfg_scale=cfg_scale, edit_image=edit_images, width=width, height=height, seed=seed, num_inference_steps=TURBO_STEPS, sigmas=TURBO_SIGMAS, tiled=tiled_vae, progress_bar_cmd=web_progress_bar) else: image = pipe(prompt=final_prompt, negative_prompt=negative_prompt, cfg_scale=cfg_scale, width=width, height=height, seed=seed, num_inference_steps=TURBO_STEPS, sigmas=TURBO_SIGMAS, tiled=tiled_vae, progress_bar_cmd=web_progress_bar) image = image.convert("RGBA") if mode == "edit" and edit_type == "mask" and transparent_alpha is not None: alpha = transparent_alpha.resize(image.size, Image.Resampling.NEAREST) image.putalpha(alpha) filename = datetime.now().strftime("%Y%m%d_%H%M%S_%f") + ".png" filepath = os.path.join(OUTPUT_DIR, filename) image.save(filepath, "PNG") # 清理本次输出对象及暂存显存,保留 pipe 以便连续生成多张图片。 del image if torch.cuda.is_available(): torch.cuda.empty_cache() print(f"生成完成:{filepath}") last_generated_filename = filename progress_state["active"] = False progress_state["step"] = progress_state["total"] progress_state["status"] = "生成完成" progress_state["error"] = "" note = "生成完成!" if task_type == "transparent": note = "生成完成:已按原生 RGBA Alpha 通道保存透明 PNG。" if task_type == "extract": note = "生成完成:已从原图提取主体并保存为透明 RGBA PNG。" if task_type == "continue": note = "生成完成:已基于上一张图片继续创作。" if mode == "edit" and edit_type == "alpha": note = "生成完成:已使用透明 PNG 作为原生编辑输入,并保留 RGBA 输出。" if transparent_alpha is not None: note = "生成完成,已按 Mask 输出透明 PNG。" result = {"success":True,"image":"/output/" + filename,"width":width,"height":height,"steps":steps,"seed":seed,"note":note} self.send_text( json.dumps( result, ensure_ascii=False ), 200, "application/json; charset=utf-8" ) except Exception as e: progress_state["active"] = False progress_state["status"] = "生成失败" progress_state["error"] = str(e) print() print("生成失败:") print(e) traceback.print_exc() gc.collect() if torch.cuda.is_available(): torch.cuda.empty_cache() result = { "success": False, "error": str(e) } self.send_text( json.dumps( result, ensure_ascii=False ), 500, "application/json; charset=utf-8" ) def log_message(self, format, *args): return # ======================================== # 启动服务器 # ======================================== def open_browser(): webbrowser.open( f"http://{HOST}:{PORT}" ) server = ThreadingHTTPServer( (HOST, PORT), WebHandler ) print() print("========================================") print("Web UI 已启动") print() print(f"http://{HOST}:{PORT}") print("========================================") print() print("按 Ctrl+C 可以停止服务器") print() threading.Timer( 1.5, open_browser ).start() try: server.serve_forever() except KeyboardInterrupt: print() print("正在关闭服务器……") server.shutdown()
感谢您的支持
支付宝
微信支付
感谢您的支持
支付宝收款二维码

打开支付宝扫描二维码(崔*杰)

感谢您的支持
微信支付收款二维码

打开微信扫描二维码(崔*杰)

上一篇比肩 Opus5.5、GPT-6 Astra!Qwen3.8-27B-Coder390 多模态 AI 模型本地部署+实测|接入 DeepSeek Harness 下一篇没有了
请我喝杯咖啡
如果喜欢本站的内容,欢迎请我喝杯咖啡
支付宝
微信支付
感谢你的支持
支付宝二维码
打开支付宝扫描二维码(崔*杰)
感谢你的支持
微信支付二维码
打开微信扫描二维码(崔*杰)