# Copyright (c) Meta Platforms, Inc. and affiliates. All rights reserved.
このチュートリアルでは、以下の方法を示します。
`torch`と`torchvision`がインストールされていることを確認してください。`pytorch3d`がインストールされていない場合は、次のセルを使用してインストールしてください。
import os
import sys
import torch
need_pytorch3d=False
try:
import pytorch3d
except ModuleNotFoundError:
need_pytorch3d=True
if need_pytorch3d:
if torch.__version__.startswith("2.2.") and sys.platform.startswith("linux"):
# We try to install PyTorch3D via a released wheel.
pyt_version_str=torch.__version__.split("+")[0].replace(".", "")
version_str="".join([
f"py3{sys.version_info.minor}_cu",
torch.version.cuda.replace(".",""),
f"_pyt{pyt_version_str}"
])
!pip install fvcore iopath
!pip install --no-index --no-cache-dir pytorch3d -f https://dl.fbaipublicfiles.com/pytorch3d/packaging/wheels/{version_str}/download.html
else:
# We try to install PyTorch3D from source.
!pip install 'git+https://github.com/facebookresearch/pytorch3d.git@stable'
import numpy as np
import torch
from pytorch3d.datasets import (
R2N2,
ShapeNetCore,
collate_batched_meshes,
render_cubified_voxels,
)
from pytorch3d.renderer import (
OpenGLPerspectiveCameras,
PointLights,
RasterizationSettings,
TexturesVertex,
look_at_view_transform,
)
from pytorch3d.structures import Meshes
from torch.utils.data import DataLoader
# add path for demo utils functions
import sys
import os
sys.path.append(os.path.abspath(''))
**Google Colab**を使用している場合は、画像グリッドをプロットするためのutilsファイルを取得してください。
!wget https://raw.githubusercontent.com/facebookresearch/pytorch3d/main/docs/tutorials/utils/plot_image_grid.py
from plot_image_grid import image_grid
または、ローカルで実行する場合は、次のセルのコメントを外して実行してください。
# from utils import image_grid
ShapeNetCoreデータセットをまだダウンロードしていない場合は、こちらの手順に従ってダウンロードしてください:https://www.shapenet.org/。ShapeNetCoreはShapeNetデータセットのサブセットです。PyTorch3Dでは、バージョン1(57カテゴリ)とバージョン2(55カテゴリ)の両方をサポートしています。
次に、以下の`SHAPENET_PATH`を、ShapeNetCoreデータセットフォルダのローカルパスに変更してください。
# Setup
if torch.cuda.is_available():
device = torch.device("cuda:0")
torch.cuda.set_device(device)
else:
device = torch.device("cpu")
SHAPENET_PATH = ""
shapenet_dataset = ShapeNetCore(SHAPENET_PATH)
R2N2データセットは、こちらの手順に従ってダウンロードできます:http://3d-r2n2.stanford.edu/。`ShapeNetRendering`と`ShapeNetVox32`のリンクを確認してください。R2N2データセットには、ShapeNetCore v.1データセットのサブセットである13カテゴリが含まれています。R2N2データセットには、各オブジェクトの独自の24個のレンダリングとボクセル化されたモデルも含まれています。
次に、以下の`R2N2_PATH`と`SPLITS_PATH`を、それぞれローカルのR2N2データセットフォルダパスと分割ファイルパスに変更してください。ここでは、R2N2の`train`分割を読み込み、各モデルのボクセルを返すようにします。
R2N2_PATH = ""
SPLITS_PATH = "None"
r2n2_dataset = R2N2("train", SHAPENET_PATH, R2N2_PATH, SPLITS_PATH, return_voxels=True)
読み込んだデータセットにインデックスを付けることで、モデルを取得できます。ShapeNetCoreとR2N2の両方で、このモデルが属するカテゴリ(synset IDの形、ImageNetのAPIで説明されているwnidと同等:http://image-net.org/download-API)、モデルID、頂点、面を調べることができます。
shapenet_model = shapenet_dataset[6]
print("This model belongs to the category " + shapenet_model["synset_id"] + ".")
print("This model has model id " + shapenet_model["model_id"] + ".")
model_verts, model_faces = shapenet_model["verts"], shapenet_model["faces"]
頂点と面を使用して、バッチ処理されたメッシュを操作するためのPyTorch3Dデータ構造である`Meshes`オブジェクトを作成できます。
model_textures = TexturesVertex(verts_features=torch.ones_like(model_verts, device=device)[None])
shapenet_model_mesh = Meshes(
verts=[model_verts.to(device)],
faces=[model_faces.to(device)],
textures=model_textures
)
R2N2では、R2N2の元のレンダリングをさらに調べることができます。たとえば、R2N2データセットの11番目のオブジェクトの2番目と3番目のビューを確認したい場合は、次のようにします。
r2n2_renderings = r2n2_dataset[10,[1,2]]
image_grid(r2n2_renderings.numpy(), rows=1, cols=2, rgb=True)
深層学習モデルのトレーニングでは、通常、バッチ単位の入力が必要です。PyTorchの`torch.utils.data.DataLoader`は、これを行うのに役立ちます。PyTorch3Dは、入力メッシュを単一の`Meshes`オブジェクト(バッチを表す)にグループ化する関数`collate_batched_meshes`を提供します。`Meshes`データ構造は、深層学習モデルの一部である可能性のある他のPyTorch3D演算子(例:`graph_conv`)によって直接使用できます。
R2N2の場合、バッチ内のすべてのモデルが同じ数のビューを持っている場合、ビュー、回転行列、平行移動行列、固有行列、ボクセルもバッチ処理されたテンソルにスタックされます。
**注記**:R2N2の`val`分割内のすべてのモデルは24個のビューを持っていますが、24個のビューを`train`と`test`分割に分割する8個のモデルがあり、その場合、`collate_batched_meshes`は行列、ビュー、ボクセルをリストとして結合することしかできません。ただし、`return_all_views = False`を設定することで、モデルの1つのビューのみを読み込むことで、これを回避できます。
batch_size = 12
r2n2_single_view = R2N2("train", SHAPENET_PATH, R2N2_PATH, SPLITS_PATH, return_all_views=False, return_voxels=True)
r2n2_loader = DataLoader(r2n2_single_view, batch_size=batch_size, collate_fn=collate_batched_meshes)
バッチ内のすべてのビュー(モデルごとに1つ)を視覚化してみましょう。
it = iter(r2n2_loader)
r2n2_batch = next(it)
batch_renderings = r2n2_batch["images"] # (N, V, H, W, 3), and in this case V is 1.
image_grid(batch_renderings.squeeze().numpy(), rows=3, cols=4, rgb=True)
`ShapeNetCore`と`R2N2`のデータローダーには、PyTorch3Dの微分可能なレンダラー実装を使用して、モデルID、カテゴリ、またはインデックスを指定することでモデルのレンダリングをサポートするカスタマイズされた`render`関数が含まれています。
# Rendering settings.
R, T = look_at_view_transform(1.0, 1.0, 90)
cameras = OpenGLPerspectiveCameras(R=R, T=T, device=device)
raster_settings = RasterizationSettings(image_size=512)
lights = PointLights(location=torch.tensor([0.0, 1.0, -2.0], device=device)[None],device=device)
まず、モデルIDで3つのモデルをレンダリングしてみます。
images_by_model_ids = shapenet_dataset.render(
model_ids=[
"13394ca47c89f91525a3aaf903a41c90",
"14755c2ee8e693aba508f621166382b0",
"156c4207af6d2c8f1fdc97905708b8ea",
],
device=device,
cameras=cameras,
raster_settings=raster_settings,
lights=lights,
)
image_grid(images_by_model_ids.cpu().numpy(), rows=1, cols=3, rgb=True)
データセットの最初の3つのモデルをレンダリングしたい場合は、インデックスでモデルをレンダリングできます。
images_by_idxs = shapenet_dataset.render(
idxs=list(range(3)),
device=device,
cameras=cameras,
raster_settings=raster_settings,
lights=lights,
)
image_grid(images_by_idxs.cpu().numpy(), rows=1, cols=3, rgb=True)
あるいは、特定のモデルには興味がなく、特定のカテゴリからランダムなモデルを見たい場合は、`categories`と`sample_nums`を指定して行うことができます。たとえば、「蛇口」カテゴリから2つのモデル、「椅子」カテゴリから3つのモデルをレンダリングしたい場合は、次のようにします。
images_by_categories = shapenet_dataset.render(
categories=["faucet", "chair"],
sample_nums=[2, 3],
device=device,
cameras=cameras,
raster_settings=raster_settings,
lights=lights,
)
image_grid(images_by_categories.cpu().numpy(), rows=1, cols=5, rgb=True)
特定のカテゴリには興味がなく、データセット全体からランダムなモデルをレンダリングしたい場合は、`sample_nums`でレンダリングするモデルの数を設定し、`categories`を指定しないようにします。
random_model_images = shapenet_dataset.render(
sample_nums=[3],
device=device,
cameras=cameras,
raster_settings=raster_settings,
lights=lights,
)
image_grid(random_model_images.cpu().numpy(), rows=1, cols=5, rgb=True)
上記のShapeNetCoreモデルと同じ方法でR2N2モデルをレンダリングできます。さらに、データセット内の元のレンダリングと同じ向きでR2N2モデルをレンダリングすることもできます。これには、R2N2のカスタマイズされた`render`関数と、`BlenderCamera`と呼ばれる別のタイプのPyTorch3Dカメラを使用します。
この例では、元のレンダリングと同じ向きで7番目のモデルをレンダリングします。まず、結果と比較するためにR2N2の元のレンダリングを取得します。
original_rendering = r2n2_dataset[6,[1,2]]["images"]
image_grid(original_rendering.numpy(), rows=1, cols=2, rgb=True)
次に、PyTorch3Dのレンダリングを視覚化します。
r2n2_oriented_images = r2n2_dataset.render(
idxs=[6],
view_idxs=[1,2],
device=device,
raster_settings=raster_settings,
lights=lights,
)
image_grid(r2n2_oriented_images.cpu().numpy(), rows=1, cols=2, rgb=True)
R2N2データローダーは、モデルのボクセルも返します。R2N2の`render_vox_to_mesh`関数を使用して、それらを視覚化できます。これにより、ボクセルが`Meshes`オブジェクトに立方体化され、レンダリングされます。
この例では、元のレンダリングと同じ向きで、データセットの10番目のモデルを視覚化します。まず、結果と比較するためにR2N2の元のレンダリングを取得します。
r2n2_model = r2n2_dataset[9,[1,2]]
original_rendering = r2n2_model["images"]
image_grid(original_rendering.numpy(), rows=1, cols=2, rgb=True)
次に、ボクセルを`render_vox_to_mesh`に渡します。
vox_render = render_cubified_voxels(r2n2_model["voxels"], device=device)
image_grid(vox_render.cpu().numpy(), rows=1, cols=2, rgb=True)