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

使用PyTorch實現去噪擴散模型

人工智能
在深入研究去噪擴散概率模型(DDPM)如何工作的細節之前,讓我們先看看生成式人工智能的一些發展,也就是DDPM的一些基礎研究。

在深入研究去噪擴散概率模型(DDPM)如何工作的細節之前,讓我們先看看生成式人工智能的一些發展,也就是DDPM的一些基礎研究。

VAE

VAE 采用了編碼器、概率潛在空間和解碼器。在訓練過程中,編碼器預測每個圖像的均值和方差。然后從高斯分布中對這些值進行采樣,并將其傳遞到解碼器中,其中輸入的圖像預計與輸出的圖像相似。這個過程包括使用KL Divergence來計算損失。VAEs的一個顯著優勢在于它們能夠生成各種各樣的圖像。在采樣階段簡單地從高斯分布中采樣,解碼器創建一個新的圖像。

GAN

在變分自編碼器(VAEs)的短短一年之后,一個開創性的生成家族模型出現了——生成對抗網絡(GANs),標志著一類新的生成模型的開始,其特征是兩個神經網絡的協作:一個生成器和一個鑒別器,涉及對抗性訓練過程。生成器的目標是從隨機噪聲中生成真實的數據,例如圖像,而鑒別器則努力區分真實數據和生成數據。在整個訓練階段,生成器和鑒別器通過競爭性學習過程不斷完善自己的能力。生成器生成越來越有說服力的數據,從而比鑒別器更聰明,而鑒別器又提高了辨別真實樣本和生成樣本的能力。這種對抗性的相互作用在生成器生成高質量、逼真的數據時達到頂峰。在采樣階段,經過GAN訓練后,生成器通過輸入隨機噪聲產生新的樣本。它將這些噪聲轉換為通常反映真實示例的數據。

為什么我們需要另一個模型架構

兩種模型都有不同的問題,雖然GANs擅長于生成與訓練集中的圖像非常相似的逼真圖像,但VAEs擅長于創建各種各樣的圖像,盡管有產生模糊圖像的傾向。但是現有的模型還沒有成功地將這兩種功能結合起來——創造出既高度逼真又多樣化的圖像。這一挑戰給研究人員帶來了一個需要解決的重大障礙。

在第一篇GAN論文發表六年后,在VAE論文發表七年后,一個開創性的模型出現了:去噪擴散概率模型(DDPM)。DDPM結合了兩個世界的優勢,擅長于創造多樣化和逼真的圖像。

在本文中,我們將深入研究DDPM的復雜性,涵蓋其訓練過程,包括正向和逆向過程,并探索如何執行采樣。在整個探索過程中,我們將使用PyTorch從頭開始構建DDPM,并完成其完整的訓練。

這里假設你已經熟悉深度學習的基礎知識,并且在深度計算機視覺方面有堅實的基礎。我們不會介紹這些基本概念,我們的目標是生成人類確信其真實性的圖像。

DDPM

去噪擴散概率模型(DDPM)是生成模型領域的一種前沿方法。與依賴顯式似然函數的傳統模型不同,DDPM通過對擴散過程進行迭代去噪來運行。這包括逐漸向圖像中添加噪聲并試圖去除該噪聲。其基本理論是基于這樣一種思想:通過一系列擴散步驟轉換一個簡單的分布,例如高斯分布,可以得到一個復雜而富有表現力的圖像數據分布。或者說通過將樣本從原始圖像分布轉移到高斯分布,我們可以創建一個模型來逆轉這個過程。這使我們能夠從全高斯分布開始,以圖像分布結束,有效地生成新圖像。

DDPM的訓練包括兩個基本步驟:產生噪聲圖像這是固定和不可學習的正向過程,以及隨后的逆向過程。逆向過程的主要目標是使用專門的機器學習模型對圖像進行去噪。

正向擴散過程

正向過程是一個固定且不可學習的步驟,但是它需要一些預定義的設置。在深入研究這些設置之前,讓我們先了解一下它是如何工作的。

這個過程的核心概念是從一個清晰的圖像開始。在用“T”表示的特定步長上,少量噪聲按照高斯分布逐漸引入。

從圖像中可以看出,噪聲是在每一步遞增的,我們深入研究這種噪音的數學表示。

噪聲是從高斯分布中采樣的。為了在每一步引入少量的噪聲,我們使用馬爾可夫鏈。要生成當前時間戳的圖像,我們只需要上次時間戳的圖像。馬爾可夫鏈的概念在這里是關鍵的,并對隨后的數學細節至關重要。

馬爾可夫鏈是一個隨機過程,其中過渡到任何特定狀態的概率僅取決于當前狀態和經過的時間,而不是之前的事件序列。這一特性簡化了噪聲添加過程的建模,使其更易于數學分析。

用beta表示的方差參數被有意地設置為一個非常小的值,目的是在每個步驟中只引入最少量的噪聲。

