精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

NeRF是什么?基于NeRF的三維重建是基于體素嗎?

人工智能 新聞
NeRF是一種生成模型,以圖像和精確姿勢為條件,生成給定圖像的3D場景的新視圖,這一過程通常被稱為“新視圖合成”。

本文經自動駕駛之心公眾號授權轉載,轉載請聯系出處。

1介紹

神經輻射場(NeRF)是深度學習和計算機視覺領域的一個相當新的范式。ECCV 2020論文《NeRF:將場景表示為視圖合成的神經輻射場》(該論文獲得了最佳論文獎)中介紹了這項技術,該技術自此大受歡迎,迄今已獲得近800次引用[1]。該方法標志著機器學習處理3D數據的傳統方式發生了巨大變化。

神經輻射場場景表示和可微分渲染過程:

通過沿著相機射線采樣5D坐標(位置和觀看方向)來合成圖像; 將這些位置輸入MLP以產生顏色和體積密度; 并使用體積渲染技術將這些值合成圖像; 該渲染函數是可微分的,因此可以通過最小化合成圖像和真實觀測圖像之間的殘差來優化場景表示。

2 What is a NeRF?

NeRF是一種生成模型,以圖像和精確姿勢為條件,生成給定圖像的3D場景的新視圖,這一過程通常被稱為“新視圖合成”。不僅如此,它還將場景的3D形狀和外觀明確定義為連續函數,可以通過marching cubes生成3D網格。盡管它們直接從圖像數據中學習,但它們既不使用convolutional層,也不使用transformer層。

多年來,機器學習應用中表示3D數據的方法很多,從3D體素到點云,再到符號距離(signed distance )函數。他們最大的共同缺點是需要預先假設一個3D模型,要么使用攝影測量或激光雷達等工具來生成3D數據,要么手工制作3D模型。然而,許多類型的物體,如高反射物體、“網格狀”物體或透明物體,都無法按比例掃描。3D重建方法通常也具有重建誤差,這可能導致影響模型精度的階梯效應或漂移。

相比之下,NeRF基于射線光場的概念。光場是描述光傳輸如何在整個3D體積中發生的函數。它描述了光線在空間中的每個x=(x,y,z)坐標和每個方向d上移動的方向,描述為θ和ξ角或單位向量。它們共同形成了描述3D場景中的光傳輸的5D特征空間。受此表示的啟發,NeRF試圖近似一個函數,該函數從該空間映射到由顏色c=(R,G,B)和濃度(density)σ組成的4D空間,可以將其視為該5D坐標空間處的光線終止的可能性(例如通過遮擋)。因此,標準NeRF是形式F:(x,d)->(c,σ)的函數。

原始的NeRF論文使用多層感知器將該函數參數化,該感知器基于一組姿勢已知的圖像上訓練得到。這是一類稱為generalized scene reconstruction的技術中的一種方法,旨在直接從圖像集合中描述3D場景。這種方法具備一些非常好的特性:

  • 直接從數據中學習
  • 場景的連續表示允許非常薄和復雜的結構,例如樹葉或網格
  • 隱含物理特性,如鏡面性和粗糙度
  • 隱式呈現場景中的照明

此后,一系列的改進論文隨之涌現,例如,少鏡頭和單鏡頭學習[2,3]、對動態場景的支持[4,5]、將光場推廣到特征場[6]、從網絡上的未校準圖像集合中學習[7]、結合激光雷達數據[8]、大規模場景表示[9]、在沒有神經網絡的情況下學習[10],諸如此類。

3 NeRF Architecture

總體而言,給定一個經過訓練的NeRF模型和一個具有已知姿勢和圖像維度的相機,我們通過以下過程構建場景:

  • 對于每個像素,從相機光心射出光線穿過場景,以在(x,d)位置收集一組樣本
  • 使用每個樣本的點和視線方向(x,d)作為輸入,以產生輸出(c,σ)值(rgbσ)
  • 使用經典的體積渲染技術構建圖像

光射場(很多文獻翻譯為"輻射場",但譯者認為"光射場"更直觀)函數只是幾個組件中的一個,一旦組合起來,就可以創建之前看到的視頻中的視覺效果。總體而言,本文包括以下幾個部分:

  • 位置編碼(Positional encoding)
  • 光射場函數近似器(MLP)
  • 可微分體渲染器(Differentiable volume renderer)
  • 分層(Stratified)取樣 層次(Hierarchical)體積采樣

為了最大限度地清晰講述,本文將每個組件的關鍵元素以盡可能簡潔的代碼展示。參考了bmild的原始實現和yenchenlin和krrish94的PyTorch實現。

3.1 Positional Encoder

就像2017年推出的transformer模型[11]一樣,NeRF也受益于位置編碼器作為其輸入。它使用高頻函數將其連續輸入映射到更高維的空間,以幫助模型學習數據中的高頻變化,從而產生更清晰的模型。這種方法避開(circumvent)了神經網絡對低頻函數偏置(bias),使NeRF能夠表示更清晰的細節。作者參考了ICML 2019上的一篇論文[12]。

如果熟悉transformerd的位置編碼,NeRF的相關實現是很標準的,它具有相同的交替正弦和余弦表達式。位置編碼器實現:

# py
class PositionalEncoder(nn.Module):
  # sine-cosine positional encoder for input points.
  def __init__( self,
                d_input: int,
                n_freqs: int,
                log_space: bool = False ):
    super().__init__()
    self.d_input = d_input
    self.n_freqs = n_freqs         # 是不是視線上的采樣頻率?
    self.log_space = log_space
    self.d_output = d_input * (1 + 2 * self.n_freqs)
    self.embed_fns = [lambda x: x] # 冒號前面的x表示函數參數,后面的表示匿名函數運算

    # Define frequencies in either linear or log scale
    if self.log_space:
      freq_bands = 2.**torch.linspace(0., self.n_freqs - 1, self.n_freqs)
    else:
      freq_bands = torch.linspace(2.**0., 2.**(self.n_freqs - 1), self.n_freqs)

    # Alternate sin and cos
    for freq in freq_bands:
      self.embed_fns.append(lambda x, freq=freq: torch.sin(x * freq))
      self.embed_fns.append(lambda x, freq=freq: torch.cos(x * freq))
  
  def forward(self, x) -> torch.Tensor:
    # Apply positional encoding to input.
    return torch.concat([fn(x) for fn in self.embed_fns], dim=-1)

思考:這個位置編碼,是對輸入點(input points)進行編碼,這個輸入點是視線上的采樣點?還是不同的視角位置點? self.n_freqs是不是視線上的采樣頻率?由此理解,應該就是視線上的采樣位置,因為如果不對視線上的采樣位置進行編碼,就無法有效表示這些位置,也就無法對它們的RGBA進行訓練。

3.2 Radiance Field Function

在原文中,光射場函數由NeRF模型表示,NeRF模型是一種典型的多層感知器,以編碼的3D點和視角方向作為輸入,并返回RGBA值作為輸出。雖然本文使用的是神經網絡,但這里可以使用任何函數逼近器(function approximator)。例如,Yu等人的后續論文Plenoxels使用球面諧波(spherical harmonics)實現了數量級的更快訓練,同時獲得有競爭力的結果[10]。

圖片圖片

NeRF模型有8層深,大多數層的特征維度為256。剩余的連接被放置在層4處。在這些層之后,產生RGB和σ值。RGB值用線性層進一步處理,然后與視線方向連接,然后通過另一個線性層,最后在輸出處與σ重新組合。NeRF模型的PyTorch模塊實現:

class NeRF(nn.Module):
  # Neural radiance fields module.
  def __init__( self,
                d_input: int = 3,                  
                n_layers: int = 8,
                d_filter: int = 256,
                skip: Tuple[int] = (4,), # (4,)只有一個元素4的元組       
                d_viewdirs: Optional[int] = None): 

    super().__init__()
    self.d_input = d_input        # 這里是3D XYZ,?
    self.skip = skip              # 是要跳過什么?為啥要跳過?被遮擋?
    self.act = nn.functional.relu
    self.d_viewdirs = d_viewdirs  # d_viewdirs 是2D方向?

    # Create model layers
    # [if_true 就執行的指令] if [if_true條件] else [if_false]
    # 是否skip的區別是,訓練輸入維度是否多3維,
    # if i in skip =  if i in (4,),似乎是判斷i是否等于4
    # self.d_input=3 :如果層id=4,網絡輸入要加3維,這是為什么?第4層有何特殊的?
    self.layers = nn.ModuleList(
      [nn.Linear(self.d_input, d_filter)] +
      [nn.Linear(d_filter + self.d_input, d_filter) if i in skip else \
       nn.Linear(d_filter  , d_filter) for i in range(n_layers - 1)]
    )

    # Bottleneck layers
    if self.d_viewdirs is not None:
      # If using viewdirs, split alpha and RGB
      self.alpha_out = nn.Linear(d_filter, 1)
      self.rgb_filters = nn.Linear(d_filter, d_filter)
      self.branch = nn.Linear(d_filter + self.d_viewdirs, d_filter // 2)
      self.output = nn.Linear(d_filter // 2, 3) # 為啥要取一半?
    else:
      # If no viewdirs, use simpler output
      self.output = nn.Linear(d_filter, 4) # d_filter=256,輸出是4維RGBA
  
  def forward(self,
              x: torch.Tensor, # ?
              viewdirs: Optional[torch.Tensor] = None) -> torch.Tensor:
   
    # Forward pass with optional view direction.
    if self.d_viewdirs is None and viewdirs is not None:
      raise ValueError('Cannot input x_direction')

    # Apply forward pass up to bottleneck
    x_input = x    # 這里的x是幾維?從下面的分離RGB和A看,應該是4D
    # 下面通過8層MLP訓練RGBA
    for i, layer in enumerate(self.layers):  # 8層,每一層進行運算
      x = self.act(layer(x)) 
      if i in self.skip:
        x = torch.cat([x, x_input], dim=-1)

    # Apply bottleneck  bottleneck 瓶頸是啥?是不是最費算力的模塊?
    if self.d_viewdirs is not None:
      # 從網絡輸出分離A,RGB還需要經過更多訓練
      alpha = self.alpha_out(x)  
      
      # Pass through bottleneck to get RGB
      x = self.rgb_filters(x) 
      x = torch.concat([x, viewdirs], dim=-1)
      x = self.act(self.branch(x)) # self.branch shape: (d_filter // 2)
      x = self.output(x)           # self.output shape: (3)

      # Concatenate alphas to output
      x = torch.concat([x, alpha], dim=-1)
    else:
      # Simple output
      x = self.output(x)
    return x

思考:這個NERF類的輸入輸出是什么?通過這個類發生了啥?從__init__函數參數看出,主要是對神經網絡的輸入、層次和維度等進行設置,輸入了5D數據,也就是視點位置和視線方向,輸出的是RGBA。問題,這個輸出的RGBA是一個點的?還是視線上一串的?如果是一串的,沒有看到位置編碼如何確定每個采樣點的RGBA?

也沒看到采樣間隔之類的說明;如果是一個點,那這個RGBA是視線上哪個點的?是不是眼睛看到的視線采樣點集合成后的點RGBA?從NERF類代碼可以看出,主要是根據視點位置和視線方向進行了多層前饋訓練,輸入5D的視點位置和視線方向,輸出4D的RGBA。

3.3 可微分體渲染器(Differentiable Volume Renderer)

RGBA輸出點位于3D空間中,因此要將它們合成圖像,需要應用論文第4節中方程1-3中描述的體積積分。本質上,沿著每個像素的視線對所有樣本進行加權求和,以獲得該像素的估計顏色值。每個RGB采樣都按其透明度alpha值進行加權:α值越高,表示采樣區域不透明的可能性越高,因此沿射線更遠的點更有可能被遮擋。累積乘積運算確保了這些進一步的點被抑制。

原始NeRF模型輸出的體繪制:

def raw2outputs(raw: torch.Tensor,
                z_vals: torch.Tensor,
                rays_d: torch.Tensor,
                raw_noise_std: float = 0.0,
                white_bkgd: bool = False) 
  -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]:

  # 將原始的NeRF輸出轉為RGB和其他映射
  # Difference between consecutive elements of `z_vals`. [n_rays, n_samples]
  dists = z_vals[..., 1:] - z_vals[..., :-1]# ?這里減法的意義是啥?
  dists = torch.cat([dists, 1e10 * torch.ones_like(dists[..., :1])], dim=-1)

  # 將每個距離乘以其對應方向光線的范數,以轉換為真實世界的距離(考慮非單位方向)
  dists = dists * torch.norm(rays_d[..., None, :], dim=-1)

  # 將噪聲添加到模型對密度的預測中,用于在訓練期間規范網絡(防止漂浮物偽影)
  noise = 0.
  if raw_noise_std > 0.:
    noise = torch.randn(raw[..., 3].shape) * raw_noise_std

  # Predict density of each sample along each ray. Higher values imply
  # higher likelihood of being absorbed at this point. [n_rays, n_samples]
  alpha = 1.0 - torch.exp(-nn.functional.relu(raw[..., 3] + noise) * dists)

  # Compute weight for RGB of each sample along each ray. [n_rays, n_samples]
  # The higher the alpha, the lower subsequent weights are driven.
  weights = alpha * cumprod_exclusive(1. - alpha + 1e-10)

  # Compute weighted RGB map.
  rgb = torch.sigmoid(raw[..., :3])  # [n_rays, n_samples, 3]
  rgb_map = torch.sum(weights[..., None] * rgb, dim=-2)  # [n_rays, 3]

  # Estimated depth map is predicted distance.
  depth_map = torch.sum(weights * z_vals, dim=-1)

  # Disparity map is inverse depth.
  disp_map = 1. / torch.max(1e-10 * torch.ones_like(depth_map),
                            depth_map / torch.sum(weights, -1))

  # Sum of weights along each ray. In [0, 1] up to numerical error.
  acc_map = torch.sum(weights, dim=-1)

  # To composite onto a white background, use the accumulated alpha map.
  if white_bkgd:
    rgb_map = rgb_map + (1. - acc_map[..., None])

  return rgb_map, depth_map, acc_map, weights


def cumprod_exclusive(tensor: torch.Tensor) -> torch.Tensor:
  # (Courtesy of https://github.com/krrish94/nerf-pytorch)
  # Compute regular cumprod first.
  cumprod = torch.cumprod(tensor, -1)
  # "Roll" the elements along dimension 'dim' by 1 element.
  cumprod = torch.roll(cumprod, 1, -1)
  # Replace the first element by "1" as this is what tf.cumprod(..., exclusive=True) does.
  cumprod[..., 0] = 1.
  return cumprod

問題:這里的主要功能是啥?輸入了什么?輸出了什么?

3.4 Stratified Sampling

相機最終拾取到的RGB值是沿著穿過該像素視線的光樣本的累積,經典的體積渲染方法是沿著該視線累積點,然后對點進行積分,在每個點估計光線在不撞擊任何粒子的情況下射行的概率。因此,每個像素都需要沿著穿過它的光線對點進行采樣。為了最好地近似積分,他們的分層采樣方法是將空間均勻地劃分為N個倉(bins),并從每個倉中均勻地抽取一個樣本。stratified sampling方法不是簡單地以相等的間隔繪制樣本,而是允許模型在連續空間中采樣,從而調節網絡在連續空間上學習。

圖片圖片

分層采樣PyTorch中實現:

def sample_stratified(rays_o: torch.Tensor,
                      rays_d: torch.Tensor,
                      near: float,
                      far: float,
                      n_samples: int,
                      perturb: Optional[bool] = True,
                      inverse_depth: bool = False)
   -> Tuple[torch.Tensor, torch.Tensor]:
  # Sample along ray from regularly-spaced bins.
  # Grab samples for space integration along ray
  t_vals = torch.linspace(0., 1., n_samples, device=rays_o.device)
  if not inverse_depth:
    # Sample linearly between `near` and `far`
    z_vals = near * (1.-t_vals) + far * (t_vals)
  else:
    # Sample linearly in inverse depth (disparity)
    z_vals = 1./(1./near * (1.-t_vals) + 1./far * (t_vals))

  # Draw uniform samples from bins along ray
  if perturb:
    mids = .5 * (z_vals[1:] + z_vals[:-1])
    upper = torch.concat([mids, z_vals[-1:]], dim=-1)
    lower = torch.concat([z_vals[:1], mids], dim=-1)
    t_rand = torch.rand([n_samples], device=z_vals.device)
    z_vals = lower + (upper - lower) * t_rand
  z_vals = z_vals.expand(list(rays_o.shape[:-1]) + [n_samples])

  # Apply scale from `rays_d` and offset from `rays_o` to samples
  # pts: (width, height, n_samples, 3)
  pts = rays_o[..., None, :] + rays_d[..., None, :] * z_vals[..., :, None]
  return pts, z_vals

3.5 層次體積采樣(Hierarchical Volume Sampling)

輻射場由兩個多層感知器表示:一個是在粗略級別上操作,對場景的廣泛結構屬性進行編碼;另一個是在精細的層面上細化細節,從而實現網格和分支等薄而復雜的結構。此外,他們接收的樣本是不同的,粗模型在整個射線中處理寬的、大多是規則間隔的樣本,而精細模型在具有強先驗的區域中珩磨(honing in)以獲得顯著信息。

這種“珩磨”過程是通過層次體積采樣流程完成的。3D空間實際上非常稀疏,存在遮擋,因此大多數點對渲染圖像的貢獻不大。因此,對具有對積分貢獻可能性高的區域進行過采樣(oversample)更有好處。他們將學習到的歸一化權重應用于第一組樣本,以在光線上創建PDF,然后再將inverse transform sampling應用于該PDF以收集第二組樣本。該集合與第一集合相結合,并被饋送到精細網絡以產生最終輸出。

分層采樣PyTorch實現:

def sample_hierarchical(rays_o: torch.Tensor,
                        rays_d: torch.Tensor,
                        z_vals: torch.Tensor,
                        weights: torch.Tensor,
                        n_samples: int,
                        perturb: bool = False) 
  -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor]:
  # Apply hierarchical sampling to the rays.
  # Draw samples from PDF using z_vals as bins and weights as probabilities.
  z_vals_mid = .5 * (z_vals[..., 1:] + z_vals[..., :-1])
  new_z_samples = sample_pdf(z_vals_mid, weights[..., 1:-1], n_samples, perturb=perturb)
  new_z_samples = new_z_samples.detach()

  # Resample points from ray based on PDF.
  z_vals_combined, _ = torch.sort(torch.cat([z_vals, new_z_samples], dim=-1), dim=-1)
  # [N_rays, N_samples + n_samples, 3]
  pts = rays_o[..., None, :] + rays_d[..., None, :] * z_vals_combined[..., :, None]  
  return pts, z_vals_combined, new_z_samples

