[AI学习:SPIN -win-安装SPIN-工具过程 SPIN win 电脑安装=accoda 环境-第五篇:代码修复])
- 1-概述
-
- (1)概述
- (2)操作流程-解决问题
-
- [1-问题:NameError: name 'SMPLWrapper' is not defined](#1-问题:NameError: name 'SMPLWrapper' is not defined)
- [2-问题:einsum(): subscript i has size 300 for operand 1 which does not broadcast with previously seen size 10](#2-问题:einsum(): subscript i has size 300 for operand 1 which does not broadcast with previously seen size 10)
- [3-问题:RuntimeError: Boolean value of Tensor with more than one value is ambiguous](#3-问题:RuntimeError: Boolean value of Tensor with more than one value is ambiguous)
- 4-模型问题:虽然成功生成obj的3D模型文件,但是模型文件不对。
- (3)操作流程-重新梳理
- (4)操作流程-成功
- (5)总结
1-概述
(1)概述
上篇已经说了,最近学习AI,看到了SPIN这个工具,可以将图片转换位3D模型,我们继续来尝试,并且将问题记录。
前篇文章:[AI学习:SPIN -win-安装SPIN-工具过程 SPIN win 电脑安装=accoda 环境-第四篇:代码修复]
我们之前布置了环境,之后往后遇到很多问题,今天来继续操作。
(2)操作流程-解决问题
1-问题:NameError: name 'SMPLWrapper' is not defined

1-原因分析:
说明在 demo_norender.py 里写了:
bash
smpl = SMPLWrapper(model_folder='data/smpl', gender='NEUTRAL', num_betas=10, device=DEVICE)
项目里并没有 SMPLWrapper 这个类(而且变量名 model_folder 也未定义)。
SPIN 的正确用法是用我们自己的 utils/smpl.py 里的 SMPL 类(它内部调用 smplx.create(model_type='smpl', num_betas=10, ...))。
2-解决方式:
在 demo_norender.py 顶部导入正确的类
bash
from utils.smpl import SMPL
import os
bash
SMPL_MODEL_DIR = os.path.join('data', 'smpl') # 你的 pkl 就在 data/smpl 下
smpl = SMPL(model_path=SMPL_MODEL_DIR, batch_size=1, gender='neutral') # gender 用小写
# 如果你的 utils/smpl.py 支持:SMPL(model_path, batch_size=1, gender='neutral', num_betas=10)
# smpl = SMPL(model_path=SMPL_MODEL_DIR, batch_size=1, gender='neutral', num_betas=10)
2-问题:einsum(): subscript i has size 300 for operand 1 which does not broadcast with previously seen size 10

1-原因分析:
还是同一个本质问题:传进 SMPL 的 betas 维度是 300,但当前 SMPL 只支持 10 个 shape 基(shapedirs=10),于是
bash
einsum(): subscript i has size 300 for operand 1 which does not broadcast with previously seen size 10
其实还是同一个根因:传进 SMPL 的 betas 维度是 300,但当前 SMPL 的形状基(shapedirs)是 10,所以 einsum('bl,mkl->bmk', [betas, shapedirs]) 在维度 l 上对不齐:
报错里写的:subscript l has size 300 for operand 1 which does not broadcast with previously seen size 10
解释:第 1 个操作数(betas)在 l 维是 300,而之前已经见到的 l 维大小是 10(来自 shapedirs)。
也就是说现在是 betas=300、shapedirs=10,不是反过来。
2-解决方式:
把 betas 截到前 10 维再喂给 SMPL 就能过。
下面给出最小可改动的"保险写法",直接贴到你 demo_norender.py 里模型前向之后、调用 smpl(...) 之前:
bash
with torch.no_grad():
pred_rotmat, pred_betas, pred_cam = model(x.float())
# ---- 重要:对齐 betas 维度到 10 ----
print("pred_betas shape before:", tuple(pred_betas.shape)) # 调试用
if pred_betas.shape[-1] != 10:
# 常见是 300,这里统一截取到前 10 维
pred_betas = pred_betas[..., :10]
print("pred_betas shape after :", tuple(pred_betas.shape))
# 统一 dtype / device
pred_betas = pred_betas.to(dtype=torch.float32, device=DEVICE)
# 只用 betas 也可以先跑通
out = smpl(betas=pred_betas)
3-问题:RuntimeError: Boolean value of Tensor with more than one value is ambiguous

1-原因分析:
bash
RuntimeError: Boolean value of Tensor with more than one value is ambiguous
File "utils/smpl.py", line 83, in __init__
sd = getattr(self._smpl, 'shapedirs', None) or getattr(self._smpl, 'shape_disps', None)
self._smpl.shapedirs 这个对象 不是 None,但它是一个 Tensor(shape_dirs 是 [6890,3,10] 的张量),而 Python 在执行 A or B 时,会尝试把 A 转成布尔值。
Tensor 有多个元素时不能转成 bool,于是抛出这个错误。
2-解决方式:
打开文件:
bash
C:\Users\Admin\SPIN\utils\smpl.py
找到大约第 83 行:
bash
sd = getattr(self._smpl, 'shapedirs', None) or getattr(self._smpl, 'shape_disps', None)
把它改成下面这样:
bash
sd = getattr(self._smpl, 'shapedirs', None)
if sd is None:
sd = getattr(self._smpl, 'shape_disps', None)
4-模型问题:虽然成功生成obj的3D模型文件,但是模型文件不对。
如下图,成功是成功生成了obj文件。
但是模型很是奇怪
1-原因分析:
过于依赖AI或者自己了解不深的时候,其实可以说对于这个模型可能不是很了解。
从这张图来看,姿态完全扭曲、上下颠倒,模型像是"摔在地上"的样子
(3)操作流程-重新梳理
1-安装PyOpenGL-accelerate

2-安装numpy和chumpy
安装 numpy1.23.5 和 chumpy0.70 是完全正确的------SPIN 官方推荐的兼容版本。

3-重新尝试

还是之前问题
这表示:shape_disps / shapedirs 的形状维度是 300,但betas 长度是 10。
换句话说,现在加载的是 SMPL-X(300 shape components) 的模型文件,但前向里用的是 SMPL(10 shape components) 的设置------于是 einsum('bl,mk->bmk', betas(...×10), shape_disps(...×300)) 就对不上了。
4-确认模型文件

5-编写测试脚本
clike
import pickle, os
pkl_path = "models/smpl/SMPL_NEUTRAL.pkl" # 注意不是 data/smpl
data = pickle.load(open(pkl_path, 'rb'), encoding='latin1')
print("shapedirs dim =", data['shapedirs'].shape[-1])

bash
import pickle
# 注意这里要用 models/smpl,不是 data/smpl
pkl_path = "models/smpl/SMPL_NEUTRAL.pkl"
with open(pkl_path, 'rb') as f:
data = pickle.load(f, encoding='latin1')
print("shapedirs dim =", data['shapedirs'].shape[-1])

5-编写测试脚本
正在用的解释器不是 Conda 里的那个(python3 可能指向别的 Python / Windows Store 启动器),脚本其实没被期望的解释器执行。
脚本里路径不对(写的是 models/smpl/...,而 SPIN 正确路径在 data/smpl/...),但即便出错也应打印报错------所以更像是 #1。
6-编写测试脚本
bash
(spin) C:\Users\Admin\SPIN>python3 test_shapedirs.py
(spin) C:\Users\Admin\SPIN>python3 test_shapedirs.py
(spin) C:\Users\Admin\SPIN>python3 test_shapedirs.py
(spin) C:\Users\Admin\SPIN>python3 test_shapedirs.py
(spin) C:\Users\Admin\SPIN>python test_shapedirs.py
[Check] trying to open: C:\Users\Admin\SPIN\models\smpl\SMPL_NEUTRAL.pkl
C:\Users\Admin\SPIN\test_shapedirs.py:9: DeprecationWarning: Please import `csc_matrix` from the `scipy.sparse` namespace; the `scipy.sparse.csc` namespace is deprecated and will be removed in SciPy 2.0.0.
data = pickle.load(f, encoding='latin1')
[OK] shapedirs shape = (6890, 3, 300) last dim = 300
现在用的 SMPL_NEUTRAL.pkl 是 SMPL-X 格式(或含 300 个 shape basis 的版本),shapedirs 最后一维是 300,而 SPIN 的模型是按 SMPL (10 维 betas) 训练的,所以才会一路触发
einsum(): subscript l has size 300 for operand 1 which does not broadcast with ... size 10
7-问题解决

Python 作用域/变量名问题:现在跑的是 demo.py,在这个脚本里保存结果时用了
bash
np.savez(outfile + '_spin.npz',
vertices=vertices,
betas=betas,
pose=pose,
camera=camera)
当前的执行路径里,vertices 从未被赋值(因此报 NameError: name 'vertices' is not defined)。常见原因有两种:
改过/注释过上面计算 vertices 的那几行;
demo.py 里 vertices 只在某个分支(比如渲染路径)里被创建,而你走的是另一个分支(或之前报过别的错,导致没有执行到创建 vertices 的那行)。
8-重新生成

bash
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
data = np.load("examples/im1010_spin.npz")
vertices = data["vertices"]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.scatter(vertices[:,0], vertices[:,1], vertices[:,2], s=1)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
plt.show()
(4)操作流程-成功
(5)总结
确实弄完后,有一段时间没有看来,中间细节大部都忘了,确实复现了论文,但确实记录做的不好,自己在这个过程种,跟随AI的脚步,但是AI在细节处理,其实不是那么好,自己有时感觉也是过于依赖AI。但是这个模型还是很有意思的。
同时这个SPIN学习也告一段落了。