NeRF 源码分析解读(二)

这篇具有很好参考价值的文章主要介绍了NeRF 源码分析解读(二)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

NeRF 源码分析解读(二)

光线的生成

由上一章节我们得到了加载到的数据,包括读取图像的数组、图像的高宽焦距、相机的 pose 、以及用于分割测试集、训练集的分割数组。得到这些数据后,我们开始进行生成光线的步骤。
生成光线的步骤是 NeRF 代码中最为关键的一步,实际上我们模拟的光线就是三维空间中在指定方向上的一系列离散的点的坐标。有了这些点坐标,我们将其投入到 NeRF 的 MLP 神经网络中,计算这个点的密度值以及颜色值。
下面我们对具体代码进行分析。

def train():
	...
	# 加载数据,具体加载代码分析详见 上一篇博客
	...
	
    if K is None:
       K = np.array([
           [focal, 0, 0.5*W],
           [0, focal, 0.5*H],
           [0, 0, 1]
       ])

注意这里的 K 。这里的 K 指的是相机的内参,具体的作用会在后面的分析中进行解释说明

1、初始化 NeRF 网络模型

def train():
	...
	# 初始化 NeRF 网络模型
	render_kwargs_train, render_kwargs_test, start, grad_vars, optimizer = create_nerf(args)

	bds_dict = {
        'near' : near,
        'far' : far,
    }
    # 更新字典,加入三维空间的边界框 bounding box
    render_kwargs_train.update(bds_dict)
    render_kwargs_test.update(bds_dict)
	...

我们首先对 create_nerf() 返回的值进行解释说明:

render_kwargs_train:一个字典,包含了用于训练的各个参数值。具体字典内容详见下面的代码分析

render_kwargs_test:

start:

grad_vars: 整个网络的梯度变量

optimizer: 整个网络的优化器

接下来我们对 create_nerf() 代码进行具体的逐行分析

def create_nerf(args):
    embed_fn, input_ch = get_embedder(args.multires, args.i_embed)  
	...

这行语句实际上获得一个编码器 embed_fn 以及一个编码后的维度,给定 embed_fn 一个输入,就可以获得输入的编码后的数据。具体的编码公式如下,详见论文 5.1 节,代码分析详见:位置编码代码注释分析。

γ ( p ) = ( sin ⁡ ( 2 0 π p ) , cos ⁡ ( 2 0 π p ) , ⋯   , sin ⁡ ( 2 L − 1 π p ) , cos ⁡ ( 2 L − 1 π p ) ) \gamma(p)=\left(\sin \left(2^{0} \pi p\right), \cos \left(2^{0} \pi p\right), \cdots, \sin \left(2^{L-1} \pi p\right), \cos \left(2^{L-1} \pi p\right)\right) γ(p)=(sin(20πp),cos(20πp),,sin(2L1πp),cos(2L1πp))

以下是网络结构的初始化代码,网络的层级模型详见论文 补充材料 pic 7。 关于 NeRF 的 model 部分我们会单独开一个章节进行解读。(待更新),总之我们只需要知道我们在这里创建了 NeRF 的粗网络,给这个粗网络输入一个 5D 的输入,就可以得到一个 (RGB,A)的输出,即:
F Θ : ( x , d ) → ( c , σ ) F_{\Theta}:(\mathbf{x}, \mathbf{d}) \rightarrow(\mathbf{c}, \sigma) FΘ:(x,d)(c,σ)
F θ F_{\theta} Fθ 就是我们创建的网络 model

