【深度学习】Normalizing flow原理推导+Pytorch实现

1、前言

N o r m a l i z i n g f l o w \boxed{Normalizing \hspace{0.1cm} flow} Normalizingflow,流模型,一种能够与目前流行的生成模型—— G A N 、 V A E \boxed{\mathbf{GAN、VAE}} GANVAE相媲美的模型。其也是一个生成模型,可是它的思路和另外两个的迂回策略却很大不同。本文我们就简单来介绍一个这个模型吧

2、引入

在生成模型中,我们的目的就是计算出数据x的概率分布。

然而,数据的分布总是千奇百怪的。其 无法被定义,无法被观测,无法被描述、无法被认知 \boxed{\mathbf{无法被定义,无法被观测,无法被描述、无法被认知}} 无法被定义,无法被观测,无法被描述、无法被认知,说成是新时代的克苏鲁都不为过。

在GAN中,其简单粗暴,直接回避数据x的概率分布而采取其他策略;在VAE中,也是求的x的概率分布的下界。

可Normalizing flow就不一样了,这是一个真正“勇敢”的模型,它直面数据x的分布,并且确切的将其算出来了。

我们来看下面的模型图

在这里插入图片描述

假设x为数据。要找出它所服从的概率分布,但是由于太复杂,我们希望找到一个相对简单的概率的概率分布再加上一点其他简单的东西的表达它。如图,P(x)的分布很复杂,P(z1)相对来说没那么复杂,于是我们就想找到它们之间的关系式;而P(z1)虽然相对来说没那么复杂,但仍不是我们所能计算的。可是对于P(zn),我们却可以计算出它,比如 P ( z n ) P(zn) P(zn)就是一个标准的多元高斯分布。所以,理论上,我们只需要一步步往后递归,就可以得到P(x)的概率分布。

实际上,概率分布之间雀食存在某种关系。我们构造一个函数, z = f ( x ) z=f(x) z=f(x),也就是x可以通过某个函数f转化成z(并且维度必须保持不变)
P x ( x ) = P z ( z ) ∣ det ⁡ ∂ z ∂ x ∣ = P z ( f ( x ) ) ∣ det ⁡ ∂ f ( x ) ∂ x ∣ P_x(x)=P_z(z)\left|\det\frac{\partial z}{\partial x}\right|=P_z(f(x))\left|\det\frac{\partial f(x)}{\partial x}\right| Px(x)=Pz(z) detxz =Pz(f(x)) detxf(x)
其中det表示求里面矩阵的行列式,外面的||表示求绝对值。

证明: \boxed{\mathbf{证明:}} 证明:
∫ x P x ( x ) d x = ∫ z P z ( z ) d z = 1 \int_x P_x(x)dx=\int_z P_z(z)dz=1 xPx(x)dx=zPz(z)dz=1
对不定积分,始终有
∣ P x ( x ) d x ∣ = ∣ P z ( z ) d z ∣ |P_x(x)dx|=|P_{z}(z)dz| Px(x)dx=Pz(z)dz
因为概率P始终大于0,所以,有
P x ( x ) ∣ d x ∣ = P z ( z ) ∣ d z ∣ ↓ P x ( x ) = P z ( z ) ∣ d z d x ∣ ↓ P x ( x ) = P z ( f ( x ) ) ∣ d f ( x ) d x ∣ \begin{aligned} P_x(x)|dx|=&P_z(z)|dz| \\\downarrow \\P_x(x)=&P_z(z)\left|\frac{dz}{dx}\right|\\\downarrow \\P_x(x)=&P_z(f(x))\left|\frac{df(x)}{dx}\right| \end{aligned} Px(x)dx=Px(x)=Px(x)=Pz(z)dzPz(z) dxdz Pz(f(x)) dxdf(x)
当x,z的维度是高维时, d f ( x ) d x \frac{df(x)}{dx} dxdf(x)就变成了一个矩阵,但是概率怎么可能会去使用矩阵来表达呢?所以实际上里面是要加上一个行列式,得
P x ( x ) = P z ( f ( x ) ) ∣ det ⁡ d f ( x ) d x ∣ P_x(x)=P_z(f(x))\left|\det\frac{df(x)}{dx}\right| Px(x)=Pz(f(x)) detdxdf(x)
对于 d f ( x ) d x \frac{df(x)}{dx} dxdf(x),其实它还有另一个名字—— 雅可比矩阵 \boxed{\mathbf{雅可比矩阵}} 雅可比矩阵