步長參數“T”決定了生成全噪聲圖像所需的步長。在本文中,該參數被設置為1000,這可能顯得很大。我們真的需要為數據集中的每個原始圖像創建1000個噪聲圖像嗎?馬爾可夫鏈方面被證明有助于解決這個問題。由于我們只需要上一步的圖像來預測下一步,并且每一步添加的噪聲保持不變,因此我們可以通過生成特定時間戳的噪聲圖像來簡化計算。采用對的再參數化技巧使我們能夠進一步簡化方程。

將式(3)中引入的新參數納入式(2)中,對式(2)進行了發展,得到了結果。

逆向擴散過程

我們已經為圖像引入了噪聲下一步就是執行逆操作了。除非我們知道初始條件,即t = 0時的未去噪圖像,否則無法從數學上實現對圖像進行逆向處理去噪。我們的目標是直接從噪聲中采樣以創建新圖像,這里缺乏關于結果的信息。所以我需要設計一種在不知道結果的情況下逐步去噪圖像的方法。所以就出現了使用深度學習模型來近似這個復雜的數學函數的解決方案。

有了一點數學背景,模型將近似于方程(5)。一個值得注意的細節是,我們將堅持DDPM原始論文并保持固定的方差,盡管也有可能使模型學習它。

該模型的任務是預測當前時間戳和前一個時間戳之間添加的噪聲的平均值。這樣做可以有效地去除噪音,達到預期的效果。但是如果我們的目標是讓模型預測從“原始圖像”到最后一個時間戳添加的噪聲呢?

除非我們知道沒有噪聲的初始圖像,否則在數學上執行逆向過程是具有挑戰性的,讓我們從定義后方差開始。

模型的任務是預測從初始圖像添加到時間戳t的圖像的噪聲。正向過程使我們能夠執行這個操作,從一個清晰的圖像開始,并在時間戳t處進展到一個有噪聲的圖像。

訓練算法

我們假設用于進行預測的模型體系結構將是一個U-Net。訓練階段的目標是:對于數據集中的每個圖像,在[0,T]范圍內隨機選擇一個時間戳,并計算正向擴散過程。這產生了一個清晰的,有點噪聲的圖像,以及實際使用的噪聲。然后利用我們對逆向過程的理解,使用該模型來預測添加到圖像中的噪聲。有了真實的和預測的噪聲,我們似乎已經進入了一個有監督的機器學習問題。

最主要的問題來了,我們應該用哪個損失函數來訓練我們的模型呢?由于處理的是概率潛在空間,Kullback-Leibler (KL)散度是一個合適的選擇。

KL散度衡量兩個概率分布之間的差異,在我們的例子中,是模型預測的分布和期望分布。在損失函數中加入KL散度不僅可以指導模型產生準確的預測,還可以確保潛在空間表示符合期望的概率結構。

KL散度可以近似為L2損失函數,所以可以得到以下損失函數:

最終我們得到了論文中提出的訓練算法。

采樣

逆向流程已經解釋完成了,下面就是如何使用了。從時刻T的一個完全隨機的圖像開始,并使用逆向過程T次,最終到達時刻0。這構成了本文中概述的第二種算法

參數

我們有很多不同的參數beta,beta_tildes,alpha, alpha_hat 等等。目前都不知道如何選擇這些參數。但是此時已知的唯一參數是T,它被設置為1000。

對于所有列出的參數,它們的選擇取決于beta。從某種意義上說,Beta決定了我們要在每一步中添加的噪聲量。因此,為了確保算法的成功,仔細選擇beta是至關重要的。其他的參數因為太多,請參考論文。

在原始論文的實驗階段探索了各種抽樣方法。最初的線性采樣方法圖像要么接收到的噪聲不足,要么變得過于嘈雜。為了解決這個問題,采用了另一種更常用的方法,即余弦采樣。余弦采樣提供了更平滑和更一致的噪聲添加。

模型Pytorch實現

我們將利用U-Net架構進行噪聲預測,之所以選擇U-Net,是因為U-Net是圖像處理、捕獲空間和特征地圖以及提供與輸入相同的輸出大小的理想架構。

考慮到任務的復雜性和對每一步使用相同模型的要求(其中模型需要能夠以相同的權重去噪完全有噪聲的圖像和稍微有噪聲的圖像),調整模型是必不可少的。這包括合并更復雜的塊,并通過正弦嵌入步驟引入對所用時間戳的感知。這些增強的目的是使模型成為去噪任務的專家。在繼續構建完整的模型之前,我們將介紹每個塊。

ConvNext塊

為了滿足提高模型復雜度的需要,卷積塊起著至關重要的作用。這里不能僅僅依賴于u-net論文中的基本塊,我們將結合ConvNext。

輸入由代表圖像的“x”和大小為“time_embedding_dim”的嵌入的時間戳可視化“t”組成。由于塊的復雜性以及與輸入和最后一層的殘差連接,在整個過程中,塊在學習空間和特征映射方面起著關鍵作用。

