[PyTorch] 퍼셉트론(Perceptron)
Posted: Updated:
AI 스터디를 하며 ‘파이토치 트랜스포머를 활용한 자연어 처리와 컴퓨터비전 심층학습’ 교재를 정리한 글입니다.
퍼셉트론(Perceptron)
인공 신경망의 한 종류로 출력이 0 또는 1인 작업을 의미하는 이진 분류 작업에 사용되는 간단한 모델
신경 세포(Neuron)가 신호를 전달하는 방식과 유사하게 구현됨
TLU(Threshold Logic Unit) 형태로, 계단 함수를 적용해 결과 반환
입력값($x$)과 노드의 가중치 곱한 값을 모두 더했을 때 임곗값보다 크면 1 출력, 작으면 0 출력
여러 입력값 입력 시 0이나 1 또는 -1에서 1 사이의 값 출력
단층 퍼셉트론(Single Layer Perceptron)
하나의 계층을 갖는 모델로, 입력을 통해 데이터가 전달되고 입력값($x$)은 각각의 가중치와 함께 노드에 전달됨
전달된 입력값($x$)과 가중치를 곱한 값이 활성화 함수에 전달
활성화 함수에서 출력값($\hat{y}$)이 계산되고 이 값을 손실 함수에 실젯값($y$)과 함께 연산해 가중치 변경
$AND, OR, NAND$는 쉽게 구현 가능하지만, $XOR$ 게이트처럼 하나의 기울기로 표현하기 어려운 단층은 사용이 어려움
import torch
import pandas as pd
from torch import nn, optim
from torch.utils.data import Dataset, DataLoader
class CustomDataset(Dataset):
def __init__(self, file_path):
df = pd.read_csv(file_path)
self.x1 = df.iloc[:, 0].values
self.x2 = df.iloc[:, 1].values
self.y = df.iloc[:, 2].values
self.length = len(df)
def __getitem__(self, index):
x = torch.FloatTensor([self.x1[index], self.x2[index]])
y = torch.FloatTensor([self.y[index]])
return x, y
def __len__(self):
return self.length
class CustomModel(nn.Module):
def __init__(self):
super().__init__()
self.layer = nn.Sequential(
nn.Linear(2, 1),
nn.Sigmoid()
)
def forward(self, x):
return self.layer(x)
train_dataset = CustomDataset("datasets/perceptron.csv")
train_dataloader = DataLoader(train_dataset, batch_size=64, shuffle=True, drop_last=True)
device = "cuda" if torch.cuda.is_available() else "cpu"
model = CustomModel().to(device)
criterion = nn.BCELoss().to(device)
optimizer = optim.SGD(model.parameters(), lr=0.01)
for epoch in range(10000): # XOR 문제에서 비용이 감소되지 않음
cost = 0.0
for x, y in train_dataloader:
x = x.to(device)
y = y.to(device)
output = model(x)
loss = criterion(output, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
cost += loss.item()
cost = cost / len(train_dataloader)
if (epoch + 1) % 1000 == 0:
print(f"Epoch: {epoch+1:4d}, Cost: {cost:.3f}")
with torch.no_grad():
model.eval()
inputs = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]]).to(device)
outputs = model(inputs)
print("----------")
print(outputs)
print(outputs <= 0.5)
출력
Epoch: 1000, Cost: 0.692
Epoch: 2000, Cost: 0.692
Epoch: 3000, Cost: 0.692
Epoch: 4000, Cost: 0.692
Epoch: 5000, Cost: 0.692
Epoch: 6000, Cost: 0.692
Epoch: 7000, Cost: 0.693
Epoch: 8000, Cost: 0.692
Epoch: 9000, Cost: 0.692
Epoch: 10000, Cost: 0.692
----------
tensor([[0.4675],
[0.5001],
[0.5038],
[0.5364]], device='cuda:0')
tensor([[ True],
[False],
[False],
[False]], device='cuda:0')
다층 퍼셉트론(Multi-Layer Perceptron, MLP)
단층 퍼셉트론을 여러개 쌓아 은닉층 생성
은닉층이 한 개 이상인 퍼셉트론 구조
은닉층을 2개 이상 연결하면 심층 신경망(Deep Neural Network, DNN)이라고 함
역전파 과정을 통해 모든 노드의 가중치와 편향을 수정해 오차가 작아지는 방향으로 학습 진행
- 입력층부터 출력층까지 순전파 진행
- 출력값(예측값)과 실젯값으로 오차 계산
- 오차를 퍼셉트론의 역방향으로 보내면서 입력된 노드의 기여도 측정
- 입력층에 도달할 때까지 노드의 기여도 측정
- 모든 가중치에 최적화 알고리즘 수행
이진 분류 작업에서 사용되는 간단하고 효율적인 모델
데이터의 복잡한 패턴을 학습할 수 없으며, 선형으로 분리되지 않는 데이터를 분류할 수 없음
import torch
import pandas as pd
from torch import nn, optim
from torch.utils.data import Dataset, DataLoader
class CustomDataset(Dataset):
def __init__(self, file_path):
df = pd.read_csv(file_path)
self.x1 = df.iloc[:, 0].values
self.x2 = df.iloc[:, 1].values
self.y = df.iloc[:, 2].values
self.length = len(df)
def __getitem__(self, index):
x = torch.FloatTensor([self.x1[index], self.x2[index]])
y = torch.FloatTensor([self.y[index]])
return x, y
def __len__(self):
return self.length
class CustomModel(nn.Module):
def __init__(self):
super().__init__()
self.layer1 = nn.Sequential(
nn.Linear(2, 2),
nn.Sigmoid()
)
self.layer2 = nn.Sequential(
nn.Linear(2, 1),
nn.Sigmoid()
)
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
return x
train_dataset = CustomDataset("datasets/perceptron.csv")
train_dataloader = DataLoader(train_dataset, batch_size=64, shuffle=True, drop_last=True)
device = "cuda" if torch.cuda.is_available() else "cpu"
model = CustomModel().to(device)
criterion = nn.BCELoss().to(device)
optimizer = optim.SGD(model.parameters(), lr=0.01)
for epoch in range(10000):
cost = 0.0
for x, y in train_dataloader:
x = x.to(device)
y = y.to(device)
output = model(x)
loss = criterion(output, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
cost += loss.item()
cost = cost / len(train_dataloader)
if (epoch + 1) % 1000 == 0:
print(f"Epoch: {epoch+1:4d}, Cost: {cost:.3f}")
with torch.no_grad():
model.eval()
inputs = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]]).to(device)
outputs = model(inputs)
print("----------")
print(outputs)
print(outputs <= 0.5)
출력
Epoch: 1000, Cost: 0.693
Epoch: 2000, Cost: 0.693
Epoch: 3000, Cost: 0.693
Epoch: 4000, Cost: 0.690
Epoch: 5000, Cost: 0.645
Epoch: 6000, Cost: 0.461
Epoch: 7000, Cost: 0.229
Epoch: 8000, Cost: 0.055
Epoch: 9000, Cost: 0.030
Epoch: 10000, Cost: 0.021
----------
tensor([[0.0196],
[0.9835],
[0.9712],
[0.0169]], device='cuda:0')
tensor([[ True],
[False],
[False],
[ True]], device='cuda:0')
댓글남기기