mehdiPrunaAI commited on
Commit
e9932d5
·
0 Parent(s):

Duplicate from mehdiPrunaAI/LTX2_3_PrunedDecoder

Browse files
.gitattributes ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ example/student/04MhZs7YN08-Scene-0048.mp4 filter=lfs diff=lfs merge=lfs -text
37
+ example/student/7y57zc-GvBA-Scene-0009.mp4 filter=lfs diff=lfs merge=lfs -text
38
+ example/student/8YSha7iU2ZI-Scene-1025.mp4 filter=lfs diff=lfs merge=lfs -text
39
+ example/student/97moBezrzLo-Scene-0076.mp4 filter=lfs diff=lfs merge=lfs -text
40
+ example/student/9GDE5-rOOfk-Scene-0010.mp4 filter=lfs diff=lfs merge=lfs -text
41
+ example/student/a5M8hWgQbjU-Scene-0191.mp4 filter=lfs diff=lfs merge=lfs -text
42
+ example/student/DZt-RtpcJZQ-Scene-0043_m2.mp4 filter=lfs diff=lfs merge=lfs -text
43
+ example/student/FAfMSWi0FSA-Scene-0200.mp4 filter=lfs diff=lfs merge=lfs -text
44
+ example/student/ijGuAu0lLNM-Scene-0008.mp4 filter=lfs diff=lfs merge=lfs -text
45
+ example/student/zFehFw9SbDw-Scene-0034.mp4 filter=lfs diff=lfs merge=lfs -text
46
+ example/teacher/04MhZs7YN08-Scene-0048.mp4 filter=lfs diff=lfs merge=lfs -text
47
+ example/teacher/7y57zc-GvBA-Scene-0009.mp4 filter=lfs diff=lfs merge=lfs -text
48
+ example/teacher/8YSha7iU2ZI-Scene-1025.mp4 filter=lfs diff=lfs merge=lfs -text
49
+ example/teacher/97moBezrzLo-Scene-0076.mp4 filter=lfs diff=lfs merge=lfs -text
50
+ example/teacher/9GDE5-rOOfk-Scene-0010.mp4 filter=lfs diff=lfs merge=lfs -text
51
+ example/teacher/a5M8hWgQbjU-Scene-0191.mp4 filter=lfs diff=lfs merge=lfs -text
52
+ example/teacher/DZt-RtpcJZQ-Scene-0043_teacher.mp4 filter=lfs diff=lfs merge=lfs -text
53
+ example/teacher/FAfMSWi0FSA-Scene-0200.mp4 filter=lfs diff=lfs merge=lfs -text
54
+ example/teacher/ijGuAu0lLNM-Scene-0008.mp4 filter=lfs diff=lfs merge=lfs -text
55
+ example/teacher/zFehFw9SbDw-Scene-0034.mp4 filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ base_model:
3
+ - Lightricks/LTX-2.3
4
+ pipeline_tag: text-to-video
5
+ ---
6
+ <!-- header start -->
7
+ <!-- 200823 -->
8
+ <div style="width: auto; margin-left: auto; margin-right: auto">
9
+ <a href="https://docs.pruna.ai/en/latest/setup/pip.html" target="_blank" rel="noopener noreferrer">
10
+ <img src="https://imgur.com/rVAgqMY.png" alt="PrunaAI" style="width: 100%; min-width: 400px; display: block; margin: auto;">
11
+ </a>
12
+ </div>
13
+ <!-- header end -->
14
+
15
+ [![GitHub](https://img.shields.io/badge/GitHub-PrunaAI-9334E9?style=plastic&logo=github&logoColor=white)](https://github.com/PrunaAI/pruna) &nbsp;
16
+ [![Twitter/X](https://img.shields.io/badge/Twitter%2FX-@PrunaAI-9334E9?style=plastic&logo=x&logoColor=white)](https://twitter.com/PrunaAI) &nbsp;
17
+ [![LinkedIn](https://img.shields.io/badge/LinkedIn-PrunaAI-9334E9?style=plastic&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/pruna-ai) &nbsp;
18
+ [![Discord](https://img.shields.io/badge/Discord-Join%20us-9334E9?style=plastic&logo=discord&logoColor=white)](https://discord.com/invite/JFQmtFKCjd) &nbsp;
19
+ [![P-Models](https://img.shields.io/badge/Performance%20Models-Try%20them%20now-9334E9?style=plastic&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MTEiIGhlaWdodD0iNDc3IiBmaWxsPSJub25lIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMjMuNzAzIDMwMC41MzJjLTEuODQyLS42NzQtNC4xNDItMS4wNTctNS43MDMtMi4wMjktMTIuNTU4LTcuODQ2LTguODM3LTI1LjE3MiA1LjI1NS0yOC4zNjFhLjY2LjY2IDAgMCAwIC4zNDgtLjIwMS42LjYgMCAwIDAgLjE1Ni0uMzZxNi40OS04MS45ODYgNjguNTc3LTEzNC42MjlhLjM0LjM0IDAgMCAwIC4wOTItLjEyNS4zMy4zMyAwIDAgMC0uMDI2LS4zLjMzLjMzIDAgMCAwLS4xMTItLjEwOGMtNC4xMTUtMi40OTctOC42NC00Ljc1LTEyLjM1My03LjQ0M2ExOTAgMTkwIDAgMCAxLTE4Ljc5NC0xNS41MjJjLTIuOTM2LTIuNzY4LTMuNzAzLTUuODkxLjU4LTcuNzdhLjUuNSAwIDAgMCAuMjgtLjYwOEM1MyA3NS45NSA0OC40MTcgNDguNTk5IDQ1LjUxOCAxOS42NXEtLjM5My0zLjg1Mi0uMjcxLTYuMzJhLjc1Ljc1IDAgMCAxIC4xMzQtLjQuNy43IDAgMCAxIC4zMjQtLjI1NXEyLjEwNC0uODQyIDUuODQ0LTEuNDMxYzU4LjExNC05LjEzNiAxMjcuMDA5IDguNDI1IDE0NC4zMDcgNzIuNjQ1cS4xMDMuMzY0LjE3OCAwIDUuMDk2LTI0LjA5NyA0LjYzOC00OC4xOTMtLjA0Ny0yLjc4NyAxLjg3OS00Ljc4OCAxMC40MDctMTAuOCAyNC43OTgtOC42ODdjNy40NzEgMS4wOTUgNy43NDIgNC42MzggNy4yMDkgMTEuMWEzMzQgMzM0IDAgMCAxLTExLjg4NCA2NC43MDYuMzg4LjM4OCAwIDAgMCAuMTgyLjQ0NC40LjQgMCAwIDAgLjE2NC4wNTFjOTIuNDIxIDguNDUzIDE1OC44NzUgNzkuNDg5IDE2NS4wODQgMTcxLjI3NGExIDEgMCAwIDAgLjEyOS40MjQuODMuODMgMCAwIDAgLjI5MS4yOTZjMy43NSAyLjE3IDYuMiAyLjIxNiA4Ljg1NSA2LjU5MiA1LjA2OCA4LjMzMiAxLjQ1IDIwLjQzMS04LjU5MyAyMi40N2ExLjcxIDEuNzEgMCAwIDAtMS4zNjUgMS40NjhxLTkuMTczIDc1LjM4My02NC43NjIgMTIzLjM3MWMtMjguNjIyIDI0LjcwNC02NS43NDQgMzkuNzQ5LTEwMy40NjQgNDIuMzMtMTAwLjM1OSA2Ljg2My0xODQuNDg2LTY1LjYyMi0xOTUuMDA1LTE2NS41N2EuOC44IDAgMCAwLS4xNTQtLjM5NS43NC43NCAwIDAgMC0uMzMzLS4yNU0xNTEuMzM4IDk3LjY0M2wxOS4wNjYgMTkuMzc1YS41LjUgMCAwIDAgLjE1LjEuNS41IDAgMCAwIC4xNzYuMDMxLjQzLjQzIDAgMCAwIC4zMTktLjE1cTEwLjg0Ny0xMi40NjUgNy40NDMtMjguMTU1Yy00LjUzNS0yMC44Ni0xOC41OTgtMzcuNjY0LTM3LjI3MS00OC4zODktMjEuMDY3LTEyLjY4OS00Ny44NjUtMTUuOTA1LTcyLjI4LTE0Ljg0cS0uNjE3LjAzLS4xNC40MjJsNjMuNDcyIDUzLjMyNmEuNC40IDAgMCAwIC4xNDQuMDcyLjM0LjM0IDAgMCAwIC4zMDEtLjA2OC4zLjMgMCAwIDAgLjA4OC0uMTI2IDQ3IDQ3IDAgMCAwIDMuMjgyLTEzLjA4MXEuMDIzLS4yMzMuMTI0LS40MzN0LjI2OC0uMzM0YzIuOTU1LTIuNDc4IDQuMTE1LjQ1OCA0LjY5NCAyLjg1MnEyLjMyIDkuNTM3LjE4NyAxOS4yNDRhMS40OCAxLjQ4IDAgMCAwIC40NCAxLjQwM3ptLTYuNTI2IDkuMjk1LTkuMDI0LTEwLjI3NmEuNy43IDAgMCAwLS4zNDMtLjIwNy44Ni44NiAwIDAgMC0uNDMzIDBxLTExLjY4IDMuMDIxLTIzLjExNC0uODIyYy01LjgxNi0zLjg1Mi0uNzU4LTUuNTE3IDIuNTktNS44MTZxNS45MTgtLjUzMyAxMS43MzUtMi41MDZhLjMuMyAwIDAgMCAuMTI3LS4wOC4zLjMgMCAwIDAgLjA3My0uMTMzLjM0LjM0IDAgMCAwIC4wMDEtLjE1NC4zNC4zNCAwIDAgMC0uMDctLjEzOGMtMTkuNDU5LTIxLjE1LTQwLjc2LTQwLjI0NS02Mi4yNzUtNTkuMjY0cS0uMzU2LS4zMTgtLjMxOC4xNWEzMDggMzA4IDAgMCAwIDguMzg3IDUxLjgwMmM0LjU5MiAxOC4zMDggMTMuNzU1IDM0LjE1NyAzMS44NDggNDEuODcycTI2LjI0NyAxMS4xODIgNTMuNzI5IDIuODMzYS41ODMuNTgzIDAgMCAwIC4yOTktLjg4OCAyMzUgMjM1IDAgMCAwLTEzLjIxMi0xNi4zNzNtNDUuMTI1IDQ5Ljc0NXEtMTIuNTk1IDEuMzE4LTIzLjQ0MS01LjU4M2MtMy4wNzctNC44OTkgMi4wNjYtOC41OTMgNS40NDItMTEuMTgzYS41ODQuNTg0IDAgMCAwIC4xODctLjcwMSA4LjQ2IDguNDYgMCAwIDAtMy40ODgtMy44NjIuODEuODEgMCAwIDAtLjgyMy4wMDljLTE2LjY5MSA5Ljk3Ny0zNC40ODUgMTAuNzgyLTUzLjE4NiA2Ljk2N3EtMS41Ny0uMzItMi44NTIuNjQ1LTYxLjQ1MSA0Ni4zNy02OS42NyAxMjMuOTEzLS42ODMgNi40MzMtMS44MDYgOC44MjdjLTIuOTQ1IDYuMzAyLTcuNzcgNy44NDUtMTQuMjIyIDkuNDcycS0uNDQ5LjExMyAwIC4yMzRjOS4yNzYgMi4zMSAxNC42OCA2LjE0MyAxNi4wNzQgMTYuNDAxIDguNDYyIDYyLjQ5IDQ4Ljk0IDExNy44NjQgMTEwLjM4MyAxMzguMzQxYTEwNCAxMDQgMCAwIDAgMTEuMDA2IDMuNTA3YzkyLjY0NSAyMy45MDkgMTgxLjIzMi0zMy42NjIgMjAyLjgwNC0xMjUuMDU0cTEuNjA5LTYuNzkgMy40NS0xOS4wODVjMS4xMDQtNy4zOTYgNS42OTUtMTIuMTE4IDEzLjE0Ny0xMy41NjguNDEyLS4wODQgMS45MDgtLjc1Ny4yODEtLjk5MS04LjA1MS0xLjE0MS0xMi4yNC02LjM4Ni0xMi45ODgtMTQuMTI4cS0xLjA3NS0xMS4yNS0yLjUxNi0xOS4wMzhjLTExLjc3Mi02My44OTItNTYuMzgzLTExNC41NzItMTE5LjI4NS0xMzEuNDZxLTE1LjEyLTMuODgtMzAuOTg3LTUuMjQ1YS4zODYuMzg2IDAgMCAwLS40MDIuMjUyIDE2OC42IDE2OC42IDAgMCAxLTExLjM1MiAyNC44NTRjLTQuMTMzIDcuNDA2LTguMTYzIDE1LjQ5NC0xNS43NTYgMTYuNDc2Ii8+PGNpcmNsZSBjeD0iMTQwLjA2NSIgY3k9IjI3My4wMyIgcj0iNTAuNjE4IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iOS4yMDMiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTQ2Ljk2NyAyNDIuMDkyYzE1LjY3MiAwIDI4LjM3NiAxMy45NjMgMjguMzc2IDMxLjE4OHMtMTIuNzA0IDMxLjE4OS0yOC4zNzYgMzEuMTg5LTI4LjM3Ny0xMy45NjQtMjguMzc3LTMxLjE4OWMwLTIuNjI1LjI5Ny01LjE3NC44NTItNy42MSAxLjYwNyAzLjcyNyA1LjMxMyA2LjMzOCA5LjYyOSA2LjMzOCA1Ljc4OSAwIDEwLjQ4MS00LjY5MyAxMC40ODItMTAuNDgycy00LjY5My0xMC40ODEtMTAuNDgyLTEwLjQ4MWMtLjc2MSAwLTEuNTA0LjA4My0yLjIxOS4yMzcgNS4xMzktNS42NzYgMTIuMjUzLTkuMTkgMjAuMTE1LTkuMTkiLz48Y2lyY2xlIGN4PSIyNjkuOTMyIiBjeT0iMjczLjAzIiByPSI1MC42MTgiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSI5LjIwMyIvPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0yNzYuODM0IDI0Mi4wOTJjMTUuNjcyIDAgMjguMzc2IDEzLjk2MyAyOC4zNzYgMzEuMTg4cy0xMi43MDQgMzEuMTg5LTI4LjM3NiAzMS4xODktMjguMzc3LTEzLjk2NC0yOC4zNzctMzEuMTg5YzAtMi42MjUuMjk3LTUuMTc0Ljg1My03LjYxIDEuNjA2IDMuNzI3IDUuMzEyIDYuMzM4IDkuNjI4IDYuMzM4IDUuNzg5IDAgMTAuNDgyLTQuNjkzIDEwLjQ4Mi0xMC40ODJzLTQuNjkzLTEwLjQ4MS0xMC40ODItMTAuNDgxYy0uNzYxIDAtMS41MDQuMDgzLTIuMjE5LjIzNyA1LjEzOS01LjY3NiAxMi4yNTQtOS4xOSAyMC4xMTUtOS4xOSIvPjxwYXRoIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSI5LjIwMyIgZD0iTTE3Ny4xMzUgMzQ1LjMyOGMuODk5LS4yNCAyLjgwMS0uMTk3IDYuMzA0LjQ2NCA2LjMxMSAxLjE5IDE2LjU4NSA0LjIyMSAyNi4xMjIgNC4yMjEgOS40NTIgMCAxNy4xMTgtMS45MjYgMjEuMzgzLTIuNjAzLjc3LS4xMjMgMS4zODUtLjE5OSAxLjg3OC0uMjM3LS4zNCAxMy44NDMtMTIuODkzIDI3LjcxLTI3Ljg2OCAyNy43MS0xNS4xNzIgMC0yNy44NzYtMTMuODM1LTI3Ljg3Ni0yOC44MTEgMC0uMzU3LjAyOS0uNTk2LjA1Ny0uNzQ0WiIvPjwvc3ZnPg==)](https://dashboard.pruna.ai/login?utm_source=huggingface&utm_medium=org_card&utm_campaign=hf_traffic)
20
+
21
+ <div align="center">
22
+
23
+ <h1 style="color: #9334E9;">⚡ PrunaVAED</h1>
24
+
25
+ <h2>A drop-in replacement decoder for LTX-2.3</h2>
26
+
27
+ <h3>
28
+ <span style="color: #9334E9;">1.7× faster</span>
29
+ &nbsp;·&nbsp;
30
+ <span style="color: #9334E9;">~50% lower peak VRAM</span>
31
+ &nbsp;·&nbsp;
32
+ Near-original visual quality
33
+ </h3>
34
+
35
+ </div>
36
+
37
+ **PrunaVAED directly replaces the video VAE decoder in
38
+ [`diffusers/LTX-2.3-Diffusers`](https://huggingface.co/diffusers/LTX-2.3-Diffusers).
39
+ The encoder and latent format remain unchanged, making it a drop-in upgrade
40
+ for faster, more memory-efficient LTX-2.3 decoding.**
41
+
42
+ ## Examples
43
+
44
+ Both columns decode the same LTX-2.3 latent from the distilled pipeline.
45
+
46
+ <table>
47
+ <tr>
48
+ <th align="center">LTX-2.3 decoder</th>
49
+ <th align="center">⚡ PrunaVAED</th>
50
+ </tr>
51
+ <tr>
52
+ <td>
53
+ <video controls autoplay muted loop playsinline
54
+ src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/teacher/04MhZs7YN08-Scene-0048.mp4">
55
+ </video>
56
+ </td>
57
+ <td>
58
+ <video controls autoplay muted loop playsinline
59
+ src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/student/04MhZs7YN08-Scene-0048.mp4">
60
+ </video>
61
+ </td>
62
+ </tr>
63
+ <tr>
64
+ <td>
65
+ <video controls autoplay muted loop playsinline
66
+ src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/teacher/FAfMSWi0FSA-Scene-0200.mp4">
67
+ </video>
68
+ </td>
69
+ <td>
70
+ <video controls autoplay muted loop playsinline
71
+ src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/student/FAfMSWi0FSA-Scene-0200.mp4">
72
+ </video>
73
+ </td>
74
+ </tr>
75
+ </table>
76
+
77
+ <details>
78
+ <summary><strong>More side-by-side comparisons</strong></summary>
79
+
80
+ <br>
81
+
82
+ <table>
83
+ <tr>
84
+ <th align="center">LTX-2.3 decoder</th>
85
+ <th align="center">⚡ PrunaVAED</th>
86
+ </tr>
87
+ <tr>
88
+ <td><video controls autoplay muted loop playsinline src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/teacher/8YSha7iU2ZI-Scene-1025.mp4"></video></td>
89
+ <td><video controls autoplay muted loop playsinline src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/student/8YSha7iU2ZI-Scene-1025.mp4"></video></td>
90
+ </tr>
91
+ <tr>
92
+ <td><video controls autoplay muted loop playsinline src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/teacher/DZt-RtpcJZQ-Scene-0043_teacher.mp4"></video></td>
93
+ <td><video controls autoplay muted loop playsinline src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/student/DZt-RtpcJZQ-Scene-0043_m2.mp4"></video></td>
94
+ </tr>
95
+ <tr>
96
+ <td><video controls autoplay muted loop playsinline src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/teacher/9GDE5-rOOfk-Scene-0010.mp4"></video></td>
97
+ <td><video controls autoplay muted loop playsinline src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/student/9GDE5-rOOfk-Scene-0010.mp4"></video></td>
98
+ </tr>
99
+ <tr>
100
+ <td><video controls autoplay muted loop playsinline src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/teacher/7y57zc-GvBA-Scene-0009.mp4"></video></td>
101
+ <td><video controls autoplay muted loop playsinline src="https://huggingface.co/mehdiPrunaAI/PrunaVAED/resolve/main/example/student/7y57zc-GvBA-Scene-0009.mp4"></video></td>
102
+ </tr>
103
+ </table>
104
+
105
+ </details>
106
+
107
+
108
+ ## Benchmark
109
+
110
+ Metrics compare videos decoded from the **same latents** by the LTX-2.3 VAED and PrunaVAED. Two set of latents were
111
+ generated with the full
112
+ [`ti2vid_two_stages`](https://github.com/Lightricks/LTX-2/blob/main/packages/ltx-pipelines/src/ltx_pipelines/ti2vid_two_stages.py)
113
+ pipeline and the
114
+ [`distilled`](https://github.com/Lightricks/LTX-2/blob/main/packages/ltx-pipelines/src/ltx_pipelines/distilled.py)
115
+ pipeline (recommended). (~4 s @ 24 fps)
116
+
117
+ | Setting | Value |
118
+ |---|---|
119
+ | Model | PrunaVAED |
120
+ | Precision | `bfloat16` |
121
+ | Batch size | 1 |
122
+ | Device | NVIDIA H100 80GB |
123
+ | Decode | Full (no tiling / rolling / `torch.compile`) |
124
+
125
+ | Latent set | Clips | PSNR ↑ | LPIPS ↓ | SSIM ↑ | Δ-frame PSNR ↑ |
126
+ |---|---:|---:|---:|---:|---:|
127
+ | Distilled two-stage · 720p | 200 | **37.87** | **0.0108** | **0.9898** | **37.28** |
128
+ | TI2Vid two-stage · 720p | 200 | **38.86** | **0.0123** | **0.9803** | **38.98** |
129
+ | Distilled two-stage · 1080p | 200 | **39.59** | **0.0067** | **0.9927** | **39.37** |
130
+
131
+ **Δ-frame PSNR** is PSNR on consecutive-frame
132
+ differences (temporal consistency).
133
+
134
+ ## Test
135
+
136
+ End-to-end smoke test: generate a short video with the diffusers LTX-2.3
137
+ **distilled** two-stage pipeline, then decode the same latent with the stock
138
+ LTX-2.3 VAE and with PrunaVAED. Writes two mp4s and prints decode time (ms).
139
+ Needs a **CUDA GPU**.
140
+
141
+ ```bash
142
+ # 1. Install the Hugging Face CLI
143
+ pip install hf
144
+
145
+ # 2. Download this repo
146
+ hf download PrunaAI/LTX23-PrunedDecoder --local-dir prunaVAED
147
+ cd prunaVAED
148
+
149
+ # 3. Install dependencies
150
+ pip install -r requirements-test.txt
151
+
152
+ # 4. Run the test (~720p, ~5 s @ 24 fps)
153
+ python tests/test_distilled_decode.py
154
+ ```
155
+
156
+ Outputs land in `outputs/test_distilled/` (`ltx23.mp4`, `prunavaed.mp4`).
157
+ Edit `PROMPT` / resolution at the top of `tests/test_distilled_decode.py` if needed.
158
+
159
+
160
+ ## Architecture
161
+
162
+ PrunaVAED is bitwise identical to LTX 2.3 VAED from `conv_in` to `up_blocks.0`. Pruning starts
163
+ at `up_blocks.1`.
164
+
165
+ | Stage | Channel reduction |
166
+ |---|---:|
167
+ | `up_blocks.0` | unchanged |
168
+ | `up_blocks.1` | 25% |
169
+ | `up_blocks.2` | 50% |
170
+ | `up_blocks.3` | 50% |
171
+
172
+ | | Teacher (LTX-2.3) | PrunaVAED |
173
+ |---|---:|---:|
174
+ | Encoder params | 318.9 M | 318.9 M (unchanged) |
175
+ | Decoder params | 407.2 M | 345.0 M (−15%) |
176
+ | **Total VAE params** | **726.1 M** | **663.9 M** |
177
+
178
+ `prunavaed/patch_diffusers.py` provides the required compatibility shim for
179
+ the pinned diffusers version.
180
+
181
+ ## Limitations
182
+
183
+ - Evaluated on 4-second clips at 24 fps.
184
+ - Benchmarked on one H100 80GB with bfloat16 and batch size 1.
185
+ - Speed and VRAM vary with hardware, resolution, batch size, and software.
186
+ - Evaluated only on two differents pipeline of LTX 2.3 ([`ti2vid_two_stages`](https://github.com/Lightricks/LTX-2/blob/main/packages/ltx-pipelines/src/ltx_pipelines/ti2vid_two_stages.py)
187
+ pipeline and the
188
+ [`distilled`](https://github.com/Lightricks/LTX-2/blob/main/packages/ltx-pipelines/src/ltx_pipelines/distilled.py))
189
+ - The weights can be adapted to the custom [`LTX-2`](https://github.com/Lightricks/LTX-2) library without retraining, but no implementation is provided for this yet.
190
+
191
+ ## What this is not
192
+
193
+ - Not a full T2V model.
194
+ - Not a replacement for the LTX denoiser/generator.
195
+ - Not compatible with arbitrary VAE latents.
196
+ - Not bit-exact with the original decoder.
197
+
198
+ ## License
199
+
200
+ PrunaVAED is a derivative of LTX-2.3 and is distributed under the
201
+ **[LTX-2 Community License Agreement](LICENSE)**. Review its use restrictions
202
+ and commercial terms before using or redistributing the model.
203
+
204
+ Helper code adapted from Hugging Face diffusers retains its Apache-2.0
205
+ attribution; see [`NOTICE`](NOTICE).
206
+
207
+ ## Try next
208
+
209
+ - **Use PrunaVAED to speed up LTX-2.3 decoding.**
210
+ - Try Pruna's end-to-end video models:
211
+ [P-Video](https://www.pruna.ai/p-video) and
212
+ [P-Video documentation](https://docs.pruna.ai/en/stable/docs_pruna_endpoints/performance_models/p-video.html).
example/student/04MhZs7YN08-Scene-0048.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:43d29de4e52f013f14a82d1f4d41d78f7bb938184f30af48d2e53d09efffe558
3
+ size 1797361
example/student/7y57zc-GvBA-Scene-0009.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2de528d80672faf55079399ddf14533ef77b274099407d35fec5fec552b89ae3
3
+ size 1716725
example/student/8YSha7iU2ZI-Scene-1025.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c4c8ebfb36da16485337d9b2a48210efa707dedf8992c55be068629e1310c03d
3
+ size 898616
example/student/97moBezrzLo-Scene-0076.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c614003deb538d3b02d5e80010f0167b9c1a0fd55e62863479db9ab0e7134c89
3
+ size 1897236
example/student/9GDE5-rOOfk-Scene-0010.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:845ad0a7d35633fe3ddf73da94534d468eb2ac36f6faa450db6c841439f785dd
3
+ size 2308198
example/student/DZt-RtpcJZQ-Scene-0043_m2.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:06f56792ff2d4793d12b4283c20788e4be6c22ea876729899b7e46614016c1f6
3
+ size 1214808
example/student/FAfMSWi0FSA-Scene-0200.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9442659a2cb5b6328bb8f0849b466a4e6b572243f1350efa93cc2cb70261ec10
3
+ size 1883423
example/student/a5M8hWgQbjU-Scene-0191.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:af8032ecb4f9e3f5db93ff04293b296979cfba55351f73a1f309e1508d412c83
3
+ size 3051778
example/student/ijGuAu0lLNM-Scene-0008.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4eb2af16643f4402da2585878e41257e951141c491556e335b72abab3a9f26eb
3
+ size 1697225
example/student/zFehFw9SbDw-Scene-0034.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cf0ff506cb5ade7308c5ad0752bbe57e0b88b37462c5d4f20be10d6c3ff7961b
3
+ size 2129229
example/teacher/04MhZs7YN08-Scene-0048.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:320db36560a3b9abac5c710bed668c0b25f8bc3b9cdd1935ba65ecec0ee2174f
3
+ size 1697633
example/teacher/7y57zc-GvBA-Scene-0009.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:004434c148e393a6be129a5682fd357b9340f035595d3f09348d764e487dd1e8
3
+ size 1697114
example/teacher/8YSha7iU2ZI-Scene-1025.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ddabd909bc729ef15a643a0a63d4937d3846c5165a99d56b83e6e3f06b743179
3
+ size 828088
example/teacher/97moBezrzLo-Scene-0076.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:dba2ff092c0d4ed2fe369c9f3525d03f0e6b8d3d240f392a366e89e5b3149ad7
3
+ size 1848784
example/teacher/9GDE5-rOOfk-Scene-0010.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a9cb3ab14edb2e0b772b5e472e1d3cb3ef802cba138095d7f52b119ea8a74c44
3
+ size 2239655
example/teacher/DZt-RtpcJZQ-Scene-0043_teacher.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:51facb9d24858bd48cdf7e565c4da9c863e875c9121e83b050233c31a59826b6
3
+ size 1174232
example/teacher/FAfMSWi0FSA-Scene-0200.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:505d374a8cc0caf0378903199684b2d0db7326ccac7c8f186d9b2eb4690f32ae
3
+ size 1864634
example/teacher/a5M8hWgQbjU-Scene-0191.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b7629400d5d318681018cd22bb934d7ba728887c307e8be69853d0d1e01f1526
3
+ size 3360331
example/teacher/ijGuAu0lLNM-Scene-0008.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b221c4b8606983128306ed1b6e7d049f300b5439b720a3f5c8bcbc9673f5b8b6
3
+ size 1711726
example/teacher/zFehFw9SbDw-Scene-0034.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:688f0d785cb9dafa858a35ac5192380df50483b81392dc1690ad32393ce536d2
3
+ size 2125596
patch_diffusers.py ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright 2026 Pruna AI
2
+ # Portions adapted from Hugging Face diffusers:
3
+ # Copyright 2026 The HuggingFace Team. Licensed under Apache-2.0.
4
+
5
+ """Monkey-patch stock diffusers so pruned LTX-2.3 decoder weights load correctly.
6
+
7
+ Stock diffusers builds the decoder graph from ``decoder_block_out_channels`` using
8
+ the *nominal* width of each up block (divided by ``upsample_factor``). It assumes the
9
+ tensor leaving block N always matches that nominal width.
10
+
11
+ PrunaVAED keeps wider skip connections between blocks and only prunes inside each
12
+ block. Example on ``up_blocks.2``:
13
+
14
+ - tensor arriving from ``up_blocks.1``: **384** ch (after 512→384 projection)
15
+ - ResNets inside ``up_blocks.2``: **128** ch (50% pruned vs LTX-2.3 decoder 256)
16
+ - ``conv_in`` projection inside the block: **384 → 256** (feeds the upsampler)
17
+
18
+ Stock diffusers wires ``up_blocks.2`` as 192 → 128 and never creates the 384→256
19
+ ``conv_in``, so ``from_pretrained`` fails with shape mismatches on PrunaVAED weights.
20
+
21
+ Fix (two ``__init__`` replacements; forward/decode unchanged)
22
+ ------------------------------------------------------------
23
+ 1. ``LTX2VideoDecoder3d``: track ``current_channels`` — the actual tensor width
24
+ between blocks — instead of recomputing from the previous block's nominal width.
25
+ 2. ``LTX2VideoUpBlock3d``: insert ``conv_in`` when ``in_channels != out_channels *
26
+ upscale_factor`` (pre-upsampler width), not when ``in_channels != out_channels``.
27
+
28
+ The LTX-2.3 decoder is unaffected (no extra projections). Safe to call before any
29
+ ``AutoencoderKLLTX2Video.from_pretrained``.
30
+ """
31
+
32
+ from __future__ import annotations
33
+
34
+ import torch
35
+ import torch.nn as nn
36
+ from diffusers.models.autoencoders import autoencoder_kl_ltx2 as ltx2
37
+
38
+
39
+ def patch_pruna_ltx2_decoder() -> None:
40
+ if getattr(ltx2, "_PRUNA_LTX2_DECODER_PATCH", False):
41
+ return
42
+
43
+ Resnet = ltx2.LTX2VideoResnetBlock3d
44
+ Upsampler = ltx2.LTX2VideoUpsampler3d
45
+ CausalConv = ltx2.LTX2VideoCausalConv3d
46
+ MidBlock = ltx2.LTX2VideoMidBlock3d
47
+ UpBlock = ltx2.LTX2VideoUpBlock3d
48
+ TimeEmb = ltx2.PixArtAlphaCombinedTimestepSizeEmbeddings
49
+ RMSNorm = ltx2.PerChannelRMSNorm
50
+
51
+ def up_init(
52
+ self,
53
+ in_channels,
54
+ out_channels=None,
55
+ num_layers=1,
56
+ dropout=0.0,
57
+ resnet_eps=1e-6,
58
+ resnet_act_fn="swish",
59
+ spatio_temporal_scale=True,
60
+ upsample_type="spatiotemporal",
61
+ inject_noise=False,
62
+ timestep_conditioning=False,
63
+ upsample_residual=False,
64
+ upscale_factor=1,
65
+ spatial_padding_mode="zeros",
66
+ ):
67
+ nn.Module.__init__(self)
68
+ out_channels = out_channels or in_channels
69
+ # Width right before the upsampler (ResNet width × upscale_factor).
70
+ # conv_in projects the incoming skip (e.g. 384) down to this width (e.g. 256).
71
+ pre = out_channels * upscale_factor
72
+ self.time_embedder = TimeEmb(in_channels * 4, 0) if timestep_conditioning else None
73
+ self.conv_in = None
74
+ if in_channels != pre: # stock diffusers compares in_channels != out_channels
75
+ self.conv_in = Resnet(
76
+ in_channels=in_channels,
77
+ out_channels=pre,
78
+ dropout=dropout,
79
+ eps=resnet_eps,
80
+ non_linearity=resnet_act_fn,
81
+ inject_noise=inject_noise,
82
+ timestep_conditioning=timestep_conditioning,
83
+ spatial_padding_mode=spatial_padding_mode,
84
+ )
85
+ self.upsamplers = None
86
+ if spatio_temporal_scale:
87
+ stride = {
88
+ "spatial": (1, 2, 2),
89
+ "temporal": (2, 1, 1),
90
+ "spatiotemporal": (2, 2, 2),
91
+ }[upsample_type]
92
+ self.upsamplers = nn.ModuleList(
93
+ [
94
+ Upsampler(
95
+ in_channels=pre,
96
+ stride=stride,
97
+ residual=upsample_residual,
98
+ upscale_factor=upscale_factor,
99
+ spatial_padding_mode=spatial_padding_mode,
100
+ ),
101
+ ]
102
+ )
103
+ self.resnets = nn.ModuleList(
104
+ [
105
+ Resnet(
106
+ in_channels=out_channels,
107
+ out_channels=out_channels,
108
+ dropout=dropout,
109
+ eps=resnet_eps,
110
+ non_linearity=resnet_act_fn,
111
+ inject_noise=inject_noise,
112
+ timestep_conditioning=timestep_conditioning,
113
+ spatial_padding_mode=spatial_padding_mode,
114
+ )
115
+ for _ in range(num_layers)
116
+ ]
117
+ )
118
+ self.gradient_checkpointing = False
119
+
120
+ def decoder_init(
121
+ self,
122
+ in_channels=128,
123
+ out_channels=3,
124
+ block_out_channels=(256, 512, 1024),
125
+ spatio_temporal_scaling=(True, True, True),
126
+ layers_per_block=(5, 5, 5, 5),
127
+ upsample_type=("spatiotemporal", "spatiotemporal", "spatiotemporal"),
128
+ patch_size=4,
129
+ patch_size_t=1,
130
+ resnet_norm_eps=1e-6,
131
+ is_causal=False,
132
+ inject_noise=(False, False, False),
133
+ timestep_conditioning=False,
134
+ upsample_residual=(True, True, True),
135
+ upsample_factor=(2, 2, 2),
136
+ spatial_padding_mode="reflect",
137
+ ):
138
+ nn.Module.__init__(self)
139
+ n = len(layers_per_block)
140
+ if isinstance(spatio_temporal_scaling, bool):
141
+ spatio_temporal_scaling = (spatio_temporal_scaling,) * (n - 1)
142
+ if isinstance(inject_noise, bool):
143
+ inject_noise = (inject_noise,) * n
144
+ if isinstance(upsample_residual, bool):
145
+ upsample_residual = (upsample_residual,) * (n - 1)
146
+
147
+ self.patch_size, self.patch_size_t = patch_size, patch_size_t
148
+ self.out_channels = out_channels * patch_size**2
149
+ self.is_causal = is_causal
150
+
151
+ ch = tuple(reversed(block_out_channels))
152
+ spatio_temporal_scaling = tuple(reversed(spatio_temporal_scaling))
153
+ layers_per_block = tuple(reversed(layers_per_block))
154
+ inject_noise = tuple(reversed(inject_noise))
155
+ upsample_residual = tuple(reversed(upsample_residual))
156
+ upsample_factor = tuple(reversed(upsample_factor))
157
+ upsample_type = tuple(upsample_type)
158
+ if len(upsample_type) == len(ch) - 1:
159
+ upsample_type = tuple(reversed(upsample_type))
160
+
161
+ width = ch[0]
162
+ self.conv_in = CausalConv(
163
+ in_channels=in_channels,
164
+ out_channels=width,
165
+ kernel_size=3,
166
+ stride=1,
167
+ spatial_padding_mode=spatial_padding_mode,
168
+ )
169
+ self.mid_block = MidBlock(
170
+ in_channels=width,
171
+ num_layers=layers_per_block[0],
172
+ resnet_eps=resnet_norm_eps,
173
+ inject_noise=inject_noise[0],
174
+ timestep_conditioning=timestep_conditioning,
175
+ spatial_padding_mode=spatial_padding_mode,
176
+ )
177
+
178
+ # Stock: input_channel = previous_nominal // factor (loses pruned skip widths).
179
+ # Patched: pass the real tensor width from the previous block as in_channels.
180
+ self.up_blocks = nn.ModuleList()
181
+ current = width
182
+ for i in range(len(ch)):
183
+ resnet_w = ch[i] // upsample_factor[i]
184
+ self.up_blocks.append(
185
+ UpBlock(
186
+ in_channels=current,
187
+ out_channels=resnet_w,
188
+ num_layers=layers_per_block[i + 1],
189
+ resnet_eps=resnet_norm_eps,
190
+ spatio_temporal_scale=spatio_temporal_scaling[i],
191
+ upsample_type=upsample_type[i],
192
+ inject_noise=inject_noise[i + 1],
193
+ timestep_conditioning=timestep_conditioning,
194
+ upsample_residual=upsample_residual[i],
195
+ upscale_factor=upsample_factor[i],
196
+ spatial_padding_mode=spatial_padding_mode,
197
+ )
198
+ )
199
+ current = resnet_w
200
+
201
+ self.norm_out = RMSNorm()
202
+ self.conv_act = nn.SiLU()
203
+ self.conv_out = CausalConv(
204
+ in_channels=current,
205
+ out_channels=self.out_channels,
206
+ kernel_size=3,
207
+ stride=1,
208
+ spatial_padding_mode=spatial_padding_mode,
209
+ )
210
+ self.time_embedder = self.scale_shift_table = self.timestep_scale_multiplier = None
211
+ if timestep_conditioning:
212
+ self.timestep_scale_multiplier = nn.Parameter(torch.tensor(1000.0))
213
+ self.time_embedder = TimeEmb(width * 2, 0)
214
+ self.scale_shift_table = nn.Parameter(torch.randn(2, width) / width**0.5)
215
+ self.gradient_checkpointing = False
216
+
217
+ UpBlock.__init__ = up_init
218
+ ltx2.LTX2VideoDecoder3d.__init__ = decoder_init
219
+ ltx2._PRUNA_LTX2_DECODER_PATCH = True
requirements-test.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --extra-index-url https://download.pytorch.org/whl/cu130
2
+ torch==2.11.0+cu130
3
+ torchvision==0.26.0+cu130
4
+ torchaudio==2.11.0+cu130
5
+ diffusers==0.39.0
6
+ huggingface_hub==1.24.0
7
+ safetensors==0.8.0
8
+ accelerate==1.13.0
9
+ imageio==2.37.3
10
+ imageio-ffmpeg==0.6.0
11
+
12
+ transformers>=4.57.0
13
+ sentencepiece>=0.2.0
14
+ protobuf>=5.0.0
15
+ Pillow>=10.0.0
16
+ numpy>=1.24.0
17
+ tqdm>=4.66.0
18
+ av>=14.0.0
19
+ pytest>=8.0.0
tests/test_distilled_decode.py ADDED
@@ -0,0 +1,223 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Quick demo: generate a short LTX-2.3 video latent, then decode it twice.
3
+
4
+ Compares the stock LTX-2.3 VAE decoder with this repo's pruned decoder
5
+ (PrunaVAED) on the *same* latent. Prints decode time (ms) and writes two mp4s.
6
+
7
+ Requires a CUDA GPU. From the repo root:
8
+
9
+ pip install -r requirements-test.txt
10
+ python tests/test_distilled_decode.py
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import statistics
16
+ import sys
17
+ import time
18
+ from pathlib import Path
19
+
20
+ import imageio.v3 as iio
21
+ import torch
22
+ from diffusers import LTX2LatentUpsamplePipeline, LTX2Pipeline
23
+ from diffusers.models.autoencoders import AutoencoderKLLTX2Video
24
+ from diffusers.pipelines.ltx2.latent_upsampler import LTX2LatentUpsamplerModel
25
+ from diffusers.pipelines.ltx2.utils import (
26
+ DEFAULT_NEGATIVE_PROMPT,
27
+ DISTILLED_SIGMA_VALUES,
28
+ STAGE_2_DISTILLED_SIGMA_VALUES,
29
+ )
30
+
31
+ torch.backends.cuda.enable_cudnn_sdp(False)
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Settings (edit these if you want)
35
+ # ---------------------------------------------------------------------------
36
+
37
+ REPO_ROOT = Path(__file__).resolve().parents[1]
38
+ sys.path.insert(0, str(REPO_ROOT))
39
+
40
+ from patch_diffusers import patch_pruna_ltx2_decoder # noqa: E402
41
+
42
+ # Official Diffusers checkpoints for the 2-stage distilled recipe.
43
+ DISTILLED_MODEL = "diffusers/LTX-2.3-Distilled-Diffusers"
44
+ SPATIAL_UPSAMPLER = "dg845/LTX-2.3-Spatial-Upsampler-Diffusers"
45
+ LTX23_VAE = "diffusers/LTX-2.3-Diffusers" # stock decoder (baseline)
46
+ PRUNED_VAE = REPO_ROOT # this repo's vae/ folder
47
+
48
+ # ~720p for 5 s @ 24 fps. Height/width must be multiples of 64 (2-stage).
49
+ HEIGHT, WIDTH, NUM_FRAMES, FPS = 704, 1280, 121, 24.0
50
+ SEED = 42
51
+ DECODE_WARMUP, DECODE_RUNS = 1, 3 # timing: 1 warm-up + median of 3 runs
52
+
53
+ PROMPT = (
54
+ "In the video, a man is seen riding a skateboard in an indoor skate park. "
55
+ "He is wearing a black cap, a grey t-shirt, and black pants. The skate park "
56
+ "has a wooden floor and a ramp. The man performs a trick by jumping and "
57
+ "flipping the skateboard under his feet while in the air. He lands on the "
58
+ "skateboard and continues to ride it."
59
+ )
60
+
61
+ DEVICE = "cuda"
62
+ DTYPE = torch.bfloat16
63
+ OUTPUT_DIR = REPO_ROOT / "outputs" / "test_distilled"
64
+
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # Helpers
68
+ # ---------------------------------------------------------------------------
69
+
70
+ def save_mp4(video: torch.Tensor, path: Path) -> None:
71
+ """Save a BCTHW tensor in [-1, 1] as an H.264 mp4."""
72
+ frames = video[0].permute(1, 2, 3, 0).clamp(-1, 1)
73
+ frames = ((frames + 1) / 2 * 255).byte().cpu().numpy()
74
+ path.parent.mkdir(parents=True, exist_ok=True)
75
+ iio.imwrite(path, frames, fps=FPS, codec="libx264")
76
+
77
+
78
+ def load_vae(model_id: str) -> AutoencoderKLLTX2Video:
79
+ """Load a video VAE decoder and put it on GPU."""
80
+ vae = AutoencoderKLLTX2Video.from_pretrained(
81
+ model_id, subfolder="vae", torch_dtype=DTYPE
82
+ )
83
+ vae = vae.to(DEVICE).eval()
84
+ vae.use_tiling = False
85
+ if hasattr(vae, "disable_tiling"):
86
+ vae.disable_tiling()
87
+ return vae
88
+
89
+
90
+ @torch.inference_mode()
91
+ def timed_decode(vae: AutoencoderKLLTX2Video, latent: torch.Tensor) -> tuple[torch.Tensor, float]:
92
+ """Decode once after warm-up; return (video on CPU, median latency in ms)."""
93
+ latent = latent.to(DEVICE, DTYPE)
94
+
95
+ with torch.autocast(DEVICE, dtype=DTYPE):
96
+ for _ in range(DECODE_WARMUP):
97
+ vae.decode(latent, return_dict=False)
98
+
99
+ times_ms = []
100
+ video = None
101
+ for _ in range(DECODE_RUNS):
102
+ torch.cuda.synchronize()
103
+ t0 = time.perf_counter()
104
+ with torch.autocast(DEVICE, dtype=DTYPE):
105
+ video = vae.decode(latent, return_dict=False)[0]
106
+ torch.cuda.synchronize()
107
+ times_ms.append((time.perf_counter() - t0) * 1000)
108
+
109
+ return video.cpu(), statistics.median(times_ms)
110
+
111
+
112
+ @torch.inference_mode()
113
+ def generate_latent(prompt: str) -> torch.Tensor:
114
+ """Run the official 2-stage distilled pipeline and return the final video latent.
115
+
116
+ Same layout as Lightricks DistilledPipeline:
117
+ stage 1 @ half-res → 2× latent upsample → stage 2 @ full-res.
118
+ """
119
+ half_h, half_w = HEIGHT // 2, WIDTH // 2
120
+ generator = torch.Generator(DEVICE).manual_seed(SEED)
121
+
122
+ pipe = LTX2Pipeline.from_pretrained(DISTILLED_MODEL, torch_dtype=DTYPE)
123
+ pipe.enable_model_cpu_offload(device=DEVICE)
124
+
125
+ # Stage 1 — cheap draft at half resolution.
126
+ print(f"1/3 Stage 1 @ {half_w}×{half_h}")
127
+ video_latent, audio_latent = pipe(
128
+ prompt=prompt,
129
+ negative_prompt=DEFAULT_NEGATIVE_PROMPT,
130
+ height=half_h,
131
+ width=half_w,
132
+ num_frames=NUM_FRAMES,
133
+ frame_rate=FPS,
134
+ num_inference_steps=len(DISTILLED_SIGMA_VALUES),
135
+ sigmas=DISTILLED_SIGMA_VALUES,
136
+ guidance_scale=1.0,
137
+ generator=generator,
138
+ output_type="latent",
139
+ return_dict=False,
140
+ )
141
+
142
+ # Upsample — bring the latent to full resolution before refining.
143
+ print(f"2/3 Upsample → {WIDTH}×{HEIGHT}")
144
+ upsampler = LTX2LatentUpsamplerModel.from_pretrained(
145
+ SPATIAL_UPSAMPLER, subfolder="latent_upsampler", torch_dtype=DTYPE
146
+ )
147
+ upsample_pipe = LTX2LatentUpsamplePipeline(vae=pipe.vae, latent_upsampler=upsampler)
148
+ upsample_pipe.enable_model_cpu_offload(device=DEVICE)
149
+ video_latent = upsample_pipe(
150
+ latents=video_latent[:1],
151
+ height=half_h,
152
+ width=half_w,
153
+ num_frames=NUM_FRAMES,
154
+ output_type="latent",
155
+ return_dict=False,
156
+ )[0]
157
+ del upsample_pipe, upsampler
158
+ torch.cuda.empty_cache()
159
+
160
+ # Stage 2 — refine at full resolution (renoises from STAGE_2 schedule).
161
+ print(f"3/3 Stage 2 @ {WIDTH}×{HEIGHT}")
162
+ video_latent, _ = pipe(
163
+ latents=video_latent,
164
+ audio_latents=audio_latent,
165
+ prompt=prompt,
166
+ negative_prompt=DEFAULT_NEGATIVE_PROMPT,
167
+ height=HEIGHT,
168
+ width=WIDTH,
169
+ num_frames=NUM_FRAMES,
170
+ frame_rate=FPS,
171
+ num_inference_steps=len(STAGE_2_DISTILLED_SIGMA_VALUES),
172
+ noise_scale=STAGE_2_DISTILLED_SIGMA_VALUES[0],
173
+ sigmas=STAGE_2_DISTILLED_SIGMA_VALUES,
174
+ guidance_scale=1.0,
175
+ generator=generator,
176
+ output_type="latent",
177
+ return_dict=False,
178
+ )
179
+
180
+ latent = video_latent.detach().cpu()
181
+ del pipe
182
+ torch.cuda.empty_cache()
183
+ return latent
184
+
185
+
186
+ def compare_decoders(latent: torch.Tensor, out_dir: Path) -> None:
187
+ """Decode the same latent with LTX-2.3 and PrunaVAED; print ms and save mp4s."""
188
+ # Needed so Diffusers can build the pruned decoder graph correctly.
189
+ patch_pruna_ltx2_decoder()
190
+
191
+ results = {}
192
+ for name, model_id in (("ltx23", LTX23_VAE), ("prunavaed", str(PRUNED_VAE))):
193
+ print(f"Decoding with {name} …")
194
+ vae = load_vae(model_id)
195
+ video, ms = timed_decode(vae, latent)
196
+ results[name] = ms
197
+ path = out_dir / f"{name}.mp4"
198
+ save_mp4(video, path)
199
+ print(f" {name}: {ms:.1f} ms → {path}")
200
+ del vae, video
201
+ torch.cuda.empty_cache()
202
+
203
+ print(f"Speedup: {results['ltx23'] / results['prunavaed']:.2f}×")
204
+
205
+
206
+ # ---------------------------------------------------------------------------
207
+ # Entry point
208
+ # ---------------------------------------------------------------------------
209
+
210
+ def main() -> None:
211
+ if not torch.cuda.is_available():
212
+ raise SystemExit("This demo needs a CUDA GPU.")
213
+
214
+ print(f"Prompt: {PROMPT[:80]}…")
215
+ print(f"Output: {OUTPUT_DIR}")
216
+
217
+ latent = generate_latent(PROMPT)
218
+ print(f"Latent shape: {tuple(latent.shape)}")
219
+ compare_decoders(latent, OUTPUT_DIR)
220
+
221
+
222
+ if __name__ == "__main__":
223
+ main()
vae/config.json ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_class_name": "AutoencoderKLLTX2Video",
3
+ "_diffusers_version": "0.38.0",
4
+ "aligned_blks_indices": null,
5
+ "aligned_feature_projection_dim": null,
6
+ "aligned_feature_projection_mode": null,
7
+ "block_out_channels": [
8
+ 256,
9
+ 512,
10
+ 1024,
11
+ 1024
12
+ ],
13
+ "decoder_block_out_channels": [
14
+ 128,
15
+ 256,
16
+ 384,
17
+ 1024
18
+ ],
19
+ "decoder_causal": false,
20
+ "decoder_inject_noise": [
21
+ false,
22
+ false,
23
+ false,
24
+ false,
25
+ false
26
+ ],
27
+ "decoder_layers_per_block": [
28
+ 4,
29
+ 6,
30
+ 4,
31
+ 2,
32
+ 2
33
+ ],
34
+ "decoder_spatial_padding_mode": "zeros",
35
+ "decoder_spatio_temporal_scaling": [
36
+ true,
37
+ true,
38
+ true,
39
+ true
40
+ ],
41
+ "down_block_types": [
42
+ "LTX2VideoDownBlock3D",
43
+ "LTX2VideoDownBlock3D",
44
+ "LTX2VideoDownBlock3D",
45
+ "LTX2VideoDownBlock3D"
46
+ ],
47
+ "downsample_type": [
48
+ "spatial",
49
+ "temporal",
50
+ "spatiotemporal",
51
+ "spatiotemporal"
52
+ ],
53
+ "encoder_causal": true,
54
+ "encoder_spatial_padding_mode": "zeros",
55
+ "in_channels": 3,
56
+ "latent_channels": 128,
57
+ "layers_per_block": [
58
+ 4,
59
+ 6,
60
+ 4,
61
+ 2,
62
+ 2
63
+ ],
64
+ "out_channels": 3,
65
+ "patch_size": 4,
66
+ "patch_size_t": 1,
67
+ "resnet_norm_eps": 1e-06,
68
+ "scaling_factor": 1.0,
69
+ "spatial_compression_ratio": 32,
70
+ "spatio_temporal_scaling": [
71
+ true,
72
+ true,
73
+ true,
74
+ true
75
+ ],
76
+ "temporal_compression_ratio": 8,
77
+ "timestep_conditioning": false,
78
+ "upsample_factor": [
79
+ 2,
80
+ 2,
81
+ 1,
82
+ 2
83
+ ],
84
+ "upsample_residual": [
85
+ false,
86
+ false,
87
+ false,
88
+ false
89
+ ],
90
+ "upsample_type": [
91
+ "spatiotemporal",
92
+ "spatiotemporal",
93
+ "temporal",
94
+ "spatial"
95
+ ]
96
+ }
vae/diffusion_pytorch_model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d2fe12c4f25ac2fbfec6e5f3e9d481f70caf52be24471f114f7d09f26f8340dd
3
+ size 1327909418