Nvidia Labs가 GAN의 train속도 및 안정성향상을 위해 개발한 기술. 전체 해상도 img에 바로 GAN을 도입❌
4×4 pixel의 저해상도 img로 G, D를 훈련 → 훈련과정층에 점진적 추가 → 해상도를 높인다.
점진적 훈련
∙ [Vanilla GAN]: [G]: 처음부터 복잡한 고해상도 img로 작동 이는 train초기, 고수준의 구조학습속도가 느릴 수 있다.
그렇다면, 저해상도 Img를 출력하게 경량 GAN을 훈련시키고 이를 기반으로 해상도를 점진적으로 높이는게 낫지 않을까?
4×4 pixel의 저해상도 img로G, D를 훈련 → 훈련과정층에 점진적 추가 → 해상도를 높인다.
progressive training
이를 progressive training, 점진적 훈련이라 한다.
∙ (a) [Generator]: ProGAN은 Interpolation을 이용, 4×4 pixel로 압축된 trainset부터 시작해 단계적으로 훈련한다. 그 후, z(latent input noise vector)를 4×4×3 img로 변환하게 생성자를 훈련시킨다.
[Discriminator]: 4×4×3인 input img를 하나의 스칼라 예측으로 변환한다. 생성자와 판별자를 확장하려면 층을 추가해야하는데, 이는 위 그림과 같다. toRGB: feature map을 RGB img로 변환하는 합성곱층 fromRGB: RGB img를 feature map으로 변환하는 합성곱층 ∙ (b), (c) [Generator]: ∙ transition단계: 새로운 UpSampling과 Conv층이 기존 신경망에 추가. 기존에 훈련된 toRGB층의 출력유지를 위해 Skip Connection이 추가. 새 층은 처음에 α로 masking된다. (α는 transition단계동안 0에서 1로 점진적으로 증가, 기존 toRGB층의 출력을 줄이고 새 toRGB층의 출력을 늘림.) 이는 새 층으로 이전될 때, 신경망이 받을 변화의 충격을 회피시킨다. 즉, 기존 toRGB층을 통과하는 data가 사라지면 신경망은 stabilization단계로 들어간다.
∙ stabilization단계: 이 단계에서 기존 toRGB층을 통한 data흐름없이 추가훈련으로 신경망의 출력을 fine-tuning한다. [Discriminator]: 판별자 또한 비슷한 과정을 진행한다. 여기서 DownSampling과 Conv층을 추가한다. 이번에는 신경망이 시작될 때, input_img바로뒤에 추가된다.
기존 fromRGB층은 residual connection으로 연결되며 transition단계에서 새층으로 전환됨에따라 점진적으로 제거된다. stabilization단계에서는 판별자가 새 층으로 fine-tuning한다. 이 과정은 4×4 img부터 전체 해상도 img인 1024×1024에 도달할 때까지 계속된다.
주요 기술.
∙ minibatch standard deviation
특성값의 표준편차를 모든 픽셀과 mini-batch에 걸쳐 평균, (상수)특성으로 판별자에 추가하는 층이다. 장점: 생성자가 출력에서 더 많은 다양성을 부여하는데 도움이 됨. mini-batch에서 다양성이 낮으면 표준편차가 작아지고, 판별자는 이 특성으로 real/fake batch를 구별가능하게 되어 생성자를 독려하게 한다.
∙equalized learning rate
보통 신경망의 가중치는 He initialize로 초기화한다. 이를 통해 입력개수가 많아지면 가중치가 0에 가까운 값으로 초기화되어, train과정의 안정성이 향상된다. 특히 이때, Adam이나 RMSProp을 사용하는데, 여기서 문제가 발생한다.
이런 optimizer들은 weight에 대한 gradient update를 정규화한다. 즉, update크기가 weight크기와 무관하다. 하지만 범위가 큰 가중치(= input이 적은 층)가 범위가 작은 가중치(= input개수가 많은 층)보다 조정하는데 상대적으로 오래걸림을 의미한다. 이로인해 ProGAN에서 생성자와 판별자의 여러층에서 train속도간 불균형이 발생하기에 균등 학습률을 활용한다.
ProGAN은 표준정규분포로 초기화된다. 즉, 층이 호출될 때마다 He초기화 계수에 따라 가중치의 크기가 조정된다.
cf) He initialize: 표준편차가 층에대한 입력개수의 제곱근에 반비례한 Gauss분포
∙Pixel-wise Normalization
ProGAN은 Batch Normalization이 아닌, 픽셀별 정규화를 사용한다. - 각 픽셀의 feature vector가 단위길이로 정규화, - signal이 신경망으로 전파되어 제어불능상태가 되는 문제를 방지.
2. StyleGAN
prev.
StyleGAN은 ProGAN논문의 초기 아이디어를 기반으로한다. (사실 판별자는 동일, 생성자만 바뀌었다.)
GAN 훈련 시, 고수준특성에 해당하는 latent space vector구별이 어렵다. ex) 주근깨를 많이 넣으려 latent space img를 조정하면 배경색이 바뀌는경우.
StyleGAN은 다양한 지점에서 Style vector를 신경망에 명시적으로 주입, 일부는 고수준특성(ex. 얼굴방향)을 일부는 저수준특성(ex. 처피뱅, 시스루뱅, ...)을 제어한다.
Mapping Network: f
input noise z∈Z를 다른 latent space w∈W로 변환하는 간단한 FFN.
목적: 생성자는 noise있는 input vector를 후속 style생성층에서 쉽게 선택가능하게 서로 다른 변동요소로 해체가능. 이를 통해 synthesis과정(주어진 style을 갖는 img생성과정)과 이미지 스타일선택과정(mapping신경망)을 분리한다.
Synthesis Network
mapping network가 제공하는 style로 실제 Img생성. 위 그림에서 볼 수 있듯, style벡터 w는 합성신경망 여러지점에서 매번 다른 밀집연결층 A를 통해 주입된다. A는 bias벡터 yb와 scale벡터 ys 2개를 출력한다.
이 벡터가 신경망의 해당지점에 주입해야할 특정 style을 정의한다. 즉, 생성될 img를 특정 style방향으로 이동시키는 방법을 합성신경망에 전달한다. 이 조정은 Adaptive Instance Normalization층으로 이뤄진다.
∙ Adaptive Instance Normalization.
AdaIN층은 reference style의 편향 yb과 스케일 ys을 이용해 각 feature map x의 평균과 분산을 조정하는 신경망층이다. AdaIN층은 층간 Style정보가 새지 않게 방지해 각 층에 주입되는 Style벡터가 해당 층의 특성에만 영향을 미치게 한다. 이를통해 원본 z벡터보다 훨씬 덜 얽힌 latent vector w를 만들 수 있다.
cf) ProGAN구조기반이기에 점진적으로 훈련된다. 즉, latent vector w를 통해 생성된 img를 완전히 제어가능하며 합성신경망 여러지점에서 w벡터를 바꿔 다양한 수준의 style을 변경가능하다.
∙Style Mixing.
trick을 사용, 생성자가 훈련 중 인접한 style간 상관관계를 활용불가능하게한다. = 각 층에 삽입된 style이 가능한 얽히지 않게 함.
하나의 latent vector z만 sampling하지 않고 두 style vector(w1, w2)에 대응하는 두 latent vector(z1, z2)가 sampling된다.
그 후, 각 층에서 w1, w2 둘 중 하나를 random하게 선택해 vector간의 가능한 모든 상관관계를 끊는다.
∙Stochastic variation.
합성신경망은 개별 머리카락의 batch나 얼굴뒤 배경같은 stochastic detail을 위해 합성곱층 다음에 (학습된 broadcasting층 B를 통해) noise를 추가한다. 여기서도 noise가 주입되는 깊이가 img에 미치는 영향의 정도를 결정한다.
또한, style입력과 Noise입력에는 img에서 충분한 분산을 생성할만큼의 확률성이 이미 존재한다.
출력결과.
여기서 두 Source A, B이미지는 다른 w벡터로 생성된다. 두 img를 합치려고 A의 w벡터를 CNN에 통과, 어느 특정지점에서 B의 w벡터로 바꾼다.
🤔이런 변경이 초기해상도에 발생하면? 자세, 얼굴모양, 안경같이 B에 있는 큰 특징의 Style이 A로 전달된다.
🤔 이런 변경이 좀 나중에 발생하면? B에서 색깔, 얼굴의 미세형태같은 미세특징의 Style이 A로전달된다. (이때, A의 큰 특징은 유지됨.)
3. StyleGAN2
prev.
이 모델은 StyleGAN기반으로 생성품질향상을 위해 몇가지 주요 변경사항이 있다. StyleGAN과는 생성자, 판별자 모두 다르다. artifact: 물방울처럼 번진것 같은 현상StyleGAN2는 위 그림같이 img의 Artifact가 거의 발생하지 않는다. 이런 Artifact는 StyleGAN의 AdaIN층으로 인해 발생하는것으로 밝혀졌다.
Weight Mod와 Demod
Artifact문제 해결을 위해 아래 그림 (d)처럼 AdaIN층을 제거하고 가중치 변조(modulation)와 복조(demodulation)단계로 대체한다.
w는 합성곱의 가중치로 runtime에 StyleGAN2의 변조∙복조단계에서 직접 update된다. 이에비해 StyleGAN의 AdaIN층은 텐서가 신경망을 통과할 때 해당 텐서에 대해 작동한다. StyleGAN의 AdaIN층은 단순 instance normalization에 이은 Style변조(scale+bias)에 해당한다. StyelGAN2는 위 그림처럼 Conv층의 출력이 아닌 Runtime에 Conv층의 Weight에 직접 Style변조 및 정규화(복조)를 적용한다.
StyleGAN2에서 각 Dense layer는 하나의 Style벡터 si를 출력한다. (i: 해당하는 Conv층에 있는 input channel index) 이 Style벡터는 아래식처럼 Conv층의 가중치에 적용되는데, 이를 변조단계라 한다: w'i,j,k = si∙wi,j,k (j: 층의 output channel index , k: 공간차원 Index) 이후 가중치를 정규화해 다시 단위표준편차를 갖도록해 train안정성을 보장하는 복조단계를 거친다: w''i,j,k = w'i,j,k / √∑i,kw'i,j,k2 + ε
결과적으로 간단한 변경을 통해 물방을 artifact방지는 물론 Style벡터로 생성된 Img제어 + 출력품질을 높인다.
Path Length Regularization
StyleGAN구조에 또다른 변경사항이 있는데, Loss Function에 경로길이규제(Path Length Regularization)라는 추가적인 penalty항을 주는 것이다.
latent space에서 어느 방향이든 고정된 크기의 거리이동 시 img에 고정된 크기변화가 발생하는 것이 좋다. 그렇기에 latent space를 가능한 매끄럽고 균일하게 하는것이 선호된다.
위 속성을 장려하기위해 Gradient Penalty가 있는 일반적 Wasserstein Loss로 아래항 최소화를 목적으로 한다: 손실함수 규제항 효율성을 위해 16-batch마다 적용하는 Lazy Regularization기법으로 두드러진 성능저하가 발생하지도 않는다.
No Progressive Training
또 다른 주요변경사항은 training방식으로 일반적 점진적 train채택이 아닌, 생성자의 Skip Connection과 판별자의 Residual Connection을 활용 →신경망을 하나로 훈련한다.
즉, 더는 각기 다른 해상도에서 독립적으로 훈련하고 혼합할 필요가 없다.
training 진행시, 생성자가 판별자를 속이기 위해 진짜같은 img를 만들어야하는데,
위 그림은 고해상도 층이 진짜같은 img를 만드는데 점차 지배적이게 됨을 보여준다.
∙ Attention을 사용하지 않는 GAN기반 모델은 Convolution feature map이 local한 정보만 처리 ∙CNN은 channel수를 늘려야만 receptive field가 넓어져 좀 더 넓은 범위를 포착가능. ∙ 이 과정에서 고수준특징을 잡기위해 정확한 위치정보를 잃는 단점이 발생.
→ Self-Attention을 도입한 SAGAN으로 이런 문제를 해결. 붉은 점: 몸통부분 픽셀 (즉, Attention이 몸통부분의 픽셀에 집중.) 초록 점:배경부분 픽셀 (이 Attention은 머리와 뒷배경에 집중.) 파란 점:꼬리부분 픽셀 (이 Attention은 멀리 떨어진 다른 꼬리픽셀에 집중.) Attention을 사용하지 않고 이렇게 넓은 범위의 pixel-independency를 유지하기란 어려운데, 특히나 새 꼬리처럼 길고 얇은 구조의 경우, 픽셀의존성 유지가 더욱 어렵다.
BigGAN
DeepMind에서 개발한 모델로 SAGAN의 아이디어를 확장시켰다. ImageNet에서 훈련된 BigGAN으로 생성된 img 물론, 추가된 내용중 매우 혁신적인 내용도 존재한다:
∙ Truncation Trick : train 시, latent분포로 z~N(0,I)를 사용하지만 sampling 시, truncated normal distribution을 사용한다 (= truncated_threshold보다 작은 z를 sampling한다.) 이때, truncated_threshold가 작을수록 다양성은 줄어들지만 생성sample신뢰도는 커진다.
임계값은 좌측부터 2, 1, 0.5, 0.04
BigGAN의 batch_size는 2048로 SAGAN의 256보다 8배 더 크다. 각 층의 channel_size도 약 50% 증가했다.
즉, SAGAN보다 BigGAN은 구조적으로 향상되었는데, 여기서 Shared Embedding과 Orthogonal Regularization이 포함된다. latent vector z를 첫번째 층뿐만아니라 Generator의 층마다 사용한다.
VAE에서 학습한 표현이 연속적이 아닌, 이산적일 수 있음을 기반으로 만들어졌다. 사후붕괴로 인해 연속적 latent space 형성하는 VAE에서 흔히 발견되는 몇가지 문제를 피하여 고품질결과를 출력한다.
[사후붕괴; posterior collaps]: 지나치게 강력한 Decoder로 학습된 latent spacce가 유용하지 않은 경우.
cf) OpenAI의 DALLE∙1 또한 VQ-VAE와 유사한 이산 latent space의 VAE를 활용한다.
Discrete Latent Space
해당 인덱스에 연관된 학습된 벡터목록(= codebook)을 의미한다.
[VQ-VAE의 Encoder]: input_img를 codebook과 비교가능한 더 작은 vector_grid로 축소하는 역할. 그 후 각 grid정사각형 벡터에 가장 가까운 codebook vector를 decoder로 전달해 decoding한다.
codebook: 길이가 d(= embedding_size)인 학습된 벡터의 목록. 이 길이는 encoder 출력과 decoder 입력의 channel수와 일치한다.
Codebook은 주어진 img내용을 이해하고 Encoder Decoder가 공유하는 학습된 이산적인개념의 집합이다. 이를 통해 Encoder가 grid사각형 라벨을 Decoder에게 의미있는 특정 code vector로 채울 수 있다. ∴ VQ-VAE의 손실함수는 Encoder의 출력벡터가 Codebook의 벡터에 최대한 가까워지도록하는 2가지항(alignment loss, commitment loss)으로 만들어진 재구성 손실이다. 이 항이 일반적인 VAE에 있는 Encoding된 분포와 표준정규분포사이 KLD로 대신한다. 다만, VQ-VAE는 새 img생성할 때마다 Decoder에 전달할 때, code grid를 어떻게 sampling해야할 지 의문점이 존재한다. 이 문제를 해결하기위해, PixelCNN으로 이전 codevector가 주어지면, Grid의 Codevector를 예측한다. 즉, "VAE처럼 prior분포가 전적이 아니라 모델에 의해 학습"된다.
VQ-GAN은 위 그림구조와 같으며, VQ-VAE구조에 몇가지 주요변경사항을 적용한다:
① Loss에 적대적항을 추가하는 GAN판별자를 포함. 다만, VQ-GAN에도 VQ-VAE가 여전히 들어가며, GAN판별자는 VAE대체가 아닌 추가적 구성요소이다.
②GAN판별자는 전체img를 한번에 보지 않고, img의 작은 patch의 real/fake를 예측 판별자예측의 개별요소는 patch기반이기에 patch style을 사용해 결정을 내린다. VAE는 실제보다 더 흐릿한 img를 생성하는데, 판별자는 더 선명한 img생성을 독려한다.
③ VQ-GAN은 input pixel을 VAE Decoder의 output pixel과 비교하는 단일 MSE재구성손실을 사용하지 않는다. 대신, Encoder의 중간층과 이에 해당하는 Decoder층에서 feature map간 차이를 계산하는 "perceptural Loss항"을 사용한다.
④ PixelCNN대신 Transformer를 모델의 AR부분으로 사용. Code Sequence를 생성하게 train. Transformer는 VQ-GAN이 완전히 train된 후 별도의 단계에서 train. sliding window내의 token만 사용한다.
ViT VQ-GAN
[Vector-quantized Image Modeling with Improved VQGAN]논문은 VQ-GAN을 더 확장한 버전이다. VQ-GAN의 Convolutional Encoder-Decoder를 Transformer로 교체한다.
∙ Encoder: ViT
img를 일련의 8×8patch로 나누고 이 patch를 tokenize하여 Encoder Transformer에 input으로 주입한다.
구체적으로, ViT VQ-GAN은 겹치지 않는 input_patch를 먼저 펼친 후 저차원 embedding공간으로 투영하고, Positional Embedding을 추가. 그 후, 이 sequence를 ViT에 주입. 만들어진 embedding은 학습된 codebook에 따라 quantize된다.
Decoder Transformer모델이 이런 code를 처리. 전체 Encoder-Decoder모델은 하나의 End2End로 훈련된다: 기존 VQ-GAN모델처럼 훈련의 두번째 단계에서 AutoRegressive Decoder Transformer를 사용해 Code Sequence를 생성한다.
따라서 ViT VQ-GAN에는 GAN Discriminator와 학습된 CodeBook이외에도 총 3개의 Transformer가 존재한다. ViT VQ-GAN으로 생성된 ImageNet Sample Image
5. 요약
prev.
ProGAN[2017]: 선구적으로 개발한 점진적 훈련개념
StyleGAN[2018]: 특정 style벡터 생성 (by mapping신경망 & 다양한 해상도 style삽입)
StyleGAN2[2020]: path length regularization같은 추가개선사항 + AdaIN를 가중치 변조∙복조단계로 대체 이는 신경망을 "점진적으로 훈련하지 않고도" 점진적 해상도개선이라는 좋은 속성을 유지시킴.
SAGAN[2018]: Attention개념을 GAN에 포함, 공간차원에 정보를 분산시켜 장거리 종속성을 감지.
BigGAN[2018]: 위 아이디어를 확장, 더 큰 신경망을 훈련
VQ-GAN[2021]: 여러 유형의 생성모델을 결합, 이산잠재공간이 있는 VAE의 개념을 도입, VQ-VAE를 기반으로 판별자가 적대손실항을 추가해 덜 흐릿하게 VAE가 생성하게함.
ViT VQ-GAN[2021]: 위 아이디어를 확장, Transformer로 Encoder-Decoder를 교체
퇴근이 제일 좋다는 직장인의 말에 공감이 점점된다ㅋㅋㅋ 아침출근때문에 그냥 졸리다ㅋㅋ 피곤🩸하고ㅠㅠ
🏋🏻 운동! (19:00 -)
이제 3대 운동보단 좀 더 세분화해서 A,B루틴 안하는 날에는 가슴,삼두, 등,이두, 어께 위주로 해봐야겠다. 아 그리고 데드나 스쿼트의 경우에는 조금 텀을 둬야겠다... 격일마다 무겁게만 하다보니 오히려 퍼포먼스가 안나오는 느낌? 그래서 스쿼트와 데드의 경우에는 일주일에 1~2번정도만 본세트무게로❗️ 나머지는 평소드는 무게의 8~90%정도의 중량만 들어야겠당
[정리]: 5x5 Strength + Local Muscle Strength Training for me
퇴근이 제일 좋다는 직장인의 말에 공감이 점점된다ㅋㅋㅋ 아침출근때문에 그냥 졸리다ㅋㅋ 피곤🩸하고ㅠㅠ
🏋🏻 운동! (19:00 -)
이제 3대 운동보단 좀 더 세분화해서 A,B루틴 안하는 날에는 가슴,삼두, 등,이두, 어께 위주로 해봐야겠다. 아 그리고 데드나 스쿼트의 경우에는 조금 텀을 둬야겠다... 격일마다 무겁게만 하다보니 오히려 퍼포먼스가 안나오는 느낌? 그래서스쿼트와 데드의 경우에는 일주일에 1~2번정도만 본세트무게로❗️ 나머지는 평소드는 무게의 8~90%정도의 중량만들어야겠당
[정리]: 5x5 Strength + Local Muscle Strength Training for me
마찬가지로 동편제(한식): 불향돼지불백? 후식으로는 내돈내산 블루베리 스무디!! << 2번째 맛도리!!!
📖 공부! (13:30-18:00)
GAI 이어서 진행!
🚍 퇴근! (18:30 - 19:00)
퇴근이 제일 좋다는 직장인의 말에 공감이 점점된다ㅋㅋㅋ 아침출근때문에 그냥 졸리다ㅋㅋ 피곤🩸하고ㅠㅠ
🏋🏻 운동! (19:00 -)
이제 3대 운동보단 좀 더 세분화해서 A,B루틴 안하는 날에는 가슴,삼두, 등,이두, 어께 위주로 해봐야겠다. 아 그리고 데드나 스쿼트의 경우에는 조금 텀을 둬야겠다... 격일마다 무겁게만 하다보니 오히려 퍼포먼스가 안나오는 느낌? 그래서스쿼트와 데드의 경우에는 일주일에 1~2번정도만 본세트무게로❗️ 나머지는 평소드는 무게의 8~90%정도의 중량만들어야겠당
[정리]: 5x5 Strength + Local Muscle Strength Training for me
<해석 끝> - Chapter 6 읽고 공부하기 - Chapter 7 읽고 공부하기(短) - Chapter 8 읽고 공부하기(短) - Chapter 9 읽고 공부하기(短) - Chapter 10 읽고 공부하기 - Chapter 12 읽고 공부하기 - Chapter 17 읽고 공부하기(短) - Chapter 18 읽고 공부하기(短) - Chapter 19 읽고 공부하기(短) - Chapter 20 읽고 공부하기
<해석도 해야할 것.> - Chapter 5 읽고 공부하기(短) - Chapter 11 읽고 공부하기 - Chapter 13 읽고 공부하기 - Chapter 14읽고 공부하기 - Chapter 15읽고 공부하기 - Chapter 16읽고 공부하기
3. Generative Deep Learning Part 1. Intro. Generative Deep Learning - Chapter 1. Generative Modeling - Chapter 2. 딥러닝
Part 2. Six Generative Modeling Method. - Chapter 3. VAE - Chapter 4. GAN - Chapter 5. AR Model - Chapter 6. Normalizing Flow Model - Chapter 7. Energy Based Model - Chapter 8. Diffusion Model
Part 3. Applications - Chapter 10. Advanced GANs - Chapter 11. Music Generation - Chapter 12. World Models - Chapter 13. Multimodal Models - Chapter 14. Conclusion
[결과]: 단순히 torch.compile으로 wrapping해준 것만으로 모델 Training이 43%빠른속도로 동작했다. (다만, 이는 A100으로 측정된 결과이고, 3090같은 시리즈는 잘 동작하지 않고 심지어 더 느릴 수 있다 언급: Caveats: On a desktop-class GPU such as a NVIDIA 3090, we’ve measured that speedups are lower than on server-class GPUs such as A100. As of today, our default backend TorchInductor supports CPUs and NVIDIA Volta and Ampere GPUs. It does not (yet) support other GPUs, xPUs or older NVIDIA GPUs.)
이를 2.2버전에서는 좀 더 완성시킨 것이다!
pytorch개발자분들은 버전이 2.x로 넘어가면서 compile함수에 좀 더 집중한다하였다. 아마 점점 학습속도를 빠르게하는 면을 강화하고, 이를 점차 확대할 것 같다. (이번에 저수준커널에도 적용한 걸 보면 거의 확실시 되는듯하다.)
개발동기:
17년 시작된 이후, Eager Execution성능향상을 위해 코드 대부분을 C++로 옮기게 되었다. (Pytorch 대부분의 소스코드가 C++기반임을 근거로 알 수 있다.) (eager execution: 그래프생성없이 연산을 즉시실행하는 환경)
이런 방식을 사용자들의 코드기여도(hackability)를 낮추는 진입장벽이 되어버렸다. 이런 eager execution의 성능향상에 한계가 있다 판단하여 compiler를 만들게 되었다. 목적은 속도는 빠르게하나 pytorch experience를 해치지 않는다는 것이다.
🤔 How to use?
torch.compile()은 기존 모델에 한줄만 추가하면 된다.
import torch
import torchvision.models as models
model = models.resnet18().cuda()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
compiled_model = torch.compile(model)
x = torch.randn(16, 3, 224, 224).cuda()
optimizer.zero_grad()
out = compiled_model(x)
out.sum().backward()
optimizer.step()
compiled_model은 신경망의 forward를 좀 더 최적화시켜 속도를 빠르게 한다.
[default]: 너무 오래걸리지 않으면서 메모리를 많이 사용하지 않는 선에서 효율적인 컴파일 진행
[reduce-overhead]: 메모리를 좀 더 사용, overhead를 줄여줌
[max-autotune]: 가장 빠른 모델생성을 위해 최적화되어있다. 다만, 컴파일에 매우 오랜시간이 걸린다.
∙ dynamic:
dynamic shape에 대해 code path를 enabling할 지 결정하는 boolean 변수이다. Compiler 최적화 과정이 프로그램을 dynamic shape 프로그램에 적용될 수 없게 만드는 경우가 있는데, 이를 조절함으로써 본인이 원하는 방향대로 컴파일을 할 수 있게 해준다. 이 부분은 아직 완벽히 이해가 되지는 않지만 데이터 shape가 변하는 상황에서graph를 유동적으로 컴파일할 수 있게끔 하는 것과 관련이 있을 것 같다.
∙ fullgraph:
Numba의nopython과 유사하다. 전체 프로그램을 하나의 그래프로 컴파일하고, 만약 실패한다면 왜 불가능한지 설명해주는 error 메세지를 띄운다. 굳이 쓰지 않아도 상관없는 옵션.
∙ backend:
어떤 compiler backend를 적용할 지 결정하게 된다. 디폴트로 정해진 값은 앞서 설명했던TorchInductor가 사용되지만, 다른 옵션들도 존재한다고 한다(제대로 알아보진 않았다).
❗️ 유의점:
compile된 모델 저장 시, state_dict만 저장가능하다.
∙ 아래는 가능!
torch.save(opt_model.state_dict(), "best.pt")
torch.save(model.state_dict(), "best.pt")
torch.save(model, "best.pt")
∙ 아래는 불가능!
torch.save(opt_model, "best.pt")
Compile 이후 사용가능한 기능:
∙ TorchDynamo
Eager Mode의 가장 용이한 점: 학습도중 model_weight에 접근하거나 값을 그대로 읽어올 수 있다.
model.conv1.weight
TorchDynamo는 이를 인지하고 만약 attribute가 변한것을 감지하면 자동으로 해당부분에 대한 변화를 다시 컴파일해준다.
∙ Inference
compile함수로 compiled_model을 생성한 후 warm-up step은 초반 latency를 줄여준다. 다만, 이부분도 차차 개선시킨다 하였다.
마찬가지로 동편제(한식): 불향돼지불백? 후식으로는 내돈내산 블루베리 스무디!! << 2번째 맛도리!!!
📖 공부! (13:30-18:00)
GAI 이어서 진행!
🚍 퇴근! (18:30 - 19:00)
퇴근이 제일 좋다는 직장인의 말에 공감이 점점된다ㅋㅋㅋ 아침출근때문에 그냥 졸리다ㅋㅋ 피곤🩸하고ㅠㅠ
🏋🏻 운동! (19:00 -)
이제 3대 운동보단 좀 더 세분화해서 A,B루틴 안하는 날에는 가슴,삼두, 등,이두, 어께 위주로 해봐야겠다. 아 그리고 데드나 스쿼트의 경우에는 조금 텀을 둬야겠다... 격일마다 무겁게만 하다보니 오히려 퍼포먼스가 안나오는 느낌? 그래서스쿼트와 데드의 경우에는 일주일에 1~2번정도만 본세트무게로❗️ 나머지는 평소드는 무게의 8~90%정도의 중량만들어야겠당
[정리]: 5x5 Strength + Local Muscle Strength Training for me
<해석 끝> - Chapter 6 읽고 공부하기 - Chapter 7 읽고 공부하기(短) - Chapter 8 읽고 공부하기(短) - Chapter 9 읽고 공부하기(短) - Chapter 10 읽고 공부하기 - Chapter 12 읽고 공부하기 - Chapter 17 읽고 공부하기(短) - Chapter 18 읽고 공부하기(短) - Chapter 19 읽고 공부하기(短) - Chapter 20 읽고 공부하기
<해석도 해야할 것.> - Chapter 5 읽고 공부하기(短) - Chapter 11 읽고 공부하기 - Chapter 13 읽고 공부하기 - Chapter 14읽고 공부하기 - Chapter 15읽고 공부하기 - Chapter 16읽고 공부하기
3. Generative Deep Learning Part 1. Intro. Generative Deep Learning - Chapter 1. Generative Modeling - Chapter 2. 딥러닝
Part 2. Six Generative Modeling Method. - Chapter 3. VAE - Chapter 4. GAN - Chapter 5. AR Model - Chapter 6. Normalizing Flow Model - Chapter 7. Energy Based Model - Chapter 8. Diffusion Model
Diffusion은 GAN과 함께 10년 넘게 Image Generation방법 중 영향력이 큰 생성모델링 기법이다. (GAN의 최대 유행: 2017~2020) Diffusion모델은 여러 Benchmark Dataset에서 기존 최신 GAN보다 성능이 뛰어난데, 특히 txt2img의 OpenAI DALL∙E, Google Imagen등에서 많이 사용된다.
Diffusion모델의 핵심기반 아이디어는 VAE, EBM과 비슷한 점이 존재한다. Contrastive Diffusion(= Score 함수) 사용 대신, Log분포의 Gradient를 직접 추정해 모델을 학습하는 EBM분야인 "Score-based Generative Model"에서 매우 중요하다.
NCSN(Noise Conditional Score Network)라는 모델이 원시 data에 여러 scale의 noise를 적용, Data밀도가 낮은 영역에서도 잘 작동하였다.
img x0를 많은 step(ex. T=1000)동안 점진적으로 손상시켜 최종적으로 "Standard Gaussian Noise"와 구별불가능하게 만든다 가정하자.
img xt-1에 분산 βt를 갖는 소량의 Gaussian Noise를 추가. 새로운 img xt를 생성하는 함수 q를 정의하자. 이 q를 적용하면, 아래처럼 점진적으로 잡음이 커지는 img sequence (x0, ... , xT)를 생성할 수 있다.
이때, update과정은 아래와 같이 수학적으로 표기가능하다.
Reparameterization Trick
🤔 q를 t번 적용하지 않고 이미지 x0+Noise인 xt로 바로 Skip가능하다면 유용하지 않을까?
위 식의 2번째 줄은 2개의 Gaussian분포를 더해 새로운 Gaussian분포를 하나 얻을 수 있다:
따라서 원본 img x0에서 정방향 diffusion과정의 어느단계로든 건너뛸 수 있게 되었다. 또한, 기존의 βt대신, āt값을 사용해 diffusion schedule을 정의할 수 있다. āt: signal(= 원본 x0)로 인한 분산 1-āt: noise(ε)로 인한 분산
∴ Foward Diffusion과정 q는 아래와 같다:
Diffusion Schedule
추가적으로 각 time step마다 다른 β를 자유로이 선택가능하다. 즉, β 나 ā 값이 t에 따라 변하는 방식을 "Diffusion Schedule"이라 한다.
[Ho et al;2020]에서는 Linear Diffusion Schedule을 선택했다. 위 논문에서는 β1=0.0001부터 ,βT=0.02까지 선형적으로 증가한다.
이후 논문에서는 Cosine Diffusion Schedule이 도입되었다. 이때, 코사인 스케줄은 ā를 아래와 같이 정의한다:
위 그림을 보면 Cosine Diffusion Schedule이 더 느리게 상승했음을 확인가능하다. 즉, img에 noise를 점진적으로 추가해 train효율성 및 생성품질을 향상한다.
Reverse Diffusion
noise추가과정을 되돌리는 신경망 pθ(xt-1|xt)를 구축하자. 이때, 신경망 pθ(xt-1|xt)는 q(xt-1|xt)의 역방향 분포를 근사화하는 신경망이다.
이를 통해 N(0, I)에서 random noise sampling 후, reverse diffusion과정을 여러번 적용해 새로운 img를생성할 수 있다:
Train Algorithm
[Reverse Diffusion과 VAE간 비교] ∙ 목표: 신경망으로 random noise를 의미있는 출력으로 변환하는 것. ∙ 차이점: - VAE는 정방향(= img2noise)과정이 모델의 일부 (= 학습됨) - Diffusion: 이에 대한 parameter가 없이 진행.
그렇기에, VAE와 동일한 Loss function을 적용한다.
⭐️ 주의점: Diffusion모델이 실제로 2개의 신경망복사본을 유지한다는 점. 경사하강법으로 train된 신경망과 이전 train step의 신경망 가중치의 EMA(지수이동평균)을 사용하는 또다른 EMA신경망이다.
2. DDPM with U-Net
DDPM with UNet
앞서 신경망의 종류를 확인했다: img에 추가된 noise를 예측하는 신경망 이제, 이에 사용할 신경망 구조를 살펴보자. Skip Connection을 통해 정보가 신경망 일부를 건너뛰고 후속층으로 signal을 흘러보낼 수 있다. 특히나 "출력이 입력크기와 같아야할 때, U-Net이 유용하다".
신경망 후속층에서 사용가능하도록 noise분산값(= 스칼라값)을 더 복잡한 표현이 가능한 고차원 벡터로 변환한다. NeRF논문에서는 문장에서 단어의 이산적인 위치를 벡터로 encoding하는 것이 아닌, 연속적인 값으로 확장했다:
보통, noise embedding길이의 절반이 되게 L=16으로 선택하고 주파수 f의 최대 scaling계수로 ln(1000) / (L-1) 을 택한다.
Residual Block구조는 아래와 같다.
일부 Residual Block에서 Block의 출력과 channel수를 일치시켜야한다. 그렇기에 Skip Connection에 kernel_size=1인 Conv2D층을 추가한다.
Down Block & UpBlock
∙ Down Block
Residual Block으로 channel수를 늘린다. 또한, img_size를 줄이려고 마지막에 AvgPooling층을 적용한다. (UpBlock과의 Skip Connection을 위해 각 Residual Block에 list를 추가해야함.)
∙ UpBlock
UpSampling2D를 진행한다. (보통 ConvTranspose나 Interpolation을 적용.) 연속된 UpBlock은 channel수를 줄이면서 DownBlock의 출력과 연결한다.
import torch
import torch.nn as nn
import torch.nn.functional as F
class SwishActivation(nn.Module):
def forward(self, x):
return x * torch.sigmoid(x)
class ResidualBlock(nn.Module):
def __init__(self, width):
super(ResidualBlock, self).__init__()
self.width = width
self.conv1 = nn.Conv2d(in_channels=width, out_channels=width, kernel_size=3, padding=1)
self.bn1 = nn.BatchNorm2d(width)
self.activation = SwishActivation()
self.conv2 = nn.Conv2d(in_channels=width, out_channels=width, kernel_size=3, padding=1)
self.bn2 = nn.BatchNorm2d(width)
def forward(self, x):
input_width = x.size(1)
if input_width == self.width:
residual = x
else:
residual = nn.Conv2d(in_channels=input_width, out_channels=self.width, kernel_size=1)(x)
x = self.bn1(x)
x = self.activation(x)
x = self.conv1(x)
x = self.bn2(x)
x = self.activation(x)
x = self.conv2(x)
x = x + residual
return x
class DownBlock(nn.Module):
def __init__(self, width, block_depth):
super(DownBlock, self).__init__()
self.width = width
self.block_depth = block_depth
self.res_blocks = nn.ModuleList([ResidualBlock(width) for _ in range(block_depth)])
self.avg_pool = nn.AvgPool2d(kernel_size=2)
def forward(self, x):
x, skips = x
for res_block in self.res_blocks:
x = res_block(x)
skips.append(x)
x = self.avg_pool(x)
return x
class UpBlock(nn.Module):
def __init__(self, width, block_depth):
super(UpBlock, self).__init__()
self.width = width
self.block_depth = block_depth
self.up_sampling = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=False)
self.res_blocks = nn.ModuleList([ResidualBlock(width) for _ in range(block_depth)])
def forward(self, x):
x, skips = x
x = self.up_sampling(x)
for res_block in self.res_blocks:
x = torch.cat([x, skips.pop()], dim=1)
x = res_block(x)
return x
3. DDPM Sampling과 DDIM
DDPM을 이용한 Sampling
훈련된 모델에서 img를 sampling해야한다. 이를 위해 reverse diffusion과정이 필요하다. 즉, random noise에서 시작해 원본이 남을 때 까지 모델로 noise를 점진적으로 제거해야한다.
모델은 random noise추가과정의 마지막 time_step에서 추가된 noise뿐만아니라 trainset의 img에 추가된 noise총량을 예측하게 훈련된다. (다만, 완전한 random noise에서 한번에 img예측은 불가능하다.)
그렇기에 두 단계를 거쳐 xt에서 xt-1로 이동한다. Step 1. 모델의 noise예측을 사용, x0의 추정치 계산 Step 2. 예측 noise를 t-1 step까지만 다시 적용해 xt-1을 생성. 이 과정을 여러단계에 걸쳐 반복하면 조금씩 점진적으로 x0에 대한 추정치로 결국 돌아갈 수 있다.. 아래 식은 이 과정을 수학적으로 보여준다: 위 식을 해석하면 다음과 같다: 첫번째 괄호:신경망 ε(t)θ에 의해 예측된 noise로 계산된 추정이미지 x0 이후 t-1 signal비율인 √āt-1로 scale을 조정, 예측된 noise를 재적용.
두번째 괄호: t-1 noise 비율인 √1 - āt-1 - σ2t로 scale 조정.
세번째 괄호: 추가적인 Gaussian Noise를 더한다.
DDIM (Denoising Diffusion Implicit Model)
DDPM에서 모든 t에 대해 σt=0인 특수한 경우. 즉, DDIM을 사용하면 생성과정이 완전히 "결정론적(deterministic)"하다. 그렇기에 Random Noise가 같다면 항상 동일한 출력을 만든다.
이는 latent space의 sample과 pixel space에서 생성된 출력사이에 잘 정의된 mapping이 있음을 나타낸다.
4. 요약
DDPM이후 DDIM논문의 아이디어는 생성과정을 완전히 결정론적으로 만들었다.
DDPM은 2가지 과정으로 나뉜다.
① 정방향 Diffusion - 일련의 작은 단계로 train data에 noise를 추가. 이때, reparameterization trick으로 어느단계에 해당하는 noise_img라도 계산가능하다. parameter선택 schedule 선택 또한 중요하다.
② 역방향 Diffusion
- 추가된 noise를 예측하는 모델로 구성. noise_img와 해당단계 noise비율이 주어지면 각 time step에서 noise를 예측하는 U-Net으로 구현된다. UpBlock: img 크기를 늘리고 channel수를 줄임. DownBlock: img 크기를 줄이고 channel수를 늘림. noise비율은 사인파임베딩(sinusoidal embedding)으로 encoding
역방향 Diffusion 단계를 늘리면 속도는 느려지나 img생성품질은 향상된다. 또한, 두 img 사이를 보간하기 위해 latent space연산을 수행한다.
- Chapter 4 읽고 공부하기(短) - Chapter 5 읽고 공부하기(短) - Chapter 11 읽고 공부하기 - Chapter 13 읽고 공부하기 - Chapter 14읽고 공부하기 - Chapter 15읽고 공부하기 - Chapter 16읽고 공부하기
3. Generative Deep Learning Part 1. Intro. Generative Deep Learning - Chapter 1. Generative Modeling - Chapter 2. 딥러닝
Part 2. Six Generative Modeling Method. - Chapter 3. VAE - Chapter 4. GAN - Chapter 5. AR Model - Chapter 6. Normalizing Flow Model - Chapter 7. Energy Based Model - Chapter 8. Diffusion Model
마찬가지로 서편제(한식): 걍 앞으로는 고기많이 나오는 동편제 먹어야지... 후식으로는 내돈내산 녹차프라푸치노!! << 솔직히 이게 제일 맛도리임
📖 공부! (13:30-18:00)
GAI 이어서 진행!
🚍 퇴근! (18:30 - 19:00)
퇴근이 제일 좋다는 직장인의 말에 공감이 점점된다ㅋㅋㅋ 아침출근때문에 그냥 졸리다ㅋㅋ 피곤🩸하고ㅠㅠ
🏋🏻 운동! (19:00 -)
이제 3대 운동보단 좀 더 세분화해서 A,B루틴 안하는 날에는 가슴,삼두, 등,이두, 어께 위주로 해봐야겠다. 아 그리고 데드나 스쿼트의 경우에는 조금 텀을 둬야겠다... 격일마다 무겁게만 하다보니 오히려 퍼포먼스가 안나오는 느낌? 그래서스쿼트와 데드의 경우에는 일주일에 1~2번정도만 본세트무게로❗️ 나머지는 평소드는 무게의 8~90%정도의 중량만들어야겠당
[정리]: 5x5 Strength + Local Muscle Strength Training for me
<해석 끝> - Chapter 6 읽고 공부하기 - Chapter 7 읽고 공부하기(短) - Chapter 8 읽고 공부하기(短) - Chapter 9 읽고 공부하기(短) - Chapter 10 읽고 공부하기 - Chapter 12 읽고 공부하기 - Chapter 17 읽고 공부하기(短) - Chapter 18 읽고 공부하기(短) - Chapter 19 읽고 공부하기(短) - Chapter 20 읽고 공부하기
<해석도 해야할 것.> - Chapter 5 읽고 공부하기(短) - Chapter 11 읽고 공부하기 - Chapter 13 읽고 공부하기 - Chapter 14읽고 공부하기 - Chapter 15읽고 공부하기 - Chapter 16읽고 공부하기
3. Generative Deep Learning Part 1. Intro. Generative Deep Learning - Chapter 1. Generative Modeling - Chapter 2. 딥러닝
Part 2. Six Generative Modeling Method. - Chapter 3. VAE - Chapter 4. GAN - Chapter 5. AR Model - Chapter 6. Normalizing Flow Model - Chapter 7. Energy Based Model - Chapter 8. Diffusion Model
에너지함수 Eθ(x)는 parameter가 θ이고 입력 img가 x를 하나의 스칼라값으로 변환하는 신경망. 이때, 여기에 Swish활성화함수를 사용한다. swish함수
이 Swish함수는 Gradient Vanishing을 완화시키는데, 특히 EBM에서 중요하다. 이 신경망은 일련의 Conv2D를 쌓아 img크기를 줄이고 channel크기를 늘린다. 마지막 층은 Linear Activation이기에 이 신경망은 (-∞,∞)의 범위값을 출력한다. 해당 코드는 아래와 같다.
🤔 How to... 에너지점수가 낮은 new sample생성? 랑주뱅 동역학기법:입력에 대한 Energy함수의 Gradient계산하는 기법 Step 1. Sample space의 임의의 지점에서 시작 Step 2. 계산된 Gradient의 반대방향으로 조금씩 이동, Energy함수를 감소. Step 3. train이후, random noise가 trainset과 유사한 img로 변환됨.
stochastic gradient Langevin Dynamic:
sample space 이동 시, 위 그림처럼 input에 소량의 random noise추가. (만약, 그렇지 않으면 local minima에 빠질 수 있음.)
다만, 일반 SGD랑은 당연히 차이가 있다. ∙ SGD: (-) 기울기방향으로 파라미터 조금씩 update, Loss최소화
∙ SGD with Langevin Dynamic: 여기에 Langevin Dynamic을 사용하면 Gradient Weight를 고정하고, input에 대한 출력의 Gradient를 계산한다. 그 후 (-) 기울기방향으로 input을 조금씩 update, 점진적으로 출력(energy score)을 최소화한다.
두 방식 모두 동일한 경사하강법을 활용하나, 다른 목적함수에 적용된다. 이론적인 Langevin Dynamic 방정식. [Langevin Sampling함수]:
def generate_samples(model, inp_imgs, steps=60, step_size=10, return_img_per_step=False):
"""
Function for sampling images for a given model.
Inputs:
model - Neural network to use for modeling E_theta
inp_imgs - Images to start from for sampling. If you want to generate new images, enter noise between -1 and 1.
steps - Number of iterations in the MCMC algorithm.
step_size - Learning rate nu in the algorithm above
return_img_per_step - If True, we return the sample at every iteration of the MCMC
"""
# Before MCMC: set model parameters to "required_grad=False"
# because we are only interested in the gradients of the input.
is_training = model.training
model.eval()
for p in model.parameters():
p.requires_grad = False
inp_imgs.requires_grad = True
# Enable gradient calculation if not already the case
had_gradients_enabled = torch.is_grad_enabled()
torch.set_grad_enabled(True)
# We use a buffer tensor in which we generate noise each loop iteration.
# More efficient than creating a new tensor every iteration.
noise = torch.randn(inp_imgs.shape, device=inp_imgs.device)
# List for storing generations at each step (for later analysis)
imgs_per_step = []
# Loop over K (steps)
for _ in range(steps):
# Part 1: Add noise to the input.
noise.normal_(0, 0.005)
inp_imgs.data.add_(noise.data)
inp_imgs.data.clamp_(min=-1.0, max=1.0)
# Part 2: calculate gradients for the current input.
out_imgs = -model(inp_imgs)
out_imgs.sum().backward()
inp_imgs.grad.data.clamp_(-0.03, 0.03) # For stabilizing and preventing too high gradients
# Apply gradients to our current samples
inp_imgs.data.add_(-step_size * inp_imgs.grad.data)
inp_imgs.grad.detach_()
inp_imgs.grad.zero_()
inp_imgs.data.clamp_(min=-1.0, max=1.0)
if return_img_per_step:
imgs_per_step.append(inp_imgs.clone().detach())
# Reactivate gradients for parameters for training
for p in model.parameters():
p.requires_grad = True
model.train(is_training)
# Reset gradient calculation to setting before this function
torch.set_grad_enabled(had_gradients_enabled)
if return_img_per_step:
return torch.stack(imgs_per_step, dim=0)
else:
return inp_imgs
Contrastive Divergence
앞서 Sampling space에서 낮으 energy를 갖는 새로운 point를 sampling하는 방법을 알아보았으니 모델 train쪽을 알아보자.
Energy함수는 확률을 출력하지 않는다 = MLE를 적용할 수 없다. (물론, 항상 그렇듯 NLL Loss최소화가 목적이다.) pθ(x)가 energy함수 Eθ(x)를 포함하는 Boltzmann 분포일 때, 이 값의 Gradient는 아래와 같다: 위 식은 직관적으로 이해가능하다: ∙ 실제 sample에 대해 큰 음의 energy score ∙ 생성된 가짜 sample에 대해 큰 양의 energy score를 출력하도록 모델 훈련 → 두 극단 간의 차이가 가능한 커지도록하여 이를 손실함수로 이용.
이때, 가짜 sample의 Energy score를 계산하려면 분포 pθ(x)에서 정확히 sampling가능해야한다. 다만, 분모계산이 어려워 불가능하다. → 대신, Langevin Sampling방법을 사용해 낮은 energy score를 갖는 sample set 생성이 가능하다.
또한, 이전 반복 sample을 buffer에 저장, 다음 batch시작점으로 순수noise대신에 이를 사용한다.
def sample_new_exmps(self, steps=60, step_size=10):
"""
Function for getting a new batch of "fake" images.
Inputs:
steps - Number of iterations in the MCMC algorithm
step_size - Learning rate nu in the algorithm above
"""
# Choose 95% of the batch from the buffer, 5% generate from scratch
n_new = np.random.binomial(self.sample_size, 0.05)
rand_imgs = torch.rand((n_new,) + self.img_shape) * 2 - 1
old_imgs = torch.cat(random.choices(self.examples, k=self.sample_size-n_new), dim=0)
inp_imgs = torch.cat([rand_imgs, old_imgs], dim=0).detach().to(device)
# Perform MCMC sampling
inp_imgs = Sampler.generate_samples(self.model, inp_imgs, steps=steps, step_size=step_size)
# Add new images to the buffer and remove old ones if needed
self.examples = list(inp_imgs.to(torch.device("cpu")).chunk(self.sample_size, dim=0)) + self.examples
self.examples = self.examples[:self.max_len]
return inp_imgs
이때, 각 step이 종료된 후, score normalization하지 않고 알고리즘에 따라 sample score는 아래로 내려가고, 가짜 sample의 점수는 위로 올라간다. 최종코드는 링크 참고.
EBM은 이후 score matching이라는 훈련기법으로 발전하였고, 이는 Denoising Diffusion Probabilistic Model이라는 모델로 발전해 DALLE∙2 및 Imagen같은 최첨단 생성모델 구현에 사용된다.
3. 기타 (BM, RBM)
Boltzmann Machine
EBM의 초기 사례중 하나로 fully connected undirected neural network이다. v: visible unit h: hidden unit W, L, J는 학습되는 Contrastive Divergence로 train. 이때, 균형점을 찾을 때 까지 v와 h사이를 번갈어서 Gibbs Sampling을 수행한다.
단점: train속도가 매우 느리고 hidden unit개수를 크게 늘릴 수 없다.
Restricted Boltzmann Machine
위의 Boltzmann machine을 확장한 RBM은 같은 종류 unit사이 connection을 제거, 2개 층으로 구성된 이분그래프(bipartite graph)를 생성한다. 이를 통해 RBM을 쌓아 더 복잡한 분포를 모델링하는 심층신뢰신경망(Deep Belief Network)을 만들 수 있다.
단점: Mixing Time(= Gibbs Sampling으로 목표상태에 도달하는데 걸린시간)이 긴 Sampling이 여전히 필요. 따라서 여전히 고차원 data 모델링에는 현실적으로 어렵다.
4. 요약
Deep EBM의 Sampling은 Langevin Dynamic으로 이뤄진다. 이 기법은 input img에 대한 점수의 gradient를 사용하여 gradient가 감소하는 방향으로 조금씩 input을 update한다.