class ConvNextBlock(nn.Module):
    def __init__(
        self,
        in_channels,
        out_channels,
        mult=2,
        time_embedding_dim=None,
        norm=True,
        group=8,
    ):
        super().__init__()
        self.mlp = (
            nn.Sequential(nn.GELU(), nn.Linear(time_embedding_dim, in_channels))
            if time_embedding_dim
            else None
        )
 
        self.in_conv = nn.Conv2d(
            in_channels, in_channels, 7, padding=3, groups=in_channels
        )
 
        self.block = nn.Sequential(
            nn.GroupNorm(1, in_channels) if norm else nn.Identity(),
            nn.Conv2d(in_channels, out_channels * mult, 3, padding=1),
            nn.GELU(),
            nn.GroupNorm(1, out_channels * mult),
            nn.Conv2d(out_channels * mult, out_channels, 3, padding=1),
        )
 
        self.residual_conv = (
            nn.Conv2d(in_channels, out_channels, 1)
            if in_channels != out_channels
            else nn.Identity()
        )
 
    def forward(self, x, time_embedding=None):
        h = self.in_conv(x)
        if self.mlp is not None and time_embedding is not None:
            assert self.mlp is not None, "MLP is None"
            h = h + rearrange(self.mlp(time_embedding), "b c -> b c 1 1")
        h = self.block(h)
        return h + self.residual_conv(x)

正弦時間戳嵌入

模型中的關鍵塊之一是正弦時間戳嵌入塊,它使給定時間戳的編碼能夠保留關于模型解碼所需的當前時間的信息,因為該模型將用于所有不同的時間戳。

這是一個非常經典的是實現,并且應用在各個地方,我們就直接貼代碼了

class SinusoidalPosEmb(nn.Module):
    def __init__(self, dim, theta=10000):
        super().__init__()
        self.dim = dim
        self.theta = theta
 
    def forward(self, x):
        device = x.device
        half_dim = self.dim // 2
        emb = math.log(self.theta) / (half_dim - 1)
        emb = torch.exp(torch.arange(half_dim, device=device) * -emb)
        emb = x[:, None] * emb[None, :]
        emb = torch.cat((emb.sin(), emb.cos()), dim=-1)
        return emb

DownSample & UpSample

class DownSample(nn.Module):
    def __init__(self, dim, dim_out=None):
        super().__init__()
        self.net = nn.Sequential(
            Rearrange("b c (h p1) (w p2) -> b (c p1 p2) h w", p1=2, p2=2),
            nn.Conv2d(dim * 4, default(dim_out, dim), 1),
        )
 
    def forward(self, x):
        return self.net(x)
 
 
 class Upsample(nn.Module):
    def __init__(self, dim, dim_out=None):
        super().__init__()
        self.net = nn.Sequential(
            nn.Upsample(scale_factor=2, mode="nearest"),
            nn.Conv2d(dim, dim_out or dim, kernel_size=3, padding=1),
        )
 
    def forward(self, x):
        return self.net(x)

時間多層感知器

這個模塊利用它來基于給定的時間戳t創建時間表示。這個多層感知器(MLP)的輸出也將作為所有修改后的ConvNext塊的輸入“t”。

這里,“dim”是模型的超參數,表示第一個塊所需的通道數。它作為后續塊中通道數量的基本計算。

sinu_pos_emb = SinusoidalPosEmb(dim, theta=10000)
 
  time_dim = dim * 4
 
  time_mlp = nn.Sequential(
      sinu_pos_emb,
      nn.Linear(dim, time_dim),
      nn.GELU(),
      nn.Linear(time_dim, time_dim),
  )

注意力

這是unet中使用的可選組件。注意力有助于增強剩余連接在學習中的作用。它通過殘差連接計算的注意機制和中低潛空間計算的特征映射,更多地關注從Unet左側獲得的重要空間信息。它來源于ACC-UNet論文。

gate 表示下塊的上采樣輸出,而x殘差表示在應用注意的水平上的殘差連接。

class BlockAttention(nn.Module):
    def __init__(self, gate_in_channel, residual_in_channel, scale_factor):
        super().__init__()
        self.gate_conv = nn.Conv2d(gate_in_channel, gate_in_channel, kernel_size=1, stride=1)
        self.residual_conv = nn.Conv2d(residual_in_channel, gate_in_channel, kernel_size=1, stride=1)
        self.in_conv = nn.Conv2d(gate_in_channel, 1, kernel_size=1, stride=1)
        self.relu = nn.ReLU()
        self.sigmoid = nn.Sigmoid()
 
    def forward(self, x: torch.Tensor, g: torch.Tensor) -> torch.Tensor:
        in_attention = self.relu(self.gate_conv(g) + self.residual_conv(x))
        in_attention = self.in_conv(in_attention)
        in_attention = self.sigmoid(in_attention)
        return in_attention * x

最后整合

將前面討論的所有塊(不包括注意力塊)整合到一個Unet中。每個塊都包含兩個殘差連接,而不是一個。這個修改是為了解決潛在的過度擬合問題。

