1. 딥러닝: 퍼셉트론과 다층 퍼셉트론

2025. 1. 13. 13:33LLM(Large Language Model)의 기초/딥러닝

1.생물학적 뉴런
* 생물학적 뉴런은 신경계를 구성하는 기본 단위로, 정보를 수집, 처리, 전달하는 기능을 담당합니다. 
* 뉴런은 크게 세 가지 주요 부분으로 나뉩니다: 수상돌기(dendrite), 세포체(cell body), 축삭(axon)입니다. 
* 수상돌기는 다른 뉴런이나 외부 자극으로부터 신호를 받아들이는 역할을 하며, 세포체는 이 신호를 처리하고 통합합니다. 
* 처리된 신호는 축삭을 통해 다음 뉴런이나 근육, 혹은 샘과 같은 다른 조직으로 전달됩니다. 
* 축삭의 끝에는 시냅스(synapse)가 있어 화학적 신호 또는 전기적 신호를 통해 다른 세포와 연결됩니다. 
* 뉴런은 이러한 작용을 통해 신경계가 복잡한 정보를 효율적으로 처리하고 전달할 수 있도록 돕습니다.

 

2. 인공 신경망
* 인공 신경망(Artificial Neural Network, ANN)은 생물학적 신경망의 구조와 기능을 모방한 계산 모델로, 여러 개의 인공 뉴런을 계층적으로 연결하여 구성됩니다. 
* 기본적으로 입력층(input layer), 은닉층(hidden layer), 출력층(output layer)으로 이루어지며, 각 층의 뉴런들은 다음 층의 뉴런과 연결되어 데이터를 전달하고 처리합니다. 
* 입력 데이터는 가중치와 활성화 함수 등의 연산을 거쳐 점차 복잡한 특징을 추출하며, 최종적으로 출력층에서 예측값이나 결과를 생성합니다. 
* 신경망은 데이터에 기반한 학습을 통해 가중치를 조정하면서 문제를 해결하도록 최적화됩니다. 
* 이러한 특성 덕분에 이미지 분류, 음성 인식, 자연어 처리 등 다양한 분야에서 뛰어난 성능을 발휘하며, 딥러닝의 주요 구성 요소로 활용됩니다. 
* ANN은 다층 구조와 비선형 활성화 함수를 통해 복잡한 데이터 간의 관계를 학습할 수 있는 강력한 도구입니다.

 

3. 인공 신경망의 역사
1940년대 ~ 1980년대
* 인공 신경망(Artificial Neural Network, ANN)의 역사는 1940년대에 시작된 초기 개념부터 현대의 딥러닝에 이르기까지 긴 발전 과정을 거쳤습니다. 
* 1943년, 워런 맥컬록(Warren McCulloch)과 월터 피츠(Walter Pitts)는 생물학적 뉴런을 수학적으로 모델링한 맥컬록-피츠 뉴런을 제안하며 ANN의 기초를 마련했습니다. 
* 1958년, 프랭크 로젠블렛(Frank Rosenblatt)은 단층 퍼셉트론(perceptron)을 개발하여 ANN이 학습과 분류 문제를 해결할 수 있음을 보여주었습니다. 
* 그러나 1969년, 마빈 민스키(Marvin Minsky)와 시모어 페이퍼트(Seymour Papert)는 퍼셉트론의 한계를 지적하며, 비선형 문제를 해결하지 못한다는 사실을 제시하였고, 이는 ANN 연구의 침체기로 이어졌습니다.

 

### 퍼셉트론
* 퍼셉트론(Perceptron)은 1958년 프랭크 로젠블렛(Frank Rosenblatt)이 제안한 인공 뉴런 모델로, 가장 간단한 형태의 인공 신경망입니다. 
* 퍼셉트론은 입력 값과 해당 가중치(weight)의 곱을 모두 더한 값에 편향(bias)을 더하고, 이를 활성화 함수(보통 계단 함수)로 변환하여 이진 출력(0 또는 1)을 생성합니다. 
* 학습 과정에서는 출력 값이 실제 값과 다를 경우, 가중치를 조정하는 방식으로 학습이 이루어집니다. 
* 퍼셉트론은 단층 구조로 선형적으로 분리 가능한 문제를 해결할 수 있지만, XOR 문제와 같은 비선형적으로 분리되는 문제를 해결하지 못하는 한계가 있습니다.

 

