인간의 뇌는 수십억 개의 뉴런을 가지고 있습니다.
뉴런이란 화학적, 전기적 신호를 처리하고 전달하는 연결된 뇌신경 세포입니다.
인공 신경망(Artificial Neural Network)은 생물학적 뉴런을 기반으로 한 수학적 모델입니다.
이번 포스팅에선 초기 인공 신경망인 퍼셉트론(Perceptron)에 대해 이야기해보겠습니다.
1. 퍼셉트론(Perceptron)
초기 인공 신경망인 퍼셉트론(Perceptron)은 다수의 입력으로부터 하나의 결과를 내보내는 알고리즘입니다.
초기 기계 학습 알고리즘 중 하나로 이진 분류 문제를 해결하기 위해 설계되었습니다.
논리 회귀 분류를 통해 단층 퍼셉트론과 다층 퍼셉트론에 대해 알아보도록 하겠습니다.
2. 논리 회귀(단층 퍼셉트론)로 AND문제 풀기
2-1. AND
AND 게이트란 두 개의 입력이 모두 1인 경우에만 출력이 1인 논리 게이트입니다.
2-2. 코드
import torch
import torch.nn as nn
import torch.optim as optim
x = [[0, 0], [0, 1], [1, 0], [1, 1]]
y = [[0], [0], [0], [1]]
x_train = torch.FloatTensor(x)
y_train = torch.FloatTensor(y)
model = nn.Sequential(
nn.Linear(2, 1),
nn.Sigmoid()
)
optimizer = optim.SGD(model.parameters(), lr=1)
epochs = 1000
for epoch in range(epochs + 1):
y_pred = model(x_train)
loss = nn.BCELoss()(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
y_bool = ((y_pred >= 0.5) == y_train).float().sum() / len(y_pred) * 100
print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {y_bool:.2f}%')
output>>
Epoch 0/1000 Loss: 0.665210 Accuracy: 75.00%
Epoch 100/1000 Loss: 0.143335 Accuracy: 100.00%
Epoch 200/1000 Loss: 0.081506 Accuracy: 100.00%
Epoch 300/1000 Loss: 0.056452 Accuracy: 100.00%
Epoch 400/1000 Loss: 0.042996 Accuracy: 100.00%
Epoch 500/1000 Loss: 0.034642 Accuracy: 100.00%
Epoch 600/1000 Loss: 0.028969 Accuracy: 100.00%
Epoch 700/1000 Loss: 0.024873 Accuracy: 100.00%
Epoch 800/1000 Loss: 0.021780 Accuracy: 100.00%
Epoch 900/1000 Loss: 0.019364 Accuracy: 100.00%
Epoch 1000/1000 Loss: 0.017426 Accuracy: 100.00%
로지스틱 회귀 모델은 2개의 입력과 1개의 출력을 갖는 선형 모델에 Sigmoid 활성화함수를 나열한 모델입니다.
model = nn.Sequential(
nn.Linear(2, 1),
nn.Sigmoid()
)
최적화 함수는 SGD(Stochastic Gradient Descent)를 사용하였습니다.
optimizer = optim.SGD(model.parameters(), lr=1)
손실함수(비용함수)는 이진 분류에 사용하는 크로스엔트로피 함수인 BCELoss()를 사용하였습니다.
loss = nn.BCELoss()(y_pred, y_train)
2-3. 결과
직선 하나로 4개의 입력을 2개로 분류가 가능합니다.
어떻게 학습을 했건 100%의 정확도를 가질 수 있는 경우인 것이지요.
3. 논리 회귀(단층 퍼셉트론)로 or 문제 풀기
3-1. OR
OR 게이트는 두 입력 모두 0인 경우를 제외한 모든 출력이 1인 논리 게이트입니다.
3-2. 코드
x = [[0, 0], [0, 1], [1, 0], [1, 1]]
y = [[0], [1], [1], [1]]
x_train = torch.FloatTensor(x)
y_train = torch.FloatTensor(y)
model = nn.Sequential(
nn.Linear(2, 1),
nn.Sigmoid()
)
optimizer = optim.SGD(model.parameters(), lr=1)
epochs = 1000
for epoch in range(epochs + 1):
y_pred = model(x_train)
loss = nn.BCELoss()(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
y_bool = ((y_pred >= 0.5) == y_train).float().sum() / len(y_pred) * 100
print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {y_bool:.2f}%')
output>>
Epoch 0/1000 Loss: 0.993666 Accuracy: 25.00%
Epoch 100/1000 Loss: 0.087962 Accuracy: 100.00%
Epoch 200/1000 Loss: 0.046496 Accuracy: 100.00%
Epoch 300/1000 Loss: 0.031249 Accuracy: 100.00%
Epoch 400/1000 Loss: 0.023439 Accuracy: 100.00%
Epoch 500/1000 Loss: 0.018719 Accuracy: 100.00%
Epoch 600/1000 Loss: 0.015566 Accuracy: 100.00%
Epoch 700/1000 Loss: 0.013314 Accuracy: 100.00%
Epoch 800/1000 Loss: 0.011627 Accuracy: 100.00%
Epoch 900/1000 Loss: 0.010316 Accuracy: 100.00%
Epoch 1000/1000 Loss: 0.009270 Accuracy: 100.00%
3-3. 결과
AND와 마찬가지로 이진 분류를 직선 하나로 할 수 있습니다.
역시나 100%로 분류를 할 수 있는 경우입니다.
4. 논리 회귀(단층 퍼셉트론)로 XOR 문제 풀기
4-1. XOR
XOR는 두 입력이 같으면 0 다르면 1을 출력하는 논리 게이트입니다.
4-2. 코드
x = [[0, 0], [0, 1], [1, 0], [1, 1]]
y = [[0], [1], [1], [0]]
x_train = torch.FloatTensor(x)
y_train = torch.FloatTensor(y)
model = nn.Sequential(
nn.Linear(2, 1),
nn.Sigmoid()
)
optimizer = optim.SGD(model.parameters(), lr=1)
epochs = 1000
for epoch in range(epochs + 1):
y_pred = model(x_train)
loss = nn.BCELoss()(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 100 == 0:
y_bool = ((y_pred >= 0.5) == y_train).float().sum() / len(y_pred) * 100
print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {y_bool:.2f}%')
output>>
Epoch 0/1000 Loss: 0.813640 Accuracy: 50.00%
Epoch 100/1000 Loss: 0.693147 Accuracy: 75.00%
Epoch 200/1000 Loss: 0.693147 Accuracy: 75.00%
Epoch 300/1000 Loss: 0.693147 Accuracy: 75.00%
Epoch 400/1000 Loss: 0.693147 Accuracy: 50.00%
Epoch 500/1000 Loss: 0.693147 Accuracy: 50.00%
Epoch 600/1000 Loss: 0.693147 Accuracy: 50.00%
Epoch 700/1000 Loss: 0.693147 Accuracy: 50.00%
Epoch 800/1000 Loss: 0.693147 Accuracy: 50.00%
Epoch 900/1000 Loss: 0.693147 Accuracy: 50.00%
Epoch 1000/1000 Loss: 0.693147 Accuracy: 50.00%
4-3. 결과
AND, OR와 다르게 50%에서 멈춘 것을 볼 수 있습니다.
직선 하나만으로는 입력에 대한 출력을 분류할 수 없습니다.
단층 퍼셉트론은 이처럼 직선만으로는 분류할 수 없는 경우를 구현할 수 없습니다.
5. 다층 퍼셉트론
단층 퍼셉트론은 선형 분리만 가능합니다.
이 한계를 개선하기 위해 다층 퍼셉트론이 등장하였습니다.
다층 퍼셉트론은 말 그대로 층이 여러개입니다.
5-1. 논리 회귀 XOR 분류 모델
model = nn.Sequential(
nn.Linear(2, 64),
nn.Sigmoid(),
nn.Linear(64, 32),
nn.Sigmoid(),
nn.Linear(32, 16),
nn.Sigmoid(),
nn.Linear(16, 1),
nn.Sigmoid()
)
# 입력 - 은닉 - 출력
print(model)
output>>
Sequential(
(0): Linear(in_features=2, out_features=64, bias=True)
(1): Sigmoid()
(2): Linear(in_features=64, out_features=32, bias=True)
(3): Sigmoid()
(4): Linear(in_features=32, out_features=16, bias=True)
(5): Sigmoid()
(6): Linear(in_features=16, out_features=1, bias=True)
(7): Sigmoid()
)
5-2. 학습
x = [[0, 0], [0, 1], [1, 0], [1, 1]]
y = [[0], [1], [1], [0]]
x_train = torch.FloatTensor(x)
y_train = torch.FloatTensor(y)
optimizer = optim.SGD(model.parameters(), lr=1)
epochs = 5000
for epoch in range(epochs + 1):
y_pred = model(x_train)
loss = nn.BCELoss()(y_pred, y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if epoch % 1000 == 0:
y_bool = (y_pred >= 0.5).float()
accuracy = (y_train == y_bool).float().sum() / len(y) * 100
print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {accuracy:.2f}%')
output>>
Epoch 0/5000 Loss: 0.693836 Accuracy: 50.00%
Epoch 1000/5000 Loss: 0.693107 Accuracy: 50.00%
Epoch 2000/5000 Loss: 0.693017 Accuracy: 50.00%
Epoch 3000/5000 Loss: 0.692406 Accuracy: 75.00%
Epoch 4000/5000 Loss: 0.021657 Accuracy: 100.00%
Epoch 5000/5000 Loss: 0.000675 Accuracy: 100.00%
50%였던 정확도가 100%로 올랐습니다.
이제 2개의 결과를 정확하게 분류할 수 있는 모델이 탄생했습니다.
5-2. 결과
아래 그림은 위 모델을 시각화한 것입니다.
입력층: nn.Linear(2, 64), nn.Sigmoid()
은닉층: nn.Linear(64, 32), nn.Sigmoid(), nn.Linear(32, 16), nn.Sigmoid()
출력층: nn.Linear(16, 1), nn.Sigmoid()
단층 퍼셉트론과 다층 퍼셉트론의 차이점중 하나는 은닉층의 유무입니다.
은닉층이란 입력층과 출력층 사이에 존재하는 층을 말합니다.
중간중간에 있는 Sigmoid()함수는 활성화함수로 각 선형 함수들이 합쳐지지 않도록 해줍니다.
또한 선형 함수를 곡선화 시키는 역할을 합니다.
이처럼 은닉층이 2개 이상인 신경망을 심층 신경망(Deep Neural Network, DNN)이라고 하고, 심층 신경망을 학습시키는 것을 딥 러닝(Deep Learning)이라고 합니다.
끝내며 🎲
본격적으로 딥러닝이 시작되었습니다.
대학교 3학년 이러닝 과목으로 딥러닝 기초 이론과 용어에 대해서 배웠던 기억이 있습니다.
(절대평가에 오픈북시험이라 공부를 거의 안 함..)
적어도 한번은 들어본 이름들이 나오니 반가운 마음에 더 열심히 공부하게 되네요.
수학적으로 깊게 탐구하기 위해선 시간이 더 필요하겠지만 지금은 제가 이해한 수준에서 쉽게 전달해보도록 하겠습니다.
감사합니다.
참고
'AI > 딥러닝' 카테고리의 다른 글
[딥러닝] CNN(Convolutional Neural Networks) - 합성곱 인공 신경망 (0) | 2024.01.10 |
---|---|
[딥러닝] 비선형 활성화 함수(Activation Functions) (2) | 2024.01.09 |
댓글