class TwoResUNet(nn.Module):
    def __init__(
        self,
        dim,
        init_dim=None,
        out_dim=None,
        dim_mults=(1, 2, 4, 8),
        channels=3,
        sinusoidal_pos_emb_theta=10000,
        convnext_block_groups=8,
    ):
        super().__init__()
        self.channels = channels
        input_channels = channels
        self.init_dim = default(init_dim, dim)
        self.init_conv = nn.Conv2d(input_channels, self.init_dim, 7, padding=3)
 
        dims = [self.init_dim, *map(lambda m: dim * m, dim_mults)]
        in_out = list(zip(dims[:-1], dims[1:]))
 
        sinu_pos_emb = SinusoidalPosEmb(dim, theta=sinusoidal_pos_emb_theta)
 
        time_dim = dim * 4
 
        self.time_mlp = nn.Sequential(
            sinu_pos_emb,
            nn.Linear(dim, time_dim),
            nn.GELU(),
            nn.Linear(time_dim, time_dim),
        )
 
        self.downs = nn.ModuleList([])
        self.ups = nn.ModuleList([])
        num_resolutions = len(in_out)
 
        for ind, (dim_in, dim_out) in enumerate(in_out):
            is_last = ind >= (num_resolutions - 1)
 
            self.downs.append(
                nn.ModuleList(
                    [
                        ConvNextBlock(
                            in_channels=dim_in,
                            out_channels=dim_in,
                            time_embedding_dim=time_dim,
                            group=convnext_block_groups,
                        ),
                        ConvNextBlock(
                            in_channels=dim_in,
                            out_channels=dim_in,
                            time_embedding_dim=time_dim,
                            group=convnext_block_groups,
                        ),
                        DownSample(dim_in, dim_out)
                        if not is_last
                        else nn.Conv2d(dim_in, dim_out, 3, padding=1),
                    ]
                )
            )
 
        mid_dim = dims[-1]
        self.mid_block1 = ConvNextBlock(mid_dim, mid_dim, time_embedding_dim=time_dim)
        self.mid_block2 = ConvNextBlock(mid_dim, mid_dim, time_embedding_dim=time_dim)
 
        for ind, (dim_in, dim_out) in enumerate(reversed(in_out)):
            is_last = ind == (len(in_out) - 1)
            is_first = ind == 0
 
            self.ups.append(
                nn.ModuleList(
                    [
                        ConvNextBlock(
                            in_channels=dim_out + dim_in,
                            out_channels=dim_out,
                            time_embedding_dim=time_dim,
                            group=convnext_block_groups,
                        ),
                        ConvNextBlock(
                            in_channels=dim_out + dim_in,
                            out_channels=dim_out,
                            time_embedding_dim=time_dim,
                            group=convnext_block_groups,
                        ),
                        Upsample(dim_out, dim_in)
                        if not is_last
                        else nn.Conv2d(dim_out, dim_in, 3, padding=1)
                    ]
                )
            )
 
        default_out_dim = channels
        self.out_dim = default(out_dim, default_out_dim)
 
        self.final_res_block = ConvNextBlock(dim * 2, dim, time_embedding_dim=time_dim)
        self.final_conv = nn.Conv2d(dim, self.out_dim, 1)
 
    def forward(self, x, time):
        b, _, h, w = x.shape
        x = self.init_conv(x)
        r = x.clone()
 
        t = self.time_mlp(time)
 
        unet_stack = []
        for down1, down2, downsample in self.downs:
            x = down1(x, t)
            unet_stack.append(x)
            x = down2(x, t)
            unet_stack.append(x)
            x = downsample(x)
 
        x = self.mid_block1(x, t)
        x = self.mid_block2(x, t)
 
        for up1, up2, upsample in self.ups:
            x = torch.cat((x, unet_stack.pop()), dim=1)
            x = up1(x, t)
            x = torch.cat((x, unet_stack.pop()), dim=1)
            x = up2(x, t)
            x = upsample(x)
 
        x = torch.cat((x, r), dim=1)
        x = self.final_res_block(x, t)
 
        return self.final_conv(x)

擴散的代碼實現

最后我們介紹一下擴散是如何實現的。由于我們已經介紹了用于正向、逆向和采樣過程的所有數學理論,所里這里將重點介紹代碼。