예시 1)

# 논리 회귀(단층 퍼셉트론)로 AND 문제 해결하기

import torch  # PyTorch 라이브러리
import torch.nn as nn  # PyTorch의 신경망 모듈
import torch.optim as optim  # PyTorch의 최적화 알고리즘 모듈

# 입력 데이터(X)와 정답 데이터(y) 정의
X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
# - X: 2차원 입력 데이터로, AND 문제의 입력값을 정의.
#   - [0, 0], [0, 1], [1, 0], [1, 1]은 AND 연산의 입력 조합.

y = torch.FloatTensor([[0], [0], [0], [1]])
# - y: 입력값(X)에 대한 정답(출력) 데이터를 정의.
#   - AND 연산의 결과:
#     - 0 AND 0 = 0
#     - 0 AND 1 = 0
#     - 1 AND 0 = 0
#     - 1 AND 1 = 1

# 모델 정의
model = nn.Sequential(
    nn.Linear(2, 1),  # 입력 2차원, 출력 1차원 (단층 퍼셉트론 구조)
    nn.Sigmoid()      # 출력값을 0~1 사이의 확률로 변환하는 활성화 함수
)
# - nn.Linear(2, 1):
#   - 입력 데이터(X)의 차원(2)을 출력 차원(1)으로 선형 변환.
#   - 선형 변환 공식: y = xWᵀ + b
# - nn.Sigmoid():
#   - 출력값을 0~1 사이의 확률로 변환하여 논리 회귀 문제에 적합.

# 최적화 알고리즘 설정
optimizer = optim.SGD(model.parameters(), lr=1)
# - optim.SGD:
#   - 확률적 경사 하강법(Stochastic Gradient Descent) 최적화 알고리즘.
# - model.parameters():
#   - 모델에서 학습 가능한 매개변수(가중치와 편향)를 가져옴.
# - lr=1:
#   - 학습률(learning rate)로, 매개변수를 업데이트할 때 사용하는 스텝 크기.

 

예시 2)

# 학습 루프 설정
epochs = 1000  # 총 학습 반복 횟수 설정

for epoch in range(epochs + 1):  # 0부터 epochs까지 학습 반복
    y_pred = model(X)  # 모델에 입력 데이터를 전달하여 예측값 계산
    # - y_pred: 모델이 계산한 출력값 (0~1 사이의 값, 확률 형태).
    
    loss = nn.BCELoss()(y_pred, y)  
    # - nn.BCELoss():
    #   - 이진 크로스 엔트로피(Binary Cross Entropy) 손실 함수.
    #   - 예측값(y_pred)과 실제값(y)의 차이를 계산하여 손실값 반환.

    optimizer.zero_grad()  # 이전 그래디언트 초기화
    loss.backward()  # 손실값을 기반으로 그래디언트 계산 (역전파)
    optimizer.step()  # 계산된 그래디언트를 사용하여 모델의 매개변수 업데이트

    if epoch % 100 == 0:  # 100 에포크마다 결과 출력
        y_bool = (y_pred >= 0.5).float()  
        # - (y_pred >= 0.5): 예측 확률(y_pred)이 0.5 이상인 경우 `1`, 미만인 경우 `0`.
        # - .float(): 부울 값을 실수로 변환.

        accuracy = (y == y_bool).float().sum() / len(y) * 100
        # - (y == y_bool): 실제값(y)과 예측값(y_bool)을 비교하여 정확히 예측한 샘플만 `True`.
        # - .float(): `True`와 `False`를 각각 1.0과 0.0으로 변환.
        # - .sum(): 정확히 예측한 샘플의 개수를 계산.
        # - / len(y): 정확히 예측한 비율 계산.
        # - * 100: 정확도를 백분율로 변환.

        print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {accuracy:.2f}%')
        # - 현재 에포크 번호, 손실값, 정확도 출력.
        # - f-string을 사용하여 손실값과 정확도를 포매팅.
