-
pytorch-3 ANN, RBM딥러닝/pytorch 2023. 7. 9. 14:53
1. ann
import torch import torch.nn as nn class ANN(nn.Module): def __init__(self, input_size, hidden_size, output_size): super(ANN, self).__init__() self.fc1 = nn.Linear(input_size, hidden_size) self.relu = nn.ReLU() self.fc2 = nn.Linear(hidden_size, output_size) def forward(self, x): out_by_input_hidden = self.fc1(x) out_by_relu = self.relu(out_by_input_hidden) out_by_hidden_output = self.fc2(out_by_relu) return out_by_hidden_output if __name__ == "__main__": input_size = 784 hidden_size = 256 output_size = 10 model = ANN(input_size, hidden_size, output_size) criterion = nn.CrossEntropyLoss() learning_rate = 0.01 optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) inputs = torch.randn(100, input_size) labels = torch.randint(0, output_size, (100,)) num_epochs = 10 for epoch in range(num_epochs): outputs = model(inputs) loss = criterion(outputs, labels) optimizer.zero_grad() loss.backward() optimizer.step() if (epoch + 1) % 1 == 0: print(f"Epoch {epoch + 1} / {num_epochs} : Loss {loss.item():.4f}") Epoch 1 / 10 : Loss 2.3058 Epoch 2 / 10 : Loss 2.2900 Epoch 3 / 10 : Loss 2.2743 Epoch 4 / 10 : Loss 2.2588 Epoch 5 / 10 : Loss 2.2434 Epoch 6 / 10 : Loss 2.2281 Epoch 7 / 10 : Loss 2.2130 Epoch 8 / 10 : Loss 2.1979 Epoch 9 / 10 : Loss 2.1830 Epoch 10 / 10 : Loss 2.1681
입력층, 은닉층, 출력층 각 하나로 이루어진 ann을 구현하는 간단한 코드이다. init에서 nn.linear 함수를 사용하여 입력층, 출력층을 지정하며 relu함수를 사용하여 은닉층의 변수를 만든다.
forward 함수를 생성하여 각 레이어를 진행해 주며 결괏값을 반환하는 모델이다.
input_size=784, hidden_size=256, output_size=10으로 할당해 준다. 학습률과 최적화 함수, 손실함수를 적절하게 지정해 준다.
모델에 정규분포로 100개의 값을 생성하여 for문을 10번 동안 돌리면서 순전파, 역전파를 하면서 옵티마이징하는 과정을 거친다. 10번의 반복동안 손실함수의 값이 계속 개선되는 것을 확인할 수 있다.
2. rbm
import torch from torch import nn import torchvision from torchvision import transforms import torchvision.utils as vutils from torch.utils.data import DataLoader class RBM(nn.Module): def __init__(self, visible_size, hidden_size): super(RBM, self).__init__() self.W = nn.Parameter(torch.randn(visible_size, hidden_size)) self.v_bias = nn.Parameter(torch.randn(visible_size)) self.h_bias = nn.Parameter(torch.randn(hidden_size)) def forward(self, x): hidden_prob = torch.sigmoid(torch.matmul(x, self.W) + self.h_bias) hidden_state = torch.bernoulli(hidden_prob) visible_prob = torch.sigmoid( torch.matmul(hidden_state, torch.transpose(self.W, 0, 1)) + self.v_bias ) return visible_prob, hidden_state if __name__ == "__main__": transform = transforms.Compose( [transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))] ) train_dataset = torchvision.datasets.MNIST( root="./data", train=True, transform=transform, download=True ) train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True) visible_size = 28 * 28 hidden_size = 256 rbm = RBM(visible_size, hidden_size) criterion = nn.BCELoss() optimizer = torch.optim.SGD(rbm.parameters(), lr=0.01) num_epochs = 10 for epoch in range(num_epochs): for images, _ in train_loader: inputs = images.view(-1, visible_size) visible_prob, _ = rbm(inputs) loss = criterion(visible_prob, inputs) optimizer.zero_grad() loss.backward() optimizer.step() print(f"Epoch {epoch + 1} / {num_epochs} : Loss {loss.item():.4f}") vutils.save_image( rbm.W.view(hidden_size, 1, 28, 28), f"weights_{epoch+1}.png", normalize=True ) inputs_display = inputs.view(-1, 1, 28, 28) outputs_display = visible_prob.view(-1, 1, 28, 28) comparison = torch.cat([inputs_display, outputs_display], dim=3) vutils.save_image( comparison, f"reconstruction_epoch_{epoch+1}.png", normalize=True ) Epoch 1 / 10 : Loss 3.0018 Epoch 2 / 10 : Loss 0.6087 Epoch 3 / 10 : Loss -2.0434 Epoch 4 / 10 : Loss -4.1794 Epoch 5 / 10 : Loss -6.2721 Epoch 6 / 10 : Loss -8.1106 Epoch 7 / 10 : Loss -9.3818 Epoch 8 / 10 : Loss -10.8449 Epoch 9 / 10 : Loss -11.7795 Epoch 10 / 10 : Loss -13.3530
간단한 제한된 볼츠만 머신을 구현한다. 제한된 볼츠만 머신은 생성형 모델기법 중 하나이다. 생성형 모델은 기존의 데이털의 분포를 활용해서 새로운 데이터를 만들어 내는 것으로 새로운 데이터의 분포를 설명할 수 있냐 없냐에 따라 명시적 모델과 암시적 모델로 구분할 수 있다.
제한된 볼츠만 머신은 명시적 모델의 한 종류이며 딥러닝 이전의 사전훈련 과정에 유용하다. 일반적으로 가시층과 은닉층으로 구성되며 가시층에서는 데이터가 위치하고 은닉층에서 데이터의 특징을 추출한다. 가시층가 은닉층 사이의 가중치를 나타내는 가중치 행렬이 존재하고 가시층, 은닉층의 편향이 각 노드에 대해서 활성화를 조절한다.
init 함수에서 가중치와 가시층, 은닉층의 편향을 정의한다. nn.parameter를 사용하여 추후에 생성자로 접근할 수 있다.
forward 함수에서 입력 x와 가중치 행렬 w를 곱하고 은닉층 편향을 더한 값에 시그모이드 함수를 적용하여 은닉 유닛의 활성화 확률을 계산한다. hidden.bernoulli 함수를 사용하여 확률을 0 또는 1로 변환한다. 이진 상태에 가중치 행렬을 transpose로 전치하여 곱하고 가시층의 바이어스를 더한 값을 시그모이드에 넣어서 가시층의 확률 값, 은닉층의 이진 상태를 반환한다.
transform.compose 내부에서 totensor와 normalize를 사용하여 입력 데이터를 정규화하고 텐서변환한다.
이후에 손글씨 데이터셋을 불러오며 손글씨 데이터에 맞는 가시층과 은닉층의 사이즈를 지정한다.
rbm모델을 생성하고 적절한 손실함수와 옵티마이저를 설정한다. rbm.parameters()를 사용하여 가중치, 가시층, 은닉층의 편향을 가져와서 옵티마이징 할 수 있다.
train_loader에서 데이터를 64개씩 가져와서 view함수로 1차원 데이터로 변환한다. 이후에 rbm모델의 inputs으로 전달하여 활성화 확률과 은닉층 상태를 반환한다. 손실함수 계산, 그라디언트 초기화, 역전파, 매개변수 업데이트를 차례대로 진행하는 과정을 10번 반복하여 가중치를 이미지로 저장하고 입력 이미지와 활성화 확률로 재조정된 이미지를 가로로 결합하여 저장한다.
이미지를 확인하면 visible_prob에 대한 입력 데이터를 볼 수 있고 가중치 값들도 확인할 수 있다.
'딥러닝 > pytorch' 카테고리의 다른 글
pytorch-5 CNN (0) 2023.07.09 pytorch-4 stride conv, dilated conv, 가중치 행렬 시각화 (0) 2023.07.09 pytorch-2 데이터로더 (0) 2023.07.03 pytorch-1 기본 문법 (0) 2023.06.26