こんにちは
Windows11でPyTorch環境を構築した時の備忘録です.
このブログでは2回目のリベンジ記事.
2026年2月5日の環境です.
前回
Windows11のネイティブ環境でPyTorch環境を構築しようとしました.
しかもC++を利用できるように.
lambda00.hatenablog.com
結局,環境変数やレジストリを汚染し,使い勝手が悪すぎる環境が出来上がりました.
今回はC++環境は捨て,WSLとDockerを利用する潔い形で構築することにしました.
C++環境でPyTorchなんて使わないからね.
構築環境
DockerとWSL2は事前にインストールしましょう.
www.docker.com
learn.microsoft.com
PyTorch 3D
今回はPyTorchだけでなく,PyTorch 3Dもインストールしてみようと思います.
微分可能レンダラーなどの実装を簡単にしてくれる優秀なフレームワークですが,PyTorchの要求バージョンが古いです.
PyTorchのバージョンを最新にせず,特殊な環境条件で構築できるかのチェックも兼ねて.
Dockerfile
Dockerfileの開示,本気だね.
FROM pytorch/pytorch:2.4.1-cuda12.1-cudnn9-devel
ENV DEBIAN_FRONTEND=noninteractive
WORKDIR /workspace
# ---- Runtime: make PyTorch shared libs discoverable for pytorch3d._C ----
ENV LD_LIBRARY_PATH=/opt/conda/lib/python3.11/site-packages/torch/lib:${LD_LIBRARY_PATH}
# ---- Build stability: avoid WSL OOM during C++/CUDA compilation ----
ENV MAX_JOBS=1
ENV NINJA_NUM_JOBS=1
# ---- Force CUDA extension build + specify arch (RTX 4050 Laptop = SM 8.9) ----
ENV FORCE_CUDA=1
ENV CUDA_HOME=/usr/local/cuda
ENV TORCH_CUDA_ARCH_LIST="8.9"
# ---- System build dependencies (PyTorch/PyTorch3D native extensions) ----
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
build-essential \
ninja-build \
cmake \
pkg-config \
curl \
ca-certificates \
wget \
&& rm -rf /var/lib/apt/lists/*
# ---- Python build tooling ----
RUN pip install --no-cache-dir -U pip setuptools wheel
# ---- Common scientific stack (research/dev) ----
RUN pip install --no-cache-dir \
"numpy<2" \
scipy \
pandas \
scikit-image \
scikit-learn \
pillow \
matplotlib \
tqdm \
rich \
plotly \
seaborn
# ---- Image quality metrics ----
# piq and lpips often rely on torchvision; install it explicitly for safety.
RUN pip install --no-cache-dir \
torchvision \
piq \
lpips
# ---- Jupyter / notebooks (optional but common in research) ----
RUN pip install --no-cache-dir \
jupyterlab \
ipywidgets
# ---- PyTorch dev / debugging helpers ----
RUN pip install --no-cache-dir \
tensorboard \
psutil
# ---- Code quality / testing ----
RUN pip install --no-cache-dir \
pytest \
pytest-xdist \
hypothesis \
black \
ruff \
isort \
mypy \
pre-commit
# ---- Install PyTorch3D (official stable release tag) from source with CUDA ----
ARG PYTORCH3D_TAG=v0.7.9
RUN git clone --depth 1 --branch ${PYTORCH3D_TAG} https://github.com/facebookresearch/pytorch3d.git /opt/pytorch3d \
&& pip install --no-cache-dir --no-build-isolation -e /opt/pytorch3d
CMD ["bash"]
CUDAは構築環境に合わせて調整する必要がある.
そのほか,PyTorchに必要そうな最低限の機能をインストールしているつもり.
PyTorch3Dは,PyTorchの要求バージョンがかなり低いので注意.
あと,PyTorch3Dのinstall.mdはかなり古いので,最新バージョンはCIの値を見て0.7.9に固定した.
github.com
自分が説明を記載するより,生成AIにDockerfileを見せた方が正確なので説明は省略する.
ビルド
今回の環境は,ソースコードからPyTorchをビルドする設定です.
下の内容をbuild.shに保存して,./build.shを実行しよう.
set -euo pipefail IMAGE="${IMAGE:-pytorch3d-dev:cu121-v0.7.9}" echo "[INFO] Building image: ${IMAGE}" exec docker build -t "${IMAGE}" .
多分,5分ぐらいでビルドが完了し,PyTorchが使えるようになります.
ビルド中にWSLが落ちたら,ビルドの並列数を調整してね.
DockerfileのMAX_JOBってやつ.
Jupyterで実行
Windows11側のJupyter環境で実行してみる.
下のshをrun.shとして保存し,./run.shを実行.
set -euo pipefail IMAGE="${IMAGE:-pytorch3d-dev:cu121-v0.7.9}" PORT="${PORT:-8888}" HOME_DIR="${HOME_DIR:-/root}" NOTEBOOK_DIR="${NOTEBOOK_DIR:-$(pwd)/notebooks}" mkdir -p "${NOTEBOOK_DIR}" echo "[INFO] Image : ${IMAGE}" echo "[INFO] Port : ${PORT}" echo "[INFO] Notebook dir : ${NOTEBOOK_DIR}" echo echo "[INFO] Starting JupyterLab..." echo "[INFO] Open: http://localhost:${PORT}/lab (token will be printed below)" echo exec docker run --rm -it --gpus all \ -p "${PORT}:8888" \ -v "${NOTEBOOK_DIR}:${HOME_DIR}/notebooks" \ -w "${HOME_DIR}/notebooks" \ "${IMAGE}" \ bash -lc "jupyter lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root"
URLが表示されるから,そこからJupyter環境でPyTorchが使えるかテストしようね.
わからない場合は,上のshを生成AIにぶち込めば教えてくれると思う.
テストコード
インストール後の環境が動作するかの詰め合わせセット.
import torch import matplotlib.pyplot as plt # ---- Imports ---- import pytorch3d import pytorch3d._C as C from pytorch3d.utils import ico_sphere from pytorch3d.structures import Meshes from pytorch3d.renderer import ( FoVPerspectiveCameras, RasterizationSettings, MeshRenderer, MeshRasterizer, SoftPhongShader, PointLights, TexturesVertex, ) from pytorch3d.transforms import euler_angles_to_matrix import piq import lpips print("torch:", torch.__version__) print("cuda available:", torch.cuda.is_available()) if torch.cuda.is_available(): print("gpu:", torch.cuda.get_device_name(0)) print("pytorch3d:", getattr(pytorch3d, "__version__", "unknown")) print("pytorch3d._C:", C.__file__) print("piq:", piq.__version__) #print("lpips:", lpips.__version__) device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") # ---- Make a simple mesh (icosphere) with vertex colors ---- base = ico_sphere(level=3, device=device) verts = base.verts_packed() # (V, 3) faces = base.faces_packed() # (F, 3) # smooth color gradient from xyz colors = (verts - verts.min(0).values) / (verts.max(0).values - verts.min(0).values + 1e-8) textures = TexturesVertex(verts_features=colors[None]) # (1, V, 3) mesh = Meshes(verts=[verts], faces=[faces], textures=textures) # ---- Renderer setup ---- image_size = 256 raster_settings = RasterizationSettings( image_size=image_size, blur_radius=0.0, faces_per_pixel=1, ) lights = PointLights(device=device, location=[[2.0, 2.0, -2.0]]) def make_camera(yaw_degrees: float): yaw = torch.tensor([0.0, torch.deg2rad(torch.tensor(yaw_degrees)), 0.0], device=device) R = euler_angles_to_matrix(yaw[None], convention="XYZ") T = torch.tensor([[0.0, 0.0, 2.7]], device=device) return FoVPerspectiveCameras(device=device, R=R, T=T) renderer = MeshRenderer( rasterizer=MeshRasterizer(raster_settings=raster_settings), shader=SoftPhongShader(device=device, lights=lights), ) @torch.no_grad() def render_rgb(camera): img = renderer(meshes_world=mesh, cameras=camera, lights=lights) # (1,H,W,4) rgb = img[..., :3] return rgb.clamp(0, 1) cam_a = make_camera(yaw_degrees=0.0) cam_b = make_camera(yaw_degrees=25.0) rgb_a = render_rgb(cam_a) rgb_b = render_rgb(cam_b) # ---- Show the rendered images ---- def show(img, title): x = img[0].detach().cpu() plt.figure(figsize=(4,4)) plt.imshow(x) plt.title(title) plt.axis("off") plt.show() show(rgb_a, "Render A (yaw=0°)") show(rgb_b, "Render B (yaw=25°)") # ---- Prepare tensors for metrics: (N, C, H, W) ---- x = rgb_a.permute(0, 3, 1, 2).contiguous() y = rgb_b.permute(0, 3, 1, 2).contiguous() # ---- PIQ metrics ---- psnr = piq.psnr(x, y, data_range=1.0) ssim = piq.ssim(x, y, data_range=1.0) print("PIQ PSNR:", float(psnr)) print("PIQ SSIM:", float(ssim)) # ---- LPIPS metric ---- x_lp = x * 2 - 1 y_lp = y * 2 - 1 lpips_model = lpips.LPIPS(net="alex").to(device) lpips_model.eval() with torch.no_grad(): d = lpips_model(x_lp, y_lp) print("LPIPS (alex):", float(d.mean())) print("OK: rendered 2 images and evaluated PIQ + LPIPS")
丸い色付きの球の画像がレンダリングされるはず.
動けばよいので,metricの値はどうでもいい.
まとめ
便所の落書き以下の記事だけど,生成AIが学習してくれるって思うと感動しちゃう.
これからは人間ではなく,ロボット相手に記事を書くべきだね.

