---->
Epoch    0/1000 Loss: 0.610043 Accuracy: 75.00%
Epoch  100/1000 Loss: 0.140965 Accuracy: 100.00%
Epoch  200/1000 Loss: 0.080709 Accuracy: 100.00%
Epoch  300/1000 Loss: 0.056060 Accuracy: 100.00%
Epoch  400/1000 Loss: 0.042764 Accuracy: 100.00%
Epoch  500/1000 Loss: 0.034491 Accuracy: 100.00%
Epoch  600/1000 Loss: 0.028863 Accuracy: 100.00%
Epoch  700/1000 Loss: 0.024794 Accuracy: 100.00%
Epoch  800/1000 Loss: 0.021719 Accuracy: 100.00%
Epoch  900/1000 Loss: 0.019316 Accuracy: 100.00%
Epoch 1000/1000 Loss: 0.017386 Accuracy: 100.00%

 

예시 3)

# 논리 회귀(단층 퍼셉트론)로 OR 문제 해결하기

# OR 연산의 입력 데이터(X)와 정답 데이터(y) 정의
X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
# - X: OR 연산의 입력값을 정의.
#   - [0, 0], [0, 1], [1, 0], [1, 1]은 OR 연산의 가능한 입력 조합.

y = torch.FloatTensor([[0], [1], [1], [1]])
# - y: 입력값(X)에 대한 정답(출력) 데이터를 정의.
#   - OR 연산의 결과:
#     - 0 OR 0 = 0
#     - 0 OR 1 = 1
#     - 1 OR 0 = 1
#     - 1 OR 1 = 1

# 모델 정의
model = nn.Sequential(
    nn.Linear(2, 1),  # 입력 2차원, 출력 1차원 (단층 퍼셉트론 구조)
    nn.Sigmoid()      # 출력값을 0~1 사이의 확률로 변환하는 활성화 함수
)
# - nn.Linear(2, 1):
#   - 입력 데이터(X)의 차원(2)을 출력 차원(1)으로 선형 변환.
#   - 선형 변환 공식: y = xWᵀ + b
# - nn.Sigmoid():
#   - 출력값을 0~1 사이로 변환하여 논리 회귀 문제에 적합.

# 최적화 알고리즘 설정
optimizer = optim.SGD(model.parameters(), lr=1)
# - optim.SGD:
#   - 확률적 경사 하강법(Stochastic Gradient Descent) 최적화 알고리즘.
# - model.parameters():
#   - 모델에서 학습 가능한 매개변수(가중치와 편향)를 가져옴.
# - lr=1:
#   - 학습률(learning rate)로, 매개변수를 업데이트할 때 사용하는 스텝 크기.

# 학습 반복 횟수 설정
epochs = 1000

# 학습 루프
for epoch in range(epochs + 1):  # 0부터 epochs까지 학습 반복
    y_pred = model(X)  # 모델에 입력 데이터를 전달하여 예측값 계산
    # - y_pred: 모델이 계산한 출력값 (0~1 사이의 값, 확률 형태).

    loss = nn.BCELoss()(y_pred, y)  
    # - nn.BCELoss():
    #   - 이진 크로스 엔트로피(Binary Cross Entropy) 손실 함수.
    #   - 예측값(y_pred)과 실제값(y)의 차이를 계산하여 손실값 반환.

    optimizer.zero_grad()  # 이전 그래디언트 초기화
    loss.backward()  # 손실값을 기반으로 그래디언트 계산 (역전파)
    optimizer.step()  # 계산된 그래디언트를 사용하여 모델의 매개변수 업데이트

    if epoch % 100 == 0:  # 100 에포크마다 결과 출력
        y_bool = (y_pred >= 0.5).float()  
        # - (y_pred >= 0.5): 예측 확률(y_pred)이 0.5 이상인 경우 `1`, 미만인 경우 `0`.
        # - .float(): 부울 값을 실수로 변환.

        accuracy = (y == y_bool).float().sum() / len(y) * 100
        # - (y == y_bool): 실제값(y)과 예측값(y_bool)을 비교하여 정확히 예측한 샘플만 `True`.
        # - .float(): `True`와 `False`를 각각 1.0과 0.0으로 변환.
        # - .sum(): 정확히 예측한 샘플의 개수를 계산.
        # - / len(y): 정확히 예측한 비율 계산.
        # - * 100: 정확도를 백분율로 변환.

        print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {accuracy:.2f}%')
        # - 현재 에포크 번호, 손실값, 정확도 출력.
        # - f-string을 사용하여 손실값과 정확도를 포매팅.
