跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI算法

阿里开源 Z-Image-Turbo 本地 Docker 部署指南

介绍如何在本地使用 Docker 部署阿里开源的 Z-Image-Turbo 图像生成模型。内容包括环境准备、模型下载、FastAPI 后端服务构建、WebUI 前端开发以及镜像打包运行。通过配置 NVIDIA 显卡加速,实现本地化无水印图片生成,支持自定义提示词与参数调整,适合拥有 RTX 3090 等高性能显卡的用户进行离线推理部署。

星落发布于 2026/3/26更新于 2026/10/2415K 浏览
阿里开源 Z-Image-Turbo 本地 Docker 部署指南

环境准备

  1. 操作系统:Ubuntu 24.04
  2. 显卡:RTX 3090 (24G) 或同等性能 NVIDIA GPU
  3. 基础软件:已安装 Docker 并配置 nvidia-container-toolkit

模型获取

从官方仓库下载 Tongyi-MAI/Z-Image-Turbo 模型权重文件,并解压至服务器指定目录(例如 /data/models/Z-Image-Turbo)。

构建服务代码

1. 后端服务 (zimage_server.py)

新建 Python 文件,代码如下。可根据实际情况修改端口和分辨率。

import os
import torch
import base64
import logging
import uvicorn
from io import BytesIO
from contextlib import asynccontextmanager
from fastapi import FastAPI, Form, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from diffusers import DiffusionPipeline
from fastapi.responses import FileResponse

# --- 配置 ---
MODEL_PATH = "/data/models/Z-Image-Turbo"
HOST = "0.0.0.0"
PORT = 8000
DEVICE = "cuda"

# 日志配置
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
logger = logging.getLogger(__name__)
ml_models = {}

@asynccontextmanager
async def lifespan(app: FastAPI):
    logger.info(f"正在加载模型:{MODEL_PATH} ...")
    try:
        # --- 官方代码逻辑移植 1: 精度设置 ---
        # 官方建议使用 bfloat16 以获得最佳性能并防止黑图
        # 如果你的显卡比较旧(不支持 bfloat16),请改回 torch.float16
        dtype = torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16
        pipe = DiffusionPipeline.from_pretrained(
            MODEL_PATH,
            torch_dtype=dtype,
            use_safetensors=True
        )
        # 移动到 GPU
        pipe.to(DEVICE)
        # --- 官方代码逻辑移植 2: 内存优化 ---
        # 如果显存不够,取消下面这行的注释
        # pipe.enable_model_cpu_offload()
        ml_models["pipe"] = pipe
        logger.info(f">>> 模型加载成功 (Precision: {dtype})")
    except Exception as e:
        logger.error(f"模型加载失败:{e}")
        raise e
    yield
    ml_models.clear()
    if torch.cuda.is_available():
        torch.cuda.empty_cache()

app = FastAPI(lifespan=lifespan)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"]
)

@app.get("/")
async def index():
    return FileResponse("/workspace/index.html")

@app.post("/api/generate")
async def generate(prompt: str = Form(...)):
    if "pipe" not in ml_models:
        raise HTTPException(status_code=503, detail="Model not loaded")
    logger.info(f"收到任务:{prompt[:50]}...")
    try:
        pipe = ml_models["pipe"]
        # --- 官方代码逻辑移植 3: 关键推理参数 ---
        image = pipe(
            prompt=prompt,
            height=1024,      # 官方默认分辨率
            width=1024,
            num_inference_steps=9,  # 官方设置:Turbo 模型只需要很少的步数
            guidance_scale=0.0,     # 【核心修复】Turbo 模型必须设为 0,否则会黑图或乱码
            output_type="pil"
        ).images[0]
        buffer = BytesIO()
        image.save(buffer, format="PNG")
        base64_img = base64.b64encode(buffer.getvalue()).decode()
        return {"image": base64_img}
    except Exception as e:
        logger.error(f"生成出错:{e}")
        raise HTTPException(status_code=500, detail=str(e))

if __name__ == "__main__":
    uvicorn.run(app, host=HOST, port=PORT)

2. 前端页面 (index.html)