def sample_pdf(bins: torch.Tensor,
               weights: torch.Tensor,
               n_samples: int,
               perturb: bool = False) -> torch.Tensor:
  # Apply inverse transform sampling to a weighted set of points.
  # Normalize weights to get PDF.
  # [n_rays, weights.shape[-1]]
  pdf = (weights + 1e-5) / torch.sum(weights + 1e-5, -1, keepdims=True) 

  # Convert PDF to CDF.
  cdf = torch.cumsum(pdf, dim=-1) # [n_rays, weights.shape[-1]]
  # [n_rays, weights.shape[-1] + 1]
  cdf = torch.concat([torch.zeros_like(cdf[..., :1]), cdf], dim=-1) 

  # Take sample positions to grab from CDF. Linear when perturb == 0.
  if not perturb:
    u = torch.linspace(0., 1., n_samples, device=cdf.device)
    u = u.expand(list(cdf.shape[:-1]) + [n_samples]) # [n_rays, n_samples]
  else:
    # [n_rays, n_samples]
    u = torch.rand(list(cdf.shape[:-1]) + [n_samples], device=cdf.device) 

  # Find indices along CDF where values in u would be placed.
  u = u.contiguous() # Returns contiguous tensor with same values.
  inds = torch.searchsorted(cdf, u, right=True) # [n_rays, n_samples]

  # Clamp indices that are out of bounds.
  below = torch.clamp(inds - 1, min=0)
  above = torch.clamp(inds, max=cdf.shape[-1] - 1)
  inds_g = torch.stack([below, above], dim=-1) # [n_rays, n_samples, 2]

  # Sample from cdf and the corresponding bin centers.
  matched_shape = list(inds_g.shape[:-1]) + [cdf.shape[-1]]
  cdf_g = torch.gather(cdf.unsqueeze(-2).expand(matched_shape), dim=-1,index=inds_g)
  bins_g = torch.gather(bins.unsqueeze(-2).expand(matched_shape), dim=-1, index=inds_g)

  # Convert samples to ray length.
  denom = (cdf_g[..., 1] - cdf_g[..., 0])
  denom = torch.where(denom < 1e-5, torch.ones_like(denom), denom)
  t = (u - cdf_g[..., 0]) / denom
  samples = bins_g[..., 0] + t * (bins_g[..., 1] - bins_g[..., 0])

  return samples # [n_rays, n_samples]