---->
Epoch    0/1000 Loss: 0.604133 Accuracy: 75.00%
Epoch  100/1000 Loss: 0.088550 Accuracy: 100.00%
Epoch  200/1000 Loss: 0.046670 Accuracy: 100.00%
Epoch  300/1000 Loss: 0.031329 Accuracy: 100.00%
Epoch  400/1000 Loss: 0.023485 Accuracy: 100.00%
Epoch  500/1000 Loss: 0.018748 Accuracy: 100.00%
Epoch  600/1000 Loss: 0.015586 Accuracy: 100.00%
Epoch  700/1000 Loss: 0.013329 Accuracy: 100.00%
Epoch  800/1000 Loss: 0.011638 Accuracy: 100.00%
Epoch  900/1000 Loss: 0.010326 Accuracy: 100.00%
Epoch 1000/1000 Loss: 0.009277 Accuracy: 100.00%

 

예시 4)

# 논리 회귀(단층 퍼셉트론)로 XOR 문제 해결하기

# XOR 연산의 입력 데이터(X)와 정답 데이터(y) 정의
X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
# - X: XOR 연산의 입력값을 정의.
#   - [0, 0], [0, 1], [1, 0], [1, 1]은 XOR 연산의 가능한 입력 조합.

y = torch.FloatTensor([[0], [1], [1], [0]])
# - y: 입력값(X)에 대한 정답(출력) 데이터를 정의.
#   - XOR 연산의 결과:
#     - 0 XOR 0 = 0
#     - 0 XOR 1 = 1
#     - 1 XOR 0 = 1
#     - 1 XOR 1 = 0

# 모델 정의
model = nn.Sequential(
    nn.Linear(2, 1),  # 입력 2차원, 출력 1차원 (단층 퍼셉트론 구조)
    nn.Sigmoid()      # 출력값을 0~1 사이의 확률로 변환하는 활성화 함수
)
# - nn.Linear(2, 1):
#   - 입력 데이터(X)의 차원(2)을 출력 차원(1)으로 선형 변환.
#   - 선형 변환 공식: y = xWᵀ + b
# - nn.Sigmoid():
#   - 출력값을 0~1 사이로 변환하여 논리 회귀 문제에 적합.

# 최적화 알고리즘 설정
optimizer = optim.SGD(model.parameters(), lr=1)
# - optim.SGD:
#   - 확률적 경사 하강법(Stochastic Gradient Descent) 최적화 알고리즘.
# - model.parameters():
#   - 모델에서 학습 가능한 매개변수(가중치와 편향)를 가져옴.
# - lr=1:
#   - 학습률(learning rate)로, 매개변수를 업데이트할 때 사용하는 스텝 크기.

# 학습 반복 횟수 설정
epochs = 1000

