因为自己看代码到这里的时候突然感觉这看不懂搞不懂他这里面的逻辑,上网搜好像没有对这个讲解特别详细的文章,现在自己理清楚思路了,在此记录一下,顺便方便后续小伙伴的学习
首先要讲解一下这段代码的作用就是根据“粗”网络的weight来去选择精细化网络的采样点,如果不知道weight是什么的,可以先去弄明白,这里不过多讲解,主要讲解sample_pdf,接下来知道它是用来干什么的,那么我们去看一下它的代码
def sample_pdf(bins, weights, N_samples, det=False, pytest=False):
# Get pdf
weights = weights + 1e-5 # prevent nans
pdf = weights / torch.sum(weights, -1, keepdim=True)
cdf = torch.cumsum(pdf, -1)
cdf = torch.cat([torch.zeros_like(cdf[...,:1]), cdf], -1) # (batch, len(bins))
# Take uniform samples
if det:
u = torch.linspace(0., 1., steps=N_samples)
u = u.expand(list(cdf.shape[:-1]) + [N_samples])
else:
u = torch.rand(list(cdf.shape[:-1]) + [N_samples])
u = u.contiguous()
inds = torch.searchsorted(cdf, u, right=True)
below = torch.max(torch.zeros_like(inds-1), inds-1)
above = torch.min((cdf.shape[-1]-1) * torch.ones_like(inds), inds)
inds_g = torch.stack([below, above], -1) # (batch, N_samples, 2)
# cdf_g = tf.gather(cdf, inds_g, axis=-1, batch_dims=len(inds_g.shape)-2)
# bins_g = tf.gather(bins, inds_g, axis=-1, batch_dims=len(inds_g.shape)-2)
matched_shape = [inds_g.shape[0], inds_g.shape[1], cdf.shape[-1]]
cdf_g = torch.gather(cdf.unsqueeze(1).expand(matched_shape), 2, inds_g)
bins_g = torch.gather(bins.unsqueeze(1).expand(matched_shape), 2, inds_g)
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
这里直接省略了那个测试那个,那个其实也不难理解嘛。就是方便复现的就指定了一下随机数种子。接下来我们分析一下这里传入的参数分别代表什么,bins你现在就把它当作是粗网络中选择出来的那些样本点(N_sample),其实不是哈,他做了一个取中点的的操作,这个你可以不用管,先暂且把它就认为粗网络中选出来的样本点,接下来分析weight就是每个样本点占的权重(不懂得可以先去搞清楚再来看这个文章,其他作者文章中有去解释的,我就不多废话了),N_sample是要在精网路中选择的样本点数,det这个参数就是选择是否是随机性采样,没什么可讲的,pytest我刚才说了,这里不讲,不影响去理解。接下来逐行去讲解一下代码首先
weights = weights + 1e-5 # prevent nans
pdf = weights / torch.sum(weights, -1, keepdim=True)
cdf = torch.cumsum(pdf, -1)
cdf = torch.cat([torch.zeros_like(cdf[...,:1]), cdf], -1) # (batch, len(bins))
这第第一句代码就是为weight加一个很小的值以免下一句的除法分母为0,接下来就是计算权重的pdf(概率密度函数)和cdf(累积分布函数)torch.cumsum这个函数就是把pdf转换成cdf没有什么可说的,下一句就是给cdf最前面加一个0,去保证累计积分是(0,1)范围内。对了前面生成的pdf和cdf都是和粗网络中样本点的权重(weight)有关,每一条光线的样本点对应着一条光线的pdf函数的一个点值,生成的cdf也是一样的,这个很重要,这个直接关系到了接下来的代码的理解。
if det:
u = torch.linspace(0., 1., steps=N_samples)
u = u.expand(list(cdf.shape[:-1]) + [N_samples])
else:
u = torch.rand(list(cdf.shape[:-1]) + [N_samples])
这一段就是是否使用均匀随机,也没什么可以说的。生成的这个u是在(0,1)范围内的。
u = u.contiguous()
inds = torch.searchsorted(cdf, u, right=True)
below = torch.max(torch.zeros_like(inds-1), inds-1)
above = torch.min((cdf.shape[-1]-1) * torch.ones_like(inds), inds)
inds_g = torch.stack([below, above], -1) # (batch, N_samples, 2)
这一段的代码,首先第一句就是把随机生成的u去放到一个连续的空间中,第二句就是通过torch.searchsorted()这个函数去找到u在cdf中对应的位置比如说cdf是[0,0.1,0.5,0.6,0.75,1]那么u中其中的一个数是0.2,那么它的inds是等于2,因为它在0.1到0.5之间。below和above是计算出0.2这个数在cdf中被哪两个位置的数夹着,比如说0.2被0.1和0.5夹着,0.1对应着是1,0.5对应着是2所以这个below和above分别对应为1和2。ind_g的含义是就是把below和above拼接起来,表示(可以和上面一样用0.2这个点去理解)这个点被哪两个夹着。
matched_shape = [inds_g.shape[0], inds_g.shape[1], cdf.shape[-1]]
cdf_g = torch.gather(cdf.unsqueeze(1).expand(matched_shape), 2, inds_g)
bins_g = torch.gather(bins.unsqueeze(1).expand(matched_shape), 2, inds_g)
这一段代码是首先先去定义了一个匹配使用的格式matched_shape,这里先不用管为什么这个定义这个格式,看接下来的代码就会理解这个为什么这么定义,[光线数量,每条光线上采样点被夹的范围,被夹的那些点]这就是matched_shape的含义,接下就是cdf_g就是表示inds_g当中below和above表示的对应的值还是一那个0.2举例,它的inds_g的值不是1和2么,意味着它被第一个点和第二个点夹着,第一个点和第二个点对应的cdf值就是cdf_g。接下来bins_g也是一样的同理,不去解释了。
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])
如果没有明白前面的那么这后面的这个估计理解不了,第一行的代码是什么意思呢,我前面不是讲过了么cdf中不都是每个样本点对应的cdf值么,而cdf_g中不是每个点的below和above么cdf_g[...,1]指的是每个点的above,而cdf_g[...,0]指的是每个点的below。用高的cdf值减去低的计算出它们差值,接下来有了这个差值denom,这个差值代表的是这个点在这个范围的概率(这里有点难理解,也可以说是这个点在这个区域,这个区域的权重是多少,这个区域的权重就是就是指的是前面说的粗模型的cdf的两个点之间相减,我尽力了,你们去理解一下,我觉得这里视频加上画图比较好理解)接下里t代表的是u这个随机点减去它的below位置对应的那个cdf值除以denom就是这个就是计算出来它占这个区域权重的多少,比如说这个区域的权重是0.4,这个denom就是0.4,u-cdf_g[...,0]就是它占这0.4的多少么,应该这个都可以理解吧,接下里就是把它对应到粗网路中的采样点中也就是samples。
总结一下其实弄明白以后这个很简单,就是通过一个随机的一系列数u去对应到粗网络中的采样点之间一个数,他是怎么对应的呢,就是通过粗网络中的weight计算出来pdf和cdf,如果粗网络中的采样点之间的cdf值差距比较大(这个区域的权重比较大,就是更有可能是物体真是存在的位置),意味着这两个点之间更应该有多一点的采样点。随机的值u也是在(0,1)基本上均匀分布的,那么如果cdf中一个区域的权重比较大,意味着有更大的“空隙”也就意味着随机生成的u的点更更容易在那个范围内,在那两个粗网络中的采样点之间也就有更多精细的采样点。