4 Training

論文中訓練NeRF推薦的每網絡8層、每層256維的架構在訓練過程中會消耗大量內存。緩解這種情況的方法是將前傳(forward pass)分成更小的部分,然后在這些部分上積累梯度。注意與minibatching的區別:梯度是在采樣光線的單個小批次上累積的,這些光線可能已經被收集成塊。如果沒有論文中使用的NVIDIA V100類似性能的GPU,可能必須相應地調整塊大小以避免OOM錯誤。Colab筆記本采用了更小的架構和更適中的分塊尺寸。

我個人發現,由于局部極小值,即使選擇了許多默認值,NeRF的訓練也有些棘手。一些有幫助的技術包括早期訓練迭代和早期重新啟動期間的中心裁剪(center cropping)。隨意嘗試不同的超參數和技術,以進一步提高訓練收斂性。

初始化

def init_models():
  # Initialize models, encoders, and optimizer for NeRF training.
  encoder = PositionalEncoder(d_input, n_freqs, log_space=log_space)
  encode = lambda x: encoder(x)
  # View direction encoders
  if use_viewdirs:
    encoder_viewdirs = PositionalEncoder(d_input, n_freqs_views,log_space=log_space)
    encode_viewdirs  = lambda x: encoder_viewdirs(x)
    d_viewdirs       = encoder_viewdirs.d_output
  else:
    encode_viewdirs = None
    d_viewdirs = None

  model = NeRF(encoder.d_output, 
               n_layers=n_layers, 
               d_filter=d_filter, skip=skip,d_viewdirs=d_viewdirs)
  model.to(device)
  model_params = list(model.parameters())
  if use_fine_model:
    fine_model = NeRF(encoder.d_output, 
                      n_layers=n_layers, 
                      d_filter=d_filter, skip=skip,d_viewdirs=d_viewdirs)
    fine_model.to(device)
    model_params = model_params + list(fine_model.parameters())
  else:
    fine_model = None

  optimizer      = torch.optim.Adam(model_params, lr=lr)
  warmup_stopper = EarlyStopping(patience=50)
  return model, fine_model, encode, encode_viewdirs, optimizer, warmup_stopper

訓練

def train():
  # Launch training session for NeRF.
  # Shuffle rays across all images.
  if not one_image_per_step:
    height, width = images.shape[1:3]
    all_rays = torch.stack([torch.stack(get_rays(height, width, focal, p), 0)
                           for p in poses[:n_training]], 0)
    rays_rgb = torch.cat([all_rays, images[:, None]], 1)
    rays_rgb = torch.permute(rays_rgb, [0, 2, 3, 1, 4])
    rays_rgb = rays_rgb.reshape([-1, 3, 3])
    rays_rgb = rays_rgb.type(torch.float32)
    rays_rgb = rays_rgb[torch.randperm(rays_rgb.shape[0])]
    i_batch = 0

  train_psnrs = []
  val_psnrs = []
  iternums = []
  for i in trange(n_iters):
    model.train()
    if one_image_per_step:
      # Randomly pick an image as the target.
      target_img_idx = np.random.randint(images.shape[0])
      target_img     = images[target_img_idx].to(device)
      if center_crop and i < center_crop_iters:
        target_img = crop_center(target_img)
      height, width = target_img.shape[:2]
      target_pose = poses[target_img_idx].to(device)
      rays_o, rays_d = get_rays(height, width, focal, target_pose)
      rays_o = rays_o.reshape([-1, 3])
      rays_d = rays_d.reshape([-1, 3])
    else:
      # Random over all images.
      batch = rays_rgb[i_batch:i_batch + batch_size]
      batch = torch.transpose(batch, 0, 1)
      rays_o, rays_d, target_img = batch
      height, width = target_img.shape[:2]
      i_batch += batch_size
      # Shuffle after one epoch
      if i_batch >= rays_rgb.shape[0]:
          rays_rgb = rays_rgb[torch.randperm(rays_rgb.shape[0])]
          i_batch = 0
    target_img = target_img.reshape([-1, 3])

    # Run one iteration of TinyNeRF and get the rendered RGB image.
    outputs = nerf_forward(rays_o, rays_d,
                           near, far, encode, model,
                           kwargs_sample_stratified=kwargs_sample_stratified,
                           n_samples_hierarchical=n_samples_hierarchical,
                           kwargs_sample_hierarchical=kwargs_sample_hierarchical,
                           fine_model=fine_model,
                           viewdirs_encoding_fn=encode_viewdirs,
                           chunksize=chunksize)
    # Backprop!
    rgb_predicted = outputs['rgb_map']
    loss = torch.nn.functional.mse_loss(rgb_predicted, target_img)
    loss.backward()
    optimizer.step()
    optimizer.zero_grad()
    psnr = -10. * torch.log10(loss)
    train_psnrs.append(psnr.item())

    # Evaluate testimg at given display rate.
    if i % display_rate == 0:
      model.eval()
      height, width = testimg.shape[:2]
      rays_o, rays_d = get_rays(height, width, focal, testpose)
      rays_o = rays_o.reshape([-1, 3])
      rays_d = rays_d.reshape([-1, 3])
      outputs = nerf_forward(rays_o, rays_d,
                             near, far, encode, model,
                             kwargs_sample_stratified=kwargs_sample_stratified,
                             n_samples_hierarchical=n_samples_hierarchical,
                             kwargs_sample_hierarchical=kwargs_sample_hierarchical,
                             fine_model=fine_model,
                             viewdirs_encoding_fn=encode_viewdirs,
                             chunksize=chunksize)
      rgb_predicted = outputs['rgb_map']
      loss = torch.nn.functional.mse_loss(rgb_predicted, testimg.reshape(-1, 3))
      val_psnr = -10. * torch.log10(loss)
      val_psnrs.append(val_psnr.item())
      iternums.append(i)

    # Check PSNR for issues and stop if any are found.
    if i == warmup_iters - 1:
      if val_psnr < warmup_min_fitness:
        return False, train_psnrs, val_psnrs
    elif i < warmup_iters:
      if warmup_stopper is not None and warmup_stopper(i, psnr):
        return False, train_psnrs, val_psnrs

  return True, train_psnrs, val_psnrs