假如 x = ( x 1 x 2 ) x = \begin{pmatrix} x_1 & x_2 \end{pmatrix} x=(x1x2)是一个二维向量,那么雅可比矩阵可表示为(各个分量相互求导)
d f ( x ) d x = [ d f 1 ( x ) d x 1 d f 2 ( x ) d x 1 d f 2 ( x ) d x 1 d f 2 ( x ) d x 2 ] \frac{df(x)}{dx}=\begin{bmatrix} \frac{df_1(x)}{dx_1} & \frac{df_2(x)}{dx_1}\\ \frac{df_2(x)}{dx_1} & \frac{df_2(x)}{dx_2} \end{bmatrix} dxdf(x)=[dx1df1(x)dx1df2(x)dx1df2(x)dx2df2(x)]
值得注意的是 z = f ( x ) 中的 f 必须存在反函数,即存在 x = f − 1 ( z ) \boxed{\mathbf{z=f(x)中的f必须存在反函数,即存在x=f^{-1}(z)}} z=f(x)中的f必须存在反函数,即存在x=f1(z),因为后面我们生成样本的时候就是从P(z)中去生成的。要反着去计算。即

3、目标函数

有了上面的转化式,我们就可以去定义目标函数了。一般地,对概率模型,我们就是采用对数极大似然估计的方法去估计出参数。所以
log ⁡ P x ( x ) = log ⁡ ( P z ( f ( x ) ) ∣ det ⁡ d f ( x ) d x ∣ ) = log ⁡ P z ( f M ( x ) ) + ∑ k = 1 M log ⁡ ∣ det ⁡ d f k ( x ) d x k ∣ (1) \begin{aligned} \log P_x(x)=&\log \left(P_z(f(x))\left|\det\frac{df(x)}{dx}\right|\right) \\=&\log P_z(f_M(x))+ \sum\limits_{k=1}^M\log\left|\det \frac{df_k(x)}{dx_k}\right| \end{aligned}\tag{1} logPx(x)==log(Pz(f(x)) detdxdf(x) )logPz(fM(x))+k=1Mlog detdxkdfk(x) (1)

其中,M表示有M层转化,对于行列式,我们有 ∣ A B ∣ = ∣ A ∣ ∣ B ∣ |AB|=|A||B| AB=A∣∣B,所以,我们按照上面所提到的递归思想,实际上就是M个雅可比矩阵相乘,取log之后变成连加,所以就变成了上面地式子,而 P z ( f ( x m ) ) P_z(f(x_m)) Pz(f(xm))是实际上就是上面提到 简单的,可以计算的概率分布 \boxed{简单的,可以计算的概率分布} 简单的,可以计算的概率分布

当然了,上面表示的是某一个样本,那么对于所有的样本我们记作 X X X

所以就变成了(单个样本用 x i x^i xi表示,共有N个样本,并且样本与样本之间独立同分布)
log ⁡ P X ( X ) = log ⁡ ∏ i = 1 N P x ( x i ) = ∑ i = 1 N log ⁡ P x ( x i ) \log P_X(X)=\log \prod\limits_{i=1}^N P_x(x^i)=\sum\limits_{i=1}^N\log P_x(x^i) logPX(X)=logi=1NPx(xi)=i=1NlogPx(xi)
每一个 log ⁡ P x x i \log P_x{x^i} logPxxi就是(式1)里面所提到的,所以可以写成
log ⁡ P X ( X ) = ∑ i = 1 N ( log ⁡ P z ( f ( x M i ) ) + ∑ k = 1 M log ⁡ ∣ det ⁡ d f k ( x i ) d x k i ∣ ) \log P_X(X)=\sum\limits_{i=1}^N \left( \log P_z(f(x^i_M))+ \sum\limits_{k=1}^M\log\left|\det \frac{df_k(x^i)}{dx^i_k}\right| \right) logPX(X)=i=1N(logPz(f(xMi))+k=1Mlog detdxkidfk(xi) )
目标很简单,最大化这个目标函数 \boxed{\mathbf{目标很简单,最大化这个目标函数}} 目标很简单,最大化这个目标函数

所以,现在就有两个问题,

①第一个就是选择一个简单的先验分布 P z P_z Pz

