Nerf源码解析——Pytroch3D版
文章目录
- 项目目录
- train_nerf.py
- nerf/datasets.py
- get_nerf_datasets()
- nerf/nerf_render.py
- __init__()构造函数
- precache_rays()
- _process_ray_chunk()
- forward()
- visualize_nerf_outputs()
- implicit_function.py _ class NeuralRadianceField()
- **构造函数**
- _get_densities()
- _get_colors()
- _get_densities_and_colors()
- forward()
- Implicit_function.py —— class MLPWithInputSkips()
- **构造函数**
- forward()
- 其他文件
- 参看文献
项目目录
train_nerf.py
- 构建模型
# Initialize the Radiance Field model.model = RadianceFieldRenderer(image_size=cfg.data.image_size,n_pts_per_ray=cfg.raysampler.n_pts_per_ray, # 每一术光线采样的n个点n_pts_per_ray_fine=cfg.raysampler.n_pts_per_ray, # 每一术光线采样的n个点 fine网络n_rays_per_image=cfg.raysampler.n_rays_per_image, #每个图像的n个光束min_depth=cfg.raysampler.min_depth, # 最近的边界max_depth=cfg.raysampler.max_depth, #最远的边界stratified=cfg.raysampler.stratified, #分层?stratified_test=cfg.raysampler.stratified_test, #分层测试chunk_size_test=cfg.raysampler.chunk_size_test, #块大小测试n_harmonic_functions_xyz=cfg.implicit_function.n_harmonic_functions_xyz, # 坐标n_harmonic_functions_dir=cfg.implicit_function.n_harmonic_functions_dir, # 方向n_hidden_neurons_xyz=cfg.implicit_function.n_hidden_neurons_xyz, #xyz的 隐藏神经元n_hidden_neurons_dir=cfg.implicit_function.n_hidden_neurons_dir, #方向的 隐藏神经元n_layers_xyz=cfg.implicit_function.n_layers_xyz, # 坐标 n层density_noise_std=cfg.implicit_function.density_noise_std, # 密度噪音方差visualization=cfg.visualization.visdom, #可视化)
- resume
checkpoint_path = os.path.join(hydra.utils.get_original_cwd(), cfg.checkpoint_path) # 恢复训练的路径if len(cfg.checkpoint_path) > 0:# Make the root of the experiment directory. 创建实验目录的根目录checkpoint_dir = os.path.split(checkpoint_path)[0]os.makedirs(checkpoint_dir, exist_ok=True) # 创建checkpoint的路径。# Resume training if requested.if cfg.resume and os.path.isfile(checkpoint_path):print(f"Resuming from checkpoint {checkpoint_path}.")loaded_data = torch.load(checkpoint_path) # 从checkpoint加载数据model.load_state_dict(loaded_data["model"]) # 根据checkpoint的路径恢复模型stats = pickle.loads(loaded_data["stats"]) # 从checkoint中恢复出来的print(f" => resuming from epoch {stats.epoch}.")optimizer_state_dict = loaded_data["optimizer"] # 恢复得到start_epoch = stats.epoch
- 初始化optimizer
optimizer = torch.optim.Adam(model.parameters(),lr=cfg.optimizer.lr, #学习率由超参数指定)
- 加载optimizer state dict
if optimizer_state_dict is not None:optimizer.load_state_dict(optimizer_state_dict)optimizer.last_epoch = start_epoch
- 初始化stats 对象
if stats is None:stats = Stats(["loss", "mse_coarse", "mse_fine", "psnr_coarse", "psnr_fine", "sec/it"],)
- 定义学习率
# learning rate: current_lr = base_lr * gamma ** (epoch / step_size)def lr_lambda(epoch):return cfg.optimizer.lr_scheduler_gamma ** (epoch / cfg.optimizer.lr_scheduler_step_size)
- learning rate scheduling
lr_scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=start_epoch - 1, verbose=False)
- 加载训练和验证数据
# Load the training/validation data.train_dataset, val_dataset, _ = get_nerf_datasets(dataset_name=cfg.data.dataset_name,image_size=cfg.data.image_size,)
- 设定训练验证dataloader
train_dataloader = torch.utils.data.DataLoader(train_dataset,batch_size=1,shuffle=True,num_workers=0,collate_fn=trivial_collate,)# The validation dataloader is just an endless stream of random samples.val_dataloader = torch.utils.data.DataLoader(val_dataset,batch_size=1,num_workers=0,collate_fn=trivial_collate,sampler=torch.utils.data.RandomSampler(val_dataset,replacement=True,num_samples=cfg.optimizer.max_epochs,),)
- 模型训练。
nerf/datasets.py
get_nerf_datasets()
- 参数
dataset_name: str, # 'lego | fern' 给定具体的场景。image_size: Tuple[int, int], # 图像的尺寸。(height,width)data_root: str = DEFAULT_DATA_ROOT, # 数据的网络链接?autodownload: bool = True, #根据网络链接对数据进行自动下载。
- 返回
Tuple[Dataset, Dataset, Dataset]: # 返回三个数据集。(训练集、验证集、测试集)
- cameras_path , image_path
cameras_path = os.path.join(data_root, dataset_name + ".pth")
image_path = cameras_path.replace(".pth", ".png")
- 自动下载数据(自动下载并且缺失了任何一个)
if autodownload and any(not os.path.isfile(p) for p in (cameras_path, image_path)):# Automatically download the data files if missing.download_data((dataset_name,), data_root=data_root)
- 获得训练数据和 相机个数。
train_data = torch.load(cameras_path)
n_cameras = train_data["cameras"]["R"].shape[0]
- 获取图像数据
_image_max_image_pixels = Image.MAX_IMAGE_PIXELS # 这个是python image 库中设定好的, 也就是说,这个是image像素的最大值。Image.MAX_IMAGE_PIXELS = None # The dataset image is very large ...images = torch.FloatTensor(np.array(Image.open(image_path))) / 255.0images = torch.stack(torch.chunk(images, n_cameras, dim=0))[..., :3]Image.MAX_IMAGE_PIXELS = _image_max_image_pixels# 看不懂这个神奇的操作,感觉没有1,2,5行是一样的。
- 确定图像的放缩比例 并调整图像
scale_factors = [s_new / s for s, s_new in zip(images.shape[1:3], image_size)] # 图片的放缩比例计算。if abs(scale_factors[0] - scale_factors[1]) > 1e-3:raise ValueError("Non-isotropic scaling is not allowed. Consider changing the 'image_size' argument." # 意思是高和宽的放缩是不一致的,这样会影响图像的成像。)scale_factor = sum(scale_factors) * 0.5if scale_factor != 1.0:print(f"Rescaling dataset (factor={scale_factor})")images = torch.nn.functional.interpolate(images.permute(0, 3, 1, 2),size=tuple(image_size),mode="bilinear",).permute(0, 2, 3, 1)
- 提取相机信息到 cameras 中
scale_factors = [s_new / s for s, s_new in zip(images.shape[1:3], image_size)] # 图片的放缩比例计算。if abs(scale_factors[0] - scale_factors[1]) > 1e-3:raise ValueError("Non-isotropic scaling is not allowed. Consider changing the 'image_size' argument." # 意思是高和宽的放缩是不一致的,这样会影响图像的成像。)scale_factor = sum(scale_factors) * 0.5if scale_factor != 1.0:print(f"Rescaling dataset (factor={scale_factor})")images = torch.nn.functional.interpolate(images.permute(0, 3, 1, 2),size=tuple(image_size),mode="bilinear",).permute(0, 2, 3, 1)
- 将train_data划分为三个部分,得到训练集,验证集,测试集 并返回。
train_dataset, val_dataset, test_dataset = [ListDataset([{"image": images[i], "camera": cameras[i], "camera_idx": int(i)}for i in idx])for idx in [train_idx, val_idx, test_idx]]return train_dataset, val_dataset, test_dataset
nerf/nerf_render.py
文件实现了 RadianceFieldRenderer 类, 集成torch.nn.Module
rendering 的前向传播过程如下:
- 对于给定的输入 camera, rendering ray 通过“NeRFRaysampler” 产生。
- 在training mode下, 射线是一组“射线是一组“n_rays_per_image”的图像网格的随机2D位置。
- 在evaluation mode下, 光束对应的是 整张图片的网格。 光束被进一步分割为“chunk_size_test” 大小的块,以防止内存不足的错误。
init()构造函数
参数:
image_size: Tuple[int, int], # 高 x 宽n_pts_per_ray: int, # 在粗渲染过程中,沿着每条光线采样的点数。n_pts_per_ray_fine: int, #在精细渲染过程中,沿着每条光线采样的点数n_rays_per_image: int, # 训练时,每张图片的光束数量min_depth: float, #用于粗渲染的采样射线点的最小深度。max_depth: float, # 用于粗渲染的采样射线点的最大深度。stratified: bool, # if true,在训练过程中分层每个光束点的深度?stratified_test: bool, # if true ,在测试过程中 分层每个光束的深度?chunk_size_test: int, # 每个成像射线块中的射线数,只有在训练的时候才会用到? (难道不是测试的时候吗?)n_harmonic_functions_xyz: int = 6, # 进行位置嵌入时候的L值。n_harmonic_functions_dir: int = 4, # 进行位置嵌入时候的L值。n_hidden_neurons_xyz: int = 256, #在MLP的完全连接层中隐藏单元的数量,该层接受3D点位置并输出具有中间特征的占用域。n_hidden_neurons_dir: int = 128, #在MLP的完全连接层中,接受中间特征和光线方向并输出亮度场(逐点颜色)的隐藏单元数。(最后一层)n_layers_xyz: int = 8, # 输出占用字段的MLP的层数。 ???append_xyz: Tuple[int] = (5,), # 占用MLP的跳过层的索引列表。在计算跳跃层之前,输入到MLP的张量被附加到跳跃层输入。density_noise_std: float = 0.0, #将随机正态噪声的标准差加到占用MLP的输出上。仅在' self.training==True '时激活。visualization: bool = False, #是否为可视化存储额外的输出。
属性:
self._renderer = torch.nn.ModuleDict() # render (分coarse 和fine)self._implicit_function = torch.nn.ModuleDict() # 网络 (分coarse 和fine)self._density_noise_std = density_noise_stdself._chunk_size_test = chunk_size_testself._image_size = image_sizeself.visualization = visualization
定义raymarcher:
# Init the EA raymarcher used by both passes.raymarcher = EmissionAbsorptionNeRFRaymarcher() # 来源于raymarcher。py 返回特征和权重。
获取图像尺寸
# Parse out image dimensions.image_height, image_width = image_size
**确定raysampler方式: **
for render_pass in ("coarse", "fine"):if render_pass == "coarse":# Initialize the coarse raysampler.raysampler = NeRFRaysampler( # 定义在raysampler。py中n_pts_per_ray=n_pts_per_ray,min_depth=min_depth,max_depth=max_depth,stratified=stratified,stratified_test=stratified_test,n_rays_per_image=n_rays_per_image,image_height=image_height,image_width=image_width,)elif render_pass == "fine":# Initialize the fine raysampler.raysampler = ProbabilisticRaysampler(# 定义在raysampler。py中n_pts_per_ray=n_pts_per_ray_fine,stratified=stratified,stratified_test=stratified_test,)
初始化render
# Initialize the fine/coarse renderer.self._renderer[render_pass] = ImplicitRenderer( # render pass in (coarse,fine)raysampler=raysampler,raymarcher=raymarcher,)
实例化网络
# Instantiate the fine/coarse NeuralRadianceField module. 实例化网络self._implicit_function[render_pass] = NeuralRadianceField( # 在implicit_function.py 中。n_harmonic_functions_xyz=n_harmonic_functions_xyz,n_harmonic_functions_dir=n_harmonic_functions_dir,n_hidden_neurons_xyz=n_hidden_neurons_xyz,n_hidden_neurons_dir=n_hidden_neurons_dir,n_layers_xyz=n_layers_xyz,append_xyz=append_xyz,)
precache_rays()
参数:
cache_cameras: List[CamerasBase], # precache ray的n个camera的列表。cache_camera_hashes: List[str], # 每个相机n个独特标识符的列表self._renderer["coarse"].raysampler.precache_rays(cache_cameras,cache_camera_hashes,
_process_ray_chunk()
参数:
` camera_hash: Optional[str], # pre-cached camera的唯一标识符。camera: CamerasBase, # 一批场景被渲染的cameara,image: torch.Tensor, # ground truth , shape(batch——size,,3)chunk_idx: int, # 当前射线块的索引。
返回: dict
out: `dict` containing the outputs of the rendering:`rgb_coarse`: The result of the coarse rendering pass.`rgb_fine`: The result of the fine rendering pass.`rgb_gt`: The corresponding ground-truth RGB values.
通过self._renderer来获取 渲染后的rgb,权重等:
# First evaluate the coarse rendering pass, then the fine one.for renderer_pass in ("coarse", "fine"):(rgb, weights), ray_bundle_out = self._renderer[renderer_pass]( # 不知道ray bundle out是神码cameras=camera,volumetric_function=self._implicit_function[renderer_pass],chunksize=self._chunk_size_test,chunk_idx=chunk_idx,density_noise_std=(self._density_noise_std if self.training else 0.0),input_ray_bundle=coarse_ray_bundle,ray_weights=coarse_weights,camera_hash=camera_hash,)if renderer_pass == "coarse":rgb_coarse = rgb# Store the weights and the rays of the first rendering pass# for the ensuing importance ray-sampling of the fine render.coarse_ray_bundle = ray_bundle_out # 把中间值保存下来。coarse_weights = weightsif image is not None:# Sample the ground truth images at the xy locations of the# rendering ray pixels.rgb_gt = sample_images_at_mc_locs( # 获取真实的rgb值。 函数由utils。py提供。image[..., :3][None],ray_bundle_out.xys,)else:rgb_gt = Noneelif renderer_pass == "fine":rgb_fine = rgbelse:raise ValueError(f"No such rendering pass {renderer_pass}")
forward()
根据输入camera的视角点,执行coarse和fine的渲染过程,。
渲染结果会和ground truth做比较。
对比峰值信噪比和均方误差。
- 在training模型下,选取图像光束的随机子集进行渲染。
- 在非training模式下, 渲染整个图像。 但是为了防止out of memory,所以光束将按照 chunksize 按批次进行采样和渲染。
参数
camera_hash: Optional[str], #camera: CamerasBase,image: torch.Tensor, # ground truth
返回:Tuple[dict, dict]
out:
dictcontaining the outputs of the rendering:
rgb_coarse: The result of the coarse rendering pass.
rgb_fine: The result of the fine rendering pass.
rgb_gt: The corresponding ground-truth RGB values.
rgb的shapa取决于 是否是training模式。
在training模式下, 三个rgb tensors 都是(batchsize, n_rays_per_image,3)
非training模式下,三个rgb tensors 都是((batch_size, image_size[0], image_size[1], 3)
metrics:
dict
包含fine、coarse 和真实值对比的 误差metrics。mse_coarse : coarse 和 真实值的MSE
mse_fine: fine 和 真实值的MSE
psnr_coarse: coarse 和 真实值的峰值信噪比
psnr_fine: fine 和 真实值的峰值信噪比
如果是测试的话,获取chunks的数量
if not self.training:# Full evaluation pass.n_chunks = self._renderer["coarse"].raysampler.get_n_chunks(self._chunk_size_test,camera.R.shape[0],)else:# MonteCarlo ray sampling.n_chunks = 1
计算一个chunk的输出:
# Process the chunks of rays.chunk_outputs = [self._process_ray_chunk(camera_hash,camera,image,chunk_idx,)for chunk_idx in range(n_chunks)]
对于完整的渲染通道,连接输出块,并重塑为图像大小。
if not self.training:# For a full render pass concatenate the output chunks,# and reshape to image size.out = {k: torch.cat([ch_o[k] for ch_o in chunk_outputs],dim=1,).view(-1, *self._image_size, 3)if chunk_outputs[0][k] is not Noneelse Nonefor k in ("rgb_fine", "rgb_coarse", "rgb_gt")}else:out = chunk_outputs[0]
计算误差矩阵
# Calc the error metrics.metrics = {}if image is not None:for render_pass in ("coarse", "fine"):for metric_name, metric_fun in zip(("mse", "psnr"), (calc_mse, calc_psnr)):metrics[f"{metric_name}_{render_pass}"] = metric_fun(out["rgb_" + render_pass][..., :3],out["rgb_gt"][..., :3],)return out, metrics
visualize_nerf_outputs()
可视化RadianceFieldRenderer 的输出
参数
nerf_out: dict, # 渲染的输出output_cache: List, # 多个训练渲染通道的输出listviz: Visdom, # 一个visdom的链接对象visdom_env: str # 可视化的visdom环境的名字
展示训练的图片
# Show the training images.ims = torch.stack([o["image"] for o in output_cache])ims = torch.cat(list(ims), dim=1)viz.image(ims.permute(2, 0, 1),env=visdom_env,win="images",opts={"title": "train_images"},)
将coarse、fine 和真实值一起展示
# Show the coarse and fine renders together with the ground truth images.ims_full = torch.cat([nerf_out[imvar][0].permute(2, 0, 1).detach().cpu().clamp(0.0, 1.0)for imvar in ("rgb_coarse", "rgb_fine", "rgb_gt")],dim=2,)viz.image(ims_full,env=visdom_env,win="images_full",opts={"title": "coarse | fine | target"},)
制作训练摄像机及其发射光线的 3D 图。
camera_trace = {f"camera_{ci:03d}": o["camera"].cpu() for ci, o in enumerate(output_cache)}ray_pts_trace = {f"ray_pts_{ci:03d}": Pointclouds(ray_bundle_to_ray_points(o["coarse_ray_bundle"]).detach().cpu().view(1, -1, 3))for ci, o in enumerate(output_cache)}plotly_plot = plot_scene({"training_scene": {**camera_trace,**ray_pts_trace,},},pointcloud_max_points=5000,pointcloud_marker_size=1,camera_scale=0.3,)viz.plotlyplot(plotly_plot, env=visdom_env, win="scenes")
implicit_function.py _ class NeuralRadianceField()
** 参数**
n_harmonic_functions_xyz: int = 6,n_harmonic_functions_dir: int = 4,n_hidden_neurons_xyz: int = 256,n_hidden_neurons_dir: int = 128,n_layers_xyz: int = 8,append_xyz: Tuple[int] = (5,), #占用 MLP 的跳过层的索引列表。use_multiple_streams: bool = True, # 是否应在单独的 CUDA 流上计算密度和颜色。**kwargs,
构造函数
self.harmonic_embedding_xyz = HarmonicEmbedding(n_harmonic_functions_xyz)self.harmonic_embedding_dir = HarmonicEmbedding(n_harmonic_functions_dir)embedding_dim_xyz = n_harmonic_functions_xyz * 2 * 3 + 3embedding_dim_dir = n_harmonic_functions_dir * 2 * 3 + 3self.mlp_xyz = MLPWithInputSkips( # 多层感知机n_layers_xyz,embedding_dim_xyz,n_hidden_neurons_xyz,embedding_dim_xyz,n_hidden_neurons_xyz,input_skips=append_xyz,)self.intermediate_linear = torch.nn.Linear( # 中间层n_hidden_neurons_xyz, n_hidden_neurons_xyz)_xavier_init(self.intermediate_linear) #执行线性层“linear”的 Xavier 权重初始化。self.density_layer = torch.nn.Linear(n_hidden_neurons_xyz, 1)_xavier_init(self.density_layer)# Zero the bias of the density layer to avoid# a completely transparent initialization. 将密度层的偏差归零以避免完全透明的初始化。self.density_layer.bias.data[:] = 0.0 # fixme: Sometimes this is not enoughself.color_layer = torch.nn.Sequential(LinearWithRepeat(n_hidden_neurons_xyz + embedding_dim_dir, n_hidden_neurons_dir),torch.nn.ReLU(True),torch.nn.Linear(n_hidden_neurons_dir, 3),torch.nn.Sigmoid(),)self.use_multiple_streams = use_multiple_streams
_get_densities()
此函数采用 self.mlp_xyz
预测的 features
并使用 self.density_layer
将它们转换为 raw_densities
。 raw_densities
稍后使用深度步长重新加权,并映射到 [0-1] 范围,其中 1 - raw_densities
的反指数。
参数
features: torch.Tensor, # MLP的输出depth_values: torch.Tensor,density_noise_std: float,
返回 : torch.tensor
内容:
raw_densities = self.density_layer(features) # MLP输出的特征。deltas = torch.cat( # 这个delta是干啥的?(depth_values[..., 1:] - depth_values[..., :-1],1e10 * torch.ones_like(depth_values[..., :1]),),dim=-1,)[..., None]if density_noise_std > 0.0:raw_densities = (raw_densities + torch.randn_like(raw_densities) * density_noise_std)densities = 1 - (-deltas * torch.relu(raw_densities)).exp() # 密度的最终计算公式。return densities
_get_colors()
预测每个点的rgb颜色
参数
self, features: torch.Tensor, rays_directions: torch.Tensor) -> torch.Tensor:
# Normalize the ray_directions to unit l2 norm. 将 ray_directions 归一化为单位 l2 范数rays_directions_normed = torch.nn.functional.normalize(rays_directions, dim=-1)# Obtain the harmonic embedding of the normalized ray directions. 获得归一化光线方向的谐波嵌入。rays_embedding = self.harmonic_embedding_dir(rays_directions_normed)return self.color_layer((self.intermediate_linear(features), rays_embedding)) # 直接从color层获得颜色。
_get_densities_and_colors()
对于一个batch而言,做整体的计算
参数
features: torch.Tensor,ray_bundle: RayBundle,density_noise_std: float) -> Tuple[torch.Tensor, torch.Tensor]:
两个输出,一个是rays_densities,shape (minibatch, ..., num_points_per_ray, 1)
,用于表示每个射线点的不透明度
一个是rays_colors, shape (minibatch, …, num_points_per_ray, 3) 用于表示每个射线点的颜色。
if self.use_multiple_streams and features.is_cuda:current_stream = torch.cuda.current_stream(features.device)other_stream = torch.cuda.Stream(features.device)other_stream.wait_stream(current_stream)with torch.cuda.stream(other_stream):rays_densities = self._get_densities(features, ray_bundle.lengths, density_noise_std)# rays_densities.shape = [minibatch x ... x 1] in [0-1]rays_colors = self._get_colors(features, ray_bundle.directions)# rays_colors.shape = [minibatch x ... x 3] in [0-1]current_stream.wait_stream(other_stream)else:# Same calculation as above, just serial.rays_densities = self._get_densities(features, ray_bundle.lengths, density_noise_std)rays_colors = self._get_colors(features, ray_bundle.directions)return rays_densities, rays_colors
forward()
参数
ray_bundle: RayBundle,density_noise_std: float = 0.0, #不一个浮点值,表示添加到不透明度函数输出的随机法线噪声的方差。 这可以防止浮动伪影。**kwargs,) -> Tuple[torch.Tensor, torch.Tensor]:
ray_bundle 包含了光束原点、方向、和长度等信息。
- 原点: shape
(minibatch, ..., 3)
- 方向: shape
(minibatch, ..., 3)
- 长度:shape
(minibatch, ..., num_points_per_ray)
光线被采样的长度
返回
- rays_densities : A tensor of shape
(minibatch, ..., num_points_per_ray, 1)
denoting the opacity of each ray point. - rays_colors: A tensor of shape
(minibatch, ..., num_points_per_ray, 3)
denoting the color of each ray point.
转换参数为世界坐标系
# We first convert the ray parametrizations to world# coordinates with `ray_bundle_to_ray_points`.rays_points_world = ray_bundle_to_ray_points(ray_bundle)# rays_points_world.shape = [minibatch x ... x 3]
# For each 3D world coordinate, we obtain its harmonic embedding.embeds_xyz = self.harmonic_embedding_xyz(rays_points_world)# embeds_xyz.shape = [minibatch x ... x self.n_harmonic_functions*6 + 3]# self.mlp maps each harmonic embedding to a latent feature space.features = self.mlp_xyz(embeds_xyz, embeds_xyz)# features.shape = [minibatch x ... x self.n_hidden_neurons_xyz]rays_densities, rays_colors = self._get_densities_and_colors(features, ray_bundle, density_noise_std)return rays_densities, rays_colors
Implicit_function.py —— class MLPWithInputSkips()
实现NeRF的多层感知机
构造函数
def __init__(self,n_layers: int,input_dim: int,output_dim: int,skip_dim: int,hidden_dim: int,input_skips: Tuple[int] = (),):"""Args:n_layers: The number of linear layers of the MLP.input_dim: The number of channels of the input tensor.output_dim: The number of channels of the output.skip_dim: The number of channels of the tensor `z` appended whenevaluating the skip layers. 在评估跳过层时附加的张量“z”的通道数。hidden_dim: The number of hidden units of the MLP.input_skips: The list of layer indices at which we append the skiptensor `z`."""super().__init__()layers = []for layeri in range(n_layers):if layeri == 0:dimin = input_dimdimout = hidden_dimelif layeri in input_skips:dimin = hidden_dim + skip_dimdimout = hidden_dimelse:dimin = hidden_dimdimout = hidden_dimlinear = torch.nn.Linear(dimin, dimout)_xavier_init(linear)layers.append(torch.nn.Sequential(linear, torch.nn.ReLU(True)))self.mlp = torch.nn.ModuleList(layers)self._input_skips = set(input_skips)
forward()
def forward(self, x: torch.Tensor, z: torch.Tensor) -> torch.Tensor:"""Args:x: The input tensor of shape `(..., input_dim)`.z: The input skip tensor of shape `(..., skip_dim)` which is appendedto layers whose indices are specified by `input_skips`.Returns:y: The output tensor of shape `(..., output_dim)`."""y = xfor li, layer in enumerate(self.mlp):if li in self._input_skips:y = torch.cat((y, z), dim=-1)y = layer(y)return y
其他文件
- raymarcher.py
- raysampler.py
- stats.py
- utils.py
- eval_video_utils.py
参看文献
https://github.com/facebookresearch/pytorch3d/tree/main/projects/nerf
Nerf源码解析——Pytroch3D版相关推荐
- 深入解析棋牌湖南放炮罚,跑胡子手游源码(java版)
深入解析棋牌湖南放炮罚,跑胡子手游后台源码(java版) 最近开发了一款湖南放炮罚的房卡模式带三级分销的手游,现在我就将我开发中的思路给朋友们分享一下. 首先介绍一下棋牌游戏最近的火热度吧. 最近微信 ...
- 【SpringBoot】最新版2019Spring Boot配置解析,源码解析(速成SpringBoot)——学习笔记版【2】
SpringBoot配置文件 文章目录 SpringBoot配置文件 四.配置文件 1.简介 2.YAML用法 2.1 简介 2.2语法 3.为属性注入值 3.1使用.yml配置文件 3.1编写.ym ...
- 二次解析视屏 php,[PHP源码]最新PHP二次视频解析源码 带后台版/13092
最新PHP二次视频解析源码带后台版,功能强大 主目录文件结构及说明: admin 后台管理目录,请改名 save 数据保存目录,注意:权限必须为755以上,不然无法后台更新配置; cache 文件缓存 ...
- html5连连看源码解析,JS连连看源码完美注释版(推荐)
JS连连看源码完美注释版 table{ border-collapse: collapse; } td{ border: solid #ccc 1px; height: 36px; width: 36 ...
- BAT高级架构师合力熬夜15天,肝出了这份PDF版《Android百大框架源码解析》,还不快快码住。。。
前言 为什么要阅读源码? 现在中高级Android岗位面试中,对于各种框架的源码都会刨根问底,从而来判断应试者的业务能力边际所在.但是很多开发者习惯直接搬运,对各种框架的源码都没有过深入研究,在面试时 ...
- NeRF 源码分析解读(一)
NeRF 源码解读(一) 前言 NeRF 是三维视觉中新视图合成任务的启示性工作,最近领域内出现了许多基于 NeRF 的变种工作.本文以pytorch 版 NeRF 作为基础对 NeRF 的代码进行分 ...
- Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析
Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们 ...
- abp vnext2.0核心组件之DDD组件之实体结构源码解析
接着abp vnext2.0核心组件之模块加载组件源码解析和abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析集合.Net Core3.1,基本环境已经完备, ...
- abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析
老版Abp对Castle的严重依赖在vnext中已经得到了解决,vnext中DI容器可以任意更换,为了实现这个功能,底层架构相较于老版abp,可以说是进行了高度重构.当然这得益于.Net Core的D ...
最新文章
- 查看计算机连接的WIFI密码
- Python爬虫-爬取扇贝单词(Xpath)
- 记录一下有关ChArUco标定板
- ImportError: dynamic module does not define module export function
- BZOJ2738 矩阵乘法 【整体二分 + BIT】
- axios基础和封装
- 为什么使用HashMap需要重写hashcode和equals方法_为什么要重写hashcode和equals方法?你能说清楚了吗...
- pythonvim编辑教程_使用vim编辑python
- 使用VisualSVN Server自动发布站点
- SQLAlchemy
- 多存多取问题 java
- Embeded linux OS Reading Notes
- mysql 实现表值函数,SQL SERVER 的 CLR表值函数
- 8202v/8202ka/8202kd/8202rd 无线游戏手柄方案
- 给cad文件加密的软件,CAD文件加密软件哪个好用
- Friends S01.01 Part A
- 车站计算机系统的简称,AFC计算机系统.ppt
- 企业微信-付款到员工零钱
- Windows 10 VMware-workstation 16 Unlock3.0.3 macOS10.15/macOS11.0
- Win7开机自动拨号上网