訓練

# Run training session(s)
for _ in range(n_restarts):
  model, fine_model, encode, encode_viewdirs, optimizer, warmup_stopper = init_models()
  success, train_psnrs, val_psnrs = train()
  if success and val_psnrs[-1] >= warmup_min_fitness:
    print('Training successful!')
    break
print(f'Done!')

5 Conclusion

輻射場標志著處理3D數據的方式發生了巨大變化。NeRF模型和更廣泛的可微分渲染正在迅速彌合圖像創建和體積場景創建之間的差距。雖然我們的組件可能看起來非常復雜,但受vanilla NeRF啟發的無數其他方法證明,基本概念(連續函數逼近器+可微分渲染器)是構建各種解決方案的堅實基礎,這些解決方案可用于幾乎無限的情況。

原文:NeRF From Nothing: A Tutorial with PyTorch | Towards Data Science

原文鏈接:https://mp.weixin.qq.com/s/zxJAIpAmLgsIuTsPqQqOVg

責任編輯:張燕妮 來源: 自動駕駛之心
相關推薦

2021-10-09 15:36:31

技術研發三維

2024-02-20 09:46:00

模型技術

2023-12-13 10:14:00

機器視覺技術

2023-08-05 13:53:34

2024-06-19 11:30:36

2023-10-27 14:54:33

智能駕駛云計算

2022-12-09 10:00:23

2022-12-22 10:15:05

神經網絡AI

2021-04-14 15:03:16

數據性能存儲

2021-03-16 09:53:35

人工智能機器學習技術

2023-06-02 14:10:05

三維重建

2024-02-29 09:38:13

神經網絡模型

2025-10-13 15:52:20

AI模型開源

2022-02-25 23:46:16

神經網絡機器學習AI

2022-09-26 15:18:15

3D智能

2023-01-31 12:30:26

模型代碼

2025-08-20 09:17:00

點贊
收藏

51CTO技術棧公眾號

