# Help with TemporalNetV2 in PyTorch

**URL:** <https://discuss.huggingface.co/t/help-with-temporalnetv2-in-pytorch/171131>\
**Category:** 🧨 Diffusers\
**Created:** [December 3, 2025, 11:44pm UTC](https://discuss.huggingface.co/t/help-with-temporalnetv2-in-pytorch/171131 "2025-12-03T23:44:27Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![carmatic](https://avatars.discourse-cdn.com/v4/letter/c/ce7236/32.png) [@carmatic](https://discuss.huggingface.co/u/carmatic)\
**Post date:** [December 3, 2025, 11:44pm UTC](https://discuss.huggingface.co/t/help-with-temporalnetv2-in-pytorch/171131/1 "2025-12-03T23:44:27Z")

</div>

I am trying to use this controlnet: [CiaraRowles/TemporalNet2 · Hugging Face](https://huggingface.co/CiaraRowles/TemporalNet2)

The files are provided as .safetensors, .ckpt, and .yaml

However my PyTorch project SPECIFICALLY requires it as a ‘diffusion\_pytorch\_model.bin’

Therefore I am trying to use this script: [diffusers/scripts/convert\_original\_stable\_diffusion\_to\_diffusers.py at main · huggingface/diffusers · GitHub](https://github.com/huggingface/diffusers/blob/main/scripts/convert_original_stable_diffusion_to_diffusers.py)

**I have tried 3 times** :

the first 2 times was with this command, to use the .ckpt file:

`python “import argparse.py” --checkpoint_path ./temporalnetversion2.ckpt --controlnet --dump_path ./ --original_config_file ./temporalnetversion2.yaml`

- With PyTorch 2.5.1 and Diffusers 0.24.0 (I think), it is blocked from using the .ckpt file due to the security update requiring PyTorch versions \>2.6.0
- Then with PyTorch 2.8.0 and Diffusers 0.35.0 , it gives the following error:

> File “C:\Users\fdasfasdfasd\import argparse.py”, line 144, in  
> pipe = download\_from\_original\_stable\_diffusion\_ckpt(  
> File “c:\Users\fdasfasdfasd.venv\lib\site-packages\diffusers\pipelines\stable\_diffusion\convert\_from\_ckpt.py”, line 1707, in download\_from\_original\_stable\_diffusion\_ckpt  
> pipe = pipeline\_class(  
> File “c:\Users\fdasfasdfasd.venv\lib\site-packages\diffusers\pipelines\controlnet\pipeline\_controlnet.py”, line 246, in **init**  
> self.register\_modules(  
> File “c:\Users\fdasfasdfasd.venv\lib\site-packages\diffusers\pipelines\pipeline\_utils.py”, line 212, in register\_modules  
> library, class\_name = \_fetch\_class\_library\_tuple(module)  
> File “c:\Users\fdasfasdfasd.venv\lib\site-packages\diffusers\pipelines\pipeline\_loading\_utils.py”, line 907, in \_fetch\_class\_library\_tuple  
> library = not\_compiled\_module. **module**.split(“.”)[0]  
> AttributeError: ‘bool’ object has no attribute ‘ **module** ’. Did you mean: ‘ **mod** ’?

- Then I used this command, to use the .safetensors file

`python “import argparse.py” --checkpoint_path ./temporalnetversion2.safetensors --controlnet --dump_path ./ --original_config_file ./temporalnetversion2.yaml`

This gives the following error

> Traceback (most recent call last):  
> File “C:\Users\fdasfasdfasd\import argparse.py”, line 144, in  
> pipe = download\_from\_original\_stable\_diffusion\_ckpt(  
> File “c:\Users\fdasfasdfasd.venv\lib\site-packages\diffusers\pipelines\stable\_diffusion\convert\_from\_ckpt.py”, line 1277, in download\_from\_original\_stable\_diffusion\_ckpt  
> checkpoint = torch.load(checkpoint\_path\_or\_dict, map\_location=device)  
> File “c:\Users\fdasfasdfasd.venv\lib\site-packages\torch\serialization.py”, line 1553, in load  
> raise pickle.UnpicklingError(\_get\_wo\_message(str(e))) from None  
> \_pickle.UnpicklingError: Weights only load failed. In PyTorch 2.6, we changed the default value of the `weights_only` argument in `torch.load` from `False` to `True`. Re-running `torch.load` with `weights_only` set to `False` will likely succeed, but it can result in arbitrary code execution. Do it only if you got the file from a trusted source.  
> Please file an issue with the following so that we can make `weights_only=True` compatible with your use case: WeightsUnpickler error: Unsupported operand 144

---

<div class="post-metadata">

**Author:** ![John6666](https://sea2.discourse-cdn.com/hellohellohello/user_avatar/discuss.huggingface.co/john6666/32/27664_2.png) [@John6666](https://discuss.huggingface.co/u/John6666)\
**Post date:** [December 4, 2025, 1:53am UTC](https://discuss.huggingface.co/t/help-with-temporalnetv2-in-pytorch/171131/2 "2025-12-04T01:53:27Z")

</div>

If you just want to use that ControlNet, it seems the converted weights are available on the Hub.

* * *

### 0. What you want and what’s going wrong

You want:

- The **TemporalNet2** controlnet from  
`https://huggingface.co/CiaraRowles/TemporalNet2`
- In **Diffusers layout** , specifically a file called  
`diffusion_pytorch_model.bin`
- So you tried to run the **Diffusers conversion script** on the original `.ckpt` / `.safetensors`.

You’re hitting two _separate_ issues:

1. **PyTorch 2.6+ security change** :  
`torch.load` now defaults to `weights_only=True` → older SD checkpoints often fail with  
`Weights only load failed ... WeightsUnpicklingError ... Unsupported operand 144`.

2. **Diffusers pipeline bug / version mismatch** :  
When the conversion script constructs `StableDiffusionControlNetPipeline`, a `bool` gets treated as a module and you get  
`AttributeError: 'bool' object has no attribute 'module'`. This is a known class of issues in Diffusers where pipeline init signatures changed and old code passes arguments in the wrong positions. ([Hugging Face](https://huggingface.co/docs/diffusers/en/api/models/controlnet "ControlNetModel"))

On top of that, TemporalNet2 is a **non-standard** ControlNet variant (6-channel input: previous frame + optical flow) so it pushes all of this into the “edge case” zone. ([GitHub](https://github.com/Mikubill/sd-webui-controlnet/discussions/1752 "Support for the TemporalNetV2 Model? #1752"))

* * *

### 1. Easiest solution (recommended): use the already-converted Diffusers checkpoint

There is **already** a Diffusers-ready TemporalNet2 on Hugging Face:

- `wav/TemporalNet2`  
Model card: “ **CiaraRowles/TemporalNet2 but converted for use with Diffusers!** ” ([Hugging Face](https://huggingface.co/wav/TemporalNet2 "wav/TemporalNet2"))

This model:

- Is the same TemporalNet2, but laid out as a **Diffusers `ControlNetModel`**.
- Already has a `diffusion_pytorch_model.safetensors` + `config.json` in the canonical Diffusers format. ([Hugging Face](https://huggingface.co/wav/TemporalNet2/blob/main/diffusion_pytorch_model.safetensors "diffusion\_pytorch\_model.safetensors · wav/TemporalNet2 at main"))

You can trivially turn that into a `.bin`:

#### 1.1. Install a compatible Diffusers version

```bash
pip install --upgrade "diffusers[torch]" transformers safetensors

```

TemporalNet2 for Diffusers was originally tested with a branch that “exposes controlnet conditioning channels” (for the extra optical-flow channels), but for the **conversion to .bin** you usually only need to load and save the weights, which is less fragile. ([Hugging Face](https://huggingface.co/wav/TemporalNet2 "wav/TemporalNet2"))

If you run into a shape mismatch when loading, you can install the same branch mentioned on the model card:

```bash
pip install git+https://github.com/JCBrouwer/diffusers@expose-controlnet-conditioning-channels

```

#### 1.2. Load `wav/TemporalNet2` and re-save as `.bin`

```python
from diffusers import ControlNetModel
import torch

# Load the already Diffusers-converted TemporalNet2
controlnet = ControlNetModel.from_pretrained(
    "wav/TemporalNet2",
    torch_dtype=torch.float16, # or float32 if you prefer
)

# Save in .bin format instead of safetensors
controlnet.save_pretrained(
    "./TemporalNet2_bin", # output directory
    safe_serialization=False, # <- forces .bin (PyTorch) instead of .safetensors
)

```

This creates:

```plaintext
./TemporalNet2_bin/
  config.json
  diffusion_pytorch_model.bin

```

That `diffusion_pytorch_model.bin` is exactly what a Diffusers-style `ControlNetModel` expects (same structure as a normal ControlNet). Diffusers docs explicitly state that `safe_serialization=False` → PyTorch `.bin`; `True` → `.safetensors`. ([Hugging Face](https://huggingface.co/docs/diffusers/en/api/models/controlnet "ControlNetModel"))

From your project’s point of view, this is a **standard Diffusers controlnet** with the TemporalNet2 architecture, and the filename and layout match what you said you need.

This route:

- Avoids `torch.load(..., weights_only=True)` entirely (no PyTorch security error).
- Avoids `StableDiffusionControlNetPipeline` construction (no `'bool' object has no attribute "module"'` issue).
- Uses a checkpoint that is explicitly documented as “CiaraRowles/TemporalNet2 converted for Diffusers”, so it matches the model you want. ([Hugging Face](https://huggingface.co/wav/TemporalNet2 "wav/TemporalNet2"))

* * *

### 2. If you insist on converting `CiaraRowles/TemporalNet2` yourself

If you really need to run the **conversion script** against the **original** repo’s weights (`temporalnetversion2.ckpt` / `.safetensors` + YAML), the key problems and fixes are:

- You must use the script correctly for `.safetensors` (add `--from_safetensors`).
- You must handle the PyTorch 2.6+ `weights_only` behavior if you stick to `.ckpt`.
- You may need to avoid or patch the Diffusers pipeline bug (`bool` as module).

#### 2.1. Your current commands and errors

1. **CKPT path, newer PyTorch + Diffusers → bool/module error**

2. **SAFETENSORS path, no `--from_safetensors` → weights\_only / unpickling error**

So to make the script work with the original TemporalNet2, you must:

- Use `--from_safetensors` for `temporalnetversion2.safetensors`; and
- Deal with the pipeline bug for `StableDiffusionControlNetPipeline`.

#### 2.2. Correct command line for the safetensors checkpoint

Use the safetensors file, and **tell the script** :

```bash
python "import argparse.py" ^
  --checkpoint_path ./temporalnetversion2.safetensors ^
  --from_safetensors ^
  --controlnet ^
  --dump_path ./TemporalNet2_diffusers ^
  --original_config_file ./temporalnetversion2.yaml
  # (optional) --to_safetensors # add this ONLY if you want .safetensors output

```

Key points in that command:

- `--from_safetensors` → script forwards `from_safetensors=True` to `download_from_original_stable_diffusion_ckpt`, which will use the **safetensors loader** , not `torch.load`. This avoids both the wrong-format issue and the `weights_only` security behavior. ([Hugging Face](https://huggingface.co/docs/diffusers/en/api/models/controlnet "ControlNetModel"))

- `--dump_path ./TemporalNet2_diffusers` → cleaner output directory that should contain:

If this works, you’re done: you now have a **Diffusers-style ControlNet directory** from the original CiaraRowles weights.

#### 2.3. If you hit the bool/module error again

If, after fixing `--from_safetensors`, you still hit something like:

```plaintext
AttributeError: 'bool' object has no attribute 'module'

```

you’re back in Diffusers version-compatibility territory. At that point, you have three realistic options:

1. **Use `ControlNetModel.from_single_file` instead of the conversion script**

2. **Pin Diffusers to a version where the script + pipeline are in sync**

3. **Last-resort patch: guard `register_modules` against bools**

Because all of this is extra complexity, the **simpler and safer route remains** : just use `wav/TemporalNet2` and re-save to `.bin`.

* * *

### 3. Why the security error appears at all

Just for clarity, the PyTorch error you saw is not a TemporalNet2 bug; it’s a **PyTorch 2.6+ default behavior** :

- Before 2.6, `torch.load(path)` meant “load anything from this pickled file”.
- From 2.6 onward, it behaves more like “load weights only” and rejects arbitrary pickled objects by default (`weights_only=True`).
- Legacy SD `.ckpt` files and some conversion code rely on full pickled objects and break under this stricter default.

The official workaround is: for trusted checkpoints, call:

```python
torch.load(path, map_location=device, weights_only=False)

```

But in your case, that’s only relevant if you insist on `.ckpt`; switching to `.safetensors` + correct loader avoids it entirely.

* * *

### 4. Summary

- You want **TemporalNet2** as a Diffusers-style controlnet with a `diffusion_pytorch_model.bin` file.

- The **cleanest solution** is:

- Your script failures are due to:

- If you really want to convert the **original** `CiaraRowles/TemporalNet2`:

---

<div class="post-metadata">

**Author:** ![carmatic](https://avatars.discourse-cdn.com/v4/letter/c/ce7236/32.png) [@carmatic](https://discuss.huggingface.co/u/carmatic)\
**Post date:** [December 4, 2025, 4:05pm UTC](https://discuss.huggingface.co/t/help-with-temporalnetv2-in-pytorch/171131/3 "2025-12-04T16:05:19Z")

</div>

Hello, thank you for telling me about [wav/TemporalNet2 · Hugging Face](https://huggingface.co/wav/TemporalNet2) , your “1.2. Load `wav/TemporalNet2` and re-save as `.bin`" conversion script worked and my project now seems to run successfully, it is accepting the 6 conditioning channels (previous RGB data + optical flow) from the controlnet, without throwing any errors, and it is generating images.

* * *

Moving forward, I am thinking of going from SD1.5 to SD-Turbo, because of the increase in performance and image quality, but am I right to assume that I can no longer use the TemporalNet because it will not be compatible ?

I know that SD Turbo is 2.1 , and in the [conversion script](https://github.com/huggingface/diffusers/blob/main/scripts/convert_original_stable_diffusion_to_diffusers.py) there is this option

> “–upcast\_attention”,
> 
> action=“store\_true”,
> 
> help=(
> 
> “Whether the attention computation should always be upcasted. This is necessary when running stable”
> 
> " diffusion 2.1."
> 
> ),

Is it an incorrect conjecture to say that this switch would make the controlnet, which was made for SD1.5, compatible with SD-Turbo?

---

<div class="post-metadata">

**Author:** ![John6666](https://sea2.discourse-cdn.com/hellohellohello/user_avatar/discuss.huggingface.co/john6666/32/27664_2.png) [@John6666](https://discuss.huggingface.co/u/John6666)\
**Post date:** [December 4, 2025, 6:13pm UTC](https://discuss.huggingface.co/t/help-with-temporalnetv2-in-pytorch/171131/4 "2025-12-04T18:13:41Z")

</div>

Hmm… ControlNet is nearly unusable with models that have even slightly different architectures. While it appears difficult to use with `SD-Turbo`, an equivalent ControlNet for standard SD 2.1 seems to exist. e.g. [https://huggingface.co/daydreamlive/TemporalNet2-stable-diffusion-2-1](https://huggingface.co/daydreamlive/TemporalNet2-stable-diffusion-2-1)

* * *

You are correct that you should **not** expect your current SD-1.5 TemporalNet2 to be “compatible” with SD-Turbo in any reliable way, and it is **incorrect** to think that `--upcast_attention` would make it compatible. That flag only changes how attention is _numerically computed_ (precision), not which base model a ControlNet is trained for.

Below is the reasoning, with canonical references.

* * *

## 1. What you have working now (SD-1.5 + TemporalNet2)

You currently have:

- Base model: **Stable Diffusion 1.5–family**.

- ControlNet: **TemporalNet2** , via

TemporalNet2 itself is described as:

> “TemporalNet was a ControlNet model designed to enhance the temporal consistency of generated outputs”

and further discussions and docs explain it as:

- A **ControlNet-style network** , architecturally matched to SD-1.5’s UNet.

- Conditioned on **6 channels** :

You converted `wav/TemporalNet2` to `diffusion_pytorch_model.bin`, and your pipeline now correctly accepts these 6 conditioning channels and produces images.

So your working configuration is:

> **SD-1.5 base + TemporalNet2 (SD-1.5-trained ControlNet, 6-channel conditioning).**

* * *

## 2. What SD-Turbo actually is (canonical reference)

The canonical reference for SD-Turbo is the Hugging Face model card `stabilityai/sd-turbo`. It states:

- **“SD-Turbo is a distilled version of Stable Diffusion 2.1, trained for real-time synthesis.”**
- The distillation uses **Adversarial Diffusion Distillation (ADD)**, which allows sampling in **1–4 steps** while retaining high image quality.

So:

- Architecturally, SD-Turbo is still a **UNet2DConditionModel** with the same high-level structure as **Stable Diffusion 2.1**.
- But its weights and denoising behavior are those of a **distilled SD-2.1** , not SD-1.5.

Community discussions also summarize this simply as:

> “That is based on SD 2.1, not 1.5.”

So **SD-Turbo is SD-2.1-family** , not SD-1.5-family.

* * *

## 3. How ControlNet (and TemporalNet2) depends on the base model

The key design of ControlNet is: it **copies the UNet blocks of the base model** and adds a trainable branch that learns to inject conditioning information:

- The official ControlNet README (canonical reference: `lllyasviel/ControlNet`) describes it as:

- The model card explicitly lists several **“ControlNet+SD1.5” models** (scribble, segmentation, etc.), emphasizing that each ControlNet is tied to a specific base family:

Independent descriptions of ControlNet’s architecture say the same thing: **extra inputs are fed into a trainable copy of the original UNet encoder** and then fused with the base model in intermediate layers.

Consequences:

1. **Shape coupling**

2. **Training-distribution coupling**

Early ControlNet documentation and A1111 guides were explicit that the first generation models were **for SD-1.5 only** and not meant to be used with SD-2.x.

TemporalNet2 is “just” a 6-channel special-purpose ControlNet:

- It uses the same ControlNet idea (copy of UNet blocks).
- But its **conditioning** is previous frame + optical flow.
- And it was **trained in the SD-1.5 ecosystem** , as the TemporalNet/TemporalNet2 repos and discussions make clear.

So your `wav/TemporalNet2` is, in effect:

> “A ControlNet-style UNet side branch that expects SD-1.5’s latent features and noise schedule.”

* * *

## 4. What `--upcast_attention` actually does (canonical script)

The `--upcast_attention` option you quoted comes from the official Diffusers conversion script  
`convert_original_stable_diffusion_to_diffusers.py`. The relevant part is:

```python
parser.add_argument(
    "--upcast_attention",
    action="store_true",
    help=(
        "Whether the attention computation should always be upcasted. "
        "This is necessary when running stable diffusion 2.1."
    ),
)

```

The **canonical meaning** of this flag is:

- In the UNet, attention is often computed in **float16** for speed and memory.

- For **Stable Diffusion 2.1** , using FP16 attention can cause **numerical issues** (overflows/instability) because of:

- `--upcast_attention` just tells Diffusers to **compute attention in float32 (FP32)** even if the rest of the model is half-precision, to avoid those stability issues.

Important:

- It **does not** change the architecture.
- It **does not** change which base model a ControlNet was trained for.
- It **does not** adapt SD-1.5-trained weights to SD-2.1/SD-Turbo.

It is purely a **numerical-stability flag** for SD-2.1-family models, not a compatibility switch.

* * *

## 5. Why an SD-1.5 TemporalNet2 is not “made compatible” with SD-Turbo

Putting this together:

### 5.1 Base families are different

- **SD-1.5** : uses CLIP-ViT/L/14 as text encoder, trained on LAION-5B v1-style data at 512×512; the original 1.x line.

- **SD-2.1** : same overall UNet parameter count as 1.5 but:

- **SD-Turbo** : is explicitly described as

So from TemporalNet2’s point of view:

- Moving from **SD-1.5 → SD-Turbo** means:

The ControlNet branch (TemporalNet2) you have was **never trained on those features**.

### 5.2 What can actually happen if you force it

If you somehow wire an SD-1.5 TemporalNet2 into an SD-Turbo pipeline:

- **Best case** :

- **Worst case** :

Either way, **`--upcast_attention` does not fix any of this** ; it only changes FP16→FP32 math inside attention layers.

### 5.3 Community guidance mirrors this

- ControlNet’s official README and model cards emphasize base-specific models (“ControlNet+SD1.5 model”, SD-2.1 branches, SDXL branches).
- A1111 ControlNet discussions explicitly state early on that the extension and its models were _for SD-1.5 only_, and not SD-2.x, until separate models appeared.

So your underlying intuition:

> “If I go from SD-1.5 to SD-Turbo, I can no longer meaningfully use the SD-1.5 TemporalNet2.”

is **essentially correct**. You should treat SD-1.5 TemporalNet2 and SD-Turbo as belonging to different ecosystems.

And the conjecture:

> “Maybe `--upcast_attention` makes the SD-1.5 TemporalNet2 compatible with SD-Turbo.”

is **incorrect**. That flag changes attention precision only; it does not retarget, re-train, or re-architect the ControlNet.

* * *

## 6. If you want SD-Turbo _and_ TemporalNet-style behavior

This part goes beyond your exact question, but it is the natural “what next?”:

- SD-Turbo is **SD-2.1-family** , so the _correct_ temporal ControlNet to combine with it would be a **TemporalNet2 trained for SD-2.1** , not the SD-1.5 version.
- There are community TemporalNet2 checkpoints published specifically for **Stable Diffusion 2.1** (e.g. model cards labeled “TemporalNet2 _stable-diffusion-2-1_”), which are architecturally aligned to SD-2.1 and are a far better match for SD-Turbo than your SD-1.5 TemporalNet2. (These we discussed earlier; they are separate repos from the original SD-1.5 TemporalNet2.)

The pattern that other projects use is the same as with 2.1 ControlNets like canny/depth:

- Base: `stabilityai/sd-turbo` (distilled SD-2.1).
- ControlNet: any **SD-2.1-trained** ControlNet (canny, depth, TemporalNet2-for-2.1, etc.).

That is _still_ a bit experimental (because SD-Turbo is distilled), but it is fundamentally more sound than trying to bolt an SD-1.5 ControlNet onto SD-Turbo.

* * *

## 7. Direct answers to your questions

> “Moving forward, I am thinking of going from SD-1.5 to SD-Turbo … am I right to assume that I can no longer use the TemporalNet because it will not be compatible?”

For your **current** TemporalNet2 (the SD-1.5 one you converted via `wav/TemporalNet2`):

- Yes, treat it as **not compatible in any reliable way with SD-Turbo**.
- Even if you can hack something that runs, it won’t be architecturally or training-wise correct for SD-2.1/SD-Turbo.

> “Is it an incorrect conjecture to say that this switch (`--upcast_attention`) would make the controlnet, which was made for SD-1.5, compatible with SD-Turbo?”

Yes, that conjecture is **incorrect** :

- `--upcast_attention` only controls **numeric precision of attention** for SD-2.1-family models (compute attention in FP32 instead of FP16).

- It does **not** :

To use TemporalNet-style control with SD-Turbo, you should look at **TemporalNet2 checkpoints trained for SD-2.1** , not reuse the SD-1.5 checkpoint with a precision flag.

* * *

### Bullet summary

- **Your current TemporalNet2** (`wav/TemporalNet2`) is a ControlNet-style model **trained for SD-1.5** , using 6-channel conditioning (previous frame + optical flow).

- **SD-Turbo** (`stabilityai/sd-turbo`) is a **distilled Stable Diffusion 2.1** model, not SD-1.5.

- **ControlNets are base-specific** : they copy the base UNet and are trained on that base model’s feature distribution (text encoder, noise schedule, dataset).

- The `--upcast_attention` flag in the conversion script **only upcasts attention math to FP32 for SD-2.1** ; it does **not** adapt SD-1.5 ControlNet weights to SD-2.1 or SD-Turbo.

- Therefore:

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/hellohellohello/original/2X/d/de4155eb4aa4108ecb32a1389d7cc37ae69f88b7.png) [@system](https://discuss.huggingface.co/u/system)\
**Post date:** [December 5, 2025, 6:14am UTC](https://discuss.huggingface.co/t/help-with-temporalnetv2-in-pytorch/171131/5 "2025-12-05T06:14:17Z")

</div>

This topic was automatically closed 12 hours after the last reply. New replies are no longer allowed.
