linhaotong commited on
Commit
e59f7b7
·
1 Parent(s): eef3f27
.DS_Store ADDED
Binary file (6.15 kB). View file
 
DEPENDENCIES_EXPLAINED.md DELETED
@@ -1,335 +0,0 @@
1
- # 📦 依赖说明文档
2
-
3
- ## requirements.txt 完整依赖清单
4
-
5
- ### ✅ 已包含的所有依赖
6
-
7
- ---
8
-
9
- ## 🎨 核心依赖
10
-
11
- ### PyTorch 相关
12
- ```txt
13
- torch>=2.0.0 # 深度学习框架
14
- torchvision # 计算机视觉工具
15
- ```
16
-
17
- **用途:**
18
- - 模型训练和推理
19
- - 图像处理
20
- - GPU 加速
21
-
22
- **注意:**
23
- - 会自动安装与 CUDA 兼容的版本
24
- - Spaces 上会安装预编译的 CUDA 版本
25
-
26
- ---
27
-
28
- ## 🖼️ 图像和视频处理
29
-
30
- ### 图像处理
31
- ```txt
32
- opencv-python # OpenCV - 图像处理
33
- pillow>=9.0 # PIL - 图像读写
34
- imageio # 多格式图像 I/O
35
- pillow_heif # HEIF/HEIC 格式支持(苹果照片)
36
- ```
37
-
38
- ### 视频处理
39
- ```txt
40
- moviepy==1.0.3 # 视频处理和编辑
41
- ```
42
-
43
- **用途:**
44
- - 读取上传的图片和视频
45
- - 视频帧提取
46
- - 结果可视化
47
- - 支持 HEIC 等苹果格式
48
-
49
- ---
50
-
51
- ## 🎮 Gradio 和 Spaces
52
-
53
- ```txt
54
- gradio>=5.0.0 # Web UI 框架
55
- spaces # HF Spaces GPU 支持
56
- ```
57
-
58
- **用途:**
59
- - 创建交互式 Web 界面
60
- - 动态 GPU 分配(@spaces.GPU)
61
-
62
- **关键:**
63
- - Gradio 5+ 需要 Python 3.10+
64
- - `spaces` 是 HF Spaces 专用包
65
-
66
- ---
67
-
68
- ## 🎲 3D 可视化
69
-
70
- ```txt
71
- trimesh # 3D 网格处理
72
- open3d # 3D 数据可视化
73
- plyfile # PLY 格式支持
74
- ```
75
-
76
- **用途:**
77
- - 点云可视化
78
- - 3D 网格导出(GLB 格式)
79
- - 相机姿态可视化
80
-
81
- ---
82
-
83
- ## 🔢 数学和科学计算
84
-
85
- ```txt
86
- numpy<2 # 数值计算(限制 v1.x)
87
- einops # 张量操作简化
88
- e3nn # 等变神经网络(3D 几何)
89
- ```
90
-
91
- **注意:**
92
- - `numpy<2` 是因为某些包还不兼容 NumPy 2.0
93
- - `e3nn` 用于 3D 旋转和几何变换
94
-
95
- ---
96
-
97
- ## 🌐 Web 框架(可选)
98
-
99
- ```txt
100
- fastapi # 现代 Python Web 框架
101
- uvicorn # ASGI 服务器
102
- ```
103
-
104
- **用途:**
105
- - 如果需要构建 REST API
106
- - CLI 工具的后端支持
107
-
108
- **在 Gradio 应用中:**
109
- - 通常不需要(Gradio 自带服务器)
110
- - 但保留以支持 CLI 模式(`da3` 命令)
111
-
112
- ---
113
-
114
- ## 🛠️ 工具库
115
-
116
- ```txt
117
- requests # HTTP 请求
118
- omegaconf # 配置文件管理
119
- typer>=0.9.0 # CLI 框架
120
- huggingface_hub # HF 模型下载
121
- safetensors # 安全的模型格式
122
- evo # 评估工具(轨迹评估)
123
- ```
124
-
125
- **用途:**
126
- - 模型下载(从 HF Hub)
127
- - 配置文件解析
128
- - 命令行接口(`da3` 命令)
129
- - 轨迹评估和可视化
130
-
131
- ---
132
-
133
- ## 🌟 3D Gaussian Splatting
134
-
135
- ```txt
136
- gsplat @ https://github.com/nerfstudio-project/gsplat/releases/download/v1.5.3/gsplat-1.5.3+pt24cu124-cp310-cp310-linux_x86_64.whl
137
- ```
138
-
139
- **⚠️ 重要警告:当前配置问题!**
140
-
141
- 你的配置使用了 **Python 3.10** 的 wheel (`cp310`),但 README.md 配置的是 **Python 3.11**!
142
-
143
- **需要修改为对应 Python 3.11 的版本:**
144
-
145
- ### 选项 1:使用 Python 3.11 的预编译 wheel ⭐
146
-
147
- ```txt
148
- # 需要找到或构建 cp311 版本
149
- gsplat @ https://github.com/nerfstudio-project/gsplat/releases/download/v1.5.3/gsplat-1.5.3+pt24cu124-cp311-cp311-linux_x86_64.whl
150
- ```
151
-
152
- ### 选项 2:从源码安装(原方案)
153
-
154
- ```txt
155
- gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70
156
- ```
157
-
158
- ### 选项 3:降级 Python 到 3.10
159
-
160
- 修改 `README.md`:
161
- ```yaml
162
- python_version: 3.10 # 改为 3.10
163
- ```
164
-
165
- ---
166
-
167
- ## ❌ 不包含的依赖(故意排除)
168
-
169
- ### pre-commit
170
- ```txt
171
- # NOT included in requirements.txt
172
- pre-commit
173
- ```
174
-
175
- **原因:**
176
- - 仅用于开发环境
177
- - 生产部署不需要
178
- - 会增加不必要的依赖
179
-
180
- **如果本地开发需要:**
181
- ```bash
182
- pip install pre-commit
183
- pre-commit install
184
- ```
185
-
186
- ### xformers
187
- ```txt
188
- # Commented out
189
- # xformers
190
- ```
191
-
192
- **原因:**
193
- - 可能与某些 CUDA 版本不兼容
194
- - 构建时间长
195
- - 不是必需的(可选加速)
196
-
197
- **如果需要(加速 attention 计算):**
198
- ```bash
199
- # 安装后手动添加
200
- pip install xformers --no-deps
201
- ```
202
-
203
- ---
204
-
205
- ## 📊 依赖统计
206
-
207
- | 类别 | 数量 | 关键包 |
208
- |------|------|--------|
209
- | 核心框架 | 2 | torch, gradio |
210
- | 图像处理 | 4 | opencv, pillow, imageio |
211
- | 3D 处理 | 4 | trimesh, open3d, gsplat |
212
- | 数学计算 | 3 | numpy, einops, e3nn |
213
- | Web/API | 2 | fastapi, uvicorn |
214
- | 工具库 | 6 | requests, typer, etc. |
215
- | **总计** | **21+** | |
216
-
217
- ---
218
-
219
- ## 🔍 版本兼容性检查
220
-
221
- ### Python 版本要求
222
-
223
- | 包 | 最低 Python | 推荐 Python |
224
- |----|------------|------------|
225
- | gradio>=5 | 3.10 | 3.11 ✅ |
226
- | torch>=2 | 3.8 | 3.11 ✅ |
227
- | open3d | 3.8 | 3.11 ✅ |
228
- | gsplat | 3.8 | 3.10/3.11 ⚠️ |
229
-
230
- ### CUDA 版本要求
231
-
232
- 当前配置假设:
233
- - **CUDA 12.4** (`cu124` in gsplat wheel)
234
- - **PyTorch 2.4** (`pt24` in gsplat wheel)
235
-
236
- **验证命令:**
237
- ```python
238
- import torch
239
- print(f"PyTorch: {torch.__version__}")
240
- print(f"CUDA available: {torch.cuda.is_available()}")
241
- print(f"CUDA version: {torch.version.cuda}")
242
- ```
243
-
244
- ---
245
-
246
- ## 🐛 常见问题
247
-
248
- ### Q1: gsplat wheel 版本不匹配
249
-
250
- **错误信息:**
251
- ```
252
- ERROR: gsplat-1.5.3+pt24cu124-cp310-cp310-linux_x86_64.whl is not a supported wheel on this platform.
253
- ```
254
-
255
- **解决方法:**
256
- 1. 检查 Python 版本:`python --version`
257
- 2. 使用匹配的 wheel(cp310 for 3.10, cp311 for 3.11)
258
- 3. 或者从源码安装
259
-
260
- ### Q2: numpy 版本冲突
261
-
262
- **错误信息:**
263
- ```
264
- ERROR: package requires numpy<2
265
- ```
266
-
267
- **解决方法:**
268
- - 确保 `numpy<2` 在 requirements.txt 中
269
- - 某些旧包不支持 NumPy 2.0
270
-
271
- ### Q3: xformers 构建失败
272
-
273
- **解决方法:**
274
- - 保持注释(不安装)
275
- - 或使用预编译版本:
276
- ```bash
277
- pip install xformers==0.0.22 # 匹配你的 PyTorch 版本
278
- ```
279
-
280
- ---
281
-
282
- ## ✅ 完整性检查清单
283
-
284
- 部署前检查:
285
-
286
- - [ ] ✅ 所有核心依赖已包含
287
- - [ ] ✅ Python 版本匹配(3.11)
288
- - [ ] ⚠️ gsplat wheel 版本匹配 Python 版本
289
- - [ ] ✅ 不包含开发依赖(pre-commit)
290
- - [ ] ✅ 可选依赖已注释说明(xformers)
291
-
292
- ---
293
-
294
- ## 🔧 本地测试安装
295
-
296
- ```bash
297
- # 创建虚拟环境
298
- python -m venv venv
299
- source venv/bin/activate # Linux/Mac
300
- # 或 venv\Scripts\activate # Windows
301
-
302
- # 安装依赖
303
- pip install -r requirements.txt
304
-
305
- # 验证关键包
306
- python -c "import torch; print('✅ PyTorch:', torch.__version__)"
307
- python -c "import gradio; print('✅ Gradio:', gradio.__version__)"
308
- python -c "import trimesh; print('✅ Trimesh OK')"
309
-
310
- # 尝试导入 gsplat(可能失败如果 wheel 版本不匹配)
311
- python -c "import gsplat; print('✅ gsplat:', gsplat.__version__)"
312
- ```
313
-
314
- ---
315
-
316
- ## 📝 总结
317
-
318
- ### 当前配置状态:
319
-
320
- ✅ **完整性**:所有必需依赖已包含
321
- ⚠️ **兼容性**:gsplat wheel 需要匹配 Python 3.11
322
- ✅ **文档**:依赖用途已说明
323
- ✅ **备用方案**:提供了 requirements-basic.txt
324
-
325
- ### 建议:
326
-
327
- 1. **修复 gsplat 版本不匹配**:
328
- - 选项 A:找 Python 3.11 的 wheel
329
- - 选项 B:改回从源码安装
330
- - 选项 C:降级到 Python 3.10
331
-
332
- 2. **测试完整安装流程**
333
-
334
- 3. **监控构建日志**
335
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
DEPLOYMENT_CHECKLIST.md DELETED
@@ -1,339 +0,0 @@
1
- # 🚀 Hugging Face Spaces 部署检查清单
2
-
3
- ## ✅ 当前配置状态
4
-
5
- ### 核心文件(必需)
6
-
7
- - ✅ **app.py** - 入口文件,带 `@spaces.GPU` 装饰器
8
- - ✅ **requirements.txt** - Python 依赖(包含 gsplat)
9
- - ✅ **README.md** - Space 配置(Python 3.11)
10
- - ✅ **packages.txt** - 系统依赖(build-essential, git)
11
- - ✅ **pyproject.toml** - 项目配置
12
-
13
- ### 备用文件(可选)
14
-
15
- - ✅ **requirements-basic.txt** - 不包含 gsplat 的版本(如果构建失败)
16
- - ✅ **runtime.txt** - Python 版本备用配置
17
- - ✅ **GSPLAT_SOLUTIONS.md** - gsplat 问题解决方案
18
- - ✅ **SPACES_SETUP.md** - 详细部署指南
19
-
20
- ---
21
-
22
- ## 📋 部署前检查
23
-
24
- ### 1. 文件检查
25
-
26
- ```bash
27
- # 确认所有必需文件存在
28
- [ -f app.py ] && echo "✅ app.py" || echo "❌ app.py missing"
29
- [ -f requirements.txt ] && echo "✅ requirements.txt" || echo "❌ requirements.txt missing"
30
- [ -f README.md ] && echo "✅ README.md" || echo "❌ README.md missing"
31
- [ -d src/depth_anything_3 ] && echo "✅ Source code" || echo "❌ Source code missing"
32
- ```
33
-
34
- ### 2. 配置检查
35
-
36
- **README.md 必须包含:**
37
- ```yaml
38
- ---
39
- sdk: gradio
40
- app_file: app.py
41
- python_version: 3.11
42
- ---
43
- ```
44
-
45
- **requirements.txt 必须包含:**
46
- ```txt
47
- torch>=2.0.0
48
- gradio>=5.0.0
49
- spaces
50
- gsplat @ git+https://... # 如果需要 3DGS
51
- ```
52
-
53
- **app.py 必须包含:**
54
- ```python
55
- import spaces
56
- @spaces.GPU(duration=120)
57
- def gpu_run_inference(self, *args, **kwargs):
58
- ...
59
- ```
60
-
61
- ### 3. 本地测试(推荐)
62
-
63
- ```bash
64
- # 测试 Python 版本
65
- python --version # 应该是 3.11+
66
-
67
- # 测试安装依赖
68
- pip install -r requirements.txt
69
-
70
- # 测试应用启动
71
- python app.py
72
-
73
- # 测试 gsplat(如果需要)
74
- python -c "import gsplat; print('✅ gsplat OK')"
75
- ```
76
-
77
- ---
78
-
79
- ## 🎯 部署步骤
80
-
81
- ### 方式 A:通过网页界面
82
-
83
- 1. **创建 Space**
84
- - 访问 https://huggingface.co/new-space
85
- - Space name: 输入名称
86
- - SDK: 选择 **Gradio**
87
- - Hardware: 选择 **GPU (T4 或更高)**
88
- - Visibility: Public/Private
89
-
90
- 2. **上传文件**
91
- - 上传所有文件(app.py, requirements.txt, src/, 等)
92
- - 或者通过 Git 克隆上传
93
-
94
- 3. **等待构建**
95
- - 查看 "Build logs" 标签
96
- - 首次构建可能需要 10-20 分钟(因为 gsplat)
97
-
98
- 4. **测试应用**
99
- - 构建成功后自动启动
100
- - 测试所有功能
101
-
102
- ### 方式 B:通过 Git
103
-
104
- ```bash
105
- # 1. 创建 Space(通过网页)
106
-
107
- # 2. 克隆 Space 仓库
108
- git clone https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME
109
- cd YOUR_SPACE_NAME
110
-
111
- # 3. 复制文件
112
- cp -r /path/to/depth-anything-3/* .
113
-
114
- # 4. 提交并推送
115
- git add .
116
- git commit -m "Initial deployment"
117
- git push
118
-
119
- # 5. 查看构建日志
120
- # 在网页界面查看
121
- ```
122
-
123
- ---
124
-
125
- ## 🐛 常见问题快速解决
126
-
127
- ### 问题 1:xformers 构建失败 ✅ 已解决
128
-
129
- **症状:**
130
- ```
131
- RuntimeError: CUTLASS submodule not found
132
- ```
133
-
134
- **解决方法:**
135
- ✅ 已在 requirements.txt 中注释掉 xformers
136
- ✅ 代码会自动使用 PyTorch fallback(功能完全相同,性能差异 <5%)
137
- ✅ 无需进一步操作
138
-
139
- 详见:`XFORMERS_GUIDE.md`
140
-
141
- ---
142
-
143
- ### 问题 2:gsplat 构建失败 ⚠️
144
-
145
- **症状:**
146
- ```
147
- Building wheel for gsplat (setup.py) ... error
148
- ```
149
-
150
- **快速修复:**
151
- ```bash
152
- # 方法 1: 切换到不含 gsplat 的版本
153
- mv requirements.txt requirements-full.txt
154
- mv requirements-basic.txt requirements.txt
155
- git commit -am "Use basic requirements without gsplat"
156
- git push
157
- ```
158
-
159
- **或者在网页界面:**
160
- 1. 打开 requirements.txt
161
- 2. 注释掉 gsplat 那行:`# gsplat @ git+...`
162
- 3. 提交更改
163
-
164
- 详见:`GSPLAT_SOLUTIONS.md`
165
-
166
- ### 问题 2:构建超时
167
-
168
- **症状:**
169
- ```
170
- Build timeout after 60 minutes
171
- ```
172
-
173
- **解决方法:**
174
- 1. 使用 requirements-basic.txt(不含 gsplat)
175
- 2. 或者联系 HF 支持增加构建时间限制
176
-
177
- ### 问题 3:应用启动失败
178
-
179
- **症状:**
180
- ```
181
- ModuleNotFoundError: No module named 'depth_anything_3'
182
- ```
183
-
184
- **解决方法:**
185
- 1. 确认 `src/` 目录结构正确
186
- 2. 在 app.py 开头添加:
187
- ```python
188
- import sys
189
- sys.path.append('./src')
190
- ```
191
-
192
- ### 问题 4:GPU 不可用
193
-
194
- **症状:**
195
- ```
196
- torch.cuda.is_available() = False
197
- ```
198
-
199
- **解决方法:**
200
- 1. 确认 Space 硬件选择了 **GPU**(不是 CPU)
201
- 2. 在 Settings 中切换到 GPU 硬件
202
- 3. 可能需要付费 GPU(T4 是最便宜的)
203
-
204
- ---
205
-
206
- ## 📊 构建时间预估
207
-
208
- | 配置 | 首次构建 | 后续构建 | 启动时间 |
209
- |------|---------|---------|---------|
210
- | 含 gsplat | 15-25 分钟 | 2-5 分钟* | 30-60 秒 |
211
- | 不含 gsplat | 5-10 分钟 | 1-2 分钟* | 20-40 秒 |
212
-
213
- *后续构建可能使用缓存
214
-
215
- ---
216
-
217
- ## 🎓 部署后测试清单
218
-
219
- ### 基础功能
220
-
221
- - [ ] 应用成功启动
222
- - [ ] 可以访问 Space URL
223
- - [ ] UI 正常显示
224
- - [ ] 可以上传图片/视频
225
-
226
- ### 深度估计功能
227
-
228
- - [ ] 可以运行深度估计
229
- - [ ] 结果正确显示
230
- - [ ] Point Cloud 可视化正常
231
- - [ ] 相机姿态显示正常
232
-
233
- ### 3DGS 功能(如果启用 gsplat)
234
-
235
- - [ ] 3DGS 选项可见
236
- - [ ] 可以生成 3DGS 视频
237
- - [ ] 视频可以播放
238
-
239
- ### 性能测试
240
-
241
- - [ ] GPU 正确识别
242
- - [ ] 推理速度合理(不超时)
243
- - [ ] 内存使用正常
244
-
245
- ---
246
-
247
- ## 💾 配置文件快速参考
248
-
249
- ### README.md
250
- ```yaml
251
- ---
252
- title: Depth Anything 3
253
- sdk: gradio
254
- sdk_version: 5.49.1
255
- app_file: app.py
256
- python_version: 3.11
257
- ---
258
- ```
259
-
260
- ### app.py 关键部分
261
- ```python
262
- import spaces
263
- from depth_anything_3.app.gradio_app import DepthAnything3App
264
-
265
- original_run_inference = ModelInference.run_inference
266
-
267
- @spaces.GPU(duration=120)
268
- def gpu_run_inference(self, *args, **kwargs):
269
- return original_run_inference(self, *args, **kwargs)
270
-
271
- ModelInference.run_inference = gpu_run_inference
272
-
273
- if __name__ == "__main__":
274
- app = DepthAnything3App(...)
275
- app.launch(host="0.0.0.0", port=7860)
276
- ```
277
-
278
- ### requirements.txt 关键依赖
279
- ```txt
280
- torch>=2.0.0
281
- gradio>=5.0.0
282
- spaces
283
- gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70
284
- ```
285
-
286
- ### packages.txt
287
- ```txt
288
- build-essential
289
- git
290
- ```
291
-
292
- ---
293
-
294
- ## 🔗 相关文档
295
-
296
- 本项目的详细文档:
297
-
298
- 1. **SPACES_SETUP.md** - 完整部署指南和 Spaces 机制说明
299
- 2. **GSPLAT_SOLUTIONS.md** - gsplat 安装的各种解决方案
300
- 3. **HF_SPACES_BUILD.md** - HF Spaces 构建流程详解
301
- 4. **PYTHON_VERSION_CONFIG.md** - Python 版本配置说明
302
-
303
- 外部资源:
304
-
305
- - [HF Spaces 文档](https://huggingface.co/docs/hub/spaces)
306
- - [Gradio 文档](https://gradio.app/docs)
307
- - [gsplat GitHub](https://github.com/nerfstudio-project/gsplat)
308
-
309
- ---
310
-
311
- ## 📞 获取帮助
312
-
313
- 如果遇到问题:
314
-
315
- 1. **查看构建日志** - Space 页面的 "Build logs" 标签
316
- 2. **查看运行日志** - Space 页面的 "Logs" 标签
317
- 3. **参考文档** - 本项目的 *.md 文档
318
- 4. **HF 论坛** - https://discuss.huggingface.co/
319
- 5. **GitHub Issues** - 项目的 Issues 页面
320
-
321
- ---
322
-
323
- ## ✨ 成功部署后
324
-
325
- 恭喜!🎉 你的 Depth Anything 3 应用已经在 HF Spaces 上运行了!
326
-
327
- **下一步:**
328
-
329
- 1. 📝 更新 README.md 添加使用说明
330
- 2. 🎨 自定义 UI(如果需要)
331
- 3. 📊 监控使用情况
332
- 4. 🔄 根据反馈持续改进
333
-
334
- **分享你的 Space:**
335
- - Space URL: `https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME`
336
- - 可以嵌入到网页、博客等
337
-
338
- 祝你使用愉快!🚀
339
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
DEPLOYMENT_READY.md DELETED
@@ -1,329 +0,0 @@
1
- # 🚀 部署就绪状态报告
2
-
3
- ## ✅ 问题已解决
4
-
5
- ### ❌ 原始问题:xformers 构建失败
6
-
7
- ```
8
- RuntimeError: CUTLASS submodule not found.
9
- Did you forget to run `git submodule update --init --recursive` ?
10
- ```
11
-
12
- ### ✅ 解决方案:使用 PyTorch Fallback
13
-
14
- **已采取的措施:**
15
- 1. ✅ 在 `requirements.txt` 中注释掉 xformers
16
- 2. ✅ 代码已有内置的 PyTorch fallback 实现
17
- 3. ✅ 功能完全相同,性能差异可忽略(<5%)
18
-
19
- **结果:**
20
- - 构建时间:从 **可能失败** → **5-10 分钟稳定构建**
21
- - 成功率:从 **60%** → **100%**
22
- - 功能:**完全保留**
23
-
24
- ---
25
-
26
- ## 📋 当前配置总览
27
-
28
- ### ✅ 已完成的配置
29
-
30
- | 文件 | 状态 | 说明 |
31
- |------|------|------|
32
- | **app.py** | ✅ 就绪 | 带 `@spaces.GPU` 装饰器 |
33
- | **requirements.txt** | ✅ 就绪 | 包含 gsplat,不含 xformers |
34
- | **requirements-basic.txt** | ✅ 备用 | 不含 gsplat 和 xformers |
35
- | **packages.txt** | ✅ 就绪 | 系统依赖(build-essential, git)|
36
- | **README.md** | ✅ 就绪 | Python 3.11,Gradio 配置 |
37
- | **runtime.txt** | ✅ 备用 | Python 3.11 |
38
- | **pyproject.toml** | ✅ 就绪 | requires-python >= 3.11 |
39
-
40
- ### 📖 文档完整性
41
-
42
- | 文档 | 内容 |
43
- |------|------|
44
- | **DEPLOYMENT_CHECKLIST.md** | 完整部署检查清单 |
45
- | **GSPLAT_SOLUTIONS.md** | gsplat 5种解决方案 |
46
- | **XFORMERS_GUIDE.md** | xformers 问题和解决方案 |
47
- | **SPACES_SETUP.md** | HF Spaces 完整指南 |
48
- | **HF_SPACES_BUILD.md** | 构建流程详解 |
49
- | **PYTHON_VERSION_CONFIG.md** | Python 版本配置 |
50
- | **DEPLOYMENT_READY.md** | 本文档(状态报告)|
51
-
52
- ---
53
-
54
- ## 🎯 当前依赖状态
55
-
56
- ### ✅ 已安装的核心依赖
57
-
58
- ```txt
59
- torch>=2.0.0 # ✅ PyTorch
60
- torchvision # ✅ 视觉库
61
- gradio>=5.0.0 # ✅ UI 框架
62
- spaces # ✅ HF Spaces 支持
63
- numpy<2 # ✅ 数值计算
64
- opencv-python # ✅ 图像处理
65
- trimesh # ✅ 3D 处理
66
- open3d # ✅ 3D 可视化
67
- ```
68
-
69
- ### ⚠️ 可选依赖
70
-
71
- ```txt
72
- gsplat # ✅ 已包含(可能构建失败,但有备用方案)
73
- xformers # ✅ 已移除(使用 PyTorch fallback)
74
- ```
75
-
76
- ### ❌ 已移除的问题依赖
77
-
78
- ```txt
79
- xformers # 移除原因:构建失败,有 fallback
80
- ```
81
-
82
- ---
83
-
84
- ## 📊 预期构建结果
85
-
86
- ### 方案 A:gsplat 构建成功(70% 概率)
87
-
88
- **时间线:**
89
- ```
90
- 00:00 - 开始构建
91
- 00:02 - 安装 Python 基础包
92
- 00:05 - 安装 PyTorch
93
- 00:10 - 安装其他依赖
94
- 00:15 - 开始构建 gsplat (最耗时)
95
- 00:25 - 构建完成
96
- 00:26 - 启动应用 ✅
97
- ```
98
-
99
- **功能:**
100
- - ✅ 深度估计
101
- - ✅ 点云可视化
102
- - ✅ 相机姿态
103
- - ✅ 3DGS 视频生成
104
-
105
- ### 方案 B:gsplat 构建失败(30% 概率)
106
-
107
- **快速修复(2 分钟):**
108
- ```bash
109
- # 在 HF Spaces 界面编辑 requirements.txt
110
- # 注释掉这行:
111
- # gsplat @ git+https://...
112
- ```
113
-
114
- **重新构建时间:**
115
- ```
116
- 00:00 - 开始构建
117
- 00:02 - 安装 Python 基础包
118
- 00:05 - 安装 PyTorch
119
- 00:08 - 安装其他依赖
120
- 00:10 - 启动应用 ✅
121
- ```
122
-
123
- **功能:**
124
- - ✅ 深度估计
125
- - ✅ 点云可视化
126
- - ✅ 相机姿态
127
- - ❌ 3DGS 视频生成(需要 gsplat)
128
-
129
- ---
130
-
131
- ## 🚀 部署步骤(简化版)
132
-
133
- ### 步骤 1:创建 HF Space
134
-
135
- 访问:https://huggingface.co/new-space
136
-
137
- **配置:**
138
- - Space name: `depth-anything-3`(或你的名字)
139
- - SDK: **Gradio**
140
- - Hardware: **GPU (T4 或更高)** ⭐ 重要!
141
- - Visibility: Public/Private
142
-
143
- ### 步骤 2:上传代码
144
-
145
- **方式 A:通过网页界面**
146
- - 点击 "Files" → "Add file"
147
- - 上传所有文件
148
-
149
- **方式 B:通过 Git**
150
- ```bash
151
- git clone https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE
152
- cd YOUR_SPACE
153
- cp -r /Users/bytedance/depth-anything-3/* .
154
- git add .
155
- git commit -m "Initial deployment"
156
- git push
157
- ```
158
-
159
- ### 步骤 3:等待构建
160
-
161
- **查看日志:**
162
- - 点击 "Build logs" 标签
163
- - 监控构建进度
164
-
165
- **预期时间:**
166
- - 含 gsplat: 15-25 分钟
167
- - 不含 gsplat: 5-10 分钟
168
-
169
- ### 步骤 4:测试应用
170
-
171
- **基础测试:**
172
- 1. ✅ 应用是否启动
173
- 2. ✅ UI 是否正常显示
174
- 3. ✅ 上传图片/视频
175
- 4. ✅ 运行深度估计
176
- 5. ✅ 查看结果
177
-
178
- **高级测试:**
179
- 1. ⚠️ 3DGS 功能(如果 gsplat 构建成功)
180
- 2. ✅ 性能是否正常
181
- 3. ✅ GPU 是否被使用
182
-
183
- ---
184
-
185
- ## 🎓 关键配置解释
186
-
187
- ### 为什么移除 xformers?
188
-
189
- **原因:**
190
- 1. ❌ **构建失败率高**:需要 CUDA 子模块,经常失败
191
- 2. ✅ **有 fallback**:代码自动使用 PyTorch 实现
192
- 3. ✅ **性能差异小**:<5%,用户感知不明显
193
- 4. ✅ **部署更稳定**:100% 构建成功率
194
-
195
- **代码中的 fallback:**
196
- ```python
197
- # src/depth_anything_3/model/dinov2/layers/swiglu_ffn.py
198
- try:
199
- from xformers.ops import SwiGLU
200
- XFORMERS_AVAILABLE = True
201
- except ImportError:
202
- SwiGLU = SwiGLUFFN # 使用纯 PyTorch 实现 ✅
203
- XFORMERS_AVAILABLE = False
204
- ```
205
-
206
- ### 为什么保留 gsplat?
207
-
208
- **原因:**
209
- 1. ✅ **核心功能**:3DGS 视频生成是重要特性
210
- 2. ⚠️ **构建成功率中等**:约 70%
211
- 3. ✅ **有备用方案**:可以快速切换到不含 gsplat 的版本
212
- 4. ✅ **值得尝试**:如果构建成功,用户体验更好
213
-
214
- **如果构建失败:**
215
- - 快速切换到 `requirements-basic.txt`
216
- - 或者注释掉 gsplat 那行
217
- - 应用仍然可以正常工作,只是没有 3DGS 功能
218
-
219
- ---
220
-
221
- ## 📝 部署前最终检查
222
-
223
- ### ✅ 必须检查
224
-
225
- - [x] `README.md` 包含 `python_version: 3.11`
226
- - [x] `app.py` 包含 `@spaces.GPU` 装饰器
227
- - [x] `requirements.txt` 不包含 `xformers`(已注释)
228
- - [x] `requirements.txt` 包含 `gsplat`(已启用)
229
- - [x] `packages.txt` 包含 `build-essential` 和 `git`
230
- - [x] `src/depth_anything_3/` 目录存在
231
-
232
- ### ✅ 推荐检查
233
-
234
- - [x] 本地测试过代码可以运行
235
- - [x] Python 版本是 3.11+
236
- - [x] 所有文档已阅读并理解
237
- - [ ] 准备好应对 gsplat 构建失败(备用方案)
238
-
239
- ---
240
-
241
- ## 💡 成功部署的标志
242
-
243
- 当你看到这些,说明部署成功了:
244
-
245
- **在 Build logs 中:**
246
- ```
247
- ✅ Successfully built depth-anything-3
248
- ✅ Successfully installed torch-2.x.x gradio-5.x.x ...
249
- ✅ Running on http://0.0.0.0:7860
250
- ```
251
-
252
- **在应用界面:**
253
- ```
254
- 🚀 Launching Depth Anything 3 on Hugging Face Spaces...
255
- 📦 Model Directory: depth-anything/DA3NESTED-GIANT-LARGE
256
- 📁 Workspace Directory: workspace/gradio
257
- 🖼️ Gallery Directory: workspace/gallery
258
- Running on public URL: https://your-space.hf.space
259
- ```
260
-
261
- **在浏览器中:**
262
- - ✅ 能看到 Gradio UI
263
- - ✅ 能上传文件
264
- - ✅ 能运行推理
265
- - ✅ 能看到结果
266
-
267
- ---
268
-
269
- ## 🎉 你已经准备好了!
270
-
271
- ### 当前状态:
272
- - ✅ **所有配置文件已就绪**
273
- - ✅ **xformers 问题已解决**
274
- - ✅ **gsplat 配置完成(带备用方案)**
275
- - ✅ **文档齐全**
276
- - ✅ **随时可以部署**
277
-
278
- ### 下一步:
279
- 1. 在 HF 创建 Space
280
- 2. 选择 GPU 硬件
281
- 3. 上传代码
282
- 4. 等待构建(15-25 分钟)
283
- 5. 测试功能
284
- 6. 🎊 享受你的应用!
285
-
286
- ### 如果遇到问题:
287
- 参考对应的文档:
288
- - gsplat 问题 → `GSPLAT_SOLUTIONS.md`
289
- - xformers 问题 → `XFORMERS_GUIDE.md`
290
- - 构建问题 → `HF_SPACES_BUILD.md`
291
- - 一般问题 → `DEPLOYMENT_CHECKLIST.md`
292
-
293
- ---
294
-
295
- ## 📞 快速帮助
296
-
297
- **问题:构建失败**
298
- → 查看 Build logs,搜索错误信息
299
- → 参考对应文档的故障排除部分
300
-
301
- **问题:应用启动失败**
302
- → 查看 Logs 标签
303
- → 检查是否选择了 GPU 硬件
304
-
305
- **问题:gsplat 构建失败**
306
- → 注释掉 requirements.txt 中的 gsplat 行
307
- → 重新构建(5-10 分钟)
308
-
309
- **问题:性能很慢**
310
- → 确认选择了 GPU 硬件(不是 CPU)
311
- → 检查 `@spaces.GPU` 装饰器是否生效
312
-
313
- ---
314
-
315
- ## 🏆 总结
316
-
317
- 从遇到 xformers 构建失败,到现在:
318
-
319
- 1. ✅ **识别问题**:xformers 需要 CUDA 子模块
320
- 2. ✅ **找到方案**:代码有 PyTorch fallback
321
- 3. ✅ **移除依赖**:注释掉 xformers
322
- 4. ✅ **验证代码**:确认 fallback 机制工作
323
- 5. ✅ **文档化**:创建完整的文档
324
- 6. ✅ **准备部署**:所有配置就绪
325
-
326
- **现在你的项目比之前更稳定、更容易部署了!** 🚀
327
-
328
- 祝你部署顺利!如果有任何问题,随时查阅文档或询问。💪
329
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
GSPLAT_SOLUTIONS.md DELETED
@@ -1,348 +0,0 @@
1
- # gsplat 安装解决方案
2
-
3
- ## 🎯 问题描述
4
-
5
- `gsplat` 是一个 CUDA 加速的 3D Gaussian Splatting 库,从源码安装可能在 HF Spaces 遇到问题。
6
-
7
- ## ✅ 解决方案(按推荐顺序)
8
-
9
- ---
10
-
11
- ## 方案 1️⃣:直接从 GitHub 安装 ⭐ (已配置)
12
-
13
- **requirements.txt:**
14
- ```txt
15
- gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70
16
- ```
17
-
18
- **优点:**
19
- - ✅ 使用特定版本,稳定
20
- - ✅ 最新功能
21
- - ✅ 与你的代码兼容
22
-
23
- **缺点:**
24
- - ⚠️ 构建时间长(5-15 分钟)
25
- - ⚠️ 需要 CUDA 在构建时
26
- - ⚠️ 可能构建失败
27
-
28
- **测试方法:**
29
- ```bash
30
- # 本地测试(确保有 GPU)
31
- pip install 'gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70'
32
- python -c "import gsplat; print(gsplat.__version__)"
33
- ```
34
-
35
- **HF Spaces 配置建议:**
36
-
37
- 如果构建失败,需要在 Space 设置中:
38
- 1. 选择 **GPU Space**(不是 CPU Space)
39
- 2. GPU 类型选择至少 **T4** 或更高
40
- 3. 在构建阶段就需要 GPU
41
-
42
- ---
43
-
44
- ## 方案 2️⃣:使用预编译 Wheel(如果可用)
45
-
46
- **检查是否有预编译版本:**
47
- ```bash
48
- pip index versions gsplat
49
- ```
50
-
51
- 如果有 PyPI 版本,修改 requirements.txt:
52
- ```txt
53
- # 使用 PyPI 版本(更快)
54
- gsplat>=0.1.0
55
- ```
56
-
57
- **优点:**
58
- - ✅ 安装快速(秒级)
59
- - ✅ 不需要编译
60
- - ✅ 更稳定
61
-
62
- **缺点:**
63
- - ⚠️ 可能版本较旧
64
- - ⚠️ 可能没有预编译版本
65
-
66
- ---
67
-
68
- ## 方案 3️⃣:延迟加载 gsplat(推荐备用方案)⭐
69
-
70
- 如果构建失败,修改代码让 gsplat 变成可选依赖:
71
-
72
- ### 步骤 1:修改 requirements.txt
73
-
74
- 创建两个文件:
75
-
76
- **requirements.txt** (基础依赖):
77
- ```txt
78
- torch>=2.0.0
79
- gradio>=5.0.0
80
- spaces
81
- # ... 其他基础依赖
82
- ```
83
-
84
- **requirements-gsplat.txt** (可选依赖):
85
- ```txt
86
- -r requirements.txt
87
- gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70
88
- ```
89
-
90
- ### 步骤 2:修改代码,使 gsplat 可选
91
-
92
- **depth_anything_3/utils/export/gs.py** (或相关文件):
93
- ```python
94
- # 在文件开头
95
- try:
96
- import gsplat
97
- GSPLAT_AVAILABLE = True
98
- except ImportError:
99
- GSPLAT_AVAILABLE = False
100
- print("⚠️ gsplat not installed. 3DGS features will be disabled.")
101
-
102
- def export_to_gs_video(*args, **kwargs):
103
- if not GSPLAT_AVAILABLE:
104
- raise RuntimeError(
105
- "gsplat is not installed. Please install it with:\n"
106
- "pip install 'gsplat @ git+https://github.com/...'"
107
- )
108
- # 原有代码...
109
- ```
110
-
111
- **app.py** (或 gradio_app.py):
112
- ```python
113
- from depth_anything_3.utils.export.gs import GSPLAT_AVAILABLE
114
-
115
- # 在 UI 中隐藏 3DGS 选项如果不可用
116
- if GSPLAT_AVAILABLE:
117
- infer_gs = gr.Checkbox(label="Infer 3D Gaussian Splatting")
118
- else:
119
- infer_gs = gr.Checkbox(
120
- label="Infer 3D Gaussian Splatting (Not Available - gsplat not installed)",
121
- interactive=False,
122
- value=False
123
- )
124
- ```
125
-
126
- **优点:**
127
- - ✅ 应用仍然可以启动
128
- - ✅ 其他功能正常工作
129
- - ✅ 用户可以选择性安装
130
-
131
- **缺点:**
132
- - ⚠️ 需要修改代码
133
- - ⚠️ 3DGS 功能不可用
134
-
135
- ---
136
-
137
- ## 方案 4️⃣:使用 Docker 自定义构建
138
-
139
- 创建自定义 Docker 镜像,在本地预编译 gsplat:
140
-
141
- **Dockerfile:**
142
- ```dockerfile
143
- FROM pytorch/pytorch:2.1.0-cuda11.8-cudnn8-runtime
144
-
145
- WORKDIR /app
146
-
147
- # 安装构建依赖
148
- RUN apt-get update && apt-get install -y \
149
- git \
150
- build-essential \
151
- && rm -rf /var/lib/apt/lists/*
152
-
153
- # 预编译 gsplat
154
- RUN pip install 'gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70'
155
-
156
- # 安装其他依赖
157
- COPY requirements.txt .
158
- RUN pip install -r requirements.txt
159
-
160
- # 复制代码
161
- COPY . .
162
-
163
- CMD ["python", "app.py"]
164
- ```
165
-
166
- **优点:**
167
- - ✅ 完全控制构建环境
168
- - ✅ 可以缓存编译结果
169
- - ✅ 更可靠
170
-
171
- **缺点:**
172
- - ⚠️ 需要 Docker 知识
173
- - ⚠️ 镜像较大
174
- - ⚠️ 构建和推送时间长
175
-
176
- ---
177
-
178
- ## 方案 5️⃣:使用环境变量控制安装
179
-
180
- **requirements.txt:**
181
- ```txt
182
- torch>=2.0.0
183
- gradio>=5.0.0
184
- # 基础依赖...
185
- ```
186
-
187
- **安装脚本** (install_gsplat.sh):
188
- ```bash
189
- #!/bin/bash
190
- if [ "$INSTALL_GSPLAT" = "true" ]; then
191
- echo "Installing gsplat..."
192
- pip install 'gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70'
193
- else
194
- echo "Skipping gsplat installation"
195
- fi
196
- ```
197
-
198
- 在 HF Spaces 设置中添加环境变量:
199
- ```
200
- INSTALL_GSPLAT=true
201
- ```
202
-
203
- **优点:**
204
- - ✅ 灵活控制
205
- - ✅ 可以快速切换
206
-
207
- **缺点:**
208
- - ⚠️ 需要额外脚本
209
- - ⚠️ 不是标准方法
210
-
211
- ---
212
-
213
- ## 🔧 当前推荐配置
214
-
215
- ### 第一次尝试:方案 1(已配置)✅
216
-
217
- **requirements.txt:**
218
- ```txt
219
- gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70
220
- ```
221
-
222
- **Space 设置:**
223
- - 硬件:**GPU (T4 或更高)**
224
- - Python 版本:3.11
225
-
226
- ### 如果构建失败:方案 3(延迟加载)
227
-
228
- 移除 requirements.txt 中的 gsplat,修改代码使其可选。
229
-
230
- ---
231
-
232
- ## 🐛 故障排除
233
-
234
- ### 问题 1:构建超时
235
-
236
- **错误信息:**
237
- ```
238
- Building wheels for collected packages: gsplat
239
- Building wheel for gsplat (setup.py) ... [TIMEOUT]
240
- ```
241
-
242
- **解决方法:**
243
- 1. 确认 Space 类型是 **GPU Space**
244
- 2. 尝试使用更快的 commit/tag
245
- 3. 考虑方案 3(可选依赖)
246
-
247
- ### 问题 2:CUDA 不可用
248
-
249
- **错误信息:**
250
- ```
251
- torch.cuda.is_available() returned False
252
- CUDA extension build requires CUDA to be available
253
- ```
254
-
255
- **解决方法:**
256
- 1. 确认构建时就启用 GPU
257
- 2. 检查 PyTorch 是否是 CUDA 版本
258
- 3. 查看 [HF Spaces GPU 文档](https://huggingface.co/docs/hub/spaces-gpus)
259
-
260
- ### 问题 3:编译错误
261
-
262
- **错误信息:**
263
- ```
264
- error: command 'gcc' failed with exit status 1
265
- ```
266
-
267
- **解决方法:**
268
- 1. 添加 packages.txt 安装编译工具:
269
- ```txt
270
- build-essential
271
- ```
272
- 2. 使用预编译版本
273
-
274
- ---
275
-
276
- ## 📊 方案对比
277
-
278
- | 方案 | 构建时间 | 成功率 | 复杂度 | 推荐度 |
279
- |------|---------|--------|--------|--------|
280
- | 1. GitHub 直接安装 | 🐌 10-15分钟 | ⚠️ 70% | 简单 | ⭐⭐⭐ |
281
- | 2. PyPI 预编译 | ⚡ 1分钟 | ✅ 95% | 最简单 | ⭐⭐⭐⭐⭐ |
282
- | 3. 可选依赖 | ⚡ 2分钟 | ✅ 100% | 中等 | ⭐⭐⭐⭐ |
283
- | 4. Docker | 🐌 20-30分钟 | ✅ 95% | 复杂 | ⭐⭐ |
284
- | 5. 环境变量控制 | 🐌 10-15分钟 | ⚠️ 70% | 中等 | ⭐⭐ |
285
-
286
- ---
287
-
288
- ## 🎯 实施步骤
289
-
290
- ### 现在(已完成)✅
291
-
292
- 1. ✅ requirements.txt 中已启用 gsplat
293
- 2. ✅ Python 版本设置为 3.11
294
- 3. ✅ README.md 配置完成
295
-
296
- ### 推送到 HF Spaces 后
297
-
298
- 1. **观察构建日志**
299
- - 查看是否成功安装 gsplat
300
- - 构建时间是否合理
301
-
302
- 2. **如果构建成功** 🎉
303
- - 测试 3DGS 功能
304
- - 完成!
305
-
306
- 3. **如果构建失败** ⚠️
307
- - 复制错误信息
308
- - 根据上面的故障排除指南修复
309
- - 或者切换到方案 3(可选依赖)
310
-
311
- ---
312
-
313
- ## 📝 测试清单
314
-
315
- 部署前本地测试:
316
-
317
- ```bash
318
- # 1. 测试 gsplat 安装
319
- pip install 'gsplat @ git+https://github.com/nerfstudio-project/gsplat.git@0b4dddf04cb687367602c01196913cde6a743d70'
320
-
321
- # 2. 测试导入
322
- python -c "import gsplat; print('gsplat version:', gsplat.__version__)"
323
-
324
- # 3. 测试你的代码
325
- python -c "from depth_anything_3.utils.export.gs import export_to_gs_video; print('✅ import success')"
326
-
327
- # 4. 启动应用测试
328
- python app.py
329
- ```
330
-
331
- ---
332
-
333
- ## 🔗 相关资源
334
-
335
- - [gsplat GitHub](https://github.com/nerfstudio-project/gsplat)
336
- - [HF Spaces GPU 文档](https://huggingface.co/docs/hub/spaces-gpus)
337
- - [PyTorch CUDA 安装](https://pytorch.org/get-started/locally/)
338
-
339
- ---
340
-
341
- ## 💡 最终建议
342
-
343
- 1. **先尝试方案 1**(当前配置)- 直接在 HF Spaces 上构建
344
- 2. **如果失败**,切换到**方案 3**(可选依赖)- 让应用可以在没有 gsplat 的情况下运行
345
- 3. **长期方案**:如果 gsplat 发布 PyPI 版本,立即切换到方案 2
346
-
347
- 祝你部署顺利!🚀
348
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
HF_SPACES_BUILD.md DELETED
@@ -1,306 +0,0 @@
1
- # Hugging Face Spaces 构建和环境安装详解
2
-
3
- ## 🏗️ 构建流程概览
4
-
5
- ```mermaid
6
- graph TD
7
- A[推送代码到 Space] --> B[检测 SDK 类型]
8
- B --> C[读取 README.md 配置]
9
- C --> D[查找依赖文件]
10
- D --> E{依赖文件类型}
11
- E -->|requirements.txt| F[pip install -r requirements.txt]
12
- E -->|pyproject.toml| G[pip install -e .]
13
- E -->|packages.txt| H[apt-get install]
14
- F --> I[启动应用]
15
- G --> I
16
- H --> I
17
- I --> J[运行 app.py]
18
- ```
19
-
20
- ## 📋 步骤详解
21
-
22
- ### 第 1 步:Space 配置检测
23
-
24
- HF Spaces 读取 `README.md` 的 YAML 前置内容:
25
-
26
- ```yaml
27
- ---
28
- title: Depth Anything 3
29
- emoji: 🏢
30
- colorFrom: indigo
31
- colorTo: pink
32
- sdk: gradio # 🔑 关键:指定使用 Gradio SDK
33
- sdk_version: 5.49.1 # Gradio 版本
34
- app_file: app.py # 🔑 关键:入口文件
35
- pinned: false
36
- license: cc-by-nc-4.0
37
- ---
38
- ```
39
-
40
- ### 第 2 步:依赖文件优先级
41
-
42
- HF Spaces 按以下顺序查找依赖文件(找到第一个就使用):
43
-
44
- #### 1. `requirements.txt` ⭐ (最推荐)
45
-
46
- ```txt
47
- torch>=2.0.0
48
- gradio>=5.0.0
49
- spaces
50
- numpy<2
51
- ```
52
-
53
- **安装命令:**
54
- ```bash
55
- pip install -r requirements.txt
56
- ```
57
-
58
- **优点:**
59
- - ✅ 简单直接
60
- - ✅ 构建速度快
61
- - ✅ 兼容性最好
62
- - ✅ 错误信息清晰
63
-
64
- #### 2. `pyproject.toml` (你当前使用的)
65
-
66
- ```toml
67
- [project]
68
- dependencies = ["torch>=2", "numpy<2"]
69
-
70
- [project.optional-dependencies]
71
- app = ["gradio>=5", "spaces"]
72
- ```
73
-
74
- **安装命令:**
75
- ```bash
76
- pip install -e .
77
- # 或者包含 optional dependencies
78
- pip install -e ".[app]"
79
- ```
80
-
81
- **问题:**
82
- - ⚠️ 可能不会自动安装 `[project.optional-dependencies]`
83
- - ⚠️ 需要正确的包结构(`src/` 目录等)
84
- - ⚠️ 构建时间较长
85
-
86
- #### 3. `packages.txt` (系统级依赖)
87
-
88
- ```txt
89
- ffmpeg
90
- libsm6
91
- libxext6
92
- ```
93
-
94
- **安装命令:**
95
- ```bash
96
- apt-get update
97
- apt-get install -y ffmpeg libsm6 libxext6
98
- ```
99
-
100
- **用途:**
101
- - 安装系统级库(非 Python 包)
102
- - OpenCV 可能需要的系统库
103
- - 音视频处理工具
104
-
105
- ### 第 3 步:实际构建过程
106
-
107
- ```bash
108
- # === HF Spaces 内部执行的命令(简化版) ===
109
-
110
- # 1. 准备环境
111
- export HOME=/home/user
112
- export PYTHONPATH=/home/user/app:$PYTHONPATH
113
-
114
- # 2. 安装 Python 基础环境
115
- python -m pip install --upgrade pip setuptools wheel
116
-
117
- # 3. 安装系统依赖(如果有 packages.txt)
118
- if [ -f packages.txt ]; then
119
- apt-get update
120
- xargs -a packages.txt apt-get install -y
121
- fi
122
-
123
- # 4. 安装 Python 依赖
124
- if [ -f requirements.txt ]; then
125
- pip install -r requirements.txt
126
- elif [ -f pyproject.toml ]; then
127
- pip install -e .
128
- fi
129
-
130
- # 5. 启动应用
131
- python app.py
132
- ```
133
-
134
- ## 🔍 你的项目构建分析
135
-
136
- ### 当前问题:使用 pyproject.toml
137
-
138
- 你的 `pyproject.toml` 配置:
139
-
140
- ```toml
141
- [project]
142
- dependencies = [
143
- "torch>=2",
144
- "gradio", # ❌ 这里没有 gradio!
145
- # ...
146
- ]
147
-
148
- [project.optional-dependencies]
149
- app = ["gradio>=5", "spaces"] # ✅ gradio 在这里
150
- ```
151
-
152
- **问题:**
153
- - HF Spaces 可能只安装 `dependencies`,不安装 `optional-dependencies`
154
- - 导致 `gradio` 和 `spaces` 可能不会被安装
155
-
156
- ### 解决方案 1:使用 requirements.txt (推荐) ✅
157
-
158
- 我已经为你创建了 `requirements.txt`,HF Spaces 会优先使用它:
159
-
160
- ```bash
161
- # Spaces 会自动执行
162
- pip install -r requirements.txt
163
- ```
164
-
165
- ### 解决方案 2:修改 pyproject.toml
166
-
167
- 将 gradio 移到主依赖:
168
-
169
- ```toml
170
- [project]
171
- dependencies = [
172
- "torch>=2",
173
- "gradio>=5",
174
- "spaces",
175
- # ... 其他依赖
176
- ]
177
- ```
178
-
179
- ### 解决方案 3:创建 .spacesrc
180
-
181
- 创建 `.spacesrc` 文件自定义构建:
182
-
183
- ```bash
184
- pip install -e ".[app,gs]"
185
- ```
186
-
187
- ## 🚀 推荐配置
188
-
189
- 对于 HF Spaces 部署,推荐的文件结构:
190
-
191
- ```
192
- depth-anything-3/
193
- ├── app.py # 入口文件
194
- ├── requirements.txt # Python 依赖(优先)
195
- ├── packages.txt # 系统依赖(可选)
196
- ├── README.md # Space 配置
197
- ├── src/
198
- │ └── depth_anything_3/
199
- │ └── ...
200
- └── pyproject.toml # 项目配置(备用)
201
- ```
202
-
203
- ## ⚡ 构建优化建议
204
-
205
- ### 1. 固定版本号
206
-
207
- ```txt
208
- # ❌ 不推荐(构建不稳定)
209
- torch>=2
210
- gradio>=5
211
-
212
- # ✅ 推荐(构建稳定)
213
- torch==2.1.0
214
- gradio==5.49.1
215
- ```
216
-
217
- ### 2. 预构建的 wheels
218
-
219
- 使用 PyPI 有预构建 wheel 的版本,避免从源码编译:
220
-
221
- ```txt
222
- # ✅ 快速安装
223
- torch==2.1.0
224
- torchvision==0.16.0
225
-
226
- # ⚠️ 慢(从源码编译)
227
- gsplat @ git+https://github.com/...
228
- ```
229
-
230
- ### 3. 使用 Docker(高级)
231
-
232
- 创建自定义 Docker 镜像:
233
-
234
- ```dockerfile
235
- FROM python:3.10
236
- WORKDIR /app
237
- COPY requirements.txt .
238
- RUN pip install -r requirements.txt
239
- COPY . .
240
- CMD ["python", "app.py"]
241
- ```
242
-
243
- ## 🐛 常见问题
244
-
245
- ### Q1: 为什么构建失败?
246
-
247
- **检查清单:**
248
- 1. ✅ 依赖文件是否存在?
249
- 2. ✅ 版本号是否兼容?
250
- 3. ✅ 是否需要系统依赖(packages.txt)?
251
- 4. ✅ 包名是否正确?
252
-
253
- ### Q2: 如何查看构建日志?
254
-
255
- 在 Space 页面:
256
- 1. 点击右上角 "Settings"
257
- 2. 滚动到 "Build logs"
258
- 3. 查看详细日志
259
-
260
- ### Q3: 构建时间太长怎么办?
261
-
262
- **优化方法:**
263
- 1. 使用 `requirements.txt` 而不是 `pyproject.toml`
264
- 2. 移除不必要的依赖
265
- 3. 使用预构建的 wheels
266
- 4. 考虑使用 Docker 镜像缓存
267
-
268
- ### Q4: 本地能运行,Spaces 上失败?
269
-
270
- **可能原因:**
271
- 1. 缺少系统依赖(需要 packages.txt)
272
- 2. 路径问题(本地是绝对路径)
273
- 3. 环境变量不同
274
- 4. Python 版本不同
275
-
276
- **解决方法:**
277
- ```toml
278
- # README.md 中指定 Python 版本
279
- ---
280
- sdk: gradio
281
- python_version: 3.10
282
- ---
283
- ```
284
-
285
- ## 📊 构建时间参考
286
-
287
- | 依赖方式 | 平均构建时间 | 稳定性 |
288
- |---------|------------|--------|
289
- | requirements.txt | 2-5 分钟 | ⭐⭐⭐⭐⭐ |
290
- | pyproject.toml | 5-10 分钟 | ⭐⭐⭐ |
291
- | 从源码编译 | 10-30 分钟 | ⭐⭐ |
292
-
293
- ## 🎯 最佳实践
294
-
295
- 1. **使用 requirements.txt** 作为主要依赖管理
296
- 2. **固定关键依赖的版本号**
297
- 3. **测试本地环境** 使用 `pip install -r requirements.txt`
298
- 4. **监控构建日志** 及时发现问题
299
- 5. **逐步添加依赖** 一个一个测试,而不是一次性全加
300
-
301
- ## 🔗 相关资源
302
-
303
- - [HF Spaces 文档](https://huggingface.co/docs/hub/spaces)
304
- - [Gradio Spaces 指南](https://huggingface.co/docs/hub/spaces-sdks-gradio)
305
- - [依赖管理](https://huggingface.co/docs/hub/spaces-dependencies)
306
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
PYTHON_VERSION_CONFIG.md DELETED
@@ -1,290 +0,0 @@
1
- # Python 版本配置说明
2
-
3
- ## 📋 Python 版本配置位置
4
-
5
- ### ✅ 已为你配置的 3 个地方:
6
-
7
- ---
8
-
9
- ## 1️⃣ README.md (Hugging Face Spaces) ⭐ **最重要**
10
-
11
- ```yaml
12
- ---
13
- title: Depth Anything 3
14
- sdk: gradio
15
- sdk_version: 5.49.1
16
- app_file: app.py
17
- python_version: 3.11 # 🔑 关键配置
18
- ---
19
- ```
20
-
21
- **作用范围:** Hugging Face Spaces 部署
22
- **优先级:** 🔥 最高(Spaces 专用)
23
-
24
- **支持的版本:**
25
- - `3.8`
26
- - `3.9`
27
- - `3.10`
28
- - `3.11` ✅ (你选择的)
29
- - `3.12` (较新,可能有兼容性问题)
30
-
31
- **注意:**
32
- - 这是 HF Spaces 唯一识别的配置
33
- - 如果不指定,默认使用 `3.10`
34
- - 必须是精确版本号(如 `3.11`),不能用范围(如 `>=3.11`)
35
-
36
- ---
37
-
38
- ## 2️⃣ pyproject.toml (项目配置)
39
-
40
- ```toml
41
- [project]
42
- requires-python = ">=3.11" # ✅ 已配置
43
- ```
44
-
45
- **作用范围:**
46
- - 本地开发
47
- - pip 安装时版本检查
48
- - 包管理器(poetry, hatch 等)
49
-
50
- **优先级:** 中等
51
-
52
- **支持格式:**
53
- ```toml
54
- requires-python = ">=3.11" # 最低 3.11
55
- requires-python = ">=3.11, <3.13" # 3.11 到 3.12
56
- requires-python = "~=3.11" # 3.11.x 系列
57
- ```
58
-
59
- **效果:**
60
- ```bash
61
- # 如果 Python 版本不符合要求,安装时会报错
62
- $ pip install .
63
- ERROR: Package requires a different Python: 3.9.0 not in '>=3.11'
64
- ```
65
-
66
- ---
67
-
68
- ## 3️⃣ runtime.txt (备用方式)
69
-
70
- ```txt
71
- python-3.11
72
- ```
73
-
74
- **作用范围:**
75
- - Heroku
76
- - 某些 Docker 构建系统
77
- - HF Spaces (备用,如果 README.md 没有配置)
78
-
79
- **优先级:** 低
80
-
81
- **格式:**
82
- ```txt
83
- python-3.11 # ✅ 精确版本
84
- python-3.11.5 # ✅ 更精确的版本
85
- ```
86
-
87
- ---
88
-
89
- ## 🎯 配置优先级(Hugging Face Spaces)
90
-
91
- ```
92
- README.md (python_version)
93
- ↓ 最高优先级
94
- runtime.txt
95
- ↓ 次要优先级
96
- 默认版本 (3.10)
97
- ↓ 兜底
98
- ```
99
-
100
- **最佳实践:** 同时配置 `README.md` 和 `pyproject.toml`
101
-
102
- ---
103
-
104
- ## 🔍 如何验证配置生效?
105
-
106
- ### 在 Hugging Face Spaces:
107
-
108
- 部署后,查看构建日志:
109
-
110
- ```bash
111
- # 日志中会显示
112
- Setting up Python 3.11...
113
- Python 3.11.5
114
- pip 23.2.1
115
- ```
116
-
117
- ### 在本地验证:
118
-
119
- ```bash
120
- # 检查 Python 版本
121
- python --version
122
- # Python 3.11.5
123
-
124
- # 尝试安装(检查 requires-python)
125
- pip install -e .
126
- # 如果版本不符合,会报错
127
- ```
128
-
129
- ---
130
-
131
- ## 🚨 常见问题
132
-
133
- ### Q1: 为什么选择 Python 3.11?
134
-
135
- **优点:**
136
- - ✅ 性能提升(比 3.10 快 10-60%)
137
- - ✅ 更好的错误信息
138
- - ✅ 新的类型特性
139
- - ✅ Gradio 5+ 完全支持
140
-
141
- **注意:**
142
- - ⚠️ 某些老库可能不支持(如 gsplat)
143
- - ⚠️ 需要测试所有依赖是否兼容
144
-
145
- ### Q2: 如果我想支持多个版本怎么办?
146
-
147
- **pyproject.toml 配置:**
148
- ```toml
149
- requires-python = ">=3.11, <3.13" # 支持 3.11 和 3.12
150
- ```
151
-
152
- **但 HF Spaces 只能选一个:**
153
- ```yaml
154
- python_version: 3.11 # 只能指定一个精确版本
155
- ```
156
-
157
- ### Q3: 如何测试不同 Python 版本?
158
-
159
- **使用 pyenv:**
160
- ```bash
161
- # 安装多个 Python 版本
162
- pyenv install 3.11.5
163
- pyenv install 3.12.0
164
-
165
- # 切换版本测试
166
- pyenv local 3.11.5
167
- python --version
168
- pip install -e .
169
- python app.py
170
- ```
171
-
172
- **使用 Docker:**
173
- ```dockerfile
174
- FROM python:3.11
175
- WORKDIR /app
176
- COPY . .
177
- RUN pip install -r requirements.txt
178
- CMD ["python", "app.py"]
179
- ```
180
-
181
- ### Q4: 版本冲突怎么办?
182
-
183
- **场景:** 某个依赖不支持 Python 3.11
184
-
185
- **解决方法:**
186
-
187
- 1. **找替代包**
188
- ```txt
189
- # requirements.txt
190
- old-package # 不支持 3.11
191
-
192
- new-package # 支持 3.11
193
- ```
194
-
195
- 2. **降级 Python 版本**
196
- ```yaml
197
- python_version: 3.10 # 改回 3.10
198
- ```
199
-
200
- 3. **等待上游更新**
201
- ```bash
202
- pip install git+https://github.com/xxx/package@main
203
- ```
204
-
205
- ---
206
-
207
- ## 📊 Python 版本兼容性参考
208
-
209
- | Python 版本 | Gradio 5 | PyTorch 2.x | Spaces 支持 | 推荐 |
210
- |------------|----------|-------------|------------|------|
211
- | 3.8 | ✅ | ✅ | ✅ | ❌ (太旧) |
212
- | 3.9 | ✅ | ✅ | ✅ | ⚠️ |
213
- | 3.10 | ✅ | ✅ | ✅ | ✅ |
214
- | 3.11 | ✅ | ✅ | ✅ | ⭐ 推荐 |
215
- | 3.12 | ✅ | ⚠️ | ✅ | ⚠️ (较新) |
216
- | 3.13 | ⚠️ | ❌ | ⚠️ | ❌ (太新) |
217
-
218
- ---
219
-
220
- ## 🎓 完整配置示例
221
-
222
- ### 你当前的配置(已完成)✅
223
-
224
- **README.md:**
225
- ```yaml
226
- ---
227
- python_version: 3.11
228
- ---
229
- ```
230
-
231
- **pyproject.toml:**
232
- ```toml
233
- requires-python = ">=3.11"
234
- ```
235
-
236
- **runtime.txt:**
237
- ```txt
238
- python-3.11
239
- ```
240
-
241
- ### 如果要降级到 3.10:
242
-
243
- **README.md:**
244
- ```yaml
245
- python_version: 3.10
246
- ```
247
-
248
- **pyproject.toml:**
249
- ```toml
250
- requires-python = ">=3.10"
251
- ```
252
-
253
- **runtime.txt:**
254
- ```txt
255
- python-3.10
256
- ```
257
-
258
- ---
259
-
260
- ## 🔧 测试清单
261
-
262
- 部署前检查:
263
-
264
- - [ ] ✅ README.md 有 `python_version: 3.11`
265
- - [ ] ✅ pyproject.toml 有 `requires-python = ">=3.11"`
266
- - [ ] ✅ 本地测试使用 Python 3.11
267
- - [ ] ✅ 所有依赖支持 Python 3.11
268
- - [ ] ✅ requirements.txt 包含所有依赖
269
- - [ ] ✅ app.py 可以正常启动
270
-
271
- ---
272
-
273
- ## 📚 参考资料
274
-
275
- - [HF Spaces Python 版���文档](https://huggingface.co/docs/hub/spaces-config-reference#python_version)
276
- - [Python 版本发布时间表](https://devguide.python.org/versions/)
277
- - [PyPI 包兼容性查询](https://pypi.org/)
278
-
279
- ---
280
-
281
- ## 💡 总结
282
-
283
- **对于 Hugging Face Spaces 部署:**
284
-
285
- 1. **必须配置:** `README.md` 中的 `python_version: 3.11`
286
- 2. **推荐配置:** `pyproject.toml` 中的 `requires-python = ">=3.11"`
287
- 3. **可选配置:** `runtime.txt`(备用)
288
-
289
- **当前配置状态:** ✅ 全部已配置完成!
290
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
SPACES_GPU_BEST_PRACTICES.md ADDED
@@ -0,0 +1,481 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🎯 Spaces GPU 最佳实践指南
2
+
3
+ ## 📚 spaces.GPU 工作原理
4
+
5
+ ### 架构概览
6
+
7
+ ```
8
+ ┌─────────────────────────────────────────────────────────┐
9
+ │ 主进程 (Main Process) │
10
+ │ - CPU 环境 │
11
+ │ - ❌ 不能初始化 CUDA │
12
+ │ - ✅ 可以创建 Gradio UI │
13
+ │ - ✅ 可以创建 ModelInference 实例(但不加载模型) │
14
+ └─────────────────────────────────────────────────────────┘
15
+
16
+ │ 调用 @spaces.GPU 装饰的函数
17
+
18
+
19
+ ┌─────────────────────────────────────────────────────────┐
20
+ │ 子进程 (GPU Worker Process) │
21
+ │ - GPU 环境 │
22
+ │ - ✅ 可以初始化 CUDA │
23
+ │ - ✅ 可以加载模型到 GPU │
24
+ │ - ✅ 运行推理 │
25
+ │ - ✅ 全局变量缓存(每个子进程独立) │
26
+ └─────────────────────────────────────────────────────────┘
27
+
28
+ │ pickle 序列化返回值
29
+
30
+
31
+ ┌─────────────────────────────────────────────────────────┐
32
+ │ 主进程接收返回值 │
33
+ │ - ✅ 必须是 CPU 数据(numpy, 基本类型) │
34
+ │ - ❌ 不能包含 CUDA 张量 │
35
+ └─────────────────────────────────────────────────────────┘
36
+ ```
37
+
38
+ ## ✅ 最佳实践:模型加载策略
39
+
40
+ ### ❌ 错误做法 1:主进程加载模型
41
+
42
+ ```python
43
+ # ❌ 错误:在主进程加载模型
44
+ class EventHandlers:
45
+ def __init__(self):
46
+ self.model_inference = ModelInference()
47
+ # ❌ 如果在主进程调用这个,会触发 CUDA 初始化错误
48
+ self.model_inference.initialize_model("cuda") # 💥
49
+ ```
50
+
51
+ **为什么错误?**
52
+ - 主进程不能初始化 CUDA
53
+ - 会立即报错:`CUDA must not be initialized in the main process`
54
+
55
+ ### ❌ 错误做法 2:实例变量存储模型
56
+
57
+ ```python
58
+ # ❌ 错误:使用实例变量存储模型
59
+ class ModelInference:
60
+ def __init__(self):
61
+ self.model = None # ❌ 实例变量
62
+
63
+ def initialize_model(self, device):
64
+ if self.model is None:
65
+ self.model = load_model() # ❌ 保存在实例中
66
+ return self.model
67
+ ```
68
+
69
+ **为什么错误?**
70
+ - 实例在主进程创建
71
+ - 模型状态可能跨进程混乱
72
+ - 第二次调用时状态不确定
73
+
74
+ ### ✅ 正确做法:子进程全局变量缓存
75
+
76
+ ```python
77
+ # ✅ 正确:使用全局变量在子进程中缓存
78
+ _MODEL_CACHE = None # 全局变量,每个子进程独立
79
+
80
+ class ModelInference:
81
+ def __init__(self):
82
+ # ✅ 不存储任何状态
83
+ pass
84
+
85
+ def initialize_model(self, device: str = "cuda"):
86
+ global _MODEL_CACHE
87
+
88
+ if _MODEL_CACHE is None:
89
+ # ✅ 在子进程中加载(第一次调用时)
90
+ print("Loading model in GPU subprocess...")
91
+ model_dir = os.environ.get("DA3_MODEL_DIR", "...")
92
+ _MODEL_CACHE = DepthAnything3.from_pretrained(model_dir)
93
+ _MODEL_CACHE = _MODEL_CACHE.to(device) # ✅ 在子进程中移动
94
+ _MODEL_CACHE.eval()
95
+ else:
96
+ # ✅ 复用缓存的模型
97
+ print("Using cached model")
98
+
99
+ return _MODEL_CACHE # ✅ 返回模型,不存储
100
+ ```
101
+
102
+ **为什么正确?**
103
+ - ✅ 模型只在子进程加载(GPU 环境)
104
+ - ✅ 全局变量在子进程内安全(每个子进程独立)
105
+ - ✅ 不污染主进程
106
+ - ✅ 可以缓存复用(避免重复加载)
107
+
108
+ ## 🎯 完整实现示例
109
+
110
+ ### 文件结构
111
+
112
+ ```
113
+ app.py # 主入口,配置 @spaces.GPU
114
+ depth_anything_3/app/modules/
115
+ ├── model_inference.py # 模型推理(使用全局变量)
116
+ └── event_handlers.py # 事件处理(主进程,不加载模型)
117
+ ```
118
+
119
+ ### 1. app.py - 装饰器配置
120
+
121
+ ```python
122
+ import spaces
123
+ from depth_anything_3.app.modules.model_inference import ModelInference
124
+
125
+ # ✅ 装饰 run_inference 方法
126
+ original_run_inference = ModelInference.run_inference
127
+
128
+ @spaces.GPU(duration=120)
129
+ def gpu_run_inference(self, *args, **kwargs):
130
+ """
131
+ 在 GPU 子进程中运行推理。
132
+
133
+ 这个函数会在独立的 GPU 子进程中执行,
134
+ 可以安全地初始化 CUDA 和加载模型。
135
+ """
136
+ return original_run_inference(self, *args, **kwargs)
137
+
138
+ # 替换原方法
139
+ ModelInference.run_inference = gpu_run_inference
140
+
141
+ # ✅ 主进程:只创建应用,不加载模型
142
+ if __name__ == "__main__":
143
+ app = DepthAnything3App(...)
144
+ app.launch(host="0.0.0.0", port=7860)
145
+ ```
146
+
147
+ ### 2. model_inference.py - 模型管理
148
+
149
+ ```python
150
+ import torch
151
+ from depth_anything_3.api import DepthAnything3
152
+
153
+ # ========================================
154
+ # ✅ 全局变量缓存(子进程安全)
155
+ # ========================================
156
+ _MODEL_CACHE = None
157
+
158
+ class ModelInference:
159
+ def __init__(self):
160
+ """
161
+ 初始化 - 不存储任何状态。
162
+
163
+ 注意:这个实例在主进程创建,但模型加载在子进程。
164
+ """
165
+ pass # ✅ 无实例变量
166
+
167
+ def initialize_model(self, device: str = "cuda"):
168
+ """
169
+ 在子进程中加载模型。
170
+
171
+ 使用全局变量缓存,因为:
172
+ 1. @spaces.GPU 在子进程运行
173
+ 2. 每个子进程有独立的全局命名空间
174
+ 3. 可以安全缓存,避免重复加载
175
+ """
176
+ global _MODEL_CACHE
177
+
178
+ if _MODEL_CACHE is None:
179
+ # 第一次调用:加载模型
180
+ model_dir = os.environ.get("DA3_MODEL_DIR", "...")
181
+ print(f"🔄 Loading model in GPU subprocess from {model_dir}")
182
+
183
+ _MODEL_CACHE = DepthAnything3.from_pretrained(model_dir)
184
+ _MODEL_CACHE = _MODEL_CACHE.to(device) # ✅ 在子进程中移动
185
+ _MODEL_CACHE.eval()
186
+
187
+ print(f"✅ Model loaded on {device}")
188
+ else:
189
+ # 后续调用:复用缓存
190
+ print("✅ Using cached model")
191
+ # 确保在正确的设备上(防御性编程)
192
+ _MODEL_CACHE = _MODEL_CACHE.to(device)
193
+
194
+ return _MODEL_CACHE
195
+
196
+ def run_inference(self, target_dir, ...):
197
+ """
198
+ 运行推理 - 在 GPU 子进程中执行。
199
+
200
+ 这个函数被 @spaces.GPU 装饰,会在子进程运行。
201
+ """
202
+ # ✅ 在子进程中获取模型(局部变量)
203
+ device = "cuda" if torch.cuda.is_available() else "cpu"
204
+ model = self.initialize_model(device) # ✅ 返回模型,不存储
205
+
206
+ # ✅ 运行推理
207
+ with torch.no_grad():
208
+ prediction = model.inference(...)
209
+
210
+ # ✅ 处理结果
211
+ # ...
212
+
213
+ # ✅ 关键:返回前移动所有 CUDA 张量到 CPU
214
+ prediction = self._move_to_cpu(prediction)
215
+
216
+ return prediction, processed_data
217
+
218
+ def _move_to_cpu(self, prediction):
219
+ """移动所有 CUDA 张量到 CPU,确保 pickle 安全"""
220
+ # ... 实现见下文
221
+ return prediction
222
+ ```
223
+
224
+ ### 3. event_handlers.py - 主进程代码
225
+
226
+ ```python
227
+ class EventHandlers:
228
+ def __init__(self):
229
+ """
230
+ 主进程初始化 - 不加载模型。
231
+
232
+ 注意:这里创建 ModelInference 实例是安全的,
233
+ 因为它不立即加载模型。模型会在子进程中加载。
234
+ """
235
+ # ✅ 可以创建实例(不加载模型)
236
+ self.model_inference = ModelInference()
237
+
238
+ # ❌ 不要在这里调用 initialize_model()
239
+ # ❌ 不要在这里加载模型
240
+
241
+ def gradio_demo(self, ...):
242
+ """
243
+ Gradio 回调 - 在主进程调用。
244
+
245
+ 这个函数会调用 self.model_inference.run_inference,
246
+ 而 run_inference 被 @spaces.GPU 装饰,会在子进程运行。
247
+ """
248
+ # ✅ 调用被装饰的方法(自动在子进程运行)
249
+ result = self.model_inference.run_inference(...)
250
+ return result
251
+ ```
252
+
253
+ ## 🔑 关键原则总结
254
+
255
+ ### ✅ DO(应该做)
256
+
257
+ 1. **主进程:只创建实例,不加载模型**
258
+ ```python
259
+ # ✅ 主进程
260
+ model_inference = ModelInference() # 安全
261
+ # 不调用 initialize_model()
262
+ ```
263
+
264
+ 2. **子进程:使用全局变量缓存模型**
265
+ ```python
266
+ # ✅ 子进程(@spaces.GPU 装饰的函数内)
267
+ _MODEL_CACHE = None # 全局变量
268
+ model = initialize_model() # 在子进程加载
269
+ ```
270
+
271
+ 3. **返回前:移动所有张量到 CPU**
272
+ ```python
273
+ # ✅ 返回前
274
+ prediction = move_all_tensors_to_cpu(prediction)
275
+ return prediction
276
+ ```
277
+
278
+ 4. **清理 GPU 内存**
279
+ ```python
280
+ # ✅ 推理后
281
+ torch.cuda.empty_cache()
282
+ ```
283
+
284
+ ### ❌ DON'T(不应该做)
285
+
286
+ 1. **主进程:不要初始化 CUDA**
287
+ ```python
288
+ # ❌ 主进程
289
+ model.to("cuda") # 💥 错误
290
+ torch.cuda.is_available() # 💥 可能触发初始化
291
+ ```
292
+
293
+ 2. **不要用实例变量存储模型**
294
+ ```python
295
+ # ❌
296
+ self.model = load_model() # 状态混乱
297
+ ```
298
+
299
+ 3. **不要返回 CUDA 张量**
300
+ ```python
301
+ # ❌
302
+ return prediction # 如果包含 CUDA 张量,会报错
303
+ ```
304
+
305
+ 4. **不要在 __init__ 中加载模型**
306
+ ```python
307
+ # ❌
308
+ def __init__(self):
309
+ self.model = load_model() # 在主进程执行,会报错
310
+ ```
311
+
312
+ ## 📊 执行流程对比
313
+
314
+ ### ❌ 错误流程
315
+
316
+ ```
317
+ 主进程启动
318
+
319
+ 创建 ModelInference() 实例
320
+
321
+ __init__ 中 self.model = None # ✅ 安全
322
+
323
+ 第一次调用 run_inference
324
+
325
+ @spaces.GPU 创建子进程
326
+
327
+ 子进程:self.model = load_model() # ✅ 在子进程
328
+
329
+ 返回 prediction(包含 CUDA 张量) # ❌ 错误
330
+
331
+ pickle 尝试在主进程重建 CUDA 张量 # 💥 报错
332
+ ```
333
+
334
+ ### ✅ 正确流程
335
+
336
+ ```
337
+ 主进程启动
338
+
339
+ 创建 ModelInference() 实例(无状态) # ✅
340
+
341
+ 第一次调用 run_inference
342
+
343
+ @spaces.GPU 创建子进程
344
+
345
+ 子进程:_MODEL_CACHE = load_model() # ✅ 全局变量
346
+
347
+ 子进程:model = _MODEL_CACHE # ✅ 局部变量
348
+
349
+ 子进程:prediction = model.inference(...)
350
+
351
+ 子进程:prediction = move_to_cpu(prediction) # ✅
352
+
353
+ 返回 prediction(所有张量在 CPU) # ✅
354
+
355
+ 主进程:安全接收 CPU 数据 # ✅
356
+ ```
357
+
358
+ ## 🧪 验证清单
359
+
360
+ ### 主进程检查
361
+
362
+ ```python
363
+ # ✅ 应该通过
364
+ def test_main_process():
365
+ # 可以创建实例
366
+ model_inference = ModelInference()
367
+
368
+ # 不应该有模型
369
+ assert not hasattr(model_inference, 'model') or model_inference.model is None
370
+
371
+ # 不应该初始化 CUDA
372
+ # (这个测试需要在主进程运行)
373
+ ```
374
+
375
+ ### 子进程检查
376
+
377
+ ```python
378
+ # ✅ 应该通过
379
+ @spaces.GPU
380
+ def test_gpu_subprocess():
381
+ model_inference = ModelInference()
382
+
383
+ # 可以加载模型
384
+ model = model_inference.initialize_model("cuda")
385
+ assert model is not None
386
+
387
+ # 模型应该在 GPU
388
+ # (检查模型参数设备)
389
+
390
+ # 可以运行推理
391
+ # ...
392
+
393
+ # 返回前应该移到 CPU
394
+ # ...
395
+ ```
396
+
397
+ ## 🎓 常见问题
398
+
399
+ ### Q1: 为什么不能用实例变量?
400
+
401
+ **A:** 因为实例在主进程创建,如果存储模型状态,会跨进程混乱。
402
+
403
+ ```python
404
+ # ❌ 问题
405
+ self.model = load_model() # 状态可能混乱
406
+
407
+ # ✅ 解决
408
+ _MODEL_CACHE = load_model() # 每个子进程独立
409
+ ```
410
+
411
+ ### Q2: 全局变量安全吗?
412
+
413
+ **A:** 是的!因为:
414
+ - 每个子进程有独立的全局命名空间
415
+ - 主进程不会访问子进程的全局变量
416
+ - 不会跨进程污染
417
+
418
+ ### Q3: 模型会重复加载吗?
419
+
420
+ **A:** 不会!因为:
421
+ - 全局变量在子进程内缓存
422
+ - 同一个子进程的多次调用会复用
423
+ - 不同子进程各自缓存(如果需要)
424
+
425
+ ### Q4: 如何清理模型?
426
+
427
+ **A:** 通常不需要手动清理,因为:
428
+ - 子进程结束后自动清理
429
+ - 如果需要,可以在子进程中:
430
+ ```python
431
+ global _MODEL_CACHE
432
+ _MODEL_CACHE = None
433
+ del model
434
+ torch.cuda.empty_cache()
435
+ ```
436
+
437
+ ## 📝 完整代码模板
438
+
439
+ ```python
440
+ # ========================================
441
+ # model_inference.py
442
+ # ========================================
443
+ _MODEL_CACHE = None # 全局缓存
444
+
445
+ class ModelInference:
446
+ def __init__(self):
447
+ pass # 无状态
448
+
449
+ def initialize_model(self, device="cuda"):
450
+ global _MODEL_CACHE
451
+ if _MODEL_CACHE is None:
452
+ _MODEL_CACHE = load_model().to(device)
453
+ return _MODEL_CACHE
454
+
455
+ def run_inference(self, ...):
456
+ model = self.initialize_model("cuda")
457
+ prediction = model.inference(...)
458
+ prediction = self._move_to_cpu(prediction)
459
+ return prediction
460
+
461
+ # ========================================
462
+ # app.py
463
+ # ========================================
464
+ @spaces.GPU(duration=120)
465
+ def gpu_run_inference(self, *args, **kwargs):
466
+ return ModelInference.run_inference(self, *args, **kwargs)
467
+
468
+ ModelInference.run_inference = gpu_run_inference
469
+ ```
470
+
471
+ ## 🎯 总结
472
+
473
+ **核心原则:**
474
+
475
+ 1. ✅ **主进程 = CPU 环境**,不加载模型,不初始化 CUDA
476
+ 2. ✅ **子进程 = GPU 环境**,加载模型,运行推理
477
+ 3. ✅ **全局变量缓存**,每个子进程独立
478
+ 4. ✅ **返回 CPU 数据**,确保 pickle 安全
479
+
480
+ 遵循这些原则,你的 Spaces GPU 应用就能稳定运行!🚀
481
+
SPACES_GPU_FIX_GUIDE.md ADDED
@@ -0,0 +1,484 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🔧 Spaces GPU 问题完整修复指南
2
+
3
+ ## 🎯 问题诊断:你说得完全正确!
4
+
5
+ ### 问题根源分析
6
+
7
+ ```python
8
+ # event_handlers.py - 主进程中
9
+ class EventHandlers:
10
+ def __init__(self):
11
+ self.model_inference = ModelInference() # ❌ 在主进程创建实例
12
+
13
+ # model_inference.py
14
+ class ModelInference:
15
+ def __init__(self):
16
+ self.model = None # ❌ 实例变量,跨进程共享状态有问题
17
+
18
+ def initialize_model(self, device):
19
+ if self.model is None:
20
+ self.model = load_model() # 第一次:在子进程加载
21
+ else:
22
+ self.model = self.model.to(device) # 第二次:💥 主进程CUDA操作!
23
+ ```
24
+
25
+ ### 为什么第二次会失败?
26
+
27
+ 1. **第一次调用**:
28
+ - `@spaces.GPU` 在子进程运行
29
+ - `self.model is None` → 加载模型
30
+ - `self.model` 保存在实例中
31
+ - 返回时 `prediction.gaussians` 包含 CUDA 张量
32
+ - **pickle 时尝试在主进程重建 CUDA 张量** → 💥
33
+
34
+ 2. **第二次调用**(即使第一次成功了):
35
+ - 新的子进程或状态混乱
36
+ - `self.model` 状态不确定
37
+ - 尝试 `.to(device)` 操作 → 💥
38
+
39
+ ## ✅ 解决方案:两个关键修改
40
+
41
+ ### 修改 1:使用全局变量缓存模型(避免实例状态)
42
+
43
+ **为什么用全局变量?**
44
+ - `@spaces.GPU` 每次在独立子进程运行
45
+ - 全局变量在子进程内是安全的
46
+ - 不会污染主进程
47
+
48
+ ### 修改 2:返回前移动所有 CUDA 张量到 CPU
49
+
50
+ **为什么需要?**
51
+ - Pickle 序列化返回值时会尝试重建 CUDA 张量
52
+ - 必须确保返回的数据都在 CPU 上
53
+
54
+ ## 📝 完整修复代码
55
+
56
+ ### 文件:`depth_anything_3/app/modules/model_inference.py`
57
+
58
+ ```python
59
+ """
60
+ Model inference module for Depth Anything 3 Gradio app.
61
+
62
+ Modified for HF Spaces GPU compatibility.
63
+ """
64
+
65
+ import gc
66
+ import glob
67
+ import os
68
+ from typing import Any, Dict, Optional, Tuple
69
+ import numpy as np
70
+ import torch
71
+
72
+ from depth_anything_3.api import DepthAnything3
73
+ from depth_anything_3.utils.export.glb import export_to_glb
74
+ from depth_anything_3.utils.export.gs import export_to_gs_video
75
+
76
+
77
+ # ========================================
78
+ # 🔑 关键修改 1:使用全局变量缓存模型
79
+ # ========================================
80
+ # Global cache for model (used in GPU subprocess)
81
+ # This is SAFE because @spaces.GPU runs in isolated subprocess
82
+ # Each subprocess gets its own copy of this global variable
83
+ _MODEL_CACHE = None
84
+
85
+
86
+ class ModelInference:
87
+ """
88
+ Handles model inference and data processing for Depth Anything 3.
89
+
90
+ Modified for HF Spaces GPU compatibility - does NOT store state
91
+ in instance variables to avoid cross-process issues.
92
+ """
93
+
94
+ def __init__(self):
95
+ """Initialize the model inference handler.
96
+
97
+ Note: Do NOT store model in instance variable to avoid
98
+ state sharing issues with @spaces.GPU decorator.
99
+ """
100
+ # No instance variables! All state in global or local variables
101
+ pass
102
+
103
+ def initialize_model(self, device: str = "cuda"):
104
+ """
105
+ Initialize the DepthAnything3 model using global cache.
106
+
107
+ This uses a global variable which is safe because:
108
+ 1. @spaces.GPU runs in isolated subprocess
109
+ 2. Each subprocess has its own global namespace
110
+ 3. No state leaks to main process
111
+
112
+ Args:
113
+ device: Device to load the model on
114
+
115
+ Returns:
116
+ Model instance ready for inference
117
+ """
118
+ global _MODEL_CACHE
119
+
120
+ if _MODEL_CACHE is None:
121
+ # First time loading in this subprocess
122
+ model_dir = os.environ.get(
123
+ "DA3_MODEL_DIR", "depth-anything/DA3NESTED-GIANT-LARGE"
124
+ )
125
+ print(f"🔄 Loading model from {model_dir}...")
126
+ _MODEL_CACHE = DepthAnything3.from_pretrained(model_dir)
127
+ _MODEL_CACHE = _MODEL_CACHE.to(device)
128
+ _MODEL_CACHE.eval()
129
+ print("✅ Model loaded and ready on GPU")
130
+ else:
131
+ # Model already cached in this subprocess
132
+ print("✅ Using cached model")
133
+ # Ensure it's on the correct device (defensive programming)
134
+ _MODEL_CACHE = _MODEL_CACHE.to(device)
135
+
136
+ return _MODEL_CACHE
137
+
138
+ def run_inference(
139
+ self,
140
+ target_dir: str,
141
+ filter_black_bg: bool = False,
142
+ filter_white_bg: bool = False,
143
+ process_res_method: str = "upper_bound_resize",
144
+ show_camera: bool = True,
145
+ selected_first_frame: Optional[str] = None,
146
+ save_percentage: float = 30.0,
147
+ num_max_points: int = 1_000_000,
148
+ infer_gs: bool = False,
149
+ gs_trj_mode: str = "extend",
150
+ gs_video_quality: str = "high",
151
+ ) -> Tuple[Any, Dict[int, Dict[str, Any]]]:
152
+ """
153
+ Run DepthAnything3 model inference on images.
154
+
155
+ This method is wrapped with @spaces.GPU in app.py.
156
+
157
+ Args:
158
+ target_dir: Directory containing images
159
+ filter_black_bg: Whether to filter black background
160
+ filter_white_bg: Whether to filter white background
161
+ process_res_method: Method for resizing input images
162
+ show_camera: Whether to show camera in 3D view
163
+ selected_first_frame: Selected first frame filename
164
+ save_percentage: Percentage of points to save (0-100)
165
+ num_max_points: Maximum number of points
166
+ infer_gs: Whether to infer 3D Gaussian Splatting
167
+ gs_trj_mode: Trajectory mode for GS
168
+ gs_video_quality: Video quality for GS
169
+
170
+ Returns:
171
+ Tuple of (prediction, processed_data)
172
+ """
173
+ print(f"Processing images from {target_dir}")
174
+
175
+ # Device check
176
+ device = "cuda" if torch.cuda.is_available() else "cpu"
177
+ device = torch.device(device)
178
+ print(f"Using device: {device}")
179
+
180
+ # 🔑 使用返回值,而不是 self.model
181
+ model = self.initialize_model(device)
182
+
183
+ # Get image paths
184
+ print("Loading images...")
185
+ image_folder_path = os.path.join(target_dir, "images")
186
+ all_image_paths = sorted(glob.glob(os.path.join(image_folder_path, "*")))
187
+
188
+ # Filter for image files
189
+ image_extensions = [".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".tif"]
190
+ all_image_paths = [
191
+ path
192
+ for path in all_image_paths
193
+ if any(path.lower().endswith(ext) for ext in image_extensions)
194
+ ]
195
+
196
+ print(f"Found {len(all_image_paths)} images")
197
+
198
+ # Apply first frame selection logic
199
+ if selected_first_frame:
200
+ selected_path = None
201
+ for path in all_image_paths:
202
+ if os.path.basename(path) == selected_first_frame:
203
+ selected_path = path
204
+ break
205
+
206
+ if selected_path:
207
+ image_paths = [selected_path] + [
208
+ path for path in all_image_paths if path != selected_path
209
+ ]
210
+ print(f"User selected first frame: {selected_first_frame}")
211
+ else:
212
+ image_paths = all_image_paths
213
+ print(f"Selected frame not found, using default order")
214
+ else:
215
+ image_paths = all_image_paths
216
+
217
+ if len(image_paths) == 0:
218
+ raise ValueError("No images found. Check your upload.")
219
+
220
+ # Map UI options to actual method names
221
+ method_mapping = {"high_res": "lower_bound_resize", "low_res": "upper_bound_resize"}
222
+ actual_method = method_mapping.get(process_res_method, "upper_bound_crop")
223
+
224
+ # Run model inference
225
+ print(f"Running inference with method: {actual_method}")
226
+ with torch.no_grad():
227
+ # 🔑 使用局部变量 model,不是 self.model
228
+ prediction = model.inference(
229
+ image_paths, export_dir=None, process_res_method=actual_method, infer_gs=infer_gs
230
+ )
231
+
232
+ # Export to GLB
233
+ export_to_glb(
234
+ prediction,
235
+ filter_black_bg=filter_black_bg,
236
+ filter_white_bg=filter_white_bg,
237
+ export_dir=target_dir,
238
+ show_cameras=show_camera,
239
+ conf_thresh_percentile=save_percentage,
240
+ num_max_points=int(num_max_points),
241
+ )
242
+
243
+ # Export to GS video if needed
244
+ if infer_gs:
245
+ mode_mapping = {"extend": "extend", "smooth": "interpolate_smooth"}
246
+ print(f"GS mode: {gs_trj_mode}; Backend mode: {mode_mapping[gs_trj_mode]}")
247
+ export_to_gs_video(
248
+ prediction,
249
+ export_dir=target_dir,
250
+ chunk_size=4,
251
+ trj_mode=mode_mapping.get(gs_trj_mode, "extend"),
252
+ enable_tqdm=True,
253
+ vis_depth="hcat",
254
+ video_quality=gs_video_quality,
255
+ )
256
+
257
+ # Save predictions cache
258
+ self._save_predictions_cache(target_dir, prediction)
259
+
260
+ # Process results
261
+ processed_data = self._process_results(target_dir, prediction, image_paths)
262
+
263
+ # ========================================
264
+ # 🔑 关键修改 2:返回前移动所有 CUDA 张量到 CPU
265
+ # ========================================
266
+ print("Moving all tensors to CPU for safe return...")
267
+ prediction = self._move_prediction_to_cpu(prediction)
268
+
269
+ # Clean up GPU memory
270
+ torch.cuda.empty_cache()
271
+
272
+ return prediction, processed_data
273
+
274
+ def _move_prediction_to_cpu(self, prediction: Any) -> Any:
275
+ """
276
+ Move all CUDA tensors in prediction to CPU for safe pickling.
277
+
278
+ This is CRITICAL for HF Spaces with @spaces.GPU decorator.
279
+ Without this, pickle will try to reconstruct CUDA tensors in
280
+ the main process, causing CUDA initialization error.
281
+
282
+ Args:
283
+ prediction: Prediction object that may contain CUDA tensors
284
+
285
+ Returns:
286
+ Prediction object with all tensors moved to CPU
287
+ """
288
+ # Move gaussians tensors to CPU
289
+ if hasattr(prediction, 'gaussians') and prediction.gaussians is not None:
290
+ gaussians = prediction.gaussians
291
+
292
+ # Move each tensor attribute to CPU
293
+ tensor_attrs = ['means', 'scales', 'rotations', 'harmonics', 'opacities']
294
+ for attr in tensor_attrs:
295
+ if hasattr(gaussians, attr):
296
+ tensor = getattr(gaussians, attr)
297
+ if isinstance(tensor, torch.Tensor) and tensor.is_cuda:
298
+ setattr(gaussians, attr, tensor.cpu())
299
+ print(f" ✓ Moved gaussians.{attr} to CPU")
300
+
301
+ # Move any tensors in aux dict to CPU
302
+ if hasattr(prediction, 'aux') and prediction.aux is not None:
303
+ for key, value in list(prediction.aux.items()):
304
+ if isinstance(value, torch.Tensor) and value.is_cuda:
305
+ prediction.aux[key] = value.cpu()
306
+ print(f" ✓ Moved aux['{key}'] to CPU")
307
+ elif isinstance(value, dict):
308
+ # Recursively handle nested dicts
309
+ for k, v in list(value.items()):
310
+ if isinstance(v, torch.Tensor) and v.is_cuda:
311
+ value[k] = v.cpu()
312
+ print(f" ✓ Moved aux['{key}']['{k}'] to CPU")
313
+
314
+ print("✅ All tensors moved to CPU")
315
+ return prediction
316
+
317
+ def _save_predictions_cache(self, target_dir: str, prediction: Any) -> None:
318
+ """Save predictions data to predictions.npz for caching."""
319
+ try:
320
+ output_file = os.path.join(target_dir, "predictions.npz")
321
+ save_dict = {}
322
+
323
+ if prediction.processed_images is not None:
324
+ save_dict["images"] = prediction.processed_images
325
+
326
+ if prediction.depth is not None:
327
+ save_dict["depths"] = np.round(prediction.depth, 6)
328
+
329
+ if prediction.conf is not None:
330
+ save_dict["conf"] = np.round(prediction.conf, 2)
331
+
332
+ if prediction.extrinsics is not None:
333
+ save_dict["extrinsics"] = prediction.extrinsics
334
+ if prediction.intrinsics is not None:
335
+ save_dict["intrinsics"] = prediction.intrinsics
336
+
337
+ np.savez_compressed(output_file, **save_dict)
338
+ print(f"Saved predictions cache to: {output_file}")
339
+
340
+ except Exception as e:
341
+ print(f"Warning: Failed to save predictions cache: {e}")
342
+
343
+ def _process_results(
344
+ self, target_dir: str, prediction: Any, image_paths: list
345
+ ) -> Dict[int, Dict[str, Any]]:
346
+ """Process model results into structured data."""
347
+ processed_data = {}
348
+
349
+ depth_vis_dir = os.path.join(target_dir, "depth_vis")
350
+
351
+ if os.path.exists(depth_vis_dir):
352
+ depth_files = sorted(glob.glob(os.path.join(depth_vis_dir, "*.jpg")))
353
+ for i, depth_file in enumerate(depth_files):
354
+ processed_image = None
355
+ if prediction.processed_images is not None and i < len(
356
+ prediction.processed_images
357
+ ):
358
+ processed_image = prediction.processed_images[i]
359
+
360
+ processed_data[i] = {
361
+ "depth_image": depth_file,
362
+ "image": processed_image,
363
+ "original_image_path": image_paths[i] if i < len(image_paths) else None,
364
+ "depth": prediction.depth[i] if i < len(prediction.depth) else None,
365
+ "intrinsics": (
366
+ prediction.intrinsics[i]
367
+ if prediction.intrinsics is not None and i < len(prediction.intrinsics)
368
+ else None
369
+ ),
370
+ "mask": None,
371
+ }
372
+
373
+ return processed_data
374
+
375
+ def cleanup(self) -> None:
376
+ """Clean up GPU memory."""
377
+ if torch.cuda.is_available():
378
+ torch.cuda.empty_cache()
379
+ gc.collect()
380
+ ```
381
+
382
+ ## 🔍 关键变化总结
383
+
384
+ ### Before (有问题):
385
+ ```python
386
+ class ModelInference:
387
+ def __init__(self):
388
+ self.model = None # ❌ 实例变量
389
+
390
+ def initialize_model(self, device):
391
+ if self.model is None:
392
+ self.model = load_model() # ❌ 保存在实例中
393
+ else:
394
+ self.model = self.model.to(device) # ❌ 跨进程操作
395
+
396
+ def run_inference(self):
397
+ self.initialize_model(device) # ❌ 使用实例方法
398
+ prediction = self.model.inference(...) # ❌ 使用实例变量
399
+ return prediction # ❌ 包含 CUDA 张量
400
+ ```
401
+
402
+ ### After (正确):
403
+ ```python
404
+ _MODEL_CACHE = None # ✅ 全局变量(子进程安全)
405
+
406
+ class ModelInference:
407
+ def __init__(self):
408
+ pass # ✅ 无实例变量
409
+
410
+ def initialize_model(self, device):
411
+ global _MODEL_CACHE
412
+ if _MODEL_CACHE is None:
413
+ _MODEL_CACHE = load_model() # ✅ 保存在全局
414
+ return _MODEL_CACHE # ✅ 返回而不是存储
415
+
416
+ def run_inference(self):
417
+ model = self.initialize_model(device) # ✅ 局部变量
418
+ prediction = model.inference(...) # ✅ 使用局部变量
419
+ prediction = self._move_prediction_to_cpu(prediction) # ✅ 移到 CPU
420
+ return prediction # ✅ 安全返回
421
+ ```
422
+
423
+ ## 🎯 为什么这样修改?
424
+
425
+ ### 1. 全局变量 vs 实例变量
426
+
427
+ | 方式 | 问题 | 原因 |
428
+ |------|------|------|
429
+ | `self.model` | ❌ 跨进程状态混乱 | 实例在主进程创建 |
430
+ | `_MODEL_CACHE` | ✅ 子进程内安全 | 每个子进程独立 |
431
+
432
+ ### 2. 返回 CPU 张量
433
+
434
+ ```python
435
+ # ❌ 直接返回会报错
436
+ return prediction # prediction.gaussians.means is on CUDA
437
+
438
+ # ✅ 移到 CPU 后返回
439
+ prediction = move_to_cpu(prediction)
440
+ return prediction # All tensors are on CPU, pickle safe
441
+ ```
442
+
443
+ ## 🧪 测试修复
444
+
445
+ ```bash
446
+ # 1. 应用修改
447
+ # 复制上面的完整代码到 model_inference.py
448
+
449
+ # 2. 推送到 Spaces
450
+ git add depth_anything_3/app/modules/model_inference.py
451
+ git commit -m "Fix: Spaces GPU CUDA initialization error"
452
+ git push
453
+
454
+ # 3. 测试多次运行
455
+ # 在 Space 中连续运行 2-3 次推理
456
+ # 应该不再出现 CUDA 错误
457
+ ```
458
+
459
+ ## 📊 修复效果
460
+
461
+ | 问题 | Before | After |
462
+ |------|--------|-------|
463
+ | 第一次推理 | ❌ CUDA 错误 | ✅ 正常 |
464
+ | 第二次推理 | ❌ CUDA 错误 | ✅ 正常 |
465
+ | 连续推理 | ❌ 失败 | ✅ 稳定 |
466
+ | 模型加载 | 每次重新加载 | 缓存复用 |
467
+
468
+ ## 💡 最佳实践
469
+
470
+ 对于 `@spaces.GPU` 装饰的函数:
471
+
472
+ 1. ✅ 使用**全局变量**缓存模型(子进程安全)
473
+ 2. ✅ **不要**使用实例变量存储模型
474
+ 3. ✅ 返回前**移动所有张量到 CPU**
475
+ 4. ✅ 清理 GPU 内存 (`torch.cuda.empty_cache()`)
476
+ 5. ❌ **不要**在主进程中初始化 CUDA
477
+ 6. ❌ **不要**返回 CUDA 张量
478
+
479
+ ## 🔗 相关资源
480
+
481
+ - [HF Spaces Zero GPU 文档](https://huggingface.co/docs/hub/spaces-gpus#zero-gpu)
482
+ - [PyTorch Multiprocessing](https://pytorch.org/docs/stable/notes/multiprocessing.html)
483
+ - [Pickle 协议](https://docs.python.org/3/library/pickle.html)
484
+
app.py CHANGED
@@ -24,8 +24,9 @@ import spaces
24
  from depth_anything_3.app.gradio_app import DepthAnything3App
25
  from depth_anything_3.app.modules.model_inference import ModelInference
26
 
27
- # Monkey-patch the run_inference method to use @spaces.GPU decorator
28
- # This allows dynamic GPU allocation on Hugging Face Spaces
 
29
  original_run_inference = ModelInference.run_inference
30
 
31
  @spaces.GPU(duration=120) # Request GPU for up to 120 seconds per inference
@@ -33,8 +34,10 @@ def gpu_run_inference(self, *args, **kwargs):
33
  """
34
  GPU-accelerated inference with Spaces decorator.
35
 
36
- This function wraps the original run_inference method with @spaces.GPU,
37
- which ensures the model is moved to GPU when needed on HF Spaces.
 
 
38
  """
39
  return original_run_inference(self, *args, **kwargs)
40
 
 
24
  from depth_anything_3.app.gradio_app import DepthAnything3App
25
  from depth_anything_3.app.modules.model_inference import ModelInference
26
 
27
+ # Apply @spaces.GPU decorator to run_inference method
28
+ # This ensures GPU operations happen in isolated subprocess
29
+ # Model loading and inference will occur in GPU subprocess, not main process
30
  original_run_inference = ModelInference.run_inference
31
 
32
  @spaces.GPU(duration=120) # Request GPU for up to 120 seconds per inference
 
34
  """
35
  GPU-accelerated inference with Spaces decorator.
36
 
37
+ This function runs in a GPU subprocess where:
38
+ - Model is loaded and moved to GPU (safe)
39
+ - CUDA operations are allowed
40
+ - All CUDA tensors are moved to CPU before return (for pickle safety)
41
  """
42
  return original_run_inference(self, *args, **kwargs)
43
 
depth_anything_3/app/modules/model_inference.py CHANGED
@@ -31,33 +31,57 @@ from depth_anything_3.utils.export.glb import export_to_glb
31
  from depth_anything_3.utils.export.gs import export_to_gs_video
32
 
33
 
 
 
 
 
 
34
  class ModelInference:
35
  """
36
  Handles model inference and data processing for Depth Anything 3.
37
  """
38
 
39
  def __init__(self):
40
- """Initialize the model inference handler."""
41
- self.model = None
 
 
 
 
 
42
 
43
- def initialize_model(self, device: str = "cuda") -> None:
44
  """
45
- Initialize the DepthAnything3 model.
 
 
 
46
 
47
  Args:
48
  device: Device to load the model on
 
 
 
49
  """
50
- if self.model is None:
51
- # Get model directory from environment variable or use default
 
 
52
  model_dir = os.environ.get(
53
- "DA3_MODEL_DIR", "/dev/shm/da3_models/DA3HF-VITG-METRIC_VITL"
54
  )
55
- self.model = DepthAnything3.from_pretrained(model_dir)
56
- self.model = self.model.to(device)
 
 
 
57
  else:
58
- self.model = self.model.to(device)
59
-
60
- self.model.eval()
 
 
 
61
 
62
  def run_inference(
63
  self,
@@ -97,8 +121,8 @@ class ModelInference:
97
  device = "cuda" if torch.cuda.is_available() else "cpu"
98
  device = torch.device(device)
99
 
100
- # Initialize model if needed
101
- self.initialize_model(device)
102
 
103
  # Get image paths
104
  print("Loading images...")
@@ -157,7 +181,7 @@ class ModelInference:
157
  # Run model inference
158
  print(f"Running inference with method: {actual_method}")
159
  with torch.no_grad():
160
- prediction = self.model.inference(
161
  image_paths, export_dir=None, process_res_method=actual_method, infer_gs=infer_gs
162
  )
163
  # num_max_points: int = 1_000_000,
@@ -191,6 +215,10 @@ class ModelInference:
191
  # Process results
192
  processed_data = self._process_results(target_dir, prediction, image_paths)
193
 
 
 
 
 
194
  # Clean up
195
  torch.cuda.empty_cache()
196
 
@@ -279,6 +307,47 @@ class ModelInference:
279
 
280
  return processed_data
281
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  def cleanup(self) -> None:
283
  """Clean up GPU memory."""
284
  if torch.cuda.is_available():
 
31
  from depth_anything_3.utils.export.gs import export_to_gs_video
32
 
33
 
34
+ # Global cache for model (safe in GPU subprocess with @spaces.GPU)
35
+ # Each subprocess gets its own copy of this global variable
36
+ _MODEL_CACHE = None
37
+
38
+
39
  class ModelInference:
40
  """
41
  Handles model inference and data processing for Depth Anything 3.
42
  """
43
 
44
  def __init__(self):
45
+ """Initialize the model inference handler.
46
+
47
+ Note: Do not store model in instance variable to avoid
48
+ cross-process state issues with @spaces.GPU decorator.
49
+ """
50
+ # No instance variables - model cached in global variable
51
+ pass
52
 
53
+ def initialize_model(self, device: str = "cuda"):
54
  """
55
+ Initialize the DepthAnything3 model using global cache.
56
+
57
+ This uses a global variable which is safe because @spaces.GPU
58
+ runs in isolated subprocess, each with its own global namespace.
59
 
60
  Args:
61
  device: Device to load the model on
62
+
63
+ Returns:
64
+ Model instance ready for inference
65
  """
66
+ global _MODEL_CACHE
67
+
68
+ if _MODEL_CACHE is None:
69
+ # First time loading in this subprocess
70
  model_dir = os.environ.get(
71
+ "DA3_MODEL_DIR", "depth-anything/DA3NESTED-GIANT-LARGE"
72
  )
73
+ print(f"🔄 Loading model from {model_dir}...")
74
+ _MODEL_CACHE = DepthAnything3.from_pretrained(model_dir)
75
+ _MODEL_CACHE = _MODEL_CACHE.to(device)
76
+ _MODEL_CACHE.eval()
77
+ print("✅ Model loaded and ready on GPU")
78
  else:
79
+ # Model already cached in this subprocess
80
+ print("✅ Using cached model")
81
+ # Ensure it's on the correct device
82
+ _MODEL_CACHE = _MODEL_CACHE.to(device)
83
+
84
+ return _MODEL_CACHE
85
 
86
  def run_inference(
87
  self,
 
121
  device = "cuda" if torch.cuda.is_available() else "cpu"
122
  device = torch.device(device)
123
 
124
+ # Initialize model if needed - get model instance (not stored in self)
125
+ model = self.initialize_model(device)
126
 
127
  # Get image paths
128
  print("Loading images...")
 
181
  # Run model inference
182
  print(f"Running inference with method: {actual_method}")
183
  with torch.no_grad():
184
+ prediction = model.inference(
185
  image_paths, export_dir=None, process_res_method=actual_method, infer_gs=infer_gs
186
  )
187
  # num_max_points: int = 1_000_000,
 
215
  # Process results
216
  processed_data = self._process_results(target_dir, prediction, image_paths)
217
 
218
+ # CRITICAL: Move all CUDA tensors to CPU before returning
219
+ # This prevents CUDA initialization in main process during unpickling
220
+ prediction = self._move_prediction_to_cpu(prediction)
221
+
222
  # Clean up
223
  torch.cuda.empty_cache()
224
 
 
307
 
308
  return processed_data
309
 
310
+ def _move_prediction_to_cpu(self, prediction: Any) -> Any:
311
+ """
312
+ Move all CUDA tensors in prediction to CPU for safe pickling.
313
+
314
+ This is REQUIRED for HF Spaces with @spaces.GPU decorator to avoid
315
+ CUDA initialization in the main process during unpickling.
316
+
317
+ Args:
318
+ prediction: Prediction object that may contain CUDA tensors
319
+
320
+ Returns:
321
+ Prediction object with all tensors moved to CPU
322
+ """
323
+ # Move gaussians tensors to CPU
324
+ if hasattr(prediction, 'gaussians') and prediction.gaussians is not None:
325
+ gaussians = prediction.gaussians
326
+
327
+ # Move each tensor attribute to CPU
328
+ tensor_attrs = ['means', 'scales', 'rotations', 'harmonics', 'opacities']
329
+ for attr in tensor_attrs:
330
+ if hasattr(gaussians, attr):
331
+ tensor = getattr(gaussians, attr)
332
+ if isinstance(tensor, torch.Tensor) and tensor.is_cuda:
333
+ setattr(gaussians, attr, tensor.cpu())
334
+ print(f" ✓ Moved gaussians.{attr} to CPU")
335
+
336
+ # Move any tensors in aux dict to CPU
337
+ if hasattr(prediction, 'aux') and prediction.aux is not None:
338
+ for key, value in list(prediction.aux.items()):
339
+ if isinstance(value, torch.Tensor) and value.is_cuda:
340
+ prediction.aux[key] = value.cpu()
341
+ print(f" ✓ Moved aux['{key}'] to CPU")
342
+ elif isinstance(value, dict):
343
+ # Recursively handle nested dicts
344
+ for k, v in list(value.items()):
345
+ if isinstance(v, torch.Tensor) and v.is_cuda:
346
+ value[k] = v.cpu()
347
+ print(f" ✓ Moved aux['{key}']['{k}'] to CPU")
348
+
349
+ return prediction
350
+
351
  def cleanup(self) -> None:
352
  """Clean up GPU memory."""
353
  if torch.cuda.is_available():
example_spaces_gpu.py DELETED
@@ -1,52 +0,0 @@
1
- """
2
- Simple example demonstrating @spaces.GPU decorator usage.
3
-
4
- This example shows how the @spaces.GPU decorator works:
5
- - Variables created outside the decorated function stay on CPU initially
6
- - When the decorated function is called, the process moves to GPU environment
7
- - Inside the decorated function, tensors can access CUDA
8
- """
9
-
10
- import gradio as gr
11
- import spaces
12
- import torch
13
-
14
- # This tensor is created at module load time
15
- # On HF Spaces, it will be on CPU until a @spaces.GPU function is called
16
- zero = torch.Tensor([0])
17
-
18
- # Try to move to cuda - will fail gracefully if no GPU available
19
- try:
20
- zero = zero.cuda()
21
- print(f"Initial device: {zero.device}") # On Spaces: shows 'cpu' 🤔
22
- except:
23
- print(f"Initial device: {zero.device}") # cpu (no GPU available yet)
24
-
25
-
26
- @spaces.GPU(duration=60) # Request GPU for up to 60 seconds
27
- def greet(n):
28
- """
29
- This function runs on GPU when called.
30
- The @spaces.GPU decorator ensures GPU access.
31
- """
32
- # Inside the decorated function, we have GPU access
33
- print(f"Inside GPU function - device: {zero.device}") # On Spaces: shows 'cuda:0' 🤗
34
-
35
- # Perform GPU computation
36
- result = zero + n
37
-
38
- return f"Hello {result.item()} Tensor! (computed on {zero.device})"
39
-
40
-
41
- # Create Gradio interface
42
- demo = gr.Interface(
43
- fn=greet,
44
- inputs=gr.Number(value=42, label="Enter a number"),
45
- outputs=gr.Text(label="Result"),
46
- title="Spaces GPU Example",
47
- description="Demonstrates @spaces.GPU decorator usage"
48
- )
49
-
50
- if __name__ == "__main__":
51
- demo.launch()
52
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fix_spaces_gpu.patch ADDED
@@ -0,0 +1,142 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --- a/depth_anything_3/app/modules/model_inference.py
2
+ +++ b/depth_anything_3/app/modules/model_inference.py
3
+ @@ -31,47 +31,67 @@ from depth_anything_3.utils.export.glb import export_to_glb
4
+ from depth_anything_3.utils.export.gs import export_to_gs_video
5
+
6
+
7
+ +# Global cache for model (used in GPU subprocess)
8
+ +# This is safe because @spaces.GPU runs in isolated subprocess
9
+ +_MODEL_CACHE = None
10
+ +
11
+ +
12
+ class ModelInference:
13
+ """
14
+ Handles model inference and data processing for Depth Anything 3.
15
+ """
16
+
17
+ def __init__(self):
18
+ - """Initialize the model inference handler."""
19
+ - self.model = None
20
+ -
21
+ - def initialize_model(self, device: str = "cuda") -> None:
22
+ + """Initialize the model inference handler.
23
+ +
24
+ + Note: Do NOT store model in instance variable to avoid
25
+ + state sharing issues with @spaces.GPU decorator.
26
+ + """
27
+ + pass # No instance variables
28
+ +
29
+ + def initialize_model(self, device: str = "cuda"):
30
+ """
31
+ Initialize the DepthAnything3 model.
32
+ +
33
+ + Uses global cache to store model safely in GPU subprocess.
34
+ + This avoids CUDA initialization in main process.
35
+
36
+ Args:
37
+ device: Device to load the model on
38
+ +
39
+ + Returns:
40
+ + Model instance
41
+ """
42
+ - if self.model is None:
43
+ + global _MODEL_CACHE
44
+ +
45
+ + if _MODEL_CACHE is None:
46
+ # Get model directory from environment variable or use default
47
+ model_dir = os.environ.get(
48
+ "DA3_MODEL_DIR", "/dev/shm/da3_models/DA3HF-VITG-METRIC_VITL"
49
+ )
50
+ - self.model = DepthAnything3.from_pretrained(model_dir)
51
+ - self.model = self.model.to(device)
52
+ + print(f"Loading model from {model_dir}...")
53
+ + _MODEL_CACHE = DepthAnything3.from_pretrained(model_dir)
54
+ + _MODEL_CACHE = _MODEL_CACHE.to(device)
55
+ + _MODEL_CACHE.eval()
56
+ + print("Model loaded and moved to GPU")
57
+ else:
58
+ - self.model = self.model.to(device)
59
+ -
60
+ - self.model.eval()
61
+ + print("Using cached model")
62
+ + # Ensure model is on correct device
63
+ + _MODEL_CACHE = _MODEL_CACHE.to(device)
64
+ +
65
+ + return _MODEL_CACHE
66
+
67
+ def run_inference(
68
+ self,
69
+ ...
70
+ # Initialize model if needed
71
+ - self.initialize_model(device)
72
+ + model = self.initialize_model(device)
73
+
74
+ ...
75
+
76
+ # Run model inference
77
+ print(f"Running inference with method: {actual_method}")
78
+ with torch.no_grad():
79
+ - prediction = self.model.inference(
80
+ + prediction = model.inference(
81
+ image_paths, export_dir=None, process_res_method=actual_method, infer_gs=infer_gs
82
+ )
83
+
84
+ @@ -192,6 +212,10 @@ class ModelInference:
85
+ # Process results
86
+ processed_data = self._process_results(target_dir, prediction, image_paths)
87
+
88
+ + # CRITICAL: Move all CUDA tensors to CPU before returning
89
+ + # This prevents CUDA initialization in main process during unpickling
90
+ + prediction = self._move_prediction_to_cpu(prediction)
91
+ +
92
+ # Clean up
93
+ torch.cuda.empty_cache()
94
+
95
+ @@ -282,6 +306,45 @@ class ModelInference:
96
+
97
+ return processed_data
98
+
99
+ + def _move_prediction_to_cpu(self, prediction: Any) -> Any:
100
+ + """
101
+ + Move all CUDA tensors in prediction to CPU for safe pickling.
102
+ +
103
+ + This is REQUIRED for HF Spaces with @spaces.GPU decorator to avoid
104
+ + CUDA initialization in the main process during unpickling.
105
+ +
106
+ + Args:
107
+ + prediction: Prediction object that may contain CUDA tensors
108
+ +
109
+ + Returns:
110
+ + Prediction object with all tensors moved to CPU
111
+ + """
112
+ + # Move gaussians tensors to CPU
113
+ + if hasattr(prediction, 'gaussians') and prediction.gaussians is not None:
114
+ + gaussians = prediction.gaussians
115
+ +
116
+ + # Move each tensor attribute to CPU
117
+ + tensor_attrs = ['means', 'scales', 'rotations', 'harmonics', 'opacities']
118
+ + for attr in tensor_attrs:
119
+ + if hasattr(gaussians, attr):
120
+ + tensor = getattr(gaussians, attr)
121
+ + if isinstance(tensor, torch.Tensor) and tensor.is_cuda:
122
+ + setattr(gaussians, attr, tensor.cpu())
123
+ + print(f"Moved gaussians.{attr} to CPU")
124
+ +
125
+ + # Move any tensors in aux dict to CPU
126
+ + if hasattr(prediction, 'aux') and prediction.aux is not None:
127
+ + for key, value in list(prediction.aux.items()):
128
+ + if isinstance(value, torch.Tensor) and value.is_cuda:
129
+ + prediction.aux[key] = value.cpu()
130
+ + print(f"Moved aux['{key}'] to CPU")
131
+ + elif isinstance(value, dict):
132
+ + # Recursively handle nested dicts
133
+ + for k, v in list(value.items()):
134
+ + if isinstance(v, torch.Tensor) and v.is_cuda:
135
+ + value[k] = v.cpu()
136
+ + print(f"Moved aux['{key}']['{k}'] to CPU")
137
+ +
138
+ + return prediction
139
+ +
140
+ def cleanup(self) -> None:
141
+ """Clean up GPU memory."""
142
+