File size: 2,889 Bytes
e9d1f07
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
"""

    This file contains implementations of the forward diffusion process

    Current Models:
    
    1) Gaussian Diffusion

"""
import torch
from torch import nn

from .beta_schedules import *

class ForwardModel(nn.Module):
    """
        (Forward Model Template)
    """
    
    def __init__(self,
                 num_timesteps=1000,
                 schedule='linear'
                ):
        
        super().__init__()
        self.schedule=schedule
        self.num_timesteps=num_timesteps
     
    @torch.no_grad()
    def forward(self, x_0, t):
        """
            Get noisy sample at t given x_0
        """
        raise NotImplemented
    
    @torch.no_grad()
    def step(self, x_t, t):
        """
            Get next sample in the process
        """
        raise NotImplemented   
        

class GaussianForwardProcess(ForwardModel):
    """
        Gassian Forward Model
    """
    
    def __init__(self,
                 num_timesteps=1000,
                 schedule='linear'
                ):
        
        super().__init__(num_timesteps=num_timesteps,
                         schedule=schedule
                        )
        
        # get process parameters
        self.register_buffer('betas',get_beta_schedule(self.schedule,self.num_timesteps))
        self.register_buffer('betas_sqrt',self.betas.sqrt())
        self.register_buffer('alphas',1-self.betas)
        self.register_buffer('alphas_cumprod',torch.cumprod(self.alphas,0))
        self.register_buffer('alphas_cumprod_sqrt',self.alphas_cumprod.sqrt())
        self.register_buffer('alphas_one_minus_cumprod_sqrt',(1-self.alphas_cumprod).sqrt())
        self.register_buffer('alphas_sqrt',self.alphas.sqrt())
     
    @torch.no_grad()
    def forward(self, x_0, t, return_noise=False):
        """
            Get noisy sample at t given x_0
            
            q(x_t | x_0)=N(x_t; alphas_cumprod_sqrt(t)*x_0, 1-alpha_cumprod(t)*I)
        """
        assert (t<self.num_timesteps).all()
        
        b=x_0.shape[0]
        mean=x_0*self.alphas_cumprod_sqrt[t].view(b,1,1,1)
        std=self.alphas_one_minus_cumprod_sqrt[t].view(b,1,1,1)
        
        noise=torch.randn_like(x_0)
        output=mean+std*noise        
        
        if not return_noise:
            return output
        else:
            return output, noise
    
    @torch.no_grad()
    def step(self, x_t, t, return_noise=False):
        """
            Get next sample in the process
            
            q(x_t | x_t-1)=N(x_t; alphas_sqrt(t)*x_0,betas(t)*I)
        """
        assert (t<self.num_timesteps).all()
        
        mean=self.alphas_sqrt[t]*x_t
        std=self.betas_sqrt[t]
        
        noise=torch.randn_like(x_0)
        output=mean+std*noise        
        
        if not return_noise:
            return output
        else:
            return output, noise