def train(epoch, model, optim, loader):
losses = 0
model.train()
for idx, (x,_) in enumerate(loader):
x = x.to(DEVICE)
optim.zero_grad()
xhat, mean,logvar = model(x)
loss = lossfunc(mean,logvar,x,xhat)
loss.backward()
optim.step()
losses+= loss.item()
if idx%200 ==0:
print(f'{100.*idx/len(loader):.1f}%, loss={loss.item():.2f}')
return losses/len(loader)
def test(epoch, model, loader):
losses = 0
model.eval()
for idx, (x,_) in enumerate(loader):
x = x.to(DEVICE)
xhat, mean,logvar = model(x)
with torch.no_grad():
loss = lossfunc(mean,logvar,x,xhat)
losses+= loss.item()
return losses/len(loader)
train_losses = []
test_losses = []
model.to(DEVICE)
for epoch in range(1,EPOCHS+1):
train_loss = train(epoch,model,optim,train_loader)
print(f'EPOCH {epoch}, train_loss={train_loss:.2f}',end='')
train_losses.append(train_loss)
test_loss = test(epoch,model,test_loader)
print(f', test_loss={test_loss:.2f}\n')
test_losses.append(test_loss)
if epoch%10 ==0:
torch.save(model.state_dict(),f'./checkpoint2/check{epoch}.pt')
print(train_losses)
print(test_losses)
Result
학습 후, 잠재 변수와 MNIST 숫자 레이블이 잠재변수 공간 어디에 위치하는지 시각화했다. 학습이 잘 되었다면 올바르게 클러스터링되어야 한다.
Z_DIM=2
잠재변수가 두 개의 실수일 때 결과이다.
과적합 이전에 적절히 멈추었다.
시각화 결과,
점이 0 주변에 올바르게 분포해 했으나, 일부 숫자는 잘 분리되지 않았다.
100개를 Train Data에서 뽑아 적절히 생성했다. 결과, 다음과 같은 숫자가 생성되었다.
생성된 숫자가 애매하게 보이는 것이 많고, 압축 및 복원 과정에서 어려움이 있었다.
Z_DIM=4
잠재 변수가 4개의 실수일 때 결과이다.
Z_DIM=2에서보다 더 낮은 Loss를 보였다!
4차원이므로 시각화가 까다롭다. 따라서 T-SNE를 이용해 차원축소했다.
각 숫자가 더욱 잘 모여있는 것으로 보인다.
생성된 이미지들은 실제로 더 또렷한 숫자들로 보였으며, 0부터 9까지 각각 또렷하게 보이는 숫자들이 적어도 하나씩 존재했다. 더 잘 최적화되었다.
−logpθ(x(i)∣z(i,l)) 는 Negative Log Likelihood이므로 크로스 엔트로피로 계산할 수 있고, 생성된 x에 대한 분포함수이다. z로부터 생성된 x가 데이터셋의 x일 확률을 계산한다. 디코더의 출력층에 이미 sigmoid를 적용해 확률값 0~1로 출력되므로, PyTorch에서 사용할 수 있는 loss는 BCELoss이다.