class DiffusionModel(nn.Module):
    SCHEDULER_MAPPING = {
        "linear": linear_beta_schedule,
        "cosine": cosine_beta_schedule,
        "sigmoid": sigmoid_beta_schedule,
    }
 
    def __init__(
        self,
        model: nn.Module,
        image_size: int,
        *,
        beta_scheduler: str = "linear",
        timesteps: int = 1000,
        schedule_fn_kwargs: dict | None = None,
        auto_normalize: bool = True,
    ) -> None:
        super().__init__()
        self.model = model
 
        self.channels = self.model.channels
        self.image_size = image_size
 
        self.beta_scheduler_fn = self.SCHEDULER_MAPPING.get(beta_scheduler)
        if self.beta_scheduler_fn is None:
            raise ValueError(f"unknown beta schedule {beta_scheduler}")
 
        if schedule_fn_kwargs is None:
            schedule_fn_kwargs = {}
 
        betas = self.beta_scheduler_fn(timesteps, **schedule_fn_kwargs)
        alphas = 1.0 - betas
        alphas_cumprod = torch.cumprod(alphas, dim=0)
        alphas_cumprod_prev = F.pad(alphas_cumprod[:-1], (1, 0), value=1.0)
        posterior_variance = (
            betas * (1.0 - alphas_cumprod_prev) / (1.0 - alphas_cumprod)
        )
 
        register_buffer = lambda name, val: self.register_buffer(
            name, val.to(torch.float32)
        )
 
        register_buffer("betas", betas)
        register_buffer("alphas_cumprod", alphas_cumprod)
        register_buffer("alphas_cumprod_prev", alphas_cumprod_prev)
        register_buffer("sqrt_recip_alphas", torch.sqrt(1.0 / alphas))
        register_buffer("sqrt_alphas_cumprod", torch.sqrt(alphas_cumprod))
        register_buffer(
            "sqrt_one_minus_alphas_cumprod", torch.sqrt(1.0 - alphas_cumprod)
        )
        register_buffer("posterior_variance", posterior_variance)
 
        timesteps, *_ = betas.shape
        self.num_timesteps = int(timesteps)
 
        self.sampling_timesteps = timesteps
 
        self.normalize = normalize_to_neg_one_to_one if auto_normalize else identity
        self.unnormalize = unnormalize_to_zero_to_one if auto_normalize else identity
 
    @torch.inference_mode()
    def p_sample(self, x: torch.Tensor, timestamp: int) -> torch.Tensor:
        b, *_, device = *x.shape, x.device
        batched_timestamps = torch.full(
            (b,), timestamp, device=device, dtype=torch.long
        )
 
        preds = self.model(x, batched_timestamps)
 
        betas_t = extract(self.betas, batched_timestamps, x.shape)
        sqrt_recip_alphas_t = extract(
            self.sqrt_recip_alphas, batched_timestamps, x.shape
        )
        sqrt_one_minus_alphas_cumprod_t = extract(
            self.sqrt_one_minus_alphas_cumprod, batched_timestamps, x.shape
        )
 
        predicted_mean = sqrt_recip_alphas_t * (
            x - betas_t * preds / sqrt_one_minus_alphas_cumprod_t
        )
 
        if timestamp == 0:
            return predicted_mean
        else:
            posterior_variance = extract(
                self.posterior_variance, batched_timestamps, x.shape
            )
            noise = torch.randn_like(x)
            return predicted_mean + torch.sqrt(posterior_variance) * noise
 
    @torch.inference_mode()
    def p_sample_loop(
        self, shape: tuple, return_all_timesteps: bool = False
    ) -> torch.Tensor:
        batch, device = shape[0], "mps"
 
        img = torch.randn(shape, device=device)
        # This cause me a RunTimeError on MPS device due to MPS back out of memory
        # No ideas how to resolve it at this point
 
        # imgs = [img]
 
        for t in tqdm(reversed(range(0, self.num_timesteps)), total=self.num_timesteps):
            img = self.p_sample(img, t)
            # imgs.append(img)
 
        ret = img # if not return_all_timesteps else torch.stack(imgs, dim=1)
 
        ret = self.unnormalize(ret)
        return ret
 
    def sample(
        self, batch_size: int = 16, return_all_timesteps: bool = False
    ) -> torch.Tensor:
        shape = (batch_size, self.channels, self.image_size, self.image_size)
        return self.p_sample_loop(shape, return_all_timesteps=return_all_timesteps)
 
    def q_sample(
        self, x_start: torch.Tensor, t: int, noise: torch.Tensor = None
    ) -> torch.Tensor:
        if noise is None:
            noise = torch.randn_like(x_start)
 
        sqrt_alphas_cumprod_t = extract(self.sqrt_alphas_cumprod, t, x_start.shape)
        sqrt_one_minus_alphas_cumprod_t = extract(
            self.sqrt_one_minus_alphas_cumprod, t, x_start.shape
        )
 
        return sqrt_alphas_cumprod_t * x_start + sqrt_one_minus_alphas_cumprod_t * noise
 
    def p_loss(
        self,
        x_start: torch.Tensor,
        t: int,
        noise: torch.Tensor = None,
        loss_type: str = "l2",
    ) -> torch.Tensor:
        if noise is None:
            noise = torch.randn_like(x_start)
        x_noised = self.q_sample(x_start, t, noise=noise)
        predicted_noise = self.model(x_noised, t)
 
        if loss_type == "l2":
            loss = F.mse_loss(noise, predicted_noise)
        elif loss_type == "l1":
            loss = F.l1_loss(noise, predicted_noise)
        else:
            raise ValueError(f"unknown loss type {loss_type}")
        return loss
 
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        b, c, h, w, device, img_size = *x.shape, x.device, self.image_size
        assert h == w == img_size, f"image size must be {img_size}"
 
        timestamp = torch.randint(0, self.num_timesteps, (1,)).long().to(device)
        x = self.normalize(x)
        return self.p_loss(x, timestamp)