国产精品色婷婷久久58| 亚洲激情自拍| 91精品啪在线观看国产60岁| 中文字幕一区二区三区四区五区六区 | 久久综合狠狠综合久久综合88| 国产不卡精品视男人的天堂| 精品国产视频在线观看| 国产亚洲成av人片在线观黄桃| 日本精品一级二级| 日韩一级特黄毛片| 高清性色生活片在线观看| 国产一区二区h| 日本亚洲欧洲色| 91在线播放观看| 成人羞羞视频在线看网址| 精品噜噜噜噜久久久久久久久试看| 不卡的看片网站| 亚洲第一区中文99精品| 亚洲男人天堂色| 国产美女一区视频| 国产精品三级久久久久三级| 国内不卡一区二区三区| 97在线播放免费观看| 亚洲欧美久久久| 欧美情侣性视频| 国产亚洲精品精品精品| 日韩理论电影中文字幕| 日韩欧美一区二区免费| 日韩在线不卡一区| 日韩视频网站在线观看| 亚洲aaa精品| 亚洲小说欧美另类激情| 成人av一区| 99久久伊人精品| av免费观看久久| 国产亲伦免费视频播放| 青草国产精品久久久久久| 97av视频在线| 精品无码久久久久久久| 欧美黄在线观看| 久久精品国产清自在天天线| 免费成人深夜天涯网站| 精品产国自在拍| 国产亚洲成精品久久| 短视频在线观看| 亚洲丝袜美腿一区| 亚洲毛片在线看| 亚洲精品视频大全| 琪琪久久久久日韩精品| 亚洲国产欧美日韩精品| 在线观看亚洲免费视频| 国产精品极品| 亚洲国产精品高清久久久| 无码国产69精品久久久久网站| 天堂av一区| 精品国产免费一区二区三区香蕉| 亚洲三级在线视频| 日韩第一区第二区| 日韩精品一区二区三区三区免费 | 国产精品va无码一区二区三区| 亚洲黄色影院| 欧洲亚洲在线视频| 青青国产在线视频| 麻豆精品在线看| 91欧美精品成人综合在线观看| 国产精品久久久国产盗摄| 黄色小说综合网站| 不卡视频一区| 天堂在线免费av| 国产日韩精品视频一区| 亚洲日本精品| 91蜜桃在线视频| 亚洲成人激情综合网| 2022亚洲天堂| 欧美a一级片| 日韩欧美中文一区| 在线亚洲午夜片av大片| 国产91xxx| 周于希免费高清在线观看| 色综合久久久久久久| 污版视频在线观看| 亚洲图色一区二区三区| 亚洲毛片在线观看.| 99久久久无码国产精品不卡| 综合一区二区三区| 欧美在线免费观看| 91tv国产成人福利| eeuss影院一区二区三区| 日韩久久精品一区二区三区| 国产激情视频在线观看| 欧美日韩国产黄| xx欧美撒尿嘘撒尿xx| 亚洲精品视频一二三区| 国产亚洲精品一区二555| 内射一区二区三区| 亚洲欧洲午夜| 成人h猎奇视频网站| 人妻一区二区三区免费| 欧美国产精品v| 999在线观看视频| 精品乱码一区二区三区四区| 亚洲韩国日本中文字幕| 激情高潮到大叫狂喷水| 国产日产高清欧美一区二区三区| 国产欧美亚洲精品| 视频在线不卡| 一区二区三区不卡在线观看 | 亚洲久久久久久久久久| 四虎永久免费在线| 久久综合九色综合欧美狠狠| 波多野结衣精品久久| 在线观看a视频| 精品久久久精品| 日本黄色一级网站| 欧美手机视频| 奇米一区二区三区四区久久| 午夜精品久久久久久久99| 中文成人综合网| 久久精品视频16| 日韩一区二区三区在线看| 国产一区二区三区在线看| 国产精品变态另类虐交| 国产一区二区三区四区在线观看 | 成人18在线| 精品欧美激情精品一区| 国产ts在线观看| 欧美在线影院| 91网站在线看| 蜜桃视频在线观看免费视频网站www| 日韩欧美国产网站| 偷偷色噜狠狠狠狠的777米奇| 欧美.日韩.国产.一区.二区| 五月开心婷婷久久| 91黄色8090| 国产女人爽到高潮a毛片| 国产三级精品三级在线专区| 116极品美女午夜一级| 久久久久久毛片免费看 | 丁香一区二区三区| 在线观看18视频网站| 久久91视频| 少妇av一区二区三区| 91视频久久久| 国产欧美视频一区二区| 亚欧在线免费观看| 国产精品三级| 国产精品视频导航| 亚洲成a人v欧美综合天堂麻豆| 色婷婷久久综合| 91网站免费视频| 日日骚欧美日韩| 亚洲国产一区二区三区在线播| 国产超碰精品| 中文字幕亚洲精品| 伊人久久一区二区| 中文字幕在线观看不卡| 91丝袜超薄交口足| 中文一区一区三区免费在线观看| 亚洲字幕在线观看| 俄罗斯一级**毛片在线播放| 亚洲第一区第一页| 狠狠人妻久久久久久| 国产拍揄自揄精品视频麻豆| 国产免费又粗又猛又爽| 午夜精品视频一区二区三区在线看| 成人免费在线网址| 欧美黑人猛交| 国产视频久久久久| 99久久伊人精品影院| 日日夜夜精品免费| 欧美日韩综合视频网址| 变态另类ts人妖一区二区| 久久精品国产秦先生| 特色特色大片在线| 99a精品视频在线观看| 欧美在线视频一二三| 91免费在线| 日韩精品自拍偷拍| 五月婷婷中文字幕| 国产精品美女视频| 免费黄色av网址| 亚洲欧美日本视频在线观看| 视频一区亚洲| 亚洲日本视频在线| 欧美亚洲国产日本| 91女主播在线观看| 亚洲成色777777在线观看影院| 亚洲精品中文字幕乱码三区91| 日本一区二区三区视频视频| 9191在线视频| 老**午夜毛片一区二区三区 | 91久久黄色| 亚洲成人第一| 国产伦乱精品| 国产日韩在线看| 免费h在线看| 日韩在线观看免费网站| 天天干视频在线| 欧美精品自拍偷拍| 日本中文字幕久久| 亚洲一区二三区| 日韩av片在线| www激情久久| 色综合久久久无码中文字幕波多| 老司机精品福利视频| 日本中文字幕一级片| 精品一区电影| 国产伦精品一区二区三区| 国产麻豆一区| 欧美孕妇性xx| 黄页网站大全在线免费观看| 中文字幕亚洲二区| 欧美亚洲日本| 亚洲成人在线网| av小说天堂网| 欧美日韩国产综合久久| 免费视频久久久| 亚洲成人自拍偷拍| 黄色一级片中国| 国产精品视频免费| 欧美成人午夜精品免费| 成人av在线网站| 黄页网站在线看| 国产综合一区二区| 2025韩国理伦片在线观看| 一区二区三区高清视频在线观看| 自拍视频一区二区三区| 精品国产123区| 免费影院在线观看一区| 卡一精品卡二卡三网站乱码| 懂色中文一区二区三区在线视频| 国产精品高清一区二区| 国产男人精品视频| 97欧美成人| 国产精品一区二区三区成人| 四虎4545www国产精品| 日韩免费在线看| 成人开心激情| 国产成人综合亚洲| 日产精品一区| 国产精国产精品| 日韩欧美精品电影| 国产精品精品久久久| 日本人体一区二区| 国产图片一区| 国产亚洲二区| 青草久久视频| 欧美日韩电影一区二区| 综合综合综合综合综合网| 免费试看一区| 欧美精品一区二区三区中文字幕| 日本精品视频一区| 成人女性视频| 亚洲一一在线| 亚洲蜜桃视频| 成人在线播放网址| 一本一本久久| 一本久道综合色婷婷五月| 日产国产欧美视频一区精品| 亚洲国产精品三区| 狠狠色丁香婷婷综合| 日本少妇一区二区三区| 懂色av一区二区三区蜜臀| 亚洲欧美日韩偷拍| 久久这里只有精品6| 精品成人无码一区二区三区| 国产精品麻豆网站| 午夜免费激情视频| 亚洲午夜久久久久久久久久久| 国产精品xxxx喷水欧美| 亚洲国产日韩在线一区模特| 亚洲黄色激情视频| 欧美无砖专区一中文字| 99热这里只有精品3| 亚洲国产精品久久久| 黄色的视频在线免费观看| 中文字幕亚洲激情| 黄色小说在线播放| 国产成+人+综合+亚洲欧洲| 永久免费观看精品视频| 国产亚洲欧美一区二区三区| 狠狠色狠狠色综合婷婷tag| 91免费视频黄| 午夜亚洲性色视频| 久久人人爽av| 99re这里都是精品| 国产视频精品免费| 午夜电影一区二区| 亚洲天堂aaa| 亚洲国产第一页| 日本在线天堂| 91精品国产91久久久久久不卡 | 国产女人在线观看| 久久精品电影一区二区| 日产福利视频在线观看| 91精品久久久久久久久久久| 牛牛影视久久网| 大地资源第二页在线观看高清版| 国产欧美另类| 中文字幕剧情在线观看| 久久久精品影视| 久久久www成人免费毛片| 在线视频国内一区二区| 欧美在线 | 亚洲| 神马国产精品影院av| 黄色漫画在线免费看| 91亚洲精华国产精华| 奇米色欧美一区二区三区| 丰满人妻一区二区三区53号| 久久一区二区三区超碰国产精品| wwwww在线观看| 国产精品国产精品国产专区不片 | 日韩欧美黄色动漫| 午夜精品久久久久久久第一页按摩 | 在线观看视频在线观看| 亚洲国产精品成人综合| 国产www在线| 亚洲精品在线一区二区| 韩国中文字幕在线| 国产精品久久久久久久久久小说 | 国产东北露脸精品视频| 麻豆一区在线观看| 色哟哟日韩精品| 国模人体一区二区| 九九精品在线视频| 3d动漫一区二区三区在线观看| 日本一区二区三区精品视频| 在线xxxxx| 不卡的av电影在线观看| 五月天婷婷色综合| 欧美精品久久久久久久多人混战| 久久久pmvav| 4438全国成人免费| 美女av一区| 国产精品无码人妻一区二区在线| 国产成人精品午夜视频免费| 18岁成人毛片| 日韩视频免费观看高清完整版 | 国产精品萝li| 国产天堂第一区| 一本色道久久综合狠狠躁篇的优点| 亚洲优女在线| 欧美亚洲免费高清在线观看| 性娇小13――14欧美| 精品人妻一区二区三区香蕉| 精品久久香蕉国产线看观看亚洲 | 欧美高跟鞋交xxxxhd| 久久免费福利| 国产成人一区二区三区别| 国产成人av电影在线播放| 久久99久久98精品免观看软件 | 午夜不卡久久精品无码免费| 亚洲一区二区三区四区中文字幕| 国产香蕉在线观看| 国产做受高潮69| 日本妇女一区| 成人在线免费播放视频| 亚洲国产高清不卡| 亚洲无码久久久久久久| 久久久999成人| 成人av综合网| 午夜肉伦伦影院| 国产精品日韩成人| 国产普通话bbwbbwbbw| 久久久久久久久久久久久久久久久久av| 国产精品毛片视频| 国产免费一区二区三区视频| 久久精品一区蜜桃臀影院| 国产一区二区女内射| 欧美国产第一页| 亚洲精品亚洲人成在线| 一区二区三区 日韩| 亚洲色大成网站www久久九九| 蜜桃av鲁一鲁一鲁一鲁俄罗斯的| 97视频在线观看视频免费视频| 国产精品欧美在线观看| 欧美激情国内自拍| 亚洲sss视频在线视频| 成人动漫在线免费观看| 不卡一区二区三区视频| 久久久人人人| 色婷婷在线视频观看| 精品亚洲一区二区三区四区五区| jizz久久久久久| 免费看欧美黑人毛片| 欧美—级在线免费片| www.成人免费视频| 日本成人免费在线| 亚洲天天影视网| 波多野结衣一本| 日韩欧美你懂的| 天然素人一区二区视频| 永久免费看av| 国产偷v国产偷v亚洲高清| 国内精品久久久久久久久久久| 欧美一级高清免费播放| 亚洲综合自拍| 91视频免费在观看| 亚洲国产精品大全| 精品三级久久久|