Buckets:

hf-doc-build/doc / diffusers /v0.43.0 /es /optimization /tensor_parallelism.html
mishig's picture
download
raw
39.2 kB
<meta charset="utf-8" /><meta name="hf:doc:metadata" content="{&quot;title&quot;:&quot;Paralelismo de tensores&quot;,&quot;local&quot;:&quot;tensor-parallelism&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;Cargar un modelo fragmentado&quot;,&quot;local&quot;:&quot;load-a-sharded-model&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Rendimiento de carga&quot;,&quot;local&quot;:&quot;loading-performance&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Limitaciones&quot;,&quot;local&quot;:&quot;limitations&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Añadir paralelismo de tensores a un modelo&quot;,&quot;local&quot;:&quot;add-tensor-parallelism-to-a-model&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;Colwise y rowwise&quot;,&quot;local&quot;:&quot;colwise-and-rowwise&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;Proyecciones fusionadas&quot;,&quot;local&quot;:&quot;fused-projections&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;Qué dejar fuera&quot;,&quot;local&quot;:&quot;what-to-leave-out&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;Restricciones y verificación&quot;,&quot;local&quot;:&quot;constraints-and-verification&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2}],&quot;depth&quot;:1}"/>
<link href="/docs/diffusers/main/en/_app/immutable/entry/start.0S0_iEoG.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/chunks/I9eooN77.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/chunks/Bupkjr9f.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/entry/app.CPdOxCbw.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/chunks/CyvZ3FS5.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/chunks/l0QnnOED.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/chunks/DnVIJfC5.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/chunks/DsnmJJEf.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/nodes/0.DteTvmQZ.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/chunks/CoSrdQax.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/nodes/347.DnqzUbRP.js" rel="modulepreload">
<link href="/docs/diffusers/main/en/_app/immutable/chunks/DSPDl1gz.js" rel="modulepreload">
<!--17gkrup--><meta name="hf:doc:metadata" content="{&quot;title&quot;:&quot;Tensor parallelism&quot;,&quot;local&quot;:&quot;tensor-parallelism&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;Load a sharded model&quot;,&quot;local&quot;:&quot;load-a-sharded-model&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Loading performance&quot;,&quot;local&quot;:&quot;loading-performance&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Limitations&quot;,&quot;local&quot;:&quot;limitations&quot;,&quot;sections&quot;:[],&quot;depth&quot;:2},{&quot;title&quot;:&quot;Add tensor parallelism to a model&quot;,&quot;local&quot;:&quot;add-tensor-parallelism-to-a-model&quot;,&quot;sections&quot;:[{&quot;title&quot;:&quot;Colwise and rowwise&quot;,&quot;local&quot;:&quot;colwise-and-rowwise&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;Fused projections&quot;,&quot;local&quot;:&quot;fused-projections&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;What to leave out&quot;,&quot;local&quot;:&quot;what-to-leave-out&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3},{&quot;title&quot;:&quot;Constraints and verification&quot;,&quot;local&quot;:&quot;constraints-and-verification&quot;,&quot;sections&quot;:[],&quot;depth&quot;:3}],&quot;depth&quot;:2}],&quot;depth&quot;:1}"/><!---->
<link href="/docs/diffusers/main/en/_app/immutable/assets/0.tn0RQdqM.css" rel="modulepreload"> <!--[--><!--[0--><!--[--><!--[0--><!--[--><p></p> <div class="items-center shrink-0 min-w-[100px] max-sm:min-w-[50px] justify-end ml-auto flex" style="float: inline-end; margin-inline-start: 10px; display: inline-flex; position: relative; z-index: 10;"><div dir="ltr" class="inline-flex rounded-md max-sm:rounded-sm"><button class="inline-flex items-center gap-1 h-7 max-sm:h-7 px-2 max-sm:px-1.5 text-sm font-medium text-gray-800 border border-r-0 rounded-l-md max-sm:rounded-l-sm border-gray-200 bg-white hover:shadow-inner dark:border-gray-850 dark:bg-gray-950 dark:text-gray-200 dark:hover:bg-gray-800" aria-live="polite"><span class="inline-flex items-center justify-center rounded-md p-0.5 max-sm:p-0 hover:text-gray-800 dark:hover:text-gray-200"><svg class="sm:size-3.5 size-3" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----></span> <span dir="auto">Copy page</span></button> <button class="inline-flex items-center justify-center w-6 max-sm:w-5 h-7 max-sm:h-7 disabled:pointer-events-none text-sm text-gray-500 hover:text-gray-700 dark:hover:text-white rounded-r-md max-sm:rounded-r-sm border border-l transition border-gray-200 bg-white hover:shadow-inner dark:border-gray-850 dark:bg-gray-950 dark:text-gray-200 dark:hover:bg-gray-800" aria-haspopup="menu" aria-expanded="false" aria-label="Open copy menu"><svg class="transition-transform text-gray-400 overflow-visible sm:size-3.5 size-3 rotate-0" width="1em" height="1em" viewBox="0 0 12 7" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1 1L6 6L11 1" stroke="currentColor"></path></svg><!----></button></div> <!--[-1--><!--]--></div><!----> <!--[0--><h1 class="relative group"><a id="tensor-parallelism" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#tensor-parallelism"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span><!---->Paralelismo de tensores<!----></span></h1><!--]--><!----> <p><a href="https://huggingface.co/spaces/nanotron/ultrascale-playbook?section=tensor_parallelism" rel="nofollow">Tensor parallelism</a> distribuye las matrices de pesos de un modelo entre varios dispositivos. Cada dispositivo mantiene una porción por columnas (<code>"colwise"</code>) o por filas (<code>"rowwise"</code>) de cada capa y calcula un resultado parcial. Un <code>AllReduce</code> o <code>AllGather</code> en el límite de la capa combina los resultados parciales para obtener la salida completa. A diferencia de <a href="./context_parallelism">context parallelism</a>, reduce la memoria de <em>weight</em> por dispositivo, lo cual es útil cuando un modelo no cabe en un solo dispositivo. Consulte <a href="../training/distributed_inference">Distributed inference</a> para compararlo con las demás estrategias.</p> <!--[1--><h2 class="relative group"><a id="load-a-sharded-model" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#load-a-sharded-model"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span><!---->Cargar un modelo fragmentado<!----></span></h2><!--]--><!----> <p>Pase un <a href="/docs/diffusers/v0.43.0/es/api/parallel#diffusers.TensorParallelConfig">TensorParallelConfig</a> al argumento <code>parallel_config</code> de <a href="/docs/diffusers/v0.43.0/es/api/models/overview#diffusers.ModelMixin.from_pretrained">from_pretrained()</a> del modelo. <code>tp_degree</code> es el número de dispositivos en los que se dividirá el modelo y debe dividir el número de cabezas de atención del modelo. La clase del modelo debe definir un <code>_tp_plan</code>, que mapea los nombres de los módulos a un estilo de partición. Para comprobar si un modelo admite la paralelización de tensores, busque este atributo en su clase, como <a href="/docs/diffusers/v0.43.0/es/api/models/flux2_transformer#diffusers.Flux2Transformer2DModel">Flux2Transformer2DModel</a>.</p> <p>Para añadir un plan a otro modelo, consulte <a href="#add-tensor-parallelism-to-a-model">Añadir paralelismo de tensores a un modelo</a>.</p> <p>Al cargar de esta manera, el checkpoint se fragmenta a medida que se lee. Cada rank lee solo su propia porción de cada peso y la coloca directamente en su GPU, por lo que ningún rank mantiene un peso de tamaño completo. La memoria por rank disminuye a medida que aumenta <code>tp_degree</code>.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copiado</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> torch
<span class="hljs-keyword">from</span> torch <span class="hljs-keyword">import</span> distributed <span class="hljs-keyword">as</span> dist
<span class="hljs-keyword">from</span> diffusers <span class="hljs-keyword">import</span> DiffusionPipeline, Flux2Transformer2DModel, TensorParallelConfig
<span class="hljs-keyword">def</span> <span class="hljs-title function_">main</span>():
dist.init_process_group(backend=<span class="hljs-string">&quot;nccl&quot;</span>)
rank, world_size = dist.get_rank(), dist.get_world_size()
<span class="hljs-comment"># torchrun sets LOCAL_RANK to this process&#x27;s GPU index on its node</span>
local_rank = <span class="hljs-built_in">int</span>(os.environ[<span class="hljs-string">&quot;LOCAL_RANK&quot;</span>])
device = torch.device(<span class="hljs-string">f&quot;cuda:<span class="hljs-subst">{local_rank}</span>&quot;</span>)
torch.cuda.set_device(device)
<span class="hljs-comment"># Each rank reads only its own shard of every planned weight, straight onto its own GPU.</span>
transformer = Flux2Transformer2DModel.from_pretrained(
<span class="hljs-string">&quot;black-forest-labs/FLUX.2-dev&quot;</span>,
subfolder=<span class="hljs-string">&quot;transformer&quot;</span>,
dtype=torch.bfloat16,
parallel_config=TensorParallelConfig(tp_degree=world_size),
)
pipeline = DiffusionPipeline.from_pretrained(
<span class="hljs-string">&quot;black-forest-labs/FLUX.2-dev&quot;</span>, transformer=transformer, dtype=torch.bfloat16
)
<span class="hljs-comment"># The transformer is already on its device; move the remaining components individually. Do not call</span>
<span class="hljs-comment"># `pipeline.to(device)` — that would move every rank&#x27;s shards onto the same device.</span>
pipeline.text_encoder.to(device)
pipeline.vae.to(device)
generator = torch.Generator().manual_seed(<span class="hljs-number">42</span>)
image = pipeline(prompt=<span class="hljs-string">&quot;a cat holding a sign that says hello&quot;</span>, generator=generator).images[<span class="hljs-number">0</span>]
<span class="hljs-keyword">if</span> rank == <span class="hljs-number">0</span>:
image.save(<span class="hljs-string">&quot;output.png&quot;</span>)
dist.destroy_process_group()
<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">&quot;__main__&quot;</span>:
main()<!----></pre></div><!----> <p>Guarde el script como <code>tensor_parallel_flux2.py</code> y ejecútelo con <code>torchrun</code>.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copiado</div><!----></button><!----></div> <pre class="language-shell "><!---->torchrun --nproc-per-node 4 tensor_parallel_flux2.py<!----></pre></div><!----> <p>El script establece <code>tp_degree</code> en <code>world_size</code>, por lo que <code>--nproc-per-node 4</code> divide el transformer en 4 GPUs.</p> <p>Solo el transformer se fragmenta. Cada rank mantiene una copia completa del codificador de texto, por lo que cada GPU necesita suficiente memoria para el codificador de texto más su parte del transformer.</p> <!--[1--><h2 class="relative group"><a id="loading-performance" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#loading-performance"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span><!---->Rendimiento de carga<!----></span></h2><!--]--><!----> <p>Cargar con <code>parallel_config</code> es más rápido y utiliza menos memoria de CPU por rank que cargar el modelo completo y luego llamar a <code>enable_parallelism()</code>. La tabla siguiente muestra los resultados para <a href="https://huggingface.co/black-forest-labs/FLUX.2-dev" rel="nofollow">black-forest-labs/FLUX.2-dev</a> (solo el transformer, 32B parámetros, bf16) en 4x A10G (23GB).</p> <table><thead><tr><th>tp_degree</th><th>método</th><th>tiempo de carga</th><th>CPU pico/rango</th></tr></thead><tbody><tr><td>4</td><td><code>from_pretrained(parallel_config=...)</code></td><td>12.5s</td><td>6.8GB</td></tr><tr><td>4</td><td><code>from_pretrained</code> + <code>enable_parallelism</code></td><td>30.4s</td><td>64.1GB</td></tr></tbody></table> <!--[1--><h2 class="relative group"><a id="limitations" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#limitations"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span><!---->Limitaciones<!----></span></h2><!--]--><!----> <p>La paralelización de tensores no funciona con algunas opciones y funciones de carga, y no se puede guardar un modelo fragmentado.</p> <ul><li>Cargar con una <code>parallel_config</code> de paralelismo de tensores no funciona con <code>device_map</code>, <code>quantization_config</code>, <code>low_cpu_mem_usage=False</code>, <code>use_flashpack=True</code> o pesos que no sean de safetensors. Cada uno de estos parámetros genera un error en lugar de cargar silenciosamente el punto de control completo.</li> <li>Combinar el paralelismo de tensores con cuantización, offloading o adaptadores LoRA también genera un error, sin importar cómo se fragmente el modelo.</li> <li>Para fragmentar un modelo que ya está en memoria, llama a <code>enable_parallelism()</code> con la misma configuración. Primero carga el modelo completo y luego lo fragmenta, por lo que cada rank necesita memoria para el checkpoint completo. Cargar con <code>parallel_config</code> evita ese coste.</li> <li>Guardar un modelo de paralelismo de tensores genera un error en <a href="/docs/diffusers/v0.43.0/es/api/models/overview#diffusers.ModelMixin.save_pretrained">save_pretrained()</a>. Guarda el modelo antes de dividirlo.</li></ul> <!--[1--><h2 class="relative group"><a id="add-tensor-parallelism-to-a-model" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#add-tensor-parallelism-to-a-model"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span><!---->Añadir paralelismo de tensores a un modelo<!----></span></h2><!--]--><!----> <p>Esta sección está dirigida a los colaboradores que deseen agregar soporte para paralelismo de tensores a un modelo de Diffusers.</p> <p>La paralelización de tensores solo funciona en modelos que definen un <code>_tp_plan</code>, un atributo de clase que asigna nombres de módulos a un estilo de particionamiento. Escribir uno consiste principalmente en emparejar cada proyección que <em>expande</em> la dimensión oculta con la proyección que la <em>contrae</em> de nuevo.</p> <p>Cada clave puede contener como máximo un <code>*</code>, y la parte anterior al <code>*</code> debe resolverse a un <a href="https://pytorch.org/docs/stable/generated/torch.nn.ModuleList.html" rel="nofollow"><code>nn.ModuleList</code></a>, de modo que una entrada cubra todos los bloques. Una clave sin <code>*</code> se aplica al propio modelo. Las rutas son relativas al modelo.</p> <!--[2--><h3 class="relative group"><a id="colwise-and-rowwise" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#colwise-and-rowwise"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span><!---->Colwise y rowwise<!----></span></h3><!--]--><!----> <table><thead><tr><th>Estilo</th><th>Fragmentos</th><th>Cada rango</th><th>Uso</th></tr></thead><tbody><tr><td><code>"colwise"</code></td><td>características de salida (dimensión 0 de <code>weight</code>)</td><td>calcula una porción de la salida</td><td><code>to_q</code>, <code>to_k</code>, <code>to_v</code>, proyección de entrada del FFN</td></tr><tr><td><code>"rowwise"</code></td><td>características de entrada (dimensión 1 de <code>weight</code>)</td><td>calcula una suma parcial</td><td><code>to_out.0</code>, proyección de salida del FFN</td></tr><tr><td><code>"rowwise_split_input"</code></td><td>características de entrada (dimensión 1 de <code>weight</code>)</td><td>calcula una suma parcial a partir de su porción de la entrada replicada</td><td>una proyección independiente cuya entrada está replicada, como una proyección de modulación AdaLN que lee el embedding del timestep</td></tr></tbody></table> <p>Acompáñe siempre <code>"colwise"</code> y <code>"rowwise"</code> en ese orden. Una proyección <code>"colwise"</code> deja su salida fragmentada, la proyección <code>"rowwise"</code> siguiente consume ese fragmento directamente y un único <code>AllReduce</code> en el límite del bloque reconstruye el resultado. Fragmentar el par de cualquier otra forma obliga a hacer un gather en el medio y comunica mucho más.</p> <p>En la atención, las proyecciones columnales de Q, K y V asignan a cada rango un subconjunto de cabezas, por lo que <code>tp_degree</code> debe dividir el número de cabezas. Los duplicados del flujo del codificador (<code>add_q_proj</code>, <code>to_add_out</code>, <code>ff_context</code>) siguen el mismo patrón que sus equivalentes en el flujo de imagen.</p> <!--[2--><h3 class="relative group"><a id="fused-projections" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#fused-projections"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span><!---->Proyecciones fusionadas<!----></span></h3><!--]--><!----> <p>Cuando un <code>Linear</code> empaqueta varios tensores lógicos a lo largo de la dimensión que se fragmenta, las rebanadas simples <code>"colwise"</code>/<code>"rowwise"</code> cortan directamente a través de la concatenación y desalinean las piezas. En su lugar, usa <code>PackedColwiseParallel</code>/<code>PackedRowwiseParallel</code>, que fragmenta cada bloque empaquetado de forma independiente.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copiado</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-comment"># in src/diffusers/models/transformers/your_model.py</span>
<span class="hljs-keyword">from</span> ...hooks.tensor_parallel <span class="hljs-keyword">import</span> PackedColwiseParallel, PackedRowwiseParallel<!----></pre></div><!----> <p>Pase <code>blocks</code>, una lista de enteros proporcionales cuya suma divide la dimensión empaquetada. Por ejemplo, use <code>[1, 1]</code> para una proyección de puerta y una de subida de SwiGLU de mitades iguales, o <code>[1, 1, 1, 3, 3]</code> para una proyección fusionada de Q, K, V, puerta y subida con <code>mlp_ratio=3</code>.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copiado</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-string">&quot;transformer_blocks.*.ff.linear_in&quot;</span>: PackedColwiseParallel([<span class="hljs-number">1</span>, <span class="hljs-number">1</span>]),<!----></pre></div><!----> <p>Cuando los tamaños de los bloques solo se conocen desde la configuración, omita <code>blocks</code> y almacene los tamaños absolutos en <code>Linear</code> durante <code>__init__</code> en su lugar, como <code>_tp_packed_col_blocks</code> o <code>_tp_packed_row_blocks</code>.</p> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copiado</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-comment"># in the attention module&#x27;s __init__</span>
<span class="hljs-variable language_">self</span>.to_out._tp_packed_row_blocks = [<span class="hljs-variable language_">self</span>.inner_dim, <span class="hljs-variable language_">self</span>.mlp_hidden_dim]<!----></pre></div><!----> <div class="code-block relative "><div class="absolute top-2.5 right-4"><button class="inline-flex items-center relative text-sm focus:text-green-500 cursor-pointer focus:outline-none transition duration-200 ease-in-out opacity-0 mx-0.5 text-gray-600 " title="code excerpt" type="button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M28,10V28H10V10H28m0-2H10a2,2,0,0,0-2,2V28a2,2,0,0,0,2,2H28a2,2,0,0,0,2-2V10a2,2,0,0,0-2-2Z" transform="translate(0)"></path><path d="M4,18H2V4A2,2,0,0,1,4,2H18V4H4Z" transform="translate(0)"></path><rect fill="none" width="32" height="32"></rect></svg><!----> <div class=" absolute pointer-events-none transition-opacity bg-black text-white py-1 px-2 leading-tight rounded font-normal shadow left-1/2 top-full transform -translate-x-1/2 translate-y-2 opacity-0 "><div class="absolute bottom-full left-1/2 transform -translate-x-1/2 w-0 h-0 border-black border-4 border-t-0" style="border-left-color: transparent; border-right-color: transparent;"></div> Copiado</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-comment"># in the model&#x27;s _tp_plan</span>
<span class="hljs-string">&quot;single_transformer_blocks.*.attn.to_out&quot;</span>: PackedRowwiseParallel(),<!----></pre></div><!----> <p>El plan en <a href="https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/transformers/transformer_flux2.py" rel="nofollow"><code>transformer_flux2.py</code></a> utiliza ambas formas. El par SwiGLU de doble flujo pasa <code>blocks</code> directamente. La proyección QKV y MLP de flujo único fusionada almacena sus tamaños en el <code>Linear</code> dentro de <code>Flux2ParallelSelfAttention.__init__</code>, ya que dependen de <code>mlp_ratio</code> y <code>mlp_mult_factor</code>.</p> <!--[2--><h3 class="relative group"><a id="what-to-leave-out" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#what-to-leave-out"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span><!---->Qué dejar fuera<!----></span></h3><!--]--><!----> <p>Los módulos que se dejan fuera del plan se replican en cada rank. Deje fuera las capas de normalización, las incrustaciones de parche y de texto, y las capas finales <code>norm_out</code> y <code>proj_out</code>. Son pequeñas, por lo que fragmentarlas ahorra poca memoria y añade comunicación. La modulación AdaLN (<code>img_mod</code> y <code>txt_mod</code>) suele ser lo suficientemente pequeña para dejarla fuera también. Cuando es grande, como <code>adaln_proj.linear</code> de MiniMax-H3, frágméntela con <code>"rowwise_split_input"</code>.</p> <!--[2--><h3 class="relative group"><a id="constraints-and-verification" class="header-link block pr-1.5 text-lg no-hover:hidden with-hover:absolute with-hover:p-1.5 with-hover:opacity-0 with-hover:group-hover:opacity-100 with-hover:right-full" href="#constraints-and-verification"><span><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 256"><path d="M167.594 88.393a8.001 8.001 0 0 1 0 11.314l-67.882 67.882a8 8 0 1 1-11.314-11.315l67.882-67.881a8.003 8.003 0 0 1 11.314 0zm-28.287 84.86l-28.284 28.284a40 40 0 0 1-56.567-56.567l28.284-28.284a8 8 0 0 0-11.315-11.315l-28.284 28.284a56 56 0 0 0 79.196 79.197l28.285-28.285a8 8 0 1 0-11.315-11.314zM212.852 43.14a56.002 56.002 0 0 0-79.196 0l-28.284 28.284a8 8 0 1 0 11.314 11.314l28.284-28.284a40 40 0 0 1 56.568 56.567l-28.285 28.285a8 8 0 0 0 11.315 11.314l28.284-28.284a56.065 56.065 0 0 0 0-79.196z" fill="currentColor"></path></svg><!----></span></a> <span><!---->Restricciones y verificación<!----></span></h3><!--]--><!----> <ul><li><code>tp_degree</code> debe dividir a <code>config.num_attention_heads</code>.</li> <li>Cada bloque empaquetado debe ser divisible <em>individualmente</em> por <code>tp_degree</code>, no solo su suma.</li></ul> <p><a href="/docs/diffusers/v0.43.0/es/api/models/overview#diffusers.ModelMixin.from_pretrained">from_pretrained()</a> y <code>enable_parallelism()</code> verifican ambas cosas antes de cargar o dividir cualquier peso.</p> <p>Valide un nuevo plan numéricamente en lugar de a simple vista: genere con una semilla fija en un solo dispositivo y luego bajo paralelismo de tensores, y compare las salidas. Un <code>"colwise"</code>/<code>"rowwise"</code> mal colocado suele ejecutarse y producir una imagen plausible pero incorrecta.</p> <blockquote class="tip"><p>Comience con un plan existente para una arquitectura similar.</p> <ul><li><a href="https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/transformers/transformer_qwenimage.py" rel="nofollow"><code>transformer_qwenimage.py</code></a> no tiene proyecciones fusionadas, por lo que cada entrada es simplemente <code>"colwise"</code> o <code>"rowwise"</code>.</li> <li><a href="https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/transformers/transformer_flux.py" rel="nofollow"><code>transformer_flux.py</code></a> añade una proyección empaquetada por filas.</li> <li><a href="https://github.com/huggingface/diffusers/blob/main/src/diffusers/models/transformers/transformer_flux2.py" rel="nofollow"><code>transformer_flux2.py</code></a> utiliza ambos estilos empaquetados.</li></ul></blockquote> <a class="!text-gray-400 !no-underline text-sm flex items-center not-prose mt-4" href="https://github.com/huggingface/diffusers/blob/main/docs/source/en/optimization/tensor_parallelism.md" target="_blank"><svg class="mr-1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" fill="currentColor" focusable="false" role="img" width="1em" height="1em" preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32"><path d="M31,16l-7,7l-1.41-1.41L28.17,16l-5.58-5.59L24,9l7,7z"></path><path d="M1,16l7-7l1.41,1.41L3.83,16l5.58,5.59L8,23l-7-7z"></path><path d="M12.419,25.484L17.639,6.552l1.932,0.518L14.351,26.002z"></path></svg><!----> <span><span class="underline">Update</span> on GitHub</span></a><!----> <p></p><!--]--><!----><!--]--><!--]--><!--]--> <!--[-1--><!--]--><!--]-->
<script>
{
__sveltekit_1qsdbwf = {
base: "/docs/diffusers/main/en",
assets: "/docs/diffusers/main/en"
};
const element = document.currentScript.parentElement;
Promise.all([
import("/docs/diffusers/main/en/_app/immutable/entry/start.0S0_iEoG.js"),
import("/docs/diffusers/main/en/_app/immutable/entry/app.CPdOxCbw.js")
]).then(([kit, app]) => {
kit.start(app, element, {
node_ids: [0, 347],
data: [null,null],
form: null,
error: null
});
});
}
</script>

Xet Storage Details

Size:
39.2 kB
·
Xet hash:
5ea4fa9973fe187d2b2d4226ca2050ee34bf6a25d0c6f9d7b85f3560a902c390

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.