擴散過程是訓練部分的模型。它打開了一個采樣接口,允許我們使用已經訓練好的模型生成樣本。

訓練的要點總結

對于訓練部分,我們設置了37,000步的訓練,每步16個批次。由于GPU內存分配限制,圖像大小被限制為128x128。使用指數移動平均(EMA)模型權重每1000步生成樣本以平滑采樣,并保存模型版本。

在最初的1000步訓練中,模型開始捕捉一些特征,但仍然錯過了某些區域。在10000步左右,這個模型開始產生有希望的結果,進步變得更加明顯。在3萬步的最后,結果的質量顯著提高,但仍然存在黑色圖像。這只是因為模型沒有足夠的樣本種類,真實圖像的數據分布并沒有完全映射到高斯分布。

有了最終的模型權重,我們可以生成一些圖片。盡管由于128x128的尺寸限制,圖像質量受到限制,但該模型的表現還是不錯的。

注:本文使用的數據集是森林地形的衛星圖片,具體獲取方式請參考源代碼中的ETL部分。

總結

我們已經完整的介紹了有關擴散模型的必要知識,并且使用Pytorch進行了完整的實現,本文的代碼:

https://github.com/Camaltra/this-is-not-real-aerial-imagery/

責任編輯:華軒 來源: DeepHub IMBA
相關推薦

2024-10-16 10:20:00

2025-02-17 12:30:00

2024-01-10 16:01:28

2024-02-20 12:59:49

動畫計算SVD

2024-05-10 07:58:03

2023-01-02 13:12:07

模型圖像

2023-12-07 13:07:59

3D模型訓練

2025-03-25 09:04:12

2023-08-31 22:24:18

Vega擴散模型圖像

2024-02-07 12:33:00

AI訓練

2025-04-27 08:22:49

2021-08-25 17:03:09

模型人工智能PyTorch

2014-04-30 15:47:12

NEC

2024-09-14 14:15:00

數據訓練

2025-04-28 09:00:00

2025-03-17 08:25:00

模型AI訓練

2025-08-20 07:49:28

2023-12-13 13:49:00

模型訓練

2025-03-04 04:00:00

擴散模型DDPM

2024-11-19 13:17:38

視覺語言模型Pytorch人工智能
點贊
收藏

51CTO技術棧公眾號