②第二个就是雅可比矩阵行列式要相对容易计算,不然假如我们的数据维度是1000维,那么它就是一个 1000 × 1000 1000\times 1000 1000×1000维的矩阵了。计算行列式的计算量是相当大。

以上,就是Normalizing flow 的大致模型结构。下面我们就某一个具体的模型来讲解以下。

4、NICE

NICE(NON - LINEAR INDEPENDENT COMPONENTS ESTIMATION),非线性分量估计。

4.1、选择转化函数(或选择合适的雅可比矩阵)

4.1.1、分块耦合层

其思想是将x的维度按某种比例划分成两部分维度。假设x的维度是D维,那么就变成两部分 x 1 ∈ ( 1 : d ) x_1 \in (1:d) x1(1:d)

x 2 ∈ ( d + 1 : D ) x_2 \in (d+1:D) x2(d+1:D)。后面表示的是维度。

现在,对其进行函数变换得到 z 1 , z 2 z_1,z_2 z1,z2
z 1 = x 1 z 2 = x 2 + m ( x 1 ) z_1=x_1\\ z_2=x_2+m(x_1) z1=x1z2=x2+m(x1)
其中, m ( x ) m(x) m(x)是一个神经网络。最后将 z 1 , z 2 z_1,z_2 z1,z2堆叠起来,形成z。

在论文中,此处的 z 2 z_2 z2其实并不一定是这样,他表达为 z 2 = g ( x 2 , m ( x 1 ) ) z_2=g(x_2,m(x_1)) z2=g(x2,m(x1)) g g g可以是其他函数。但论文中作者在实践的时候就是使用的加性耦合层。并且其具有特殊性。

我们知道,每一次的转化,我们都是需要计算其雅可比矩阵的行列式,作为目标函数的一部分。我们来看它的雅可比矩阵
[ ∂ z 1 ∂ x 1 ∂ z 1 ∂ x 2 ∂ z 2 ∂ x 1 ∂ z 2 ∂ x 2 ] = [ 1 0 d z 2 ∂ x ( x 1 ) 1 ] \begin{bmatrix} \frac{\partial z_1}{\partial x_1} & \frac{\partial z_1}{\partial x_2} \\ \frac{\partial z_2}{\partial x_1} & \frac{\partial z_2}{\partial x_2} \end{bmatrix}= \begin{bmatrix} 1 & 0 \\ \frac{dz_2}{\partial x(x_1)} & 1 \end{bmatrix} [x1z1x1z2x2z1x2z2]=[1x(x1)dz201]
我们计算并不需要行列式本身,我们需要的是它的行列式,所以此处行列式的值不就是1吗?而前面所提到的 log ⁡ ∣ det ⁡ d f k ( x ) d x k ∣ = log ⁡ 1 = 0 \log\left|\det \frac{df_k(x)}{dx_k}\right|=\log 1 =0 log detdxkdfk(x) =log1=0

后面生成数据的时候是需要反函数的,所以有反函数。
x 1 = z 1 x 2 = z 2 − m ( z 1 ) x_1=z_1\\ x_2=z_2-m(z_1) x1=z1x2=z2m(z1)
容易看到,我们对其进行分块,一部分经过了变化,一部分不经过变化。我们进行M次的变化,如果每次都是 x 1 x_1 x1不经过变化,只变化 x 2 x_2 x2,这样是不合理的。因此,我们会交替进行,假设上面的z为第一次变化。在第二次变化,我们就
z 2 ( 2 ) = z 2 z 1 ( 2 ) = z 1 + m ( z 2 ) z_2^{(2)}=z_2\\ z_1^{(2)}=z_1+m(z_2) z2(2)=z2z1(2)=z1+m(z2)

4.1.2、缩放

在经过了M次的分块耦合层之后,论文中提到,会最终的输出 z ( M ) z^{(M)} z(M)做一次缩放。即引入一个与 z n z_n zn相同维度的向量s。记最终结果为h,则
h = s ⋅ z ( M ) h=s\cdot z^{(M)} h=sz(M)
即对应元素相乘。同样的,求出它的雅可比矩阵(仍然以二维为例)
[ ∂ h 1 ∂ z 1 ( M ) ∂ h 1 ∂ z 2 ( M ) ∂ h 2 ∂ z 1 ( M ) ∂ h 2 ∂ z 2 ( M ) ] = [ s 1 0 0 s 2 ] \begin{bmatrix} \frac{\partial h_1}{\partial z^{(M)}_1} & \frac{\partial h_1}{\partial z^{(M)}_2} \\ \frac{\partial h_2}{\partial z^{(M)}_1} & \frac{\partial h_2}{\partial z^{(M)}_2} \end{bmatrix}= \begin{bmatrix} s_1 & 0 \\ 0 & s_2 \end{bmatrix} z1(M)h1z1(M)h2z2(M)h1z2(M)h2 =[s100s2]
所以行列式为
∑ i = 1 D log ⁡ s i \sum\limits_{i=1}^D\log s_i i=1Dlogsi
D为 s i s_i si的维度。

