Buckets:
| <meta charset="utf-8" /><meta name="hf:doc:metadata" content="{"title":"IterativePipelineBlocks","local":"iterativepipelineblocks","sections":[{"title":"Loop steps","local":"loop-steps","sections":[],"depth":2},{"title":"Loop wrapper","local":"loop-wrapper","sections":[],"depth":2},{"title":"Nesting loops","local":"nesting-loops","sections":[],"depth":2},{"title":"Streaming","local":"streaming","sections":[],"depth":2},{"title":"LoopSequentialPipelineBlocks","local":"loopsequentialpipelineblocks","sections":[],"depth":2}],"depth":1}"/> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/entry/start.CQi6m7Bo.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/chunks/yuZJWuex.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/chunks/jDjavuwI.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/entry/app.B0IgqLyE.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/chunks/CMF6C6Mt.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/chunks/g6hU78NK.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/chunks/DsnmJJEf.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/chunks/i0LL_sTA.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/nodes/0.B-yJr4fO.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/chunks/9Uo8d8lw.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/nodes/279.C-enSSll.js" rel="modulepreload"> | |
| <link href="/docs/diffusers/pr_14159/en/_app/immutable/chunks/BLbO27j4.js" rel="modulepreload"> | |
| <!--11a2igx--><meta name="hf:doc:metadata" content="{"title":"IterativePipelineBlocks","local":"iterativepipelineblocks","sections":[{"title":"Loop steps","local":"loop-steps","sections":[],"depth":2},{"title":"Loop wrapper","local":"loop-wrapper","sections":[],"depth":2},{"title":"Nesting loops","local":"nesting-loops","sections":[],"depth":2},{"title":"Streaming","local":"streaming","sections":[],"depth":2},{"title":"LoopSequentialPipelineBlocks","local":"loopsequentialpipelineblocks","sections":[],"depth":2}],"depth":1}"/><!----> | |
| <link href="/docs/diffusers/pr_14159/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: right; margin-left: 10px; display: inline-flex; position: relative; z-index: 10;"><div 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>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="iterativepipelineblocks" 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="#iterativepipelineblocks"><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>IterativePipelineBlocks</span></h1><!--]--><!----> <p><a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.IterativePipelineBlocks">IterativePipelineBlocks</a> is a multi-block type that runs its sub-blocks multiple times. It is used to build a denoising loop where the sub-blocks predict the noise and step the scheduler, then the loop runs them once per timestep. You can also nest one <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.IterativePipelineBlocks">IterativePipelineBlocks</a> under another to build an autoregressive video pipeline that generates chunk after chunk. A loop can stream each iteration to the caller when its <code>stream</code> method is implemented.</p> <p>Use this block type when a pipeline must repeat a sequence of blocks while carrying state between iterations and, when implemented, streaming progress to the caller.</p> <p>Two classes are involved in building a loop.</p> <table><thead><tr><th>Class</th><th>Role</th><th>State it works with</th></tr></thead><tbody><tr><td><a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.ModularLoopPipelineBlocks">ModularLoopPipelineBlocks</a></td><td>A <em>loop step</em>: a regular block that runs inside a loop, once per iteration</td><td>The full <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.modular_pipelines.PipelineState">PipelineState</a>, through its own <code>get_block_state</code> / <code>set_block_state</code>; also receives the loop variables as call arguments</td></tr><tr><td><a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.IterativePipelineBlocks">IterativePipelineBlocks</a></td><td>The <em>loop</em> itself: holds the loop logic and runs its steps once per iteration; loops can nest and stream</td><td>Its block state holds only its own <code>loop_inputs</code>; all data flows between its steps through the <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.modular_pipelines.PipelineState">PipelineState</a></td></tr></tbody></table> <p>This guide uses a few closely related terms, so let’s define them upfront.</p> <ul><li><strong>Pipeline state</strong> is the shared <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.modular_pipelines.PipelineState">PipelineState</a> every block reads and writes. It is the only place where data crosses blocks and survives an iteration.</li> <li><strong>Block state</strong> is one block’s declared view of the pipeline state: what its <code>get_block_state</code> returns and its <code>set_block_state</code> writes back. For a loop wrapper, it holds only the loop’s <code>loop_inputs</code>.</li> <li><strong>Loop inputs</strong> are the loop wrapper’s own input declaration: what the loop logic itself reads to drive the iteration (the <code>timesteps</code> it iterates over, for example).</li> <li><strong>Loop variables</strong> are the per-iteration values the loop passes to its steps as call arguments (<code>i</code>, <code>t</code>). They are never written to the pipeline state.</li></ul> <blockquote><p>[!TIP][IterativePipelineBlocks](/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.IterativePipelineBlocks) replaces <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.LoopSequentialPipelineBlocks">LoopSequentialPipelineBlocks</a>; see the <a href="#loopsequentialpipelineblocks">LoopSequentialPipelineBlocks</a> guide for the differences.</p></blockquote> <!--[1--><h2 class="relative group"><a id="loop-steps" 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="#loop-steps"><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>Loop steps</span></h2><!--]--><!----> <p>A loop step is a <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.ModularLoopPipelineBlocks">ModularLoopPipelineBlocks</a>. It is a regular <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.ModularPipelineBlocks">ModularPipelineBlocks</a> — it declares <code>inputs</code> and <code>intermediate_outputs</code>, and reads and writes the <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.modular_pipelines.PipelineState">PipelineState</a> through <code>get_block_state</code> / <code>set_block_state</code> — with one difference. Its <code>__call__</code> also receives the loop’s <em>loop variables</em> as arguments. For example, a denoising loop can pass the step index <code>i</code> and the timestep <code>t</code>.</p> <p>Loop variables are local to the loop and act as its bookkeeping, not pipeline data. The loop hands them to each step as plain call arguments for that one iteration, and they are never written to the <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.modular_pipelines.PipelineState">PipelineState</a>. Anything that has to outlive the iteration goes through the state instead, like <code>noise_pred</code> and <code>latents</code> below. A streaming consumer does see them, each <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.StreamEvent">StreamEvent</a> carries that iteration’s values in <code>event.loop_kwargs</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> Copied</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-keyword">from</span> diffusers.modular_pipelines <span class="hljs-keyword">import</span> ModularLoopPipelineBlocks, InputParam, OutputParam | |
| <span class="hljs-keyword">class</span> <span class="hljs-title class_">DenoiserStep</span>(<span class="hljs-title class_ inherited__">ModularLoopPipelineBlocks</span>): | |
| model_name = <span class="hljs-string">"test"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">description</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> <span class="hljs-string">"predicts the noise for one timestep"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">inputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [InputParam(name=<span class="hljs-string">"latents"</span>, required=<span class="hljs-literal">True</span>)] | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">intermediate_outputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [OutputParam(name=<span class="hljs-string">"noise_pred"</span>)] | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, components, state, i, t</span>): | |
| block_state = <span class="hljs-variable language_">self</span>.get_block_state(state) | |
| block_state.noise_pred = block_state.latents * <span class="hljs-number">0</span> + t <span class="hljs-comment"># stands in for the denoiser</span> | |
| <span class="hljs-variable language_">self</span>.set_block_state(state, block_state) | |
| <span class="hljs-keyword">return</span> components, state | |
| <span class="hljs-keyword">class</span> <span class="hljs-title class_">SchedulerStep</span>(<span class="hljs-title class_ inherited__">ModularLoopPipelineBlocks</span>): | |
| model_name = <span class="hljs-string">"test"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">description</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> <span class="hljs-string">"updates the latents with the noise prediction"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">inputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [InputParam(name=<span class="hljs-string">"latents"</span>, required=<span class="hljs-literal">True</span>), InputParam(name=<span class="hljs-string">"noise_pred"</span>, required=<span class="hljs-literal">True</span>)] | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">intermediate_outputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [OutputParam(name=<span class="hljs-string">"latents"</span>)] | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, components, state, i, t</span>): | |
| block_state = <span class="hljs-variable language_">self</span>.get_block_state(state) | |
| block_state.latents = block_state.latents + block_state.noise_pred | |
| <span class="hljs-variable language_">self</span>.set_block_state(state, block_state) | |
| <span class="hljs-keyword">return</span> components, state<!----></pre></div><!----> <p>Because each step works on the <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.modular_pipelines.PipelineState">PipelineState</a>, the values it writes (<code>noise_pred</code>, the updated <code>latents</code>) are visible to the next step in the same iteration and to the next iteration. <code>latents</code> is read at the start of every iteration and written at the end of it.</p> <!--[1--><h2 class="relative group"><a id="loop-wrapper" 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="#loop-wrapper"><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>Loop wrapper</span></h2><!--]--><!----> <p>The loop itself is a subclass of <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.IterativePipelineBlocks">IterativePipelineBlocks</a>. It declares:</p> <ul><li><code>loop_variables</code>, the names of the variables passed to each step on every iteration. Steps receive loop variables as keyword arguments. A step can name only the variables it uses if its <code>__call__</code> accepts <code>**kwargs</code>. Otherwise, it must name every loop variable. The loop validates these signatures when it is constructed and raises for unknown or missing variables.</li> <li><code>loop_inputs</code>, the inputs the loop logic itself reads — here the <code>timesteps</code> it iterates. They join the inputs aggregated from the steps (see below), and they are what <code>get_block_state</code> returns for the loop block.</li> <li><code>__call__</code>, the loop logic: read the loop’s block state, and call <code>loop_step</code> once per iteration with the loop variables. <code>loop_step</code> runs every step once.</li></ul> <p>The wrapper defines only the loop logic. Which steps run inside it should be attached separately, in a subclass:</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> Copied</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-keyword">import</span> torch | |
| <span class="hljs-keyword">from</span> diffusers.modular_pipelines <span class="hljs-keyword">import</span> IterativePipelineBlocks | |
| <span class="hljs-keyword">class</span> <span class="hljs-title class_">DenoiseLoopWrapper</span>(<span class="hljs-title class_ inherited__">IterativePipelineBlocks</span>): | |
| model_name = <span class="hljs-string">"test"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">description</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> <span class="hljs-string">"denoises the latents over the timesteps"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">loop_variables</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [<span class="hljs-string">"i"</span>, <span class="hljs-string">"t"</span>] | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">loop_inputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [InputParam(name=<span class="hljs-string">"timesteps"</span>, required=<span class="hljs-literal">True</span>)] | |
| <span class="hljs-meta"> @torch.no_grad()</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, components, state</span>): | |
| block_state = <span class="hljs-variable language_">self</span>.get_block_state(state) | |
| <span class="hljs-keyword">for</span> i, t <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(block_state.timesteps): | |
| components, state = <span class="hljs-variable language_">self</span>.loop_step(components, state, i=i, t=t) | |
| <span class="hljs-keyword">return</span> components, state | |
| <span class="hljs-keyword">class</span> <span class="hljs-title class_">DenoiseLoop</span>(<span class="hljs-title class_ inherited__">DenoiseLoopWrapper</span>): | |
| block_classes = [DenoiserStep, SchedulerStep] | |
| block_names = [<span class="hljs-string">"denoiser"</span>, <span class="hljs-string">"scheduler"</span>]<!----></pre></div><!----> <p>This separation means the same loop logic can work with different combinations of loop steps. For example, subclass the wrapper again with different <code>block_classes</code>. Steps can also be attached to the loop with <code>from_blocks_dict()</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> Copied</div><!----></button><!----></div> <pre class="language-py "><!---->loop = DenoiseLoopWrapper.from_blocks_dict({<span class="hljs-string">"denoiser"</span>: DenoiserStep(), <span class="hljs-string">"scheduler"</span>: SchedulerStep()})<!----></pre></div><!----> <p>You can also change what runs inside a loop you already have: add a step, reorder, swap one out. For example, you can insert a logging step like this:</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> Copied</div><!----></button><!----></div> <pre class="language-py "><!---->loop = DenoiseLoopWrapper.from_blocks_dict(loop.sub_blocks.copy().insert(<span class="hljs-string">"log"</span>, LogStep(), <span class="hljs-number">1</span>))<!----></pre></div><!----> <p>An <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.IterativePipelineBlocks">IterativePipelineBlocks</a> is a <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.SequentialPipelineBlocks">SequentialPipelineBlocks</a>, so it <a href="./sequential_pipeline_blocks#aggregated-inputs-and-outputs">aggregates</a> its steps’ <code>inputs</code> and <code>intermediate_outputs</code> the same way any assembled block does, and adds <code>loop_inputs</code> / <code>loop_intermediate_outputs</code> on top. <code>DenoiseLoop.inputs</code> is therefore <code>timesteps</code> (its own) and <code>latents</code> (what the steps need from outside the loop) — but not <code>noise_pred</code>, which <code>DenoiserStep</code> produces before <code>SchedulerStep</code> reads it, so it is satisfied inside the loop. The assembled loop ends up with the same kind of input/output contract as a single block, which is what lets it be dropped into a <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.SequentialPipelineBlocks">SequentialPipelineBlocks</a>, or into another loop. Outputs the steps write persist in the state after the loop. Run it like any other block:</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> Copied</div><!----></button><!----></div> <pre class="language-py "><!---->pipeline = DenoiseLoop().init_pipeline() | |
| state = pipeline(latents=torch.tensor(<span class="hljs-number">0.0</span>), timesteps=torch.tensor([<span class="hljs-number">1.0</span>, <span class="hljs-number">2.0</span>, <span class="hljs-number">3.0</span>])) | |
| state.get(<span class="hljs-string">"latents"</span>) <span class="hljs-comment"># tensor(6.) — 0 + 1 + 2 + 3</span><!----></pre></div><!----> <p>The wrapper contains only the loop logic, i.e. how to iterate through its steps, so its <code>loop_inputs</code> should be just what that takes (the <code>timesteps</code> above). All data flows through the steps, which read and write the pipeline state directly. In the example above, <code>DenoiserStep</code> writes <code>noise_pred</code> to the state and <code>SchedulerStep</code> reads it back and writes the updated <code>latents</code>. The wrapper touches none of them. If the loop logic seems to need to do more than iterate, for example, collect results, you should add a loop step for it instead. In <code>wan_animate_2</code>, a small collect step appends each segment’s decoded frames to <code>segment_frames</code>, and the next segment’s prep step reads it back to condition on. Under <a href="#streaming">streaming</a>, the partial collection is visible after every iteration. What we don’t want is the wrapper doing it inline:</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> Copied</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-comment"># don't: loop logic collecting results itself</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, components, state</span>): | |
| block_state = <span class="hljs-variable language_">self</span>.get_block_state(state) | |
| segment_frames = [] | |
| <span class="hljs-keyword">for</span> k <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(block_state.num_segments): | |
| components, state = <span class="hljs-variable language_">self</span>.loop_step(components, state, k=k) | |
| segment_frames.append(state.get(<span class="hljs-string">"out_frames"</span>)) <span class="hljs-comment"># reaching into the state: make this a collect loop step</span> | |
| ...<!----></pre></div><!----> <!--[1--><h2 class="relative group"><a id="nesting-loops" 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="#nesting-loops"><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>Nesting loops</span></h2><!--]--><!----> <p>An <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.IterativePipelineBlocks">IterativePipelineBlocks</a> can be a step of another one. An autoregressive video pipeline generates a chunk of frames at a time, so it is an outer loop over chunks. Each of its iterations prepares the chunk’s latents from the frames generated so far, runs a full denoising loop over them, and appends the result to the history.</p> <p>The inner denoising loop is a step of the outer loop, so its <code>__call__</code> must accept the outer loop’s variables (or take <code>**kwargs</code> if it ignores them), and it declares <code>loop_variables</code> of its own for its own steps. The two sets are independent. <code>k</code> arrives as a call argument and the inner loop is free to use it — the wan-animate-2 denoise loop puts the chunk index in its progress bar — but it is not forwarded to the steps, which are passed the inner loop’s <code>i</code> and <code>t</code>.</p> <p>This is the structure this section builds:</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> Copied</div><!----></button><!----></div> <pre class=" "><!---->VideoLoop <span class="hljs-keyword">outer</span> <span class="hljs-keyword">loop</span> — loop_variables ["k"], iterates <span class="hljs-keyword">over</span> chunks | |
| ├─ <span class="hljs-keyword">prepare</span> PrepareChunkStep (leaf step, takes k) | |
| ├─ denoise ChunkDenoiseLoop (the <span class="hljs-keyword">INNER</span> <span class="hljs-keyword">loop</span> — a step <span class="hljs-keyword">of</span> the <span class="hljs-keyword">outer</span> one) | |
| │ ├─ denoiser DenoiserStep (takes the <span class="hljs-keyword">inner</span> <span class="hljs-keyword">loop</span><span class="hljs-string">'s i, t) | |
| │ └─ scheduler SchedulerStep | |
| └─ update UpdateHistoryStep (leaf step, takes k)</span><!----></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> Copied</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-keyword">class</span> <span class="hljs-title class_">ChunkDenoiseLoopWrapper</span>(<span class="hljs-title class_ inherited__">IterativePipelineBlocks</span>): | |
| model_name = <span class="hljs-string">"test"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">description</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> <span class="hljs-string">"denoises one chunk over the timesteps"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">loop_variables</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [<span class="hljs-string">"i"</span>, <span class="hljs-string">"t"</span>] | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">loop_inputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [InputParam(name=<span class="hljs-string">"timesteps"</span>, required=<span class="hljs-literal">True</span>)] | |
| <span class="hljs-meta"> @torch.no_grad()</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, components, state, k</span>): <span class="hljs-comment"># `k` comes from the outer video loop</span> | |
| block_state = <span class="hljs-variable language_">self</span>.get_block_state(state) | |
| <span class="hljs-keyword">for</span> i, t <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(block_state.timesteps): | |
| components, state = <span class="hljs-variable language_">self</span>.loop_step(components, state, i=i, t=t) | |
| <span class="hljs-keyword">return</span> components, state | |
| <span class="hljs-keyword">class</span> <span class="hljs-title class_">ChunkDenoiseLoop</span>(<span class="hljs-title class_ inherited__">ChunkDenoiseLoopWrapper</span>): | |
| block_classes = [DenoiserStep, SchedulerStep] | |
| block_names = [<span class="hljs-string">"denoiser"</span>, <span class="hljs-string">"scheduler"</span>]<!----></pre></div><!----> <p><code>ChunkDenoiseLoop</code> is the <em>inner</em> loop that denoises a single chunk. It becomes a step of the outer loop below, which iterates over the chunks. At each <code>k</code>, it prepares the chunk’s latents from the history, runs the full inner denoising loop over them, and records the result:</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> Copied</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-keyword">class</span> <span class="hljs-title class_">PrepareChunkStep</span>(<span class="hljs-title class_ inherited__">ModularLoopPipelineBlocks</span>): | |
| model_name = <span class="hljs-string">"test"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">description</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> <span class="hljs-string">"prepares this chunk's latents from the history"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">inputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [InputParam(name=<span class="hljs-string">"history"</span>, required=<span class="hljs-literal">True</span>)] | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">intermediate_outputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [OutputParam(name=<span class="hljs-string">"latents"</span>)] | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, components, state, k</span>): | |
| block_state = <span class="hljs-variable language_">self</span>.get_block_state(state) | |
| block_state.latents = block_state.history + k | |
| <span class="hljs-variable language_">self</span>.set_block_state(state, block_state) | |
| <span class="hljs-keyword">return</span> components, state | |
| <span class="hljs-keyword">class</span> <span class="hljs-title class_">UpdateHistoryStep</span>(<span class="hljs-title class_ inherited__">ModularLoopPipelineBlocks</span>): | |
| model_name = <span class="hljs-string">"test"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">description</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> <span class="hljs-string">"records the denoised chunk"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">inputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [InputParam(name=<span class="hljs-string">"latents"</span>, required=<span class="hljs-literal">True</span>)] | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">intermediate_outputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [OutputParam(name=<span class="hljs-string">"history"</span>)] | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, components, state, k</span>): | |
| block_state = <span class="hljs-variable language_">self</span>.get_block_state(state) | |
| block_state.history = block_state.latents | |
| <span class="hljs-variable language_">self</span>.set_block_state(state, block_state) | |
| <span class="hljs-keyword">return</span> components, state | |
| <span class="hljs-keyword">class</span> <span class="hljs-title class_">VideoLoopWrapper</span>(<span class="hljs-title class_ inherited__">IterativePipelineBlocks</span>): | |
| model_name = <span class="hljs-string">"test"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">description</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> <span class="hljs-string">"generates the video chunk by chunk"</span> | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">loop_variables</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [<span class="hljs-string">"k"</span>] | |
| <span class="hljs-meta"> @property</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">loop_inputs</span>(<span class="hljs-params">self</span>): | |
| <span class="hljs-keyword">return</span> [InputParam(name=<span class="hljs-string">"num_chunks"</span>, required=<span class="hljs-literal">True</span>)] | |
| <span class="hljs-meta"> @torch.no_grad()</span> | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">__call__</span>(<span class="hljs-params">self, components, state</span>): | |
| block_state = <span class="hljs-variable language_">self</span>.get_block_state(state) | |
| <span class="hljs-keyword">for</span> k <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(block_state.num_chunks): | |
| components, state = <span class="hljs-variable language_">self</span>.loop_step(components, state, k=k) | |
| <span class="hljs-keyword">return</span> components, state | |
| <span class="hljs-keyword">class</span> <span class="hljs-title class_">VideoLoop</span>(<span class="hljs-title class_ inherited__">VideoLoopWrapper</span>): | |
| block_classes = [PrepareChunkStep, ChunkDenoiseLoop, UpdateHistoryStep] | |
| block_names = [<span class="hljs-string">"prepare"</span>, <span class="hljs-string">"denoise"</span>, <span class="hljs-string">"update"</span>]<!----></pre></div><!----> <p>Run the outer loop like any other block:</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> Copied</div><!----></button><!----></div> <pre class="language-py "><!---->pipeline = VideoLoop().init_pipeline() | |
| state = pipeline(num_chunks=<span class="hljs-number">2</span>, timesteps=torch.tensor([<span class="hljs-number">1.0</span>, <span class="hljs-number">2.0</span>]), history=torch.tensor(<span class="hljs-number">0.0</span>)) | |
| state.get(<span class="hljs-string">"history"</span>) <span class="hljs-comment"># tensor(7.) — chunk 0: 0 + 0 + 3 = 3, chunk 1: 3 + 1 + 3 = 7</span><!----></pre></div><!----> <p><code>history</code> is carried from one iteration to the next. <code>UpdateHistoryStep</code> writes it at the end of one, and <code>PrepareChunkStep</code> reads it at the start of the next. Because the reader comes before the writer, it is one of the loop’s inputs — which is why <code>pipeline(history=...)</code> works above — and like any input it has to come from either the user or an earlier block. If seeding it isn’t meaningful (a decoder cache, the previous chunk’s frames), have the block that runs before the loop declare it as an output and set its initial value. It then drops out of the pipeline’s signature.</p> <!--[1--><h2 class="relative group"><a id="streaming" 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="#streaming"><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>Streaming</span></h2><!--]--><!----> <p>To let <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline#diffusers.ModularPipeline.stream">stream()</a> hand back the live state after every iteration, also implement <code>stream</code>. This is the same loop written as a generator over <code>stream_step</code>, which runs one iteration like <code>loop_step</code> and additionally yields a <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.StreamEvent">StreamEvent</a> for it (after the events of any nested loop):</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> Copied</div><!----></button><!----></div> <pre class="language-py "><!----><span class="hljs-keyword">class</span> <span class="hljs-title class_">DenoiseLoop</span>(<span class="hljs-title class_ inherited__">IterativePipelineBlocks</span>): | |
| ... | |
| <span class="hljs-keyword">def</span> <span class="hljs-title function_">stream</span>(<span class="hljs-params">self, components, state</span>): | |
| block_state = <span class="hljs-variable language_">self</span>.get_block_state(state) | |
| <span class="hljs-keyword">for</span> i, t <span class="hljs-keyword">in</span> <span class="hljs-built_in">enumerate</span>(block_state.timesteps): | |
| components, state = <span class="hljs-keyword">yield</span> <span class="hljs-keyword">from</span> <span class="hljs-variable language_">self</span>.stream_step(components, state, i=i, t=t) | |
| <span class="hljs-keyword">return</span> components, state<!----></pre></div><!----> <p>A nested loop’s <code>stream</code> takes the outer loop’s variables exactly like its <code>__call__</code> does. Streaming is opt-in per loop.<code>pipeline.blocks.supports_streaming</code> tells you whether every loop on the path implements it. See <a href="./modular_pipeline#streaming">Streaming</a> for the consumer side.</p> <!--[1--><h2 class="relative group"><a id="loopsequentialpipelineblocks" 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="#loopsequentialpipelineblocks"><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>LoopSequentialPipelineBlocks</span></h2><!--]--><!----> <p><a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.LoopSequentialPipelineBlocks">LoopSequentialPipelineBlocks</a> is the earlier loop type and is still used by existing pipelines. It differs in three ways:</p> <ol><li>Steps share one flattened <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.modular_pipelines.BlockState">BlockState</a> that the wrapper extracts before the loop (instead of each step reading the <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_states#diffusers.modular_pipelines.PipelineState">PipelineState</a> itself).</li> <li>It cannot contain another loop.</li> <li>It cannot stream.</li></ol> <p>Use <a href="/docs/diffusers/pr_14159/en/api/modular_diffusers/pipeline_blocks#diffusers.IterativePipelineBlocks">IterativePipelineBlocks</a> for new pipelines.</p> <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/modular_diffusers/iterative_pipeline_blocks.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_hmnr13 = { | |
| base: "/docs/diffusers/pr_14159/en", | |
| assets: "/docs/diffusers/pr_14159/en" | |
| }; | |
| const element = document.currentScript.parentElement; | |
| Promise.all([ | |
| import("/docs/diffusers/pr_14159/en/_app/immutable/entry/start.CQi6m7Bo.js"), | |
| import("/docs/diffusers/pr_14159/en/_app/immutable/entry/app.B0IgqLyE.js") | |
| ]).then(([kit, app]) => { | |
| kit.start(app, element, { | |
| node_ids: [0, 279], | |
| data: [null,null], | |
| form: null, | |
| error: null | |
| }); | |
| }); | |
| } | |
| </script> | |
Xet Storage Details
- Size:
- 57.5 kB
- Xet hash:
- 50bbd1a02fd8cb210a2698b1dba5836186bc3cc4171c15c6f805fab4bf354c6b
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.