def create_nerf(args):
	...
	# 初始化MLP模型参数,网络的层级模型详见论文 补充材料 pic 7
    model = NeRF(D=args.netdepth, W=args.netwidth,
                 input_ch=input_ch, output_ch=output_ch, skips=skips,
                 input_ch_views=input_ch_views, use_viewdirs=args.use_viewdirs).to(device)
    # 模型中的梯度变量
    grad_vars = list(model.parameters())
    ...
    # 定义一个查询点的颜色和密度的匿名函数,实际上给定点坐标,方向,以及查询网络,我们就可以得到该点在该网络下的输出([rgb,alpha])
    network_query_fn = lambda inputs, viewdirs, network_fn : run_network(inputs, viewdirs, network_fn,
                                                                embed_fn=embed_fn,
                                                                embeddirs_fn=embeddirs_fn,
                                                                netchunk=args.netchunk  # 网络批处理查询点的数量)

可以看到这里的 network_query_fn 是一个匿名函数,真正起作用的函数是 run_network() 。下面我们对 run_network() 进行分析,观察我们是如何生成给定点的颜色和密度的。
run_network() 代码分析如下:

def run_network(inputs, viewdirs, fn, embed_fn, embeddirs_fn, netchunk=1024*64):
    """
    对 input 进行处理,应用 神经网络 fn
    """
    inputs_flat = torch.reshape(inputs, [-1, inputs.shape[-1]])
	embedded = embed_fn(inputs_flat)  # 对输入进行位置编码,得到编码后的结果,是一个 array 数组

	if viewdirs is not None:
		# 视图不为 None,即输入了视图方向,那么我们就应该考虑对视图方向作出处理,用以生成颜色
		input_dirs = viewdirs[:, None].expand(inputs.shape)
		input_dirs_flat = torch.reshape(input_dirs, [-1, input_dirs.shape[-1]])
		embedded_dirs = embeddirs_fn(input_dirs_flat)  # 对输入方向进行编码
		embedded = torch.cat([embedded, embedded_dirs], -1)  # 将编码后的位置和方向聚合到一起

	outputs_flat = batchify(fn, netchunk)(embedded)  # 将编码过的点以批处理的形式输入到 网络模型 中得到 输出(RGB,A)
	outputs = torch.reshape(outputs_flat, list(inputs.shape[:-1]) + [outputs_flat.shape[-1]])
	return outputs

这里的 batchify() 函数会把 embedded 数组分批输入到网络 fn 中,前向传播得到对应的 (RGB,A)。
接下来我们继续对 create_nerf() 进行分析

def create_nerf(args):
	...
	# 创建网络的优化器
    optimizer = torch.optim.Adam(params=grad_vars, lr=args.lrate, betas=(0.9, 0.999))
	
	...
	# 关于加载已有模型的部分我们不在逐行分析,对整体算法的分析没有任何影响

	...
	
	# 注意看,现在整体的初始化已经完成,我们需要对返回值进行一些处理
	render_kwargs_train = {
        'network_query_fn' : network_query_fn,
        'perturb' : args.perturb,
        'N_importance' : args.N_importance,
        'network_fine' : model_fine,
        'N_samples' : args.N_samples,
        'network_fn' : model,
        'use_viewdirs' : args.use_viewdirs,
        'white_bkgd' : args.white_bkgd,
        'raw_noise_std' : args.raw_noise_std,
    }

    # NDC 空间,只对前向场景有效,具体解释可以看论文,这里不再展开
    if args.dataset_type != 'llff' or args.no_ndc:
        print('Not ndc!')
        render_kwargs_train['ndc'] = False
        render_kwargs_train['lindisp'] = args.lindisp

    render_kwargs_test = {k : render_kwargs_train[k] for k in render_kwargs_train}
    render_kwargs_test['perturb'] = False
    render_kwargs_test['raw_noise_std'] = 0.

    return render_kwargs_train, render_kwargs_test, start, grad_vars, optimizer

下面我们对字典 render_kwargs_train 中的键值进行分析:

'network_query_fn' : network_query_fn,  # 上文已经解释过了,这是一个匿名函数,
给这个函数输入位置坐标,方向坐标,以及神经网络,就可以利用神经网络返回该点对应的 颜色和密度

'perturb' : args.perturb,  # 扰动,对整体算法理解没有影响

'N_importance' : args.N_importance,  # 每条光线上细采样点的数量

'network_fine' : model_fine,  # 论文中的 精细网络

'N_samples' : args.N_samples,  # 每条光线上粗采样点的数量

'network_fn' : model,  # 论文中的 粗网络

'use_viewdirs' : args.use_viewdirs,  # 是否使用视点方向,影响到神经网络是否输出颜色

'white_bkgd' : args.white_bkgd,  # 如果为 True 将输入的 png 图像的透明部分转换成白色

'raw_noise_std' : args.raw_noise_std,  # 归一化密度

以上我们完成了 NeRF 模型的初始化部分。我们在下一章节继续对 train() 函数进行分析。NeRF源码分析解读(三)文章来源地址https://www.toymoban.com/news/detail-403224.html

到了这里,关于NeRF 源码分析解读(二)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flink 深入理解任务执行计划,即Graph生成过程(源码解读)

    我们先看一下,Flink 是如何描述作业的执行计划的。以这个 DataStream 作业为例,Flink 会基于它先生成一个 StreamGraph。这是一个有向无环图,图中的节点对应着计算逻辑,图中的边则对应着数据的分发方式。 Flink 会根据节点的并行度以及他们之间的连边方式,把一些计算节点进

    2024年02月22日
    浏览(43)
  • Spring Boot源码解读与原理分析

      最近机缘巧合之下,读到了 LinkedBear 编写的《Spring Boot源码解读与原理分析》这本书,本人花了一周的时间认真研读了一下这本书,真的是受益匪浅,特此推荐给大家,好书不容错过啊。 LinkedBear 是一名资深的Java开发工程师,常年致力于底层技术的研究,同时也通过技术

    2024年02月08日
    浏览(46)
  • 《Spring Boot源码解读与原理分析》书籍推荐

    Spring Boot 1.0.0 早在2014年就已经发布,只不过到了提倡“降本增效”的今天,Spring Boot才引起了越来越多企业的关注。Spring Boot是目前Java EE开发中颇受欢迎的框架之一。依托于底层Spring Framework的基础支撑,以及完善强大的特性设计,Spring Boot已成为业界流行的应用和微服务开发

    2024年02月14日
    浏览(36)
  • Diffusion Models可控视频生成Control-A-Video:论文和源码解读

    Diffusion Models专栏文章汇总:入门与实战 前言: Diffusion视频生成的时间连贯性问题是可控视频生成问题最大的挑战。Control-A-Video提出的时空一致性建模法、残差噪声初始化法和首帧定型法能有效解决这一问题,非常值得我们借鉴。博主详细解读论文和代码,并给出一些自己的

    2024年02月06日
    浏览(42)
  • 【论文解读】基于神经辐射场NeRF的像素级交互式编辑(Seal-3D)

    来源:投稿 作者:橡皮 编辑:学姐 论文链接:https://arxiv.org/pdf/2307.15131 项目主页:https://windingwind.github.io/seal-3d/ 随着隐式神经表征或神经辐射场(NeRF)的普及,人们迫切需要与隐式三维模型交互的编辑方法,以完成重建场景的后期处理和三维内容创建等任务。虽然以前的作

    2024年02月03日
    浏览(44)
  • SpringBoot源码解读与原理分析(五)SpringBoot的装配机制

    前面三小节分别介绍了Spring Framewoek的模块装配、条件装配和SPI机制。下面正式进入Spring Boot的装配机制。 实际上, Spring Boot的自动装配是模块装配+条件装配+SPI机制的组合使用 ,而这一切都凝聚在Spring Boot主启动类的@SpringBootApplication注解上。 @SpringBootApplication注解是由三个注

    2024年02月19日
    浏览(48)
  • SpringBoot源码解读与原理分析(二十七)嵌入式Tomcat

    当Web应用需要部署运行时,传统的做法是将项目打包成war包,然后部署到外置的Web容器中(如最常用的Tomcat容器)。 SpringBoot的一大重要特性是支持嵌入式Web容器,基于SpringBoot的Web应用仅凭一个单独的jar包即可独立运行。 8.1.1 嵌入式Tomcat与普通Tomcat 嵌入式Tomcat是一种可以嵌

    2024年02月22日
    浏览(48)
  • SpringBoot源码解读与原理分析(六)WebMvc场景的自动装配

    了解了SpringBoot的自动装配机制之后,研究一个常见且实用的场景:当项目整合SpringWebMvc后SpringBoot的自动装配都做了什么? 2.6.1 WebMvcAutoConfiguration 引入spring-boot-starter-web依赖后,SpringBoot会进行WebMvc的自动装配,处理的核心是一个叫WebMvcAutoConfiguration的自动配置类。 由以上源码

    2024年02月21日
    浏览(50)
  • 伪随机生成器(rand函数),随机数种子(srand函数)详细解读与分析:

    a.生成随机数; b.生成0~100以内的随机数 c.随机数的连续输出及其连续输出情况讲解与分析 首先我们来看一下rand函数(伪随机数生成器):   rand函数,即伪随机数生成器,该函数返回类型为整型,没有参数,即产生一个在(0-rand_max(十六进制的ox7ffff转化为整数即32767)的一个

    2024年02月11日
    浏览(50)
  • Java进阶(HashMap)——面试时HashMap常见问题解读 & 结合源码分析

    List、Set、HashMap作为Java中常用的集合,需要深入认识其原理和特性。 本篇博客介绍常见的关于Java中HashMap集合的面试问题,结合源码分析题目背后的知识点。 关于List的博客文章如下: Java进阶(List)——面试时List常见问题解读 结合源码分析 关于的Set的博客文章如下: Jav

    2024年02月08日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包