其反函数为
z ( M ) = s ( − 1 ) h z^{(M)}=s^{(-1)}h z(M)=s(1)h
所以对于目标函数可以变为
log ⁡ P X ( X ) = ∑ i = 1 N ( log ⁡ P z ( h ) + ∑ i = 1 D log ⁡ s i ) \log P_X(X)=\sum\limits_{i=1}^N \left( \log P_z(h)+ \sum\limits_{i=1}^D\log s_i \right) logPX(X)=i=1N(logPz(h)+i=1Dlogsi)

4.2、选择合适的先验分布 P ( z ) P(z) P(z)

在论文中,其对先验分布是假设各个维度都相互独立的。即
P ( z ) = ∏ i = 1 D P ( z i ) P(z)=\prod\limits_{i=1}^DP(z_i) P(z)=i=1DP(zi)
并且对其分布论文是给了两个建议,一个是高斯分布,另一个就是logistic分布。

假如是高斯分布的时候(并且是标准高斯)
log ⁡ P ( z ) = log ⁡ ∏ i = 1 D P ( z i ) = ∑ i = 1 D log ⁡ P ( z i ) = ∑ i = 1 D log ⁡ 1 2 π exp ⁡ { − z i 2 2 } = ∑ i = 1 D ( log ⁡ 1 2 π − z i 2 2 ) \begin{aligned} \log P(z)=&\log\prod\limits_{i=1}^DP(z_i) \\=&\sum\limits_{i=1}^D\log P(z_i) \\=&\sum\limits_{i=1}^D \log\frac{1}{\sqrt{2\pi}}\exp\left\{-\frac{z_i^2}{2}\right\} \\=&\sum\limits_{i=1}^D\left(\log \frac{1}{\sqrt{2\pi}}-\frac{z_i^2}{2}\right) \end{aligned} logP(z)====logi=1DP(zi)i=1DlogP(zi)i=1Dlog2π 1exp{2zi2}i=1D(log2π 12zi2)
前面的 log ⁡ \log log那一项显然不在我们优化的参数之内, 我们最终目标函数可以写成 \boxed{\mathbf{我们最终目标函数可以写成}} 我们最终目标函数可以写成
log ⁡ P X ( X ) = ∑ i = 1 N ( ∑ i = 1 D ( log ⁡ s i − h i 2 2 ) ) \log P_X(X)=\sum\limits_{i=1}^N \left(\sum\limits_{i=1}^D\left(\log s_i - \frac{h_i^2}{2} \right) \right) logPX(X)=i=1N(i=1D(logsi2hi2))

容易看到,当每一个维度对应的 s i 越大,则说明该维度越不重要。因为如果是重要的 s i ,那么 h i 刚好与其相反,阻止其增大。 \boxed{容易看到,当每一个维度对应的s_i越大,则说明该维度越不重要。 因为如果是重要的s_i,那么h_i刚好与其相反,阻止其增大。} 容易看到,当每一个维度对应的si越大,则说明该维度越不重要。因为如果是重要的si,那么hi刚好与其相反,阻止其增大。

5、代码实现(Pytorch)

根据原论文,其有4个加性耦合层,一个加性耦合层里面的m(x)是五层1000个神经元的神经网络。对于Mnist这个数据集来说,选用的是Logistic分布。采样方法是从0,1分布中采样,通过反函数采样出z。论文中训练的很长,长达1500个epochs之后。我仅仅训练了1000个(用了整整两个小时)。(感兴趣的可以训练到2000或更多,应当会好一些)

在这里插入图片描述

