How to Stop a Hugging Face Pipeline Operation (Diffusers & Transformers)
Original question: How to stop hugging face pipeline operation
To stop a Hugging Face pipeline operation, you must use the correct interruption mechanism for the specific library you are using. The transformers pipeline class supports a stopping_criteria parameter, while the diffusers pipeline class requires setting the _interrupt property to True inside a callback function passed to callback_on_step_end. Attempting to use stopping_criteria with a diffusers pipeline will not work because the two libraries have separate interruption implementations.
The Full Answer
Hugging Face provides two major libraries for running machine learning models: transformers (for text, audio, and vision models) and diffusers (for diffusion models used in image generation). Each library has its own pipeline class and its own method for interrupting or stopping a running pipeline operation. Confusing the two is a common mistake that leads to code that appears correct but does nothing.
Understanding the Two Libraries
transformerspipeline: Used for tasks like text classification, question answering, summarization, and text generation. It supports astopping_criteriaparameter that accepts aStoppingCriteriaListobject. This list contains callable objects that are evaluated at each generation step. If any callable returnsTrue, generation stops.diffuserspipeline: Used for image generation with diffusion models (e.g., Stable Diffusion, Kandinsky). It does not supportstopping_criteria. Instead, it provides acallback_on_step_endparameter that accepts a function called after each denoising step. To interrupt generation, you setpipeline._interrupt = Trueinside that callback.
The Problem with Using stopping_criteria on a diffusers Pipeline
In the original question, the user attempted to stop a diffusers pipeline (specifically DiffusionPipeline from the diffusers library) by passing a stopping_criteria parameter. This approach fails because DiffusionPipeline does not inspect or use the stopping_criteria argument. The parameter is silently ignored. The debugger breakpoint on return flag never triggers because the custom stopping criteria function is never called.
Here is the incorrect code from the question:
import torch
from diffusers import DiffusionPipeline
from transformers import StoppingCriteriaList
pipe = DiffusionPipeline.from_pretrained(
"kandinsky-community/kandinsky-3", variant="fp16", torch_dtype=torch.float16
)
pipe.enable_sequential_cpu_offload()
prompt = "Cemetery of abandoned vehicles, many different rusty cars"
flag = False
def custom_stopping_criteria(
input_ids: torch.LongTensor, score: torch.FloatTensor, **kwargs
) -> bool:
return flag
stopping_criteria = StoppingCriteriaList([custom_stopping_criteria])
image = pipe(prompt, stopping_criteria=stopping_criteria).images[0]
image.show()
This code will run the full 50 denoising steps (or whatever the default is for the model) without interruption, regardless of the flag variable.
The Correct Approach for diffusers Pipelines
As confirmed in the accepted answer on Stack Overflow, the diffusers library has its own interruption mechanism. You must use the callback_on_step_end parameter to provide a function that will be called at the end of each denoising step. Inside that function, you set pipeline._interrupt = True to stop the generation.
Here is the corrected code, adapted from the accepted answer:
import torch
from diffusers import DiffusionPipeline
# Using a smaller model for demonstration
model_id = "OFA-Sys/small-stable-diffusion-v0"
pipe = DiffusionPipeline.from_pretrained(
model_id, torch_dtype=torch.float16
)
pipe.enable_sequential_cpu_offload()
prompt = "Cemetery of abandoned vehicles, many different rusty cars"
def interrupt_callback(pipeline, i, t, callback_kwargs):
pipeline._interrupt = True
return callback_kwargs
image = pipe(
prompt,
callback_on_step_end=interrupt_callback,
)
What this code does:
- It loads a diffusion pipeline from the
diffuserslibrary. The example usesOFA-Sys/small-stable-diffusion-v0for demonstration, but you can replace it with any model ID (e.g.,kandinsky-community/kandinsky-3). - It enables sequential CPU offloading to save GPU memory (optional but recommended for large models).
- It defines a callback function
interrupt_callbackthat receives four arguments:pipeline: the pipeline object itself.i: the current step number (0-indexed).t: the current timestep value. The exact meaning oftis not documented in the source, but it is passed by the pipeline.callback_kwargs: a dictionary of keyword arguments that the pipeline passes to the callback. This must be returned from the callback to maintain state.
- Inside the callback, it sets
pipeline._interrupt = True. This is a special attribute that the pipeline checks after each step. If it isTrue, the pipeline stops the generation loop immediately. - The callback returns
callback_kwargsto satisfy the pipeline's expectation. - The pipeline is called with
callback_on_step_end=interrupt_callback. The generation will stop after the first step because the callback sets_interrupttoTrueon the first call.
Output from the accepted answer:
1/50 [00:01<01:21, 1.67s/it]
Potential NSFW content was detected in one or more images. A black image will be returned instead. Try again with a different prompt and/or seed.
This output shows that only 1 out of 50 steps was completed before the pipeline was interrupted. The NSFW warning is incidental to the example and not related to the interruption mechanism.
Making the Interruption Conditional
In practice, you will not want to interrupt the pipeline on the very first step. You will want to stop it based on some condition, such as user input, a timeout, or a quality metric. Here is how to implement a conditional interruption:
import torch
from diffusers import DiffusionPipeline
import threading
import time
model_id = "OFA-Sys/small-stable-diffusion-v0"
pipe = DiffusionPipeline.from_pretrained(
model_id, torch_dtype=torch.float16
)
pipe.enable_sequential_cpu_offload()
prompt = "Cemetery of abandoned vehicles, many different rusty cars"
# A flag that can be set from another thread (e.g., a UI button)
stop_flag = False
def interrupt_callback(pipeline, i, t, callback_kwargs):
if stop_flag:
pipeline._interrupt = True
return callback_kwargs
# Simulate a user pressing stop after 3 seconds
def delayed_stop():
global stop_flag
time.sleep(3)
stop_flag = True
threading.Thread(target=delayed_stop, daemon=True).start()
image = pipe(
prompt,
callback_on_step_end=interrupt_callback,
)
This example uses a global stop_flag that can be set from any thread. The callback checks the flag at each step and sets _interrupt when the flag becomes True. The pipeline will stop at the end of the current step.
The Correct Approach for transformers Pipelines
If you are using a transformers pipeline (e.g., for text generation), the stopping_criteria parameter works as expected. Here is a brief example for completeness:
from transformers import pipeline, StoppingCriteriaList, StoppingCriteria
import torch
class StopOnKeyword(StoppingCriteria):
def __init__(self, keyword):
self.keyword = keyword
def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor, **kwargs) -> bool:
# Check if the last generated token matches the keyword
last_token = input_ids[0, -1].item()
return last_token == self.keyword
pipe = pipeline("text-generation", model="gpt2")
# This will stop generation when the token for "stop" is generated
# Note: this is a simplified example; you would need the actual token ID
stopping_criteria = StoppingCriteriaList([StopOnKeyword(50256)]) # 50256 is the EOS token for GPT-2
output = pipe("Hello, I am", stopping_criteria=stopping_criteria)
print(output)
This is not directly related to the original question, but it clarifies the correct usage for transformers pipelines.
Common Pitfalls
-
Using
stopping_criteriawithdiffuserspipelines: This is the most common mistake. Thediffuserslibrary does not supportstopping_criteria. The parameter is silently ignored, and the pipeline runs to completion. Always check which library your pipeline object comes from. -
Forgetting to return
callback_kwargs: The callback function passed tocallback_on_step_endmust return thecallback_kwargsdictionary. If you forget, the pipeline will raise an error or behave unpredictably. -
Setting
_interruptoutside the callback: The_interruptattribute is checked only at the end of each denoising step. Setting it outside the callback (e.g., before callingpipe()) will have no effect. It must be set inside a callback that runs during the generation loop. -
Using
_interruptwithtransformerspipelines: The_interruptattribute is specific todiffuserspipelines. It does not exist ontransformerspipeline objects. Attempting to set it will raise anAttributeError. -
Thread safety: If you set
_interruptfrom a different thread (e.g., a UI button handler), be aware that the pipeline runs in the main thread. The callback is called from the main thread, so there is no race condition. However, if you use a global flag, ensure it is properly synchronized (e.g., usingthreading.Eventorthreading.Lock) if you have multiple threads reading and writing it. -
NSFW detection: As seen in the accepted answer output, some models have built-in NSFW detection that can return a black image. This is unrelated to interruption but can be confusing if you expect a partially generated image.
Related Questions
How do I stop a diffusers pipeline after a specific number of steps?
You can stop the pipeline after a specific number of steps by checking the step index i inside the callback. For example, to stop after 10 steps, use if i >= 9: pipeline._interrupt = True (since i is 0-indexed). This is useful for debugging or generating quick previews.
Can I resume a stopped diffusers pipeline?
No, the diffusers pipeline does not support resuming from an interrupted state. Once _interrupt is set to True, the generation loop exits and the pipeline returns whatever latents were computed up to that point. You would need to save the intermediate state manually if you want to resume later.
What happens to the output when I interrupt a diffusers pipeline?
The pipeline returns the latents as they were at the end of the last completed step. These latents are then decoded into an image. The quality of the image will be lower than if the full number of steps were completed, but it will be a valid image (unless NSFW detection intervenes).
How do I stop a transformers text generation pipeline?
Use the stopping_criteria parameter with a StoppingCriteriaList. Each criteria object must implement a __call__ method that returns True when generation should stop. This is the standard approach and is well documented in the transformers library.
The #1 AI Newsletter
The most important ai updates, guides, and fixes โ one weekly email.
No spam, unsubscribe anytime. Privacy policy
Sources & References
This page was researched from 2 independent sources, combined and verified for completeness.
- 1.How to stop hugging face pipeline operationStack Overflow
- 2.Answer by cronoik (score 1, accepted)Stack Overflow ยท primary source
Related Answers
Keep exploring
Latest error solutions
Skip the manual work
Ready-made AI workflows and automation templates โ import and run instead of building from scratch.