新建 HTML 文件,注意将 API 请求地址中的 IP 替换为实际服务器 IP。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Z-Image-Turbo WebUI</title>
    <style>
        :root {
            --primary-color: #4a90e2;
            --primary-hover: #357abd;
            --bg-color: #f5f7fa;
            --card-bg: #ffffff;
            --text-color: #333333;
            --border-radius: 12px;
            --shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
        }
        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            background-color: var(--bg-color);
            color: var(--text-color);
            margin: 0;
            min-height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }
        .container {
            background-color: var(--card-bg);
            padding: 40px;
            border-radius: var(--border-radius);
            box-shadow: var(--shadow);
            width: 100%;
            max-width: 550px;
            text-align: center;
            transition: transform 0.3s ease;
        }
        h2 {
            margin-top: 0;
            margin-bottom: 30px;
            color: #2c3e50;
            font-weight: 700;
            letter-spacing: -0.5px;
        }
        .input-group {
            margin-bottom: 25px;
            text-align: left;
        }
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #4a5568;
            font-size: 14px;
        }
        textarea {
            width: 100%;
            padding: 14px 16px;
            font-size: 16px;
            border: 2px solid #e2e8f0;
            border-radius: 8px;
            box-sizing: border-box;
            transition: all 0.3s ease;
            outline: none;
            background-color: #f8fafc;
            font-family: inherit;
            resize: none;
            min-height: 52px;
            overflow-y: hidden;
            line-height: 1.5;
        }
        textarea:focus {
            border-color: var(--primary-color);
            background-color: #fff;
            box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.1);
        }
        button {
            background-color: var(--primary-color);
            color: white;
            border: none;
            padding: 14px 30px;
            font-size: 16px;
            font-weight: 600;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.2s ease;
            width: 100%;
            box-shadow: 0 4px 6px rgba(74, 144, 226, 0.2);
        }
        button:hover {
            background-color: var(--primary-hover);
            transform: translateY(-1px);
            box-shadow: 0 6px 8px rgba(74, 144, 226, 0.3);
        }
        button:active {
            transform: translateY(0);
            box-shadow: 0 2px 4px rgba(74, 144, 226, 0.2);
        }
        button:disabled {
            background-color: #cbd5e0;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }
        .download-btn {
            background-color: #48bb78;
            margin-top: 15px;
            display: none; /* Hidden by default */
            box-shadow: 0 4px 6px rgba(72, 187, 120, 0.2);
        }
        .download-btn:hover {
            background-color: #38a169;
            box-shadow: 0 6px 8px rgba(72, 187, 120, 0.3);
        }
        .download-btn:active {
            box-shadow: 0 2px 4px rgba(72, 187, 120, 0.2);
        }
        #result {
            margin-top: 30px;
            min-height: 60px;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-direction: column;
        }
        img {
            max-width: 100%;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            animation: fadeIn 0.6s cubic-bezier(0.22, 1, 0.36, 1);
        }
        @keyframes fadeIn {
            from { opacity: 0; transform: translateY(10px) scale(0.98); }
            to { opacity: 1; transform: translateY(0) scale(1); }
        }
        .loading {
            display: inline-block;
            width: 30px;
            height: 30px;
            border: 3px solid #f3f3f3;
            border-top: 3px solid var(--primary-color);
            border-radius: 50%;
            animation: spin 1s linear infinite;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
        .error-message {
            color: #e53e3e;
            background: #fff5f5;
            padding: 12px 16px;
            border-radius: 8px;
            font-size: 14px;
            border: 1px solid #fed7d7;
            width: 100%;
            box-sizing: border-box;
        }
        .status-text {
            color: #718096;
            font-size: 14px;
            margin-top: 10px;
        }
    </style>
</head>
<body>
<div class="container">
    <h2>Z-Image-Turbo WebUI</h2>
    <div class="input-group">
        <label for="prompt">Prompt 提示词</label>
        <textarea id="prompt" placeholder="输入提示词,例如:a cat in the snow" rows="1"></textarea>
    </div>
    <button id="generateBtn" onclick="generate()">生成图片</button>
    <button id="downloadBtn" class="download-btn" onclick="downloadImage()">下载图片</button>
    <div id="result"></div>
</div>
<script>
// Auto-resize textarea
const promptInput = document.getElementById("prompt");
promptInput.addEventListener("input", function(){
    this.style.height = "auto";
    this.style.height = this.scrollHeight + "px";
});

async function generate(){
    const resultDiv = document.getElementById("result");
    const btn = document.getElementById("generateBtn");
    const downloadBtn = document.getElementById("downloadBtn");
    const prompt = promptInput.value.trim();
    if(!prompt){
        // Shake animation for empty input
        promptInput.style.borderColor = "#e53e3e";
        promptInput.focus();
        setTimeout(()=>{ promptInput.style.borderColor = ""; }, 2000);
        return;
    }
    // UI Loading State
    btn.disabled = true;
    downloadBtn.style.display = "none"; // Hide download button during generation
    btn.innerHTML = '<span></span> 生成中...';
    resultDiv.innerHTML = ""; // Clear previous result

    const formData = new FormData();
    formData.append("prompt", prompt);
    try{
        let resp = await fetch("http://IP:8000/api/generate", {
            method: "POST",
            body: formData,
        });
        if(!resp.ok){
            throw new Error(`HTTP error! status: ${resp.status}`);
        }
        let data = await resp.json();
        if(data.image){
            resultDiv.innerHTML = `<img src="data:image/png;base64,${data.image}" alt="Generated Image" />`;
            downloadBtn.style.display = "block"; // Show download button
        }else{
            throw new Error("No image data received");
        }
    }catch(error){
        console.error(error);
        resultDiv.innerHTML = `<div>生成失败:${error.message}</div>`;
    }finally{
        btn.disabled = false;
        btn.textContent = "生成图片";
    }
}

function downloadImage(){
    const img = document.querySelector("#result img");
    if(img){
        const a = document.createElement("a");
        a.href = img.src;
        a.download = `z-image-${Date.now()}.png`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
    }
}

// Allow Enter key to submit (Shift+Enter for new line)
promptInput.addEventListener("keydown", function(event){
    if(event.key === "Enter" && !event.shiftKey){
        event.preventDefault();
        generate();
    }
});
</script>
</body>
</html>

镜像构建与运行

1. 构建 Dockerfile

将上述两个文件放在与 Dockerfile 同一目录下。

Dockerfile 内容:

# 1. 基础镜像:改用 CUDA 12.4 (目前 PyTorch 支持最好的高版本)
# 即使物理机驱动是 CUDA 13,容器内用 CUDA 12.4 也是完全兼容的
FROM nvidia/cuda:13.0.1-runtime-ubuntu22.04

# 2. 环境变量设置
ENV DEBIAN_FRONTEND=noninteractive \
LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
PYTHONUNBUFFERED=1 \
# 显存优化参数
PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
# 设置默认模型路径,方便 Python 代码读取
MODEL_PATH=/data/models/Z-Image-Turbo

# 3. 安装系统依赖
# 增加了 git (pip 安装 git+... 需要) 和 curl
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3 python3-pip python3-venv \
    git build-essential wget curl ca-certificates \
    libgl1 libglib2.0-0 libsm6 libxrender1 libxext6 \
&& rm -rf /var/lib/apt/lists/*

# 4. 升级 pip
RUN python3 -m pip install --upgrade pip
WORKDIR /workspace

# 5. 安装 PyTorch (CUDA 13 版本)
# 这里使用了 cu130 的源,确保下载到支持 GPU 的版本
RUN pip install --no-cache-dir torch torchvision --index-url https://download.pytorch.org/whl/cu130

# 6. 安装 Diffusers 和相关 AI 依赖
# 补充了 sentencepiece 和 protobuf (Transformers 必须)
RUN pip install --no-cache-dir git+https://github.com/huggingface/diffusers.git
RUN pip install --no-cache-dir transformers accelerate safetensors modelscope sentencepiece protobuf

# 7. 安装 Web 服务依赖
RUN pip install --no-cache-dir fastapi "uvicorn[standard]" pillow aiofiles python-multipart

# 8. 复制代码文件
COPY zimage_server.py /workspace/zimage_server.py
# 如果你有 index.html 也复制进去,没有则注释掉
COPY index.html /workspace/index.html

# 9. 暴露端口
EXPOSE 8000

# 10. 启动命令
# 确保 host 是 0.0.0.0 才能被外部访问
CMD ["uvicorn", "zimage_server:app", "--host", "0.0.0.0", "--port", "8000"]

2. 构建镜像

docker build -t zimage-server:v1 .

3. 运行容器

使用以下命令运行。请根据实际路径修改挂载点。

docker run --gpus all -d \
  -p 8000:8000 \
  -v /data/models/Z-Image-Turbo:/data/models/Z-Image-Turbo \
  -v ./index.html:/workspace/index.html:ro \
  -v ./zimage_server.py:/workspace/zimage_server.py:ro \
  --name zimage-container \
  zimage-server:v1

4. 验证运行状态

查看日志确认模型加载成功:

docker logs -f zimage-container

使用 Web 界面生图

在浏览器访问 http://服务器 IP:8000,输入提示词即可生成图片。

示例提示词: 一张融合'写实质感 + 二次元画风 + 高级 CG 渲染'的《鬼灭之刃》主题海报。主体是一位站在画面中央的灶门炭治郎,保持原有动漫面部特征与配色,但皮肤、眼睛、发丝与纹理采用写实级 CG 材质表现。角色手持日轮刀,刀刃释放淡蓝色'水之呼吸'CG 能量特效,能量呈流体状发光纹路,带有轻微粒子散射效果。他脚下是一块从雾气弥漫的浅水水面中浮出的深色湿润板岩,倒影清晰、略带二次元柔光边缘。光照与氛围(写实光影 + 动漫色调):金黄清晨体积光穿透森林树叶倾泻而下,形成真实物理感十足的体积雾与丁达尔效应,同时保留二次元式干净、高对比的光影边缘。斑驳的光斑落在炭治郎的脸部、刀刃与衣褶上,使写实材质与动漫色块互相融合。刀刃能量在水面上形成微光焦散 Caustics,与周围冷色雾气形成强烈视觉对比,制造史诗感。细节与材质(写实纹理 × 二次元线条):写实但带柔化处理的角色皮肤、精致的眼部渲染、半写实发丝质感。额头伤痕、耳饰与日轮刀纹路清晰,既保留原动画设计,又加入微微的金属反射与磨损细节。服装布料带有真实褶皱纹理,但边缘保留柔和的二次元描线。板岩湿润且带有微苔纹理,水面拥有真实反射与轻微折射,同时保持略微卡通化的干净色彩。背景灰烬微粒与落花片呈 CG 粒子效果,略带景深虚化。技术规格(CG 渲染 + 动漫视觉):采用虚幻引擎 5 超写实 CG 渲染风格混合高饱和、干净色块的二次元调色。8K 画质,面部与刀刃 Logo 区域超高清对焦。电影级光线追踪、漫反射 + 高光双层材质处理。动漫式色彩分级(高对比、清晰色层)与写实 CG 高动态范围光照融合。整体呈现电影海报级质感、CG 角色精度和动漫角色辨识度。

目录

  1. 环境准备
  2. 模型获取
  3. 构建服务代码
  4. 1. 后端服务 (zimage_server.py)
  5. --- 配置 ---
  6. 日志配置
  7. 2. 前端页面 (index.html)
  8. 镜像构建与运行
  9. 1. 构建 Dockerfile
  10. 1. 基础镜像:改用 CUDA 12.4 (目前 PyTorch 支持最好的高版本)
  11. 即使物理机驱动是 CUDA 13,容器内用 CUDA 12.4 也是完全兼容的
  12. 2. 环境变量设置
  13. 显存优化参数
  14. 设置默认模型路径,方便 Python 代码读取
  15. 3. 安装系统依赖
  16. 增加了 git (pip 安装 git+... 需要) 和 curl
  17. 4. 升级 pip
  18. 5. 安装 PyTorch (CUDA 13 版本)
  19. 这里使用了 cu130 的源,确保下载到支持 GPU 的版本
  20. 6. 安装 Diffusers 和相关 AI 依赖
  21. 补充了 sentencepiece 和 protobuf (Transformers 必须)
  22. 7. 安装 Web 服务依赖
  23. 8. 复制代码文件
  24. 如果你有 index.html 也复制进去,没有则注释掉
  25. 9. 暴露端口
  26. 10. 启动命令
  27. 确保 host 是 0.0.0.0 才能被外部访问
  28. 2. 构建镜像
  29. 3. 运行容器
  30. 4. 验证运行状态
  31. 使用 Web 界面生图

更多推荐文章

查看全部
  • Python 文件操作深度解析与避坑指南
  • PojavLauncher iOS 使用指南:在 iPhone 和 iPad 上运行 Minecraft Java 版
  • 大疆无人机五种反制手段实测:干扰枪与激光武器效果对比
  • 大模型训练流水线并行(PP)性能评价指标与分析方法
  • 知网 AIGC 检测算法 2026 升级:新规则解读与应对策略
  • Windows 本地部署 OpenClaw 接入飞书机器人配置
  • Linux 进程间通信进阶:管道与共享内存实战
  • 5 步实现 ESP32 无人机合规识别:ArduRemoteID 开源方案详解
  • Ollama v0.17.0 更新:OpenClaw 自动安装、Web 搜索与 Tokenizer 性能优化
  • PCL点云处理算法全解析
  • Stable Diffusion 陶瓷风艺术写真实战:InstantID 插件整合指南
  • 大模型基础:架构、微调与工程应用指南
  • 精选 GitHub 开源量化交易系统与工具推荐
  • Anthropic AI Agent 构建最佳实践与核心范式解析
  • 学生成绩管理系统:从需求分析到代码落地实战
  • 离散化与线段树解决机器人摧毁墙壁问题
  • Linux C++ 多进程编程:fork 函数与进程管理机制
  • OkHttp3 网络请求中的代理选择与路由策略详解
  • 国家精品公开课:Python 网络爬虫与数据分析实战
  • 2024 AI 大模型面试常见问题与答案解析

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online