AI学习:SPIN -win-安装SPIN-工具过程 SPIN win 电脑安装=accoda 环境-第五篇:代码修复]
[AI学习:SPIN -win-安装SPIN-工具过程 SPIN win 电脑安装=accoda 环境-第五篇:代码修复])
- 1-概述
- (1)概述
- (2)操作流程-解决问题
- 1-问题:NameError: name 'SMPLWrapper' is not defined
- 1-原因分析:
- 2-解决方式:
- 2-问题:einsum(): subscript i has size 300 for operand 1 which does not broadcast with previously seen size 10
- 1-原因分析:
- 2-解决方式:
- 3-问题:RuntimeError: Boolean value of Tensor with more than one value is ambiguous
- 1-原因分析:
- 2-解决方式:
- 4-模型问题:虽然成功生成obj的3D模型文件,但是模型文件不对。
- 1-原因分析:
- (3)操作流程-重新梳理
- 1-安装PyOpenGL-accelerate
- 2-安装numpy和chumpy
- 3-重新尝试
- 4-确认模型文件
- 5-编写测试脚本
- 5-编写测试脚本
- 6-编写测试脚本
- 7-问题解决
- 8-重新生成
- (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 里写了:
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 顶部导入正确的类
from utils.smpl import SMPL
import os
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),于是
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(…) 之前:
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-原因分析:
RuntimeError: Boolean value of Tensor with more than one value is ambiguousFile "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-解决方式:
打开文件:
C:\Users\Admin\SPIN\utils\smpl.py
找到大约第 83 行:
sd = getattr(self._smpl, 'shapedirs', None) or getattr(self._smpl, 'shape_disps', None)
把它改成下面这样:
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-编写测试脚本
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])
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-编写测试脚本
(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,在这个脚本里保存结果时用了
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-重新生成
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3Ddata = 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学习也告一段落了。