import torch
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision.transforms import transforms
from  torch import nn
from tqdm import tqdm
import matplotlib.pyplot as plt
from torch.functional import  F
class Coupling(nn.Module):
    def __init__(self,input_dim,hidden_dim,hidden_layer,odd_flag):
        '''
        加性耦合层
        @param input_dim: 输入维度
        @param hidden_dim: 隐藏层维度
        @param hidden_layer: 隐藏层个数
        @param odd_flag: 当前耦合层是否是在整个模型中属于奇数(用作调换切分顺序)
        '''
        super().__init__()
        #用作判断是否需要互换切分的位置
        self.odd_flag=odd_flag%2

        #五层隐藏层,神经元1000
        self.input_transform=nn.Sequential(
            nn.Linear(input_dim//2,hidden_dim),
            nn.ReLU()
        )
        self.m=nn.ModuleList([
            nn.Sequential(
                nn.Linear(hidden_dim,hidden_dim),
                nn.ReLU(),
            ) for _ in range(hidden_layer-1)
        ])
        #输出为原始维度
        self.out_transform=nn.Sequential(
            nn.Linear(hidden_dim,input_dim//2),
        )
    def forward(self,x,reverse):
        '''
        @param x:  数据 [ batch_size , 784 ]
        @param reverse: 是否是反向推导(z->x)
        @return:
        '''
        batch_size,W=x.shape #取出维度
        #重构维度(为了切分)
        x=x.reshape(batch_size,W//2,2)

        #按奇偶性划分
        if self.odd_flag:
            x1, x2 = x[:, :, 0], x[:, :, 1]
        else:
            x2, x1 = x[:, :, 0], x[:, :, 1]

        #将x2输入神经网络
        input_transfrom=self.input_transform(x2)
        for i in self.m:
            input_transfrom=i(input_transfrom)
        out_transform=self.out_transform(input_transfrom)

        #是否是反向推导
        if reverse:
            x1=x1-out_transform #反函数
        else:
            x1=x1+out_transform

        #将数据组合回来
        if self.odd_flag:
            x=torch.stack((x1,x2),dim=2)
        else:
            x=torch.stack((x2,x1),dim=2)

        return x.reshape(-1,784)

class Scale(nn.Module):
    def __init__(self,input_dim):
        '''
        缩放层
        @param input_dim: 输入数据维度
        '''
        super().__init__()

        #构造与数据同维度的s
        self.s=nn.Parameter(torch.zeros(1,input_dim))
    def forward(self,x,reverse):
        '''
        @param x: 输入数据
        @param reverse: 是否是反向推导
        @return:
        '''
        if reverse:
            result=torch.exp(-self.s)*x #反函数
        else:
            result=torch.exp(self.s)*x
        return result,self.s
class NICE(nn.Module):
    def __init__(self,couping_num):
        '''
        @param couping_num: 耦合层个数
        '''
        super().__init__()
        #初始化耦合层
        self.couping=nn.ModuleList([
            Coupling(784,1000,5,odd_flag=i+1)
            for i in torch.arange(couping_num)
        ])
        #初始化缩放层
        self.scale=Scale(784)

    def forward(self,x,reverse):

        '''
        前向推导
        @param x: 输入数据
        @param reverse: #是否是反向
        @return:
        '''
        for i in self.couping:
            x=i(x,reverse)
        h,s=self.scale(x,reverse)
        return h,s
    def likeihood(self,h,s):
        #计算极大似然估计
        loss_s = torch.sum(s) #s的log雅可比行列式损失
        log_prob = proior.log_prob(h) #logictic分布极大似然
        loss_prob = torch.sum(log_prob, dim=1) #案列求和
        loss = loss_s + loss_prob #总损失
        #由于pytorch是最小值优化,故取反
        return -loss
    def generate(self,h):
        '''
        @param h: logistic分布采样所得
        @return:
        '''
        z,s=self.scale(h,True)
        for i in reversed(self.couping):
            z=i(z,True)
        return z
def train():
    #归一化
    transformer = transforms.Compose([
        transforms.ToTensor()
    ])
    #载入数据
    data = MNIST("data", transform=transformer, download=True)
    #存入写入器
    dataloader = DataLoader(data, batch_size=200, shuffle=True,num_workers=4)
    #初始化模型
    nice = NICE(4).to(device)
    #优化器
    optimer = torch.optim.Adam(params=nice.parameters(), lr=1e-3,eps=1e-4,betas=(0.9,0.999))

    #开始训练
    epochs = 1000

    for epoch in torch.arange(epochs):
        loss_all = 0
        dataloader_len = len(dataloader)
        for i in tqdm(dataloader, desc="第{}轮次".format(epoch)):
            sample, label = i
            sample = sample.reshape(-1, 784).to(device)

            h, s = nice(sample, False) #预测
            loss = nice.likeihood(h, s).mean() #计算损失

            optimer.zero_grad() #归零
            loss.backward() #反向传播
            optimer.step() #更新

            with torch.no_grad():
                loss_all += loss
        print("损失为{}".format(loss_all / dataloader_len))
        torch.save(nice, "nice.pth")

class Logistic(torch.distributions.Distribution):
    '''
    Logistic 分布
    '''
    def __init__(self):
        super(self, self).__init__()

    def log_prob(self, x):

        return -(F.softplus(x) + F.softplus(-x))

    def sample(self, size):

        z = torch.distributions.Uniform(0., 1.).sample(size)
        return torch.log(z) - torch.log(1. - z)
if __name__ == '__main__':
    # 是否有闲置GPU
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    #先验分布
    proior = Logistic()

    #训练
    train()

    #预测
    x=proior.sample((10,784))#采样

    #载入模型
    nice=torch.load("nice.pth",map_location=device)
    #生成数据
    result=nice.generate(x)
    result=result.reshape(-1,28,28)
    for i in range(10):
        plt.subplot(2,5,i+1)
        img=result[i].detach().numpy()
        plt.imshow(img)
        plt.gray()
    plt.show()

6、结束

以上,就是Normalizing flow 的全部内容了。如有问题,还望指出。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/281936.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【网络安全 | Misc】Ditf 安恒九月赛

正文 binwalk发现rar: 修改后缀,打开需要密码: 修改高度: 得到密码: StRe1izia得到一个流量包: 联系上文搜素png得到: 追踪流: 得到Base64代码: flag{Oz_4nd_Hir0_lov3_F…

算法通关村第十四关—堆能高效解决的经典问题(白银)

堆能高效解决的经典问题 一、在数组中找第K大的元素 LeetCode215 给定整数数组ums和整数k,请返回数组中第k个最大的元素。请注意,你需要找的是数组排序后的第k个最大的元素,而不是第k个不同的元素。 示例1: 输入:[3,2,1,5,6,4]和…

循环生成对抗网络(CycleGAN)

一、说明 循环生成对抗网络(CycleGAN)是一种训练深度卷积神经网络以执行图像到图像翻译任务的方法。网络使用不成对的数据集学习输入和输出图像之间的映射。 二、基本介绍 CycleGAN 是图像到图像的翻译模型,就像Pix2Pix一样。Pix2Pix模型面临…

计算机组成原理复习7

内存管理 文章目录 内存管理存储器概述存储器的分类按在计算机中的作用(层次)分类按存储介质分类按存取方式分类按信息的可保存性分类 存储器的性能指标存储容量单位成本存储速度:数据传输率数据的宽度/存储周期 存储器的层次化结构多级存储系…

抖音详情API:从零开始构建抖音应用

随着短视频的兴起,抖音已经成为了一个全球范围内的热门平台。对于开发人员而言,利用抖音详情API从零开始构建抖音应用具有巨大的潜力和机会。本文将为你提供从零开始构建抖音应用的指南,包括开发环境搭建、API请求格式、用户认证等关键环节&a…

八. 实战:CUDA-BEVFusion部署分析-环境搭建

目录 前言0. 简述1. CUDA-BEVFusion浅析2. CUDA-BEVFusion环境配置2.1 简述2.2 源码下载2.3 模型数据下载2.4 基础软件安装2.5 protobuf安装2.5.1 apt 方式安装2.5.2 源码方式安装 2.6 编译运行2.6.1 配置 environment.sh2.6.2 利用TensorRT构建模型2.6.3 编译运行程序 2.7 拓展…

【电子通识】LED有关的几个参数和定义

主波长与峰值波长 看LED灯数据手册的时候会发现有两种不同的波长参数:“峰值波长 Peak Wavelength”和 “主波长 Dominant Wavelength”,那么这两个波长代表什么? 峰值波长 λP(Peak Wavelength ) : 定义为光谱辐射功率最大处所对…

JavaScript元素根据父级元素宽高缩放

/*** 等比缩放* param wrap 外部容器* param container 待缩放的容器* returns {{width: number, height: number}}* 返回值:width:宽度, height:高度*/aspectRatio(wrap: any, container: any) {// w h / ratio, h w * ratioconst wrapW wrap.width;const wrapH…

2023年度总结——关于如何认清自己是个FW

前言 不到各位有没有今年过得特别快的感觉。写总结时候一整理,我敲,我今年这么忙? 从三月份开说 三月份 这段时间刚开学,还算比较懵懂。不过初生牛犊不怕虎,那个寒假学了点怎么挖edusrc,开学迫不及待地…

AI按理说应该最擅长理工,为啥先冲击文艺行业?

介绍 本人数据AI工程师,我的观点对全行业都有冲击,当AI大模型持续进化之时,没有一家公司能独善其身。 本文从产业架构上、论文体量、基础Pass能力、通用大模型、AI开源社区、业务属性大模型、内容消费工具、创作工具赛道、企业服务这些板块…

day12--java高级编程:网络通讯

5 Day19–网络通信(Socket通信) 说明: io流是跟本地的文件进行数据的传输,读或者写。网络通信:数据在网络中进行的传输。 本章专题与脉络 1. 网络编程概述 Java是 Internet 上的语言,它从语言级上提供了对网络应用程序的支持&…

常用的 MySQL 可视化客户端

数据库可视化客户端(GUI)让用户在和数据库进行交互时,能直观地查看、创建和修改对象,如:表、行和列。让数据库操作变得更方便了。 今天,我们来了解下目前市场上最常用的 MySQL 可视化客户端。 官方&#x…

Stata18软件安装包下载及安装教程

Stata 18下载链接:https://docs.qq.com/doc/DUm5pRlFJaWV5aWtY 1.选中下载好的安装包,右键选择解压到“Stata18”文件夹 2.选中“SetupStata18.exe”,右键以管理员身份运行 3.点击“Next” 4.选择“I accept.....”,选择“Next” 5.点击“Nex…

MySQL Too many connections报错

MySQL 时不时出现Too many connections报错,重启MySQL就好了 但是过段时间又出现 一、解决方案: 1.修改mysql最大连接数 set global max_connections500; 以上是修改立即生效的,重启MySQL就会还原回去 在MySQL配置文件修改 max_connection…

matalb实践(十二):减肥

1.题目 2.解答 2.1模型假设 1.体重增加正比于吸收的热量,平均每8000kcal增加体重1kg 2.身体正常代谢引起的体重减少正比于体重,每周每千克体重消耗热量一般在200kcal至320kcal之间,且因人而异,这相当于体重70kg的人每天消耗2000k…

【ECharts系列】ECharts 图表渲染问题解决方案

1 问题描述 echats 渲染,第一次的时候只出现Y轴数值,不出现X轴数值,切换下页面,X轴数值就能出现。 2 原因分析 如果在使用ECharts渲染时,X轴数值只在切换页面后才出现,可能是因为ECharts在初始化时没有正确…

计算机视觉:朗伯光度立体法(Lambertian Photometric Stereo)

计算机视觉:朗伯光度立体法(Lambertian Photometric Stereo) 光度立体法简介朗伯光度立体法算法原理朗伯光度立体法matlab程序示例Albedo图Normal图Re_rendered图 参考文献 光度立体法简介 光度立体法,即Photometric Stereo, 最早…

Layui弹窗带标签可切换图表的应用Demo

提供Layui弹窗带页签的Demo写法 文章目录 前言一、展示效果二、详细代码1.代码2.简单释义 总结 前言 之前因为有需求,需要开发Layui的弹出框,同时弹窗框需要支持,页签点击切换内容,特此整理了这一篇文章,提供给需要的…

【Image】超硬核数学推导——WGAN的先“破”后“立”

GAN的实现 上一篇文章中我们说到了GAN的数学解释 min ⁡ G max ⁡ D V ( D , G ) E x ∼ p data ( x ) [ log ⁡ D ( x ) ] E z ∼ p z ( z ) [ log ⁡ ( 1 − D ( G ( z ) ) ) ] − log ⁡ 4 2 J S D ( p data ∥ p g ) ≥ − log ⁡ 4 , where [ p d a t a p g ] \mi…

力扣题目学习笔记(OC + Swift)24. 两两交换链表中的节点

24. 两两交换链表中的节点 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 方法一、递归 首先定义递归终止条件: …