# 학습 루프
for epoch in range(epochs + 1):  # 0부터 epochs까지 학습 반복
    y_pred = model(X)  # 모델에 입력 데이터를 전달하여 예측값 계산
    # - y_pred: 모델이 계산한 출력값 (0~1 사이의 값, 확률 형태).

    loss = nn.BCELoss()(y_pred, y)  
    # - nn.BCELoss():
    #   - 이진 크로스 엔트로피(Binary Cross Entropy) 손실 함수.
    #   - 예측값(y_pred)과 실제값(y)의 차이를 계산하여 손실값 반환.

    optimizer.zero_grad()  # 이전 그래디언트 초기화
    loss.backward()  # 손실값을 기반으로 그래디언트 계산 (역전파)
    optimizer.step()  # 계산된 그래디언트를 사용하여 모델의 매개변수 업데이트

    if epoch % 100 == 0:  # 100 에포크마다 결과 출력
        y_bool = (y_pred >= 0.5).float()  
        # - (y_pred >= 0.5): 예측 확률(y_pred)이 0.5 이상인 경우 `1`, 미만인 경우 `0`.
        # - .float(): 부울 값을 실수로 변환.

        accuracy = (y == y_bool).float().sum() / len(y) * 100
        # - (y == y_bool): 실제값(y)과 예측값(y_bool)을 비교하여 정확히 예측한 샘플만 `True`.
        # - .float(): `True`와 `False`를 각각 1.0과 0.0으로 변환.
        # - .sum(): 정확히 예측한 샘플의 개수를 계산.
        # - / len(y): 정확히 예측한 비율 계산.
        # - * 100: 정확도를 백분율로 변환.

        print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {accuracy:.2f}%')
        # - 현재 에포크 번호, 손실값, 정확도 출력.
        # - f-string을 사용하여 손실값과 정확도를 포매팅.
 --->
Epoch    0/1000 Loss: 0.707292 Accuracy: 25.00%
Epoch  100/1000 Loss: 0.693147 Accuracy: 50.00%
Epoch  200/1000 Loss: 0.693147 Accuracy: 75.00%
Epoch  300/1000 Loss: 0.693147 Accuracy: 50.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%

 

### 1980년대 ~ 2000년대
* 1980년대에 이르러 역전파(backpropagation) 알고리즘이 재발견되면서 ANN이 다시 주목받기 시작했습니다. 
* 특히 제프리 힌턴(Geoffrey Hinton) 등 연구자들의 공헌으로 다층 퍼셉트론(Multi-Layer Perceptron, MLP)이 비선형 문제를 해결할 수 있음을 보였고, ANN 연구가 활발해졌습니다. 
* 1990년대에는 합성곱 신경망(CNN)과 순환 신경망(RNN) 등 특화된 구조가 개발되며 ANN이 더 복잡한 문제를 다룰 수 있게 되었습니다.

 

 

예시 1)

# 다층 퍼셉트론(Multi-Layer Perceptron, MLP) 모델 정의

model = nn.Sequential(
    nn.Linear(2, 4),  # 첫 번째 선형 계층: 입력(2차원) → 은닉층(4차원)
    nn.Sigmoid(),     # 활성화 함수: Sigmoid (은닉층의 비선형성 추가)
    nn.Linear(4, 1),  # 두 번째 선형 계층: 은닉층(4차원) → 출력(1차원)
    nn.Sigmoid()      # 활성화 함수: Sigmoid (출력을 0~1 사이 확률로 변환)
)
# - nn.Sequential:
#   - 계층을 순차적으로 쌓아 신경망을 정의.
#   - 각 계층은 순서대로 연결되어 데이터를 처리.

# - nn.Linear(in_features, out_features):
#   - 선형 변환 계층(fully connected layer).
#   - 입력 크기(`in_features`)에서 출력 크기(`out_features`)로 변환.
# - nn.Sigmoid():
#   - 활성화 함수로, 각 출력값을 0~1 사이의 값으로 변환.
#   - 비선형성을 추가하여 XOR와 같은 비선형 문제를 해결 가능.

# 모델 구조 출력
print(model)
# - 모델의 계층 구조를 출력하여 확인.
--->
Sequential(
  (0): Linear(in_features=2, out_features=4, bias=True)
  (1): Sigmoid()
  (2): Linear(in_features=4, out_features=1, bias=True)
  (3): Sigmoid()
)

--->

 

예시 2)

# 논리 회귀(다층 퍼셉트론)로 XOR 문제 해결하기