在线一区二区三区做爰视频网站| 成人免费黄色大片| 色偷偷噜噜噜亚洲男人| 日韩精品aaa| 岛国毛片av在线| www国产成人免费观看视频 深夜成人网| 国产精品jvid在线观看蜜臀| 麻豆网址在线观看| 日韩理论电影中文字幕| 欧美日韩成人高清| 欧美一区二区中文字幕| 香蕉视频在线免费看| 成人黄色777网| 国产精品爽黄69天堂a| 国产精品16p| 水蜜桃久久夜色精品一区| 欧美精品一区二区在线观看| 91女神在线观看| 黄色污网站在线观看| 亚洲欧美一区二区久久| 久久综合伊人77777麻豆| 国产精品久久无码一三区| 国产九九精品| 欧美激情videos| 精品伦精品一区二区三区视频密桃| 国产精品天天看天天狠| 欧美精品日日鲁夜夜添| 国产精品动漫网站| 成人bbav| 亚洲成人www| 黄色污污在线观看| 天天综合视频在线观看| 2021中文字幕一区亚洲| 国产精品国产三级欧美二区| 一区二区三区精彩视频| 久久久久久久欧美精品| 91精品国产色综合久久不卡98口 | 国产精品wwwww| 亚洲羞羞网站| 国产精品国产三级国产有无不卡| 久久综合九色欧美狠狠| 污视频在线免费观看| 国产91精品精华液一区二区三区| 91精品视频免费看| 夜夜爽8888| 麻豆成人91精品二区三区| 国产国语刺激对白av不卡| 国产成人无码精品| 一区视频在线| 高清欧美性猛交xxxx黑人猛交| 免费网站观看www在线观| 图片区亚洲欧美小说区| www亚洲欧美| 中国1级黄色片| 久久看人人摘| 日韩中文在线中文网三级| 日本伦理一区二区三区| 久久影视一区| 久久久精品中文字幕| 国产高清视频免费在线观看| 天天综合网91| 欧美成人全部免费| 最新一区二区三区| 午夜日韩福利| 亚洲91精品在线| 99久在线精品99re8热| 国产欧美另类| 国产不卡视频在线| 亚洲性猛交富婆| 国产呦精品一区二区三区网站| 91免费人成网站在线观看18| 精品女同一区二区三区| 成人久久久精品乱码一区二区三区| 国产chinese精品一区二区| 色哟哟中文字幕| 久久久久久一级片| 亚洲一一在线| 日日夜夜天天综合入口| 亚洲成人精品在线观看| 国产成人精品视频ⅴa片软件竹菊| 欧美极品免费| 欧美一区午夜视频在线观看| 在线播放av网址| 精品在线91| 久久久国产精彩视频美女艺术照福利| 国产女片a归国片aa| 亚洲人成久久| 国产精品人成电影| 精品黑人一区二区三区国语馆| eeuss鲁片一区二区三区在线观看| 欧美精彩一区二区三区| 免费看美女视频在线网站| 亚洲午夜精品17c| 99久久国产宗和精品1上映| 亚洲精品成a人ⅴ香蕉片| 精品成人一区二区三区| 天天操天天舔天天射| 午夜亚洲福利| 国产成人精品免费久久久久 | 精品成人私密视频| 国产一级久久久久毛片精品| 欧美 日韩 国产一区二区在线视频 | 日本高清在线观看视频| 欧美日韩在线视频首页| 亚欧美在线观看| 久久精品国产亚洲5555| 神马国产精品影院av| 国产无码精品在线播放| 激情五月激情综合网| 精品日本一区二区| 日本美女在线中文版| 亚洲r级在线视频| 网站在线你懂的| 最新亚洲精品| 久久久亚洲天堂| 国产麻豆一精品一男同| 久久久精品日韩欧美| 日韩激情视频一区二区| 欧洲亚洲精品久久久久| 亚洲美女视频网| 国产无遮挡又黄又爽| 国产精品自在在线| 亚洲不卡中文字幕| 成人性生活视频| 精品av久久707| 欧美 日韩 国产 一区二区三区| 亚洲视频二区| 狠狠爱一区二区三区| 色呦呦网站在线观看| 欧美人妖巨大在线| 国产破处视频在线观看| 久久婷婷丁香| 久久久久网址| 蜜桃视频在线观看播放| 亚洲国产精品成人va在线观看| 女人18毛片毛片毛片毛片区二| 视频一区二区国产| 欧美国产二区| 伊伊综合在线| 亚洲精选一区二区| 看片网址国产福利av中文字幕| gogogo免费视频观看亚洲一| 欧美在线一区视频| 99re6热只有精品免费观看| 欧美成人剧情片在线观看| 国产熟女一区二区三区五月婷| 亚洲欧美自拍偷拍| 免费在线观看污网站| 91一区在线| 成人日韩在线电影| 黄色免费网站在线观看| 欧美福利视频一区| 91麻豆免费视频网站| 久草在线在线精品观看| 综合久久国产| 精品久久国产一区| 欧美黄色性视频| 天堂在线中文网| 欧美性猛交xxxx黑人猛交| 日韩在线免费观看av| 视频一区在线视频| 一区二区三区av在线| 久久久精品区| 久久免费视频在线观看| 午夜福利视频一区二区| 色综合久久综合网| 潮喷失禁大喷水aⅴ无码| 狠狠色伊人亚洲综合成人| 日韩不卡一二区| 成人福利免费在线观看| 国产91精品不卡视频| h视频在线播放| 欧美一区午夜精品| 韩国av中文字幕| 亚洲国产岛国毛片在线| 色姑娘综合天天| 国产精品乱看| 一区二区三区欧美成人| 51精品国产| 国产精品99久久久久久久久久久久| 91吃瓜网在线观看| 精品免费国产二区三区| 老熟妇仑乱一区二区av| 亚洲视频一区二区在线观看| 麻豆短视频在线观看| 男人的天堂亚洲在线| 在线国产精品网| 久久aimee| 国产欧美亚洲精品| 成人免费网站观看| 色妞一区二区三区| 人妻少妇一区二区三区| 欧美视频自拍偷拍| 日本少妇吞精囗交| 国产精品欧美久久久久一区二区| 国产精品一级无码| 天堂精品中文字幕在线| 国产a级黄色大片| 国产中文字幕一区二区三区 | 中文字幕亚洲乱码| 亚洲精品极品| 国产大尺度在线观看| 亚洲人成亚洲精品| 91传媒视频免费| 国产一区二区主播在线| 78色国产精品| 污片在线免费观看| 精品国产欧美成人夜夜嗨| 亚洲色欧美另类| 欧美tickling网站挠脚心| 久久这里只有精品9| 五月天丁香久久| 国产精品老熟女一区二区| 中文字幕免费观看一区| 国产 xxxx| 国产盗摄一区二区三区| 亚洲精品一二三四五区| 一本色道久久综合亚洲精品高清 | av网站网址在线观看| 亚洲人成网站免费播放| 欧美自拍第一页| 欧美一区二区三区公司| 一级特黄色大片| 91成人免费在线| 久久久免费高清视频| 亚洲福利视频三区| 欧美日韩成人免费观看| 日韩一区中文字幕| 综合 欧美 亚洲日本| 久久精品亚洲一区二区三区浴池| 白嫩情侣偷拍呻吟刺激| 粉嫩高潮美女一区二区三区| 成人三级做爰av| 精品一区二区成人精品| 拔插拔插华人永久免费| 免费人成网站在线观看欧美高清| 免费在线观看的av网站| 亚洲欧美网站| 免费高清在线观看免费| 国产日韩1区| 狠狠爱免费视频| 午夜在线精品偷拍| 久久婷婷五月综合色国产香蕉| 亚洲影院一区| 激情综合网婷婷| 日韩福利视频网| 日韩av片网站| 激情五月婷婷综合网| 青青草原播放器| 国产电影精品久久禁18| 精品伦一区二区三区| 丁香啪啪综合成人亚洲小说 | 久久久久久久久网站| 伊人影院在线视频| 欧美激情小视频| 精品人人视频| 国产91久久婷婷一区二区| 国产麻豆久久| 91免费看片网站| 懂色av一区二区| 欧美精品二区三区四区免费看视频| 天堂成人娱乐在线视频免费播放网站| 免费成人深夜夜行视频| 欧美日韩中文一区二区| 水蜜桃亚洲一二三四在线| 久久精品高清| 奇米777四色影视在线看| 亚洲黄色影院| 男女污污的视频| 国产在线视频不卡二| 中国xxxx性xxxx产国| 久久噜噜亚洲综合| 日韩在线观看免| 亚洲成人av一区二区| 人人妻人人爽人人澡人人精品| 精品视频在线免费看| 亚洲第一页在线观看| 日韩精品中文字幕有码专区| 97在线观看免费观看高清| 欧美超级乱淫片喷水| 亚洲性受xxx喷奶水| 国产欧美日韩综合精品| 国产精品白丝av嫩草影院| 欧美综合激情| 欧美99久久| 成人在线看视频| 国产麻豆精品久久一二三| 国产精品伦子伦| 1024成人网| 日本午夜视频在线观看| 欧美人与禽zozo性伦| 天天干在线观看| 久久精品国产99国产精品澳门| 国产在线精彩视频| 成人午夜小视频| 久久综合影院| 美女扒开大腿让男人桶| 美日韩一级片在线观看| 精品人妻伦一二三区久| 亚洲青青青在线视频| 欧美日韩a v| 亚洲第一综合天堂另类专| 午夜免费福利在线观看| 45www国产精品网站| 欧美日韩黄网站| 亚洲欧洲久久| 久久久久国内| 中文字幕 日本| 国产在线视频资源| 亚洲黄色成人| 在线观看av日韩| 波波电影院一区二区三区| 日本免费www| 午夜视频一区二区| 亚洲天堂中文网| 日韩精品亚洲元码| 日本电影在线观看| 国产精品免费久久久久影院| 久久超级碰碰| 午夜啪啪福利视频| 蜜乳av一区二区三区| 在线不卡av电影| 午夜激情综合网| 黄色av网站免费在线观看| 久久精品人人做人人爽| 日韩色淫视频| 色阁综合av| 久久激情一区| 一本加勒比北条麻妃| 红桃视频成人在线观看| 欧美视频一二区| 欧美国产视频一区二区| 超碰国产精品一区二页| 亚洲欧洲精品一区二区| 视频一区国产视频| 成人无码av片在线观看| 色综合久久久网| 日韩二区三区| 日本精品久久久久久久| 欧美禁忌电影网| 任你操这里只有精品| 成人av网址在线| 国产精品suv一区二区69| 精品国精品自拍自在线| 日本无删减在线| 国产视频99| 亚洲巨乳在线| 国产艳俗歌舞表演hd| 91久久国产综合久久| 一广人看www在线观看免费视频| 国产精品免费电影| 99精品综合| 4438x全国最大成人| 一区二区三区加勒比av| 成人久久久精品国产乱码一区二区 | 日批视频免费在线观看| 亚洲国产欧美一区二区三区同亚洲| 欧美理论电影| 国内一区二区三区在线视频| 亚洲免费精品| 公侵犯人妻一区二区三区| 91国产精品成人| 欧美jizz18hd性欧美| 91久久偷偷做嫩草影院| 极品中文字幕一区| 瑟瑟视频在线观看| 色国产综合视频| 国产一二区在线| 粉嫩高清一区二区三区精品视频 | 曰韩不卡视频| 激情综合网激情| 欧美色图亚洲天堂| 亚洲成人a**站| 色天使综合视频| 亚洲一区美女| 福利电影一区二区| 国产91国语对白在线| 日韩一区二区久久久| 亚洲91网站| 欧美女人性生活视频| 成人免费在线观看入口| 亚洲成a人片在线| 日韩美女在线观看一区| 亚洲色图88| 亚洲欧美视频在线播放| 欧美人伦禁忌dvd放荡欲情| 国产乱妇乱子在线播视频播放网站| 奇米影视首页 狠狠色丁香婷婷久久综合 | 熟妇人妻va精品中文字幕 | 国产一区二区三区四区福利| 麻豆国产精品| 久久久久久香蕉| 亚洲自拍偷拍图区| 成人高潮成人免费观看| 国产精品一区二区三区四区五区| 日韩经典一区二区| 国产网友自拍视频| 日韩在线中文字| 夜夜春成人影院| 亚洲av人人澡人人爽人人夜夜|