この記事では、あなたにその背後にある基本的なコアの直感を与えるために、PyTorch で実装された基本的な拡散モデルをトレーニングするコードで、拡散モデルの本質を分解しようとします。 Definition: 定義 : ↓↓↓ データは、マルコフの連鎖に続く分散段階を通じて音を鳴らす(それは毎回のステップが前回の時間段階に依存するストーカスティックな出来事の連続であるため)、その後、逆のプロセスを学ぶことで再構築される。 Diffusion model 少し振り返って、拡散モデルの背後にあるコアアイデアを理解しましょう。 著者はこれを以下のように記述する。 “ ”[1] Deep Unsupervised Learning using Non-Equilibrium Thermodynamics(非均衡熱力学) Deep Unsupervised Learning using Non-Equilibrium Thermodynamics(非均衡熱力学) 非均衡統計物理学にインスピレーションを与えた本質的なアイデアは、データ分布における構造を、反復的な前進分散プロセスを通じて体系的に、ゆっくりと破壊することです。 The essential idea, inspired by non-equilibrium statistical physics, is to systematically and slowly destroy structure in a data distribution through an iterative forward diffusion process. We then learn a reverse diffusion process that restores structure in data, yielding a highly flexible and tractable generative model of the data. 拡散プロセスは本質的に前方と逆の段階に分かれています。拡散モデルを使用して現実的な高品質な画像を生成する例を挙げてみましょう。 We start with a real, high-quality image and add noise to it in steps to arrive at pure noise. Basically, we want to destroy the structure in the non-random data distribution that exists at the start. Forward Diffusion Phase: Here, q is our forward process, the output of the forward process at time step t, is an input at time step t. N is a normal distribution with mean and variance. x_t x_(t-1) sqrt(1 - β_t) x_{t-1} β_tI [also called the schedule] here controls the amount of noise added at time step = t whose value ranges from 0→1. Depending on the type of schedule you use, you arrive at what is close to pure noise sooner or later. i.e. β_1,…,β_T is a variance schedule (that is either learned or fixed) which, if well-behaved, ensures that is almost an isotropic Gaussian at sufficiently large T. β_t x_T This is where the actual machine learning takes place. As the name suggests, we try to transform the noise back into a sample from the target distribution in this phase. i.e. the model is learning to denoise pure Gaussian noise into a clean image. Once the neural network has been trained, this ability can be used to generate new images out of Gaussian noise through step-by-step reverse diffusion. Reverse Diffusion Phase: Since one cannot readily estimate , we need to learn a model to approximate the conditional probabilities for the reverse diffusion process. q(x_(t-1)|x_t) p_theta We want to model the probability density of an earlier time step given the current. If we apply this reverse formula for all time steps T→0, we can trace our steps back to the original data distribution. The time step information is provided usually as positional embeddings to the model. It is worth mentioning here that the diffusion model at a given timestep to make it equivalent to the image at the start, and not just the delta between the current and previous time step. However, we only subtract part of it and move to the next step. That is how the diffusion process works. predicts the entire noise to be removed 基本的には、分散型モデルを ガウシアの騒音を増やすことで、そして、 この騒々しいプロセスを逆転させることによって破ったもの。トレーニングの後、単純にデータを生成するために、分散モデルを使用することができます。 詳細な数学的な説明については、このブログ(4)をご覧ください。 destroys the structure in training data learns to recover passing randomly sampled noise through the “learned” denoising process Implementation: 実施: わたしたちは使います。 102カテゴリーにわたる花の画像を含む、この記事の目的のために非常にシンプルなモデルを構築し、拡散モデルのコアアイデアと実装を理解する。 Oxford Flowers102データセット ガウシアンの合計もまたガウシアンであるため、騒音の加算は連続的であるが、特定の時間段階のための入力画像の騒音バージョンを事前計算することができる。 Forward phase: def linear_beta_schedule(timesteps, start=1e-4, end=2e-2): """Creates a linearly increasing noise schedule.""" return torch.linspace(start, end, timesteps) def get_idx_from_list(vals, t, x_shape): """ Returns a specific index t of a passed list of values vals. """ batch_size = t.shape[0] out = vals.gather(-1, t.cpu()) return out.reshape(batch_size, *((1,) * (len(x_shape) - 1))).to(t.device) def forward_diffusion_sample(x_0, t, device="cpu"): """ Takes an image and a timestep as input and returns the noisy version of it.""" noise = torch.randn_like(x_0) sqrt_alphas_cumprod_t = get_index_from_list(sqrt_alphas_cumprod, t, x_0.shape) sqrt_one_minus_alphas_cumprod_t = get_idx_from_list(sqrt_one_minus_alphas_cumprod, t, x_0.shape) return sqrt_alphas_cumprod_t.to(device) * x_0.to(device) + sqrt_one_minus_alphas_cumprod_t.to(device) * noise.to(device), noise.to(device) T = 300 # Total number of timesteps betas = linear_beta_schedule(T) # Precompute values for efficiency alphas = 1. - betas alphas_cumprod = torch.cumprod(alphas, dim=0) alphas_cumprod_prev = F.pad(alphas_cumprod[:-1], (1, 0), value=1.0) sqrt_recip_alphas = torch.sqrt(1. / alphas) sqrt_alphas_cumprod = torch.sqrt(alphas_cumprod) sqrt_one_minus_alphas_cumprod = torch.sqrt(1. - alphas_cumprod) posterior_variance = betas * (1. - alphas_cumprod_prev) / (1. - alphas_cumprod) This is the denoising phase where the model learns to estimate the noise that was added at each time step. We use a simple U-Net neural network that takes in noisy image and time step [provided as positional embedding] and predicts the noise. シンプルなU-Netニューラルネットワークを使用して、騒々しい画像とタイムステップ(ポジションの埋め込みとして提供)をとる。 以下の層は、時刻の文脈をキャプチャしてコンヴュレーション出力を条件づけるシノイドタイムステップの埋め込みを使用しています. This architecture is inspired by [2] and optimized variants presented in [3]. Reverse Diffusion Phase: ConvBlock class SinusoidalPositionEmbeddings(nn.Module): def __init__(self, dim): super().__init__() self.dim = dim def forward(self, t): half_dim = self.dim // 2 scale = math.log(10000) / (half_dim - 1) freqs = torch.exp(torch.arange(half_dim, device=t.device) * -scale) angles = t[:, None] * freqs[None, :] return torch.cat([angles.sin(), angles.cos()], dim=-1) class ConvBlock(nn.Module): def __init__(self, in_channels, out_channels, time_emb_dim, upsample=False): super().__init__() self.time_mlp = nn.Linear(time_emb_dim, out_channels) self.upsample = upsample self.conv1 = nn.Conv2d(in_channels * 2 if upsample else in_channels, out_channels, kernel_size=3, padding=1) self.transform = ( nn.ConvTranspose2d(out_channels, out_channels, kernel_size=4, stride=2, padding=1) if upsample else nn.Conv2d(out_channels, out_channels, kernel_size=4, stride=2, padding=1) ) self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1) self.bn1 = nn.BatchNorm2d(out_channels) self.bn2 = nn.BatchNorm2d(out_channels) self.relu = nn.ReLU() def forward(self, x, t): h = self.bn1(self.relu(self.conv1(x))) time_emb = self.relu(self.time_mlp(t))[(..., ) + (None,) * 2] h = h + time_emb h = self.bn2(self.relu(self.conv2(h))) return self.transform(h) class SimpleUNet(nn.Module): """Simplified U-Net for denoising diffusion models.""" def __init__(self): super().__init__() image_channels = 3 down_channels = (64, 128, 256, 512, 1024) up_channels = (1024, 512, 256, 128, 64) output_channels = 3 time_emb_dim = 32 self.time_mlp = nn.Sequential( SinusoidalPositionEmbeddings(time_emb_dim), nn.Linear(time_emb_dim, time_emb_dim), nn.ReLU() ) self.init_conv = nn.Conv2d(image_channels, down_channels[0], kernel_size=3, padding=1) self.down_blocks = nn.ModuleList([ ConvBlock(down_channels[i], down_channels[i+1], time_emb_dim) for i in range(len(down_channels) - 1) ]) self.up_blocks = nn.ModuleList([ ConvBlock(up_channels[i], up_channels[i+1], time_emb_dim, upsample=True) for i in range(len(up_channels) - 1) ]) self.final_conv = nn.Conv2d(up_channels[-1], output_channels, kernel_size=1) def forward(self, x, t): t_emb = self.time_mlp(t) x = self.init_conv(x) skip_connections = [] for block in self.down_blocks: x = block(x, t_emb) skip_connections.append(x) for block in self.up_blocks: skip_x = skip_connections.pop() x = torch.cat([x, skip_x], dim=1) x = block(x, t_emb) return self.final_conv(x) model = SimpleUnet() トレーニングの目的は、単純なMSE損失であり、実際の騒音とその騒音のモデルの予測の違いを計算することです。 def get_loss(model, x_0, t, device): x_noisy, noise = forward_diffusion_sample(x_0, t, device) noise_pred = model(x_noisy, t) return F.mse_loss(noise, noise_pred) 最後に、300の時代のモデルをトレーニングした後、純粋なガウシアの騒音をサンプル化し、学習した逆拡散プロセスを通じてそれを供給することによって、花の現実的なイメージを生成し始めることができます。 References: Deep Unsupervised Learning using Nonequilibrium Thermodynamics Sohl-Dickstein, J. et al.[2015] デノーシング・ディファッション・シンボリズム・モデル Ho et al. [2020] Diffusion Models Beat GANs on Image Synthesis Dhariwal and Nichol [2021] この素晴らしいブログは、拡散モデルの背後にある数学に深く浸透するためのものです。 This repository access to a collection of resources and papers on Diffusion Models. このリポジトリは、ディファッションモデルに関するリソースと論文のコレクションにアクセスできます。 この驚くべきブログ このリポジトリ