# XOR 연산의 입력 데이터(X)와 정답 데이터(y) 정의
X = torch.FloatTensor([[0, 0], [0, 1], [1, 0], [1, 1]])
# - X: XOR 연산의 입력값을 정의.
#   - [0, 0], [0, 1], [1, 0], [1, 1]은 XOR 연산의 가능한 입력 조합.

y = torch.FloatTensor([[0], [1], [1], [0]])
# - y: 입력값(X)에 대한 정답(출력) 데이터를 정의.
#   - XOR 연산의 결과:
#     - 0 XOR 0 = 0
#     - 0 XOR 1 = 1
#     - 1 XOR 0 = 1
#     - 1 XOR 1 = 0

# 최적화 알고리즘 설정
optimizer = optim.SGD(model.parameters(), lr=1)
# - optim.SGD:
#   - 확률적 경사 하강법(Stochastic Gradient Descent) 최적화 알고리즘.
# - model.parameters():
#   - 모델에서 학습 가능한 매개변수(가중치와 편향)를 가져옴.
# - lr=1:
#   - 학습률(learning rate)로, 매개변수를 업데이트할 때 사용하는 스텝 크기.

# 학습 반복 횟수 설정
epochs = 1000

# 학습 루프
for epoch in range(epochs + 1):  # 0부터 epochs까지 학습 반복
    y_pred = model(X)  # 모델에 입력 데이터를 전달하여 예측값 계산
    # - y_pred: 모델이 계산한 출력값 (0~1 사이의 값, 확률 형태).

    loss = nn.BCELoss()(y_pred, y)  
    # - nn.BCELoss():
    #   - 이진 크로스 엔트로피(Binary Cross Entropy) 손실 함수.
    #   - 예측값(y_pred)과 실제값(y)의 차이를 계산하여 손실값 반환.

    optimizer.zero_grad()  # 이전 그래디언트 초기화
    loss.backward()  # 손실값을 기반으로 그래디언트 계산 (역전파)
    optimizer.step()  # 계산된 그래디언트를 사용하여 모델의 매개변수 업데이트

    if epoch % 100 == 0:  # 100 에포크마다 결과 출력
        y_bool = (y_pred >= 0.5).float()  
        # - (y_pred >= 0.5): 예측 확률(y_pred)이 0.5 이상인 경우 `1`, 미만인 경우 `0`.
        # - .float(): 부울 값을 실수로 변환.

        accuracy = (y == y_bool).float().sum() / len(y) * 100
        # - (y == y_bool): 실제값(y)과 예측값(y_bool)을 비교하여 정확히 예측한 샘플만 `True`.
        # - .float(): `True`와 `False`를 각각 1.0과 0.0으로 변환.
        # - .sum(): 정확히 예측한 샘플의 개수를 계산.
        # - / len(y): 정확히 예측한 비율 계산.
        # - * 100: 정확도를 백분율로 변환.

        print(f'Epoch {epoch:4d}/{epochs} Loss: {loss:.6f} Accuracy: {accuracy:.2f}%')
        # - 현재 에포크 번호, 손실값, 정확도 출력.
        # - f-string을 사용하여 손실값과 정확도를 포매팅.
 --->
Epoch    0/1000 Loss: 0.696326 Accuracy: 50.00%
Epoch  100/1000 Loss: 0.693282 Accuracy: 50.00%
Epoch  200/1000 Loss: 0.693132 Accuracy: 50.00%
Epoch  300/1000 Loss: 0.693015 Accuracy: 50.00%
Epoch  400/1000 Loss: 0.692822 Accuracy: 50.00%
Epoch  500/1000 Loss: 0.692270 Accuracy: 50.00%
Epoch  600/1000 Loss: 0.689365 Accuracy: 50.00%
Epoch  700/1000 Loss: 0.657556 Accuracy: 75.00%
Epoch  800/1000 Loss: 0.475295 Accuracy: 75.00%
Epoch  900/1000 Loss: 0.142640 Accuracy: 100.00%
Epoch 1000/1000 Loss: 0.055724 Accuracy: 100.00%

 

