Create fixcudn.py
Browse files- fixcudn.py +210 -0
fixcudn.py
ADDED
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python3
|
2 |
+
# fix_isotropic3d_deps.py
|
3 |
+
# Otomasi perbaikan libigl (igl) & (opsional) tinycudann untuk Isotropic3D/threestudio.
|
4 |
+
|
5 |
+
import os
|
6 |
+
import sys
|
7 |
+
import subprocess
|
8 |
+
import shlex
|
9 |
+
import json
|
10 |
+
import glob
|
11 |
+
from pathlib import Path
|
12 |
+
|
13 |
+
IS_ROOT = (os.geteuid() == 0) if hasattr(os, "geteuid") else False
|
14 |
+
|
15 |
+
def run(cmd, env=None, check=True):
|
16 |
+
print(f"\n>>> {cmd}")
|
17 |
+
result = subprocess.run(shlex.split(cmd), env=env, stdout=sys.stdout, stderr=sys.stderr)
|
18 |
+
if check and result.returncode != 0:
|
19 |
+
print(f"[ERROR] Command failed: {cmd}")
|
20 |
+
sys.exit(result.returncode)
|
21 |
+
return result.returncode
|
22 |
+
|
23 |
+
def py_run(code, check=True):
|
24 |
+
print(f"\n>>> python - <<'PY' ...")
|
25 |
+
p = subprocess.Popen([sys.executable, "-c", code])
|
26 |
+
p.wait()
|
27 |
+
if check and p.returncode != 0:
|
28 |
+
print("[ERROR] Inline python failed.")
|
29 |
+
sys.exit(p.returncode)
|
30 |
+
return p.returncode
|
31 |
+
|
32 |
+
def detect_torch():
|
33 |
+
code = r"""
|
34 |
+
import json, sys
|
35 |
+
try:
|
36 |
+
import torch
|
37 |
+
info = {
|
38 |
+
"torch_version": torch.__version__,
|
39 |
+
"cuda_runtime": getattr(torch.version, "cuda", None),
|
40 |
+
"cuda_available": torch.cuda.is_available(),
|
41 |
+
"device_capability": None,
|
42 |
+
"device_name": None,
|
43 |
+
}
|
44 |
+
if info["cuda_available"]:
|
45 |
+
info["device_name"] = torch.cuda.get_device_name(0)
|
46 |
+
info["device_capability"] = torch.cuda.get_device_capability(0)
|
47 |
+
print(json.dumps(info))
|
48 |
+
except Exception as e:
|
49 |
+
print(json.dumps({"error": str(e)}))
|
50 |
+
"""
|
51 |
+
out = subprocess.check_output([sys.executable, "-c", code], text=True)
|
52 |
+
return json.loads(out.strip())
|
53 |
+
|
54 |
+
def set_cuda_env(cuda_home_guess=None):
|
55 |
+
# best-effort set CUDA paths
|
56 |
+
candidates = []
|
57 |
+
if cuda_home_guess:
|
58 |
+
candidates.append(cuda_home_guess)
|
59 |
+
candidates += [
|
60 |
+
"/usr/local/cuda",
|
61 |
+
"/usr/local/cuda-12.5", "/usr/local/cuda-12.4", "/usr/local/cuda-12.3",
|
62 |
+
"/usr/local/cuda-12.2", "/usr/local/cuda-12.1", "/usr/local/cuda-12.0",
|
63 |
+
"/usr/local/cuda-11.8", "/usr/local/cuda-11.7",
|
64 |
+
]
|
65 |
+
for c in candidates:
|
66 |
+
if Path(c).exists():
|
67 |
+
os.environ["CUDA_HOME"] = c
|
68 |
+
os.environ["PATH"] = f"{c}/bin:" + os.environ.get("PATH", "")
|
69 |
+
os.environ["LD_LIBRARY_PATH"] = f"{c}/lib64:" + os.environ.get("LD_LIBRARY_PATH", "")
|
70 |
+
print(f"[INFO] Using CUDA at {c}")
|
71 |
+
return
|
72 |
+
print("[WARN] CUDA not found on typical paths; proceeding anyway.")
|
73 |
+
|
74 |
+
def apt_install(packages):
|
75 |
+
if not IS_ROOT:
|
76 |
+
print("[WARN] Skipping apt-get because this process is not root.")
|
77 |
+
return
|
78 |
+
run("apt-get update")
|
79 |
+
run(f"apt-get install -y {' '.join(packages)}")
|
80 |
+
|
81 |
+
def pip_install(pkgs, flags=""):
|
82 |
+
run(f"{sys.executable} -m pip install -U {flags} {' '.join(pkgs)}")
|
83 |
+
|
84 |
+
def remove_old_igl():
|
85 |
+
# pip uninstall
|
86 |
+
run(f"{sys.executable} -m pip uninstall -y igl || true", check=False)
|
87 |
+
# hard cleanup
|
88 |
+
code = r"""
|
89 |
+
import sys, os, glob, shutil
|
90 |
+
removed = []
|
91 |
+
for sp in sys.path:
|
92 |
+
for pat in ("igl", "igl-*"):
|
93 |
+
for p in glob.glob(os.path.join(sp, pat)):
|
94 |
+
try:
|
95 |
+
if os.path.isdir(p):
|
96 |
+
shutil.rmtree(p, ignore_errors=True)
|
97 |
+
else:
|
98 |
+
os.remove(p)
|
99 |
+
removed.append(p)
|
100 |
+
except Exception: pass
|
101 |
+
print("\n".join(removed))
|
102 |
+
"""
|
103 |
+
print("[INFO] Removing leftover igl files (if any):")
|
104 |
+
py_run(code, check=False)
|
105 |
+
|
106 |
+
def build_libigl(src_dir="/Isotropic3D/libigl-python-bindings"):
|
107 |
+
# clone if needed
|
108 |
+
if not Path(src_dir).exists():
|
109 |
+
run(f"git clone --recursive https://github.com/libigl/libigl-python-bindings.git {src_dir}")
|
110 |
+
else:
|
111 |
+
run(f"git -C {src_dir} submodule update --init --recursive")
|
112 |
+
|
113 |
+
# install with no build isolation so it sees our env
|
114 |
+
run(f"{sys.executable} -m pip install -v --no-build-isolation .", env=os.environ | {}, check=True)
|
115 |
+
|
116 |
+
def verify_igl():
|
117 |
+
code = r"""
|
118 |
+
import igl
|
119 |
+
print("igl module path:", igl.__file__)
|
120 |
+
print("has fast_winding_number_for_meshes:", hasattr(igl, "fast_winding_number_for_meshes"))
|
121 |
+
"""
|
122 |
+
py_run(code)
|
123 |
+
|
124 |
+
def compute_arch_from_capability(cap=None):
|
125 |
+
# map major.minor to CMake arch (rounded typical)
|
126 |
+
# Lovelace(8.9)=89, Ampere(8.6)=86, A100(8.0)=80, Turing(7.5)=75, Volta(7.0)=70
|
127 |
+
mapping = {(8,9): 89, (8,6): 86, (8,0): 80, (7,5): 75, (7,0): 70}
|
128 |
+
if isinstance(cap, (list, tuple)) and len(cap) >= 2:
|
129 |
+
return mapping.get((cap[0], cap[1]), cap[0]*10 + cap[1])
|
130 |
+
return None
|
131 |
+
|
132 |
+
def ensure_tinycudann(src_dir="/Isotropic3D/tiny-cuda-nn", arch=None):
|
133 |
+
# uninstall old
|
134 |
+
run(f"{sys.executable} -m pip uninstall -y tinycudann tiny-cuda-nn || true", check=False)
|
135 |
+
|
136 |
+
# clone if needed
|
137 |
+
if not Path(src_dir).exists():
|
138 |
+
run(f"git clone --recursive https://github.com/NVlabs/tiny-cuda-nn.git {src_dir}")
|
139 |
+
else:
|
140 |
+
run(f"git -C {src_dir} submodule update --init --recursive")
|
141 |
+
|
142 |
+
bind_dir = Path(src_dir) / "bindings" / "torch"
|
143 |
+
if not bind_dir.exists():
|
144 |
+
print("[ERROR] tiny-cuda-nn bindings/torch not found.")
|
145 |
+
sys.exit(2)
|
146 |
+
|
147 |
+
env = os.environ.copy()
|
148 |
+
if arch:
|
149 |
+
env["TCNN_CUDA_ARCHITECTURES"] = str(arch)
|
150 |
+
env["TORCH_CUDA_LIST"] = "" # avoid confusion
|
151 |
+
# Build with no build isolation so it can use our Torch/pybind11
|
152 |
+
run(f"{sys.executable} -m pip install -v --no-build-isolation .", env=env | {}, check=True)
|
153 |
+
|
154 |
+
def verify_tcnn():
|
155 |
+
code = r"""
|
156 |
+
import torch
|
157 |
+
import tinycudann as tcnn
|
158 |
+
print("tinycudann import OK; torch", torch.__version__)
|
159 |
+
"""
|
160 |
+
py_run(code)
|
161 |
+
|
162 |
+
def main():
|
163 |
+
import argparse
|
164 |
+
ap = argparse.ArgumentParser(description="Fix igl and (optional) tinycudann for Isotropic3D.")
|
165 |
+
ap.add_argument("--cuda-home", type=str, default=None, help="Custom CUDA_HOME path (optional).")
|
166 |
+
ap.add_argument("--do-tcnn", action="store_true", help="Also build tiny-cuda-nn bindings.")
|
167 |
+
ap.add_argument("--libigl-src", type=str, default="/Isotropic3D/libigl-python-bindings")
|
168 |
+
ap.add_argument("--tcnn-src", type=str, default="/Isotropic3D/tiny-cuda-nn")
|
169 |
+
args = ap.parse_args()
|
170 |
+
|
171 |
+
# 0) Toolchain + backend
|
172 |
+
apt_install(["build-essential", "cmake", "ninja-build", "git", "libeigen3-dev"])
|
173 |
+
pip_install(["pip", "wheel", "setuptools", "scikit-build-core", "pybind11", "numpy"])
|
174 |
+
|
175 |
+
# 1) CUDA env (best effort)
|
176 |
+
set_cuda_env(args.cuda_home)
|
177 |
+
|
178 |
+
# 2) Reinstall igl properly
|
179 |
+
print("\n=== Reinstalling libigl (igl) ===")
|
180 |
+
remove_old_igl()
|
181 |
+
# Install from local clone or clone to default dir then install
|
182 |
+
if Path(args.libigl_src).exists():
|
183 |
+
run(f"git -C {args.libigl_src} submodule update --init --recursive")
|
184 |
+
run(f"{sys.executable} -m pip install -v --no-build-isolation .", env=os.environ | {}, check=True)
|
185 |
+
else:
|
186 |
+
build_libigl(args.libigl_src)
|
187 |
+
print("\n=== Verifying igl ===")
|
188 |
+
verify_igl()
|
189 |
+
|
190 |
+
# 3) (Optional) Build tinycudann
|
191 |
+
if args.do_tcnn:
|
192 |
+
print("\n=== Building tiny-cuda-nn / tinycudann ===")
|
193 |
+
info = detect_torch()
|
194 |
+
print(f"[INFO] Torch info: {info}")
|
195 |
+
arch = None
|
196 |
+
if info.get("cuda_available") and info.get("device_capability"):
|
197 |
+
arch = compute_arch_from_capability(info["device_capability"])
|
198 |
+
print(f"[INFO] Detected GPU capability {info['device_capability']} -> arch {arch}")
|
199 |
+
else:
|
200 |
+
print("[WARN] CUDA not available from torch; proceeding without arch hint.")
|
201 |
+
ensure_tinycudann(args.tcnn_src, arch=arch)
|
202 |
+
print("\n=== Verifying tinycudann ===")
|
203 |
+
verify_tcnn()
|
204 |
+
|
205 |
+
print("\n[OK] All done. You can now run Isotropic3D:")
|
206 |
+
print(" cd /Isotropic3D")
|
207 |
+
print(" python launch.py --config configs/isotropic3d-shading.yaml --train --gpu 0")
|
208 |
+
|
209 |
+
if __name__ == "__main__":
|
210 |
+
main()
|