4. 비선형 활성화 함수
* 비선형 활성화 함수는 신경망에서 선형 변환만으로는 표현할 수 없는 복잡한 비선형 패턴을 학습할 수 있도록 도와주는 함수입니다. 
* 입력 값을 비선형적으로 변환하여 신경망의 계층마다 다른 특징을 학습하게 하며, 이를 통해 선형 함수들의 조합으로는 표현할 수 없는 복잡한 함수와 데이터 분포를 모델링할 수 있습니다. 
* 주요 예로 ReLU, Sigmoid, Tanh 등이 있으며, 이 함수들은 출력 값을 제한하거나 왜곡하여 학습을 안정화하고, 신경망이 더 강력한 표현력을 가지도록 만듭니다.

 

### 1-1. 시크모이드

# 필요한 라이브러리 임포트
import numpy as np  # 수치 계산을 위한 라이브러리
import matplotlib.pyplot as plt  # 데이터 시각화를 위한 라이브러리

# Sigmoid 함수 정의
def sigmoid(x):
    return 1 / (1 + np.exp(-x))
    # - np.exp(-x): x 값에 대한 지수 함수(e^(-x))를 계산.
    # - 1 / (1 + np.exp(-x)): Sigmoid 함수 공식.
    #   - 입력값(x)을 0~1 사이로 변환.
    #   - x가 음수일수록 출력값은 0에 가까워지고,
    #     x가 양수일수록 출력값은 1에 가까워짐.

# x 값의 범위 설정
x = np.arange(-5.0, 5.0, 0.1)
# - np.arange(start, stop, step):
#   - -5.0부터 5.0까지 0.1 간격으로 값을 생성.
#   - 결과는 [-5.0, -4.9, ..., 4.9]와 같은 배열.

# Sigmoid 함수 적용
y = sigmoid(x)
# - x 배열의 각 원소에 대해 Sigmoid 함수 값을 계산하여 y 배열 생성.

# Sigmoid 함수 시각화
plt.plot(x, y)  # x와 y 값을 사용해 그래프를 그림.
plt.plot([0, 0], [1.0, 0.0], ':')  
# - [0, 0]: x축에서 0을 기준으로 수직선을 그림.
# - [1.0, 0.0]: y축의 시작(1.0)과 끝(0.0)을 연결.
# - ':'은 점선 스타일을 의미.
plt.title('Sigmoid Function')  # 그래프 제목 설정.
plt.show()  # 그래프 출력.

---->

 

### 4-2. 하이퍼볼릭탄젠트
* 하이퍼볼릭 탄젠트(흔히 Tanh 함수라고 불림)는 비선형 활성화 함수 중 하나로, 입력 값을 -1에서 1 사이의 값으로 변환하는 함수입니다. 
* 입력 값이 큰 양수일수록 1에 가까워지고, 큰 음수일수록 -1에 가까워집니다. 
* 이 함수는 출력 범위가 대칭적이어서 Sigmoid 함수와 달리 출력이 0을 기준으로 분포되므로, 데이터가 양수와 음수로 분리되는 문제에서 더 적합합니다. 
* 그러나 입력 값이 매우 크거나 작을 경우 기울기가 거의 0에 가까워지는 "기울기 소실" 문제가 발생할 수 있습니다. 
* Tanh는 주로 출력 값의 분포를 중심에 맞추고 싶을 때 사용됩니다.

 

예시 1)

# 필요한 라이브러리 임포트
import numpy as np  # 수치 계산을 위한 라이브러리
import matplotlib.pyplot as plt  # 데이터 시각화를 위한 라이브러리

# x 값의 범위 설정
x = np.arange(-5.0, 5.0, 0.1)
# - np.arange(start, stop, step):
#   - -5.0부터 5.0까지 0.1 간격으로 값을 생성.
#   - 결과는 [-5.0, -4.9, ..., 4.9]와 같은 배열.

# Tanh 함수 적용
y = np.tanh(x)
# - np.tanh(x):
#   - 입력값(x)에 대해 쌍곡탄젠트(Tanh) 함수를 적용.
#   - Tanh 함수 공식:
#     \[
#     \text{Tanh}(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}}
#     \]
#   - 결과는 [-1, 1] 범위의 값을 반환.
#   - x가 음수일수록 출력값은 -1에 가까워지고,
#     x가 양수일수록 출력값은 1에 가까워짐.

# Tanh 함수 시각화
plt.plot(x, y)  # x와 y 값을 사용해 Tanh 함수 그래프를 그림.
plt.plot([0, 0], [1.0, 0.0], ':')  
# - [0, 0]: x축에서 0을 기준으로 수직선을 그림.
# - [1.0, 0.0]: y축의 시작(1.0)과 끝(0.0)을 연결.
# - ':'은 점선 스타일을 의미.
plt.axhline(y=0, color='orange', linestyle='--')  
# - axhline(y=0): y=0에 가로선(수평선)을 그림.
# - color='orange': 수평선의 색상을 주황색으로 설정.
# - linestyle='--': 수평선을 점선 스타일로 설정.
plt.title('Tanh Function')  # 그래프 제목 설정.
plt.show()  # 그래프 출력.

---->

 

### 4-3. 렐루(Rectified Linear Unit)
* ReLU(Rectified Linear Unit)는 신경망에서 가장 널리 사용되는 비선형 활성화 함수 중 하나로, 입력 값이 0보다 크면 그대로 출력하고, 0 이하이면 0을 출력하는 함수입니다.
* 출력 값이 양수인 경우 기울기가 1로 일정하게 유지되므로 기울기 소실 문제를 완화할 수 있습니다.
* 이로 인해 학습이 빠르고 효율적이며, 깊은 신경망에서 성능이 뛰어난 것으로 알려져 있습니다.
* 그러나 ReLU는 입력 값이 0 이하일 때 기울기가 0이 되어 학습되지 않는 "죽은 ReLU" 문제가 발생할 수 있으며, 이를 보완하기 위해 Leaky ReLU와 같은 변형 함수들이 개발되었습니다.

 

예시 1)

# ReLU (Rectified Linear Unit) 함수 시각화

plt.plot(x, y)  
# - x: 입력 데이터.
# - y: ReLU 함수가 적용된 출력값(양수는 그대로, 음수는 0으로 변환).
# - x와 y를 사용하여 ReLU 함수의 그래프를 그림.

plt.plot([0, 0], [5.0, 0.0], ':')  
# - [0, 0]: x축에서 0을 기준으로 수직선을 그림.
# - [5.0, 0.0]: y축의 시작(5.0)과 끝(0.0)을 연결.
# - ':'은 점선 스타일로 설정하여 보조선을 강조.

plt.title('ReLU Function')  
# - 그래프 제목을 "ReLU Function"으로 설정.

plt.show()  
# - 그래프를 출력하여 화면에 표시.

--->

 

 

##4-4. 소프트맥스

 

예시 1)

# Softmax 함수 구현 및 시각화

# x 값의 범위 설정
x = np.arange(-5.0, 5.0, 0.1)
# - np.arange(start, stop, step):
#   - -5.0부터 5.0까지 0.1 간격으로 값을 생성.
#   - 결과는 [-5.0, -4.9, ..., 4.9]와 같은 배열.

# Softmax 함수 계산
y = np.exp(x) / np.sum(np.exp(x))
# - np.exp(x): x 배열의 각 요소에 대해 지수 함수(e^x)를 계산.
# - np.sum(np.exp(x)): x 배열의 모든 요소에 대해 e^x 값을 계산한 후 합산.
# - Softmax 공식:
#   \[
#   S(x_i) = \frac{e^{x_i}}{\sum_{j} e^{x_j}}
#   \]
#   - 입력값을 확률 분포로 변환하여 각 값이 0~1 사이에 속하며, 전체 합은 1이 됨.

# Softmax 함수 시각화
plt.plot(x, y)  # x와 y 값을 사용해 Softmax 함수 그래프를 그림.
plt.title('Softmax Function')  # 그래프 제목을 "Softmax Function"으로 설정.
plt.show()  # 그래프를 출력.

--->

 

 

728x90
LIST