딥러닝을 깨우는 마법 버튼, 활성화 함수 완전 정복: ReLU부터 GELU·SwiGLU·TeLU까지
딥러닝 모델의 성능은 어떤 활성화 함수를 선택하는지에 따라 크게 달라질 수 있습니다. 이 글에서는 딥러닝의 기초가 되는 활성화 함수의 역할부터, Sigmoid와 ReLU를 거쳐 최신 Transformer 모델에 사용되는 GELU, SwiGLU, TeLU에 이르기까지 그 발전 과정과 핵심 특징을 총정리합니다. 특히, 많은 분들이 실수하는 출력층 함수 선택법(회귀, 이진/다중 분류)을 명확히 제시하고, 실제 프로젝트에 바로 적용할 수 있는 실용적인 선택 가이드를 제공하는 것을 목표로 합니다.

1. 활성화 함수란 무엇이고 왜 필요할까요?
신경망의 뉴런은 입력 신호에 가중치를 곱하고 편향을 더하는 단순한 선형 연산()을 수행합니다. 만약 이 선형 연산의 결과가 그대로 다음 층으로 전달된다면, 아무리 층을 깊게 쌓아도 전체 네트워크는 결국 하나의 거대한 선형 함수와 다를 바 없게 됩니다. 즉, 복잡한 데이터 패턴을 학습할 수 없다는 의미입니다.
활성화 함수(Activation Function)는 바로 이 지점에서 선형적인 계산 결과에 비선형성(Non-linearity)을 더해주는 역할을 합니다. 이 비선형성 덕분에 신경망은 직선이 아닌, 복잡하고 구불구불한 결정 경계를 만들어낼 수 있으며, 비로소 딥러닝 모델이라 부를 수 있는 강력한 표현력을 갖게 됩니다. 더 자세한 설명은 Do You Know?의 딥러닝 기초 포스트에서 확인하실 수 있습니다.
2. 세대별 활성화 함수 발전 과정과 특징
활성화 함수는 딥러닝의 역사와 함께 발전해 왔습니다. 각 함수의 장단점을 이해하면 어떤 상황에 무엇을 써야 할지 명확해집니다.

2.1. 1세대: 초창기 신경망을 이끌었던 함수들 (Sigmoid, Tanh)
Sigmoid (시그모이드)

- 특징: 모든 입력값을 0과 1 사이의 값으로 변환해, 확률처럼 해석하기 용이합니다.
- 문제점: 입력값이 0에서 멀어질수록 기울기가 0에 가까워지는 기울기 소실(Vanishing Gradient) 문제가 치명적입니다. 이는 깊은 신경망의 학습을 어렵게 만드는 주된 원인이었습니다.
- 현재의 쓰임새: 이런 단점 때문에 은닉층에서는 거의 사용되지 않으며, 주로 이진 분류 문제의 출력층에서 제한적으로 사용됩니다.
torch.sigmoid(x)
nn.Sigmoid()
import torch
import torch.nn as nn
# 1. 레이어 정의
sigmoid = nn.Sigmoid()
# 2. 입력 데이터 생성
input_data = torch.tensor([-1.0, 0.0, 1.0])
# 3. 적용
output = sigmoid(input_data)
print(output)
# 결과: tensor([0.2689, 0.5000, 0.7311])
import torch
# 입력 데이터
x = torch.tensor([-10.0, 0.0, 10.0])
# 함수처럼 바로 사용
y = torch.sigmoid(x)
print(y)
# 결과: tensor([4.5398e-05, 5.0000e-01, 9.9995e-01])Tanh (하이퍼볼릭 탄젠트)

- 특징: 출력 범위를 -1과 1 사이로 확장하고, 출력값의 중심이 0(Zero-centered)이 되도록 개선한 함수입니다. 이 덕분에 Sigmoid보다는 학습 효율이 다소 높습니다.
- 문제점: Sigmoid와 마찬가지로 입력값이 커지면 기울기 소실 문제가 여전히 발생합니다.
- 현재의 쓰임새: 주로 RNN이나 LSTM 같은 순환 신경망 모델의 내부 구조에서 찾아볼 수 있습니다.
torch.tanh(x)
nn.Tanh()
import torch
import torch.nn as nn
# 1. 레이어 정의
tanh = nn.Tanh()
# 2. 입력 데이터 (음수, 0, 양수 포함)
input_data = torch.tensor([-2.0, 0.0, 2.0])
# 3. 적용
output = tanh(input_data)
print(output)
# 결과: tensor([-0.9640, 0.0000, 0.9640])
# 특징: 입력이 0일 때 정확히 0이 나옵니다.
import torch
# 입력 데이터
x = torch.tensor([-10.0, 0.0, 10.0])
# 함수처럼 바로 사용
y = torch.tanh(x)
print(y)
# 결과: tensor([-1., 0., 1.])
# 범위가 -1에서 1 사이로 압축됩니다.2.2. 2세대: 딥러닝의 부흥을 이끈 ReLU와 변형들
ReLU (렐루)

- 특징: 라는 간단한 수식처럼, 입력이 0보다 작으면 0, 크면 입력값을 그대로 출력합니다.
- 장점: 연산이 매우 빠르고, 양수 구간에서는 기울기가 1로 유지되어 기울기 소실 문제를 효과적으로 해결했습니다. AlexNet 이후 딥러닝의 부흥을 이끈 일등공신이라 할 수 있습니다.
- 문제점: 입력이 음수이면 기울기도 0이 되어 뉴런이 아예 학습 과정에서 비활성화되는 ‘죽은 ReLU(Dying ReLU)’ 현상이 발생할 수 있습니다.
- 현재의 쓰임새: 이런 단점에도 불구하고, 여전히 대부분의 CNN과 MLP 모델에서 은닉층의 표준(Default)으로 사용됩니다.
nn.ReLU()
import torch.nn.functional as F
F.relu(x)
import torch
import torch.nn as nn
# 데이터 생성 (배치 크기 2, 특징 3개)
input_tensor = torch.randn(2, 3)
print("입력:\n", input_tensor)
# 1. nn.ReLU 인스턴스 생성
relu_layer = nn.ReLU()
# 2. 입력 통과
output_tensor = relu_layer(input_tensor)
print("\n출력 (nn.ReLU):\n", output_tensor)
# --- 실제 모델에서의 사용 예시 ---
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
# 계층 정의 시점에 포함
self.layer1 = nn.Linear(10, 20)
self.relu = nn.ReLU()
self.layer2 = nn.Linear(20, 5)
# 또는 nn.Sequential 사용 시
self.model_seq = nn.Sequential(
nn.Linear(10, 20),
nn.ReLU(inplace=True), # inplace=True는 메모리 절약에 도움됨
nn.Linear(20, 5)
)
def forward(self, x):
x = self.layer1(x)
x = self.relu(x) # 정의된 계층 사용
x = self.layer2(x)
return x
import torch
import torch.nn.functional as F # 관례적으로 F로 임포트합니다.
# 데이터 생성
input_tensor = torch.randn(2, 3)
print("입력:\n", input_tensor)
# functional.relu 함수 직접 호출
output_tensor = F.relu(input_tensor)
print("\n출력 (F.relu):\n", output_tensor)
# --- 실제 모델에서의 사용 예시 ---
class SimpleNetF(nn.Module):
def __init__(self):
super(SimpleNetF, self).__init__()
# 가중치가 있는 계층만 정의
self.layer1 = nn.Linear(10, 20)
self.layer2 = nn.Linear(20, 5)
def forward(self, x):
x = self.layer1(x)
x = F.relu(x) # forward 안에서 함수로 적용
x = self.layer2(x)
return xLeaky ReLU, PReLU, ELU

- 아이디어: 죽은 ReLU 문제를 해결하기 위해 등장했습니다. 음수 입력에 대해 0이 아닌 작은 기울기를 부여하는 것이 핵심입니다.
- Leaky ReLU: 음수 부분에 0.01과 같은 작은 상수를 곱해줍니다.
- PReLU: 이 기울기 값 자체를 학습 가능한 파라미터로 설정합니다.
- ELU: 음수 부분을 부드러운 지수 곡선으로 만들어 노이즈에 더 강건하게 대응합니다.
- 추천: ReLU를 사용했을 때 학습이 불안정하거나 성능이 정체된다면, 이 함수들을 대안으로 고려해볼 수 있습니다.
2.3. 3세대: 최신 모델이 선택한 고성능 함수들
Transformer 기반의 거대 언어 모델(LLM)이 주류가 되면서, ReLU보다 더 부드럽고 표현력이 좋은 활성화 함수들이 주목받고 있습니다.
Swish (SiLU) & Mish

- 특징: ReLU와 유사하지만 0 근처에서 부드러운 곡선 형태를 띠어, 더 안정적인 그래디언트 흐름을 가능하게 합니다. 깊은 네트워크에서 ReLU보다 더 나은 성능을 보이는 것으로 알려져 있습니다. (예: EfficientNet, YOLOv5)
nn.SiLU(inplace=True)
import torch.nn.functional as F
F.silu(x)
import torch
import torch.nn as nn
# --- 사용 예시 ---
# 1. 레이어 정의
silu_layer = nn.SiLU()
# inplace=True 옵션을 주면 메모리를 약간 아낄 수 있습니다. (입력 데이터를 덮어씀)
# silu_layer = nn.SiLU(inplace=True)
# 2. 입력 데이터 생성 (예: 배치 크기 2, 특징 크기 5)
input_tensor = torch.randn(2, 5)
print("Input:\n", input_tensor)
# 3. 적용
output_tensor = silu_layer(input_tensor)
print("\nOutput (nn.SiLU):\n", output_tensor)
# --- 실제 모델 내부에서의 사용 예시 ---
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1)
self.bn1 = nn.BatchNorm2d(16)
# 여기서 활성화 함수로 SiLU를 선언합니다.
self.act1 = nn.SiLU(inplace=True)
self.fc = nn.Linear(16 * 32 * 32, 10)
def forward(self, x):
x = self.conv1(x)
x = self.bn1(x)
x = self.act1(x) # 적용
# ... 이하 생략 ...
return x
import torch
import torch.nn.functional as F
# 입력 데이터 생성
input_tensor = torch.randn(2, 5)
# 함수형 API로 직접 호출
# F.silu 혹은 F.si_lu 둘 다 사용 가능합니다.
output_functional = F.silu(input_tensor)
# output_functional = F.si_lu(input_tensor, inplace=True) # inplace 지원
print("Output (F.silu):\n", output_functional)
# --- 모델 forward 내부 사용 예시 ---
class SimpleModel(nn.Module):
def __init__(self):
super().__init__()
self.fc1 = nn.Linear(10, 20)
def forward(self, x):
x = self.fc1(x)
# 별도 층 선언 없이 바로 사용
x = F.silu(x)
return xGELU (젤루)

- 특징: 입력값에 정규분포의 누적분포함수를 곱하는, 확률적 개념이 적용된 함수입니다.
- 장점: 복잡한 패턴 학습에 유리하며, BERT, GPT 등 대부분의 Transformer 모델에서 표준 활성화 함수로 채택되었습니다.
nn.GELU()
import torch.nn.functional as F
F.gelu(x)
import torch
import torch.nn as nn
class MyModel(nn.Module):
def __init__(self, input_size, hidden_size):
super(MyModel, self).__init__()
self.fc1 = nn.Linear(input_size, hidden_size)
# GELU 레이어 선언
self.act = nn.GELU()
self.fc2 = nn.Linear(hidden_size, 10)
def forward(self, x):
x = self.fc1(x)
# GELU 적용
x = self.act(x)
x = self.fc2(x)
return x
# 사용 예시
model = MyModel(input_size=20, hidden_size=50)
dummy_input = torch.randn(5, 20)
output = model(dummy_input)
print(output.shape)
import torch
import torch.nn.functional as F
# 입력 데이터
x = torch.randn(5)
print("Input:", x)
# GELU 함수 적용
output = F.gelu(x)
print("Output:", output)SwiGLU (스위글루)

- : 입력 벡터입니다.
- : 학습 가능한 가중치 행렬(Weight Matrices)입니다. (즉, 입력 $x$가 두 갈래로 나뉘어 들어갑니다.)
- : 이 부분이 ‘게이트(Gate)’ 역할을 합니다. 0~1 사이의 값(또는 그 이상)을 출력하여 정보의 흐름을 조절합니다.
- : 이 부분이 실제 정보(값, Value)를 담고 있는 선형 변환입니다.
- : 요소별 곱(Element-wise product)입니다. 게이트의 값에 따라 정보가 통과되거나 차단됩니다.
- 특징: GLU(Gated Linear Unit)에 Swish를 결합한 형태로, 입력의 일부를 ‘게이트’로 사용하여 정보의 흐름을 조절합니다.
- 장점: Llama 3와 같은 최신 LLM들이 채택하여, GELU보다 더 나은 성능을 보여주는 것으로 알려져 있습니다. 다만, 연산은 더 복잡합니다.
import torch
import torch.nn as nn
import torch.nn.functional as F
class SwiGLUFFN(nn.Module):
"""
SwiGLU 활성화 메커니즘을 사용하는 Feed-Forward Network 구현.
LLaMA, PaLM 등 최신 LLM에서 사용되는 구조입니다.
"""
def __init__(self, dim_in, dim_hidden, dim_out=None, bias=False):
"""
Args:
dim_in (int): 입력 차원 크기 (모델의 hidden dimension)
dim_hidden (int): FFN 내부의 중간 차원 크기 (보통 dim_in의 4배 또는 8/3배)
dim_out (int, optional): 출력 차원 크기. None이면 dim_in과 동일하게 설정.
bias (bool): 선형 층에 편향(bias) 사용 여부. 최신 모델들은 보통 False로 설정.
"""
super().__init__()
if dim_out is None:
dim_out = dim_in
# W_gate와 W_value를 하나의 선형 층으로 결합하여 효율성 증대
# 입력 차원에서 hidden 차원의 2배로 투영합니다.
self.w12 = nn.Linear(dim_in, 2 * dim_hidden, bias=bias)
# Swish 활성화 함수 (beta=1인 경우 SiLU와 동일)
self.act = nn.SiLU()
# 최종 출력을 위한 투영 층 (W_out)
self.w3 = nn.Linear(dim_hidden, dim_out, bias=bias)
def forward(self, x):
"""
Args:
x (torch.Tensor): 입력 텐서. Shape: (batch_size, seq_len, dim_in)
Returns:
torch.Tensor: 출력 텐서. Shape: (batch_size, seq_len, dim_out)
"""
# 1. Gate와 Value를 위한 통합 투영
# shape: (batch, seq, 2 * dim_hidden)
projected = self.w12(x)
# 2. 마지막 차원을 기준으로 절반으로 나눔 (Chunking)
# gate shape: (batch, seq, dim_hidden)
# value shape: (batch, seq, dim_hidden)
gate, value = torch.chunk(projected, 2, dim=-1)
# 3. SwiGLU 연산 적용: Swish(gate) * value
# shape: (batch, seq, dim_hidden)
hidden = self.act(gate) * value
# 4. 최종 출력 차원으로 투영
# shape: (batch, seq, dim_out)
output = self.w3(hidden)
return output
# --- 사용 예시 ---
if __name__ == '__main__':
# 하이퍼파라미터 설정
batch_size = 4
seq_len = 64
model_dim = 512 # 입력/출력 차원 (d_model)
# LLaMA 스타일 중간 차원 계산 (보통 d_model * 8/3 반올림)
hidden_dim = int(2 * model_dim * 4 / 3)
# 또는 간단히 4배: hidden_dim = 4 * model_dim
print(f"Model dimension: {model_dim}")
print(f"FFN Hidden dimension: {hidden_dim}")
# 모듈 초기화
# 최신 트렌드에 맞춰 bias=False 설정
swiglu_ffn = SwiGLUFFN(dim_in=model_dim, dim_hidden=hidden_dim, bias=False)
# 모델 구조 출력
print("\nModel Structure:")
print(swiglu_ffn)
# 더미 입력 데이터 생성
x = torch.randn(batch_size, seq_len, model_dim)
print(f"\nInput shape: {x.shape}")
# Forward pass
output = swiglu_ffn(x)
print(f"Output shape: {output.shape}")
# 간단한 검증
assert output.shape == (batch_size, seq_len, model_dim)
print("\nSwiGLU FFN pass successful!")TeLU (텔루)

- 특징: 2024년경 제안된 비교적 새로운 함수로, ReLU의 단순성과 Tanh의 부드러움을 결합하여 빠르고 안정적인 학습을 목표로 합니다. 아직 연구가 더 필요하지만 가능성을 주목받고 있습니다.
x * torch.tanh(torch.exp(x))
import torch
import torch.nn as nn
import torch.nn.functional as F
# --- 1. 함수형 구현 (Functional API) ---
def telu_functional(x):
"""
TeLU (Tanh Exponential Linear Unit) activation function.
Formula: f(x) = x * tanh(exp(x))
"""
# torch.exp(x)가 너무 커지면 overflow가 발생할 수 있으나,
# tanh가 이를 1로 안정적으로 잡아줍니다.
# 일반적인 딥러닝 입력 범위에서는 이 구현으로 충분합니다.
return x * torch.tanh(torch.exp(x))
# --- 2. 모듈형 구현 (nn.Module API) ---
class TeLU(nn.Module):
"""
Applies the TeLU function element-wise:
Shape:
- Input: (N, *) where * means, any number of additional dimensions
- Output: (N, *), same shape as the input
"""
def __init__(self):
super(TeLU, self).__init__()
def forward(self, x):
return telu_functional(x)
# --- 사용 예시 ---
if __name__ == '__main__':
# 테스트 입력 데이터 생성
x = torch.randn(2, 5, requires_grad=True)
print("Input x:\n", x)
# 1. 함수형 API 사용 예시
output_f = telu_functional(x)
print("\nOutput (functional):\n", output_f)
# 2. 모듈형 API 사용 예시 (nn.Sequential 모델 내 사용)
model = nn.Sequential(
nn.Linear(5, 10),
TeLU(), # 레이어로 추가
nn.Linear(10, 2)
)
# 모델 통과 테스트
output_m = model(x)
print("\nModel Output shape with TeLU layer:", output_m.shape)
# 역전파(Backpropagation) 테스트
loss = output_m.sum()
loss.backward()
print("\nGradient computed successfully on input x:\n", x.grad is not None)2.4. 새로운 패러다임: Kolmogorov-Arnold Networks (KAN)
2024년 MIT 연구진이 발표한 Kolmogorov-Arnold Networks (KAN)은 기존 MLP(Multi-Layer Perceptron)의 패러다임을 완전히 뒤집는 혁신적인 아키텍처예요. 전통적인 신경망과는 근본적으로 다른 접근 방식을 취하고 있어서, “활성화 함수의 미래”로 주목받고 있답니다.
기존 MLP vs KAN: 무엇이 다를까요?
전통적인 MLP의 구조:
- 노드(뉴런)에 고정된 활성화 함수 (ReLU, GELU 등)
- 엣지(연결)에 학습 가능한 가중치 (선형 변환)
- 계산:
KAN의 혁신적인 구조:
- 노드는 단순히 입력을 합산만 함 (활성화 함수 없음!)
- 엣지에 학습 가능한 활성화 함수 (B-spline 기반)
- 계산: 각 엣지가 독립적인 비선형 함수를 학습
이는 Kolmogorov-Arnold 표현 정리(Kolmogorov-Arnold Representation Theorem)에서 영감을 받은 것으로, “모든 다변수 연속 함수는 1변수 함수들의 조합으로 표현 가능하다”는 수학적 원리를 신경망에 적용한 결과예요.
KAN의 핵심: B-Spline 활성화 함수
KAN의 각 엣지는 B-Spline(Basis Spline)이라는 수학적 기법으로 활성화 함수를 표현해요.
수식:
여기서:
- : B-spline 기저 함수 (고정)
- : 학습 가능한 제어점 파라미터
- : 전체 활성화 크기를 조절하는 스케일 파라미터
B-Spline은 여러 개의 다항식을 부드럽게 이어 붙인 함수로, 곱셈, 나눗셈, 지수, 로그 등 복잡한 비선형 함수를 단일 층에서 표현할 수 있어요. MLP가 여러 층을 쌓아야 표현할 수 있는 것을 KAN은 한 층으로 해결할 수 있는 거죠.
KAN의 장점
- 파라미터 효율성
- 같은 성능을 내는 데 MLP보다 100배 적은 파라미터 필요
- 예: PDE 풀이에서 2층 폭-10 KAN = 4층 폭-100 MLP (파라미터 100배 차이)
- 더 빠른 수렴
- 신경 스케일링 법칙이 MLP보다 우수 (이론적/실험적으로 검증)
- 복잡한 수식이나 물리 법칙 학습에서 특히 효과적
- 해석 가능성 (Interpretability)
- 각 엣지의 활성화 함수를 시각화하면 어떤 변환이 일어나는지 직관적으로 이해 가능
- 과학자들이 수학·물리 법칙을 재발견하는 데 협력자 역할
- 상징적 회귀(Symbolic Regression)에서 탁월
- 데이터에서 수학 공식을 역추출하는 작업에서 MLP를 압도
KAN의 단점 및 한계
- 범용 작업에서는 MLP가 여전히 우세
- 2024년 공정 비교 연구(arXiv 2407.16674)에 따르면, 이미지 분류, NLP, 오디오 처리 등에서는 MLP가 더 나은 성능
- KAN이 우위를 보이는 건 주로 수식 표현(Symbolic Formula Representation) 작업
- 학습 안정성
- B-spline 초기화가 까다롭고, 학습 과정이 불안정할 수 있어요
- Adam 옵티마이저보다 L-BFGS가 필요한 경우도 있음
- 연속 학습(Continual Learning)에서 망각 문제
- 클래스 증분 학습(Class-Incremental Learning)에서 MLP보다 더 심한 망각 현상
- 실무 생태계 부족
- PyTorch/TensorFlow에 기본 내장되지 않아 커스텀 구현 필요
- 최적화 도구, 튜토리얼이 아직 부족
KAN의 활용 분야
KAN이 특히 강력한 분야:
| 분야 | 설명 | 예시 |
|---|---|---|
| 편미분 방정식(PDE) 풀이 | 물리학, 공학 문제 모델링 | 나비에-스토크스 방정식, 열 전달 |
| 상징적 회귀 | 데이터에서 수학 공식 발견 | (E=mc^2), 케플러 법칙 재발견 |
| 밀도 범함수 이론(DFT) | 양자화학 계산 | 분자 궤도 에너지 예측 |
| 과학적 발견 | 물리·수학 법칙 탐색 | 새로운 물리 상수 관계 도출 |
MLP가 여전히 나은 분야:
- 일반적인 이미지 분류 (CIFAR-10, ImageNet)
- 자연어 처리 (텍스트 분류, 감정 분석)
- 오디오 처리
- 대부분의 표준 머신러닝 벤치마크
실무 적용 시 고려사항
- 문제 유형 확인
- 수식/물리 법칙 학습 → KAN 고려
- 일반 분류/회귀 → MLP가 안전
- 파라미터 효율성이 중요한가?
- 모델 크기를 극도로 줄여야 한다면 KAN 실험 가치 있음
- 해석 가능성이 필수인가?
- 과학 연구, 의료 진단 등 “왜?”가 중요하다면 KAN의 강점 활용
- 현재는 연구 단계
- 2024년 발표된 신기술이라 Production 환경보다는 연구·실험용
- 향후 “Kansformer” (KAN + Transformer) 같은 하이브리드 모델 가능성
KAN의 미래
KAN은 “활성화 함수를 학습한다”는 근본적으로 새로운 아이디어를 제시했어요. 현재는 특정 과학적 작업에 특화되어 있지만, 앞으로는:
- Transformer와의 결합 (“Kansformer”)
- 하이브리드 아키텍처 (MLP + KAN 조합)
- 도메인 특화 최적화 (생물정보학, 금융 시계열 등)
등으로 발전할 가능성이 높아요. ReLU가 2012년 AlexNet 이후 표준이 되기까지 시간이 걸렸듯이, KAN도 점진적으로 실무에 스며들 것으로 예상됩니다.
KAN에 대한 보다 자세한 내용은 MLP는 죽었다? Kolmogorov-Arnold Networks (KAN) 완벽 해부! 학습 가능한 활성화 함수의 혁명를 참고해주세요.
3. [핵심] 출력층 활성화 함수 선택 가이드
은닉층 활성화 함수는 실험적으로 선택할 여지가 있지만, 출력층(Output Layer) 함수는 문제 유형에 따라 정해진 규칙을 따라야 합니다. 여기서의 실수는 모델의 근본적인 목적을 해칠 수 있습니다.

3.1. 회귀 (Regression): 연속적인 값을 예측할 때
- 추천 함수: Linear (활성화 함수 없음)
- 이유: 모델이 예측해야 할 값(예: 주가, 온도, 매출)은 범위 제한이 없는 실수입니다. 여기에 Sigmoid나 ReLU 같은 함수를 적용하면 예측값이 특정 범위(0~1 또는 0 이상)로 제한되어 올바른 예측이 불가능해집니다. 따라서 아무런 활성화 함수를 적용하지 않는 것이 정답입니다.
3.2. 이진 분류 (Binary Classification): 두 개 중 하나를 결정할 때
- 추천 함수: Sigmoid
- 이유: 최종 출력값을 0과 1 사이의 확률로 변환해 줍니다. 예를 들어, 0.5를 기준으로 그보다 크면 ‘True’, 작으면 ‘False’로 판단할 수 있어 직관적입니다.
3.3. 다중 분류 (Multi-class Classification): 여러 개 중 하나를 고를 때
- 추천 함수: Softmax
- 이유: 출력 노드 전체의 값을 합하면 1이 되는 확률 분포로 만들어줍니다. 예를 들어, [개, 고양이, 새]에 대한 예측값이 [0.7, 0.2, 0.1]처럼 나와, 가장 확률이 높은 ‘개’를 최종 예측으로 선택할 수 있게 합니다. 각 클래스가 상호 배타적인 경우에 사용됩니다.
4. 한눈에 보는 활성화 함수 비교 표

| 세대 | 함수명 | 주요 특징 | 장점 | 단점 | 추천 분야 |
|---|---|---|---|---|---|
| 1세대 | Sigmoid | S자 곡선, 0~1 범위 | 확률 해석 용이, 이진 분류에 직관적 | 기울기 소실, Not zero-centered | 이진 분류 출력층 |
| 1세대 | Tanh | -1~1 S자 곡선 | Zero-centered, Sigmoid보다 학습 안정 | 여전히 기울기 소실 | RNN/LSTM 은닉 상태 |
| 2세대 | ReLU | 0에서 꺾인 직선 | 매우 빠름, 기울기 소실 완화, 희소 활성화 | Dying ReLU, Not zero-centered | CNN, 일반 MLP 은닉층 기본값 |
| 2세대 | Leaky ReLU | 음수도 약간 통과 | Dying ReLU 완화, 음수 구간 기울기 유지 | α 튜닝 필요 | GAN, 의료 영상, 깊은 CNN |
| 2세대 | PReLU | 음수 기울기 학습 | 데이터에 맞게 최적화, 유연성 | 파라미터 증가, 과적합 위험 | 대형 CNN, 복잡한 패턴 |
| 2세대 | ELU | 음수 구간 지수 곡선 | 평균 0 근처, Dying ReLU 해결, 노이즈에 강함 | 지수 연산 비용 | 잡음 많은 데이터, 의료 영상 |
| 2세대 | SELU | 스케일된 ELU | 자동 정규화, 깊은 네트워크 안정 | 특정 구조·초기화 필요 | MLP 기반 추천·CTR 예측 |
| 3세대 | Swish(SiLU) | 부드러운 ReLU | 깊은 네트워크에서 성능 우수, 비단조성 | Sigmoid 연산 비용 | EfficientNet, YOLOv5 등 최신 CNN |
| 3세대 | Mish | Swish 변형 | ReLU/Swish보다 높은 정확도 보고, 부드러운 미분 | 계산 복잡, 학습 시간 증가 | CIFAR, ResNet, 객체 인식 |
| 3세대 | GELU | 확률적 ReLU | Transformer에서 표준, 안정적 gradient | CDF 계산 비용 | BERT, GPT, 대부분의 Transformer |
| 3세대 | SwiGLU | Swish + GLU | LLM에서 높은 성능, 강력한 게이팅 | 구현·연산 복잡 | Llama 계열, 대형 LLM |
| 3세대 | TeLU | ReLU + 부드러움 | 빠른 수렴, 안정적 학습(논문 보고) | 아직 실무 채택 초기 | 범용 딥러닝, ReLU 대체 후보 |
| 출력층 | Softmax | 확률 분포 출력 | 다중 클래스 분류 표준, 해석 용이 | 지수 연산, 클래스 많으면 비용 ↑ | 다중 분류 출력층 (ImageNet 등) |
| 출력층 | Linear | 항등 함수 | 회귀에 적합, 단순 | 비선형성 없음 | 회귀 문제 (주가, 수요 예측 등) |
5. 모델·도메인별 추천 활성화 함수: 무엇을 어디에 쓸까?

활성화 함수 선택은 사실 모델 구조 + 데이터 특성에 따라 달라집니다. 현업에서 많이 쓰는 조합을 정리하면 다음과 같습니다.
5.1. CNN (이미지 분류, 객체 탐지 등)
- 기본값: ReLU
- 성능/안정성 더 뽑고 싶을 때: Swish(SiLU), Mish
- 노이즈·의료 영상 등 극단값 많은 경우: ELU, Leaky ReLU
EfficientNet, YOLO 계열이 Swish/SiLU를 채택한 이유는, 깊은 레이어에서도 정보 손실을 덜 하면서 부드럽게 gradient를 흘려보내기 위해서입니다.
5.2. RNN / LSTM / GRU (시계열, 자연어 등)
- 은닉 상태: Tanh + Sigmoid 조합이 여전히 표준입니다.
- 출력층:
- 이진 분류: Sigmoid
- 다중 분류: Softmax
최신 트렌드는 순수 RNN보다 Transformer로 넘어갔지만, 여전히 시계열·수요 예측 글처럼 LSTM이 필요한 도메인에서는 Tanh/Sigmoid 조합이 깊게 쓰입니다.
5.3. Transformer / LLM (BERT, GPT, Llama, Vision Transformer 등)
- 은닉층: GELU, SwiGLU, 일부 Swish/Mish 변형
- 출력층: Softmax
Transformer 설명 글과 여러 LLM 구조 비교 글에서도, Feed-Forward Network(FFN) 부분에 ReLU 대신 GELU·SwiGLU를 쓰는 것이 이제 사실상 “표준”으로 자리 잡았습니다.
- GPT, BERT 등: GELU
- Llama 계열: SwiGLU
5.4. GAN, 생성 모델
- Generator 은닉층: Leaky ReLU (Dying ReLU 방지 + gradient 유지)
- Discriminator 은닉층: Leaky ReLU
- 출력층:
- 이미지 생성: Tanh(픽셀을 -1~1로 스케일할 때), 또는 Sigmoid(0~1)
6. 실전 체크리스트: 프로젝트 시작 전에 이것만 확인하자

마지막으로, 프로젝트를 시작할 때 쓸 수 있는 활성화 함수 체크리스트를 정리해 보겠습니다. 하이퍼파라미터 튜닝 글(하이퍼파라미터 튜닝 가이드)에서도 강조하지만, 활성화 함수는 학습률·배치 크기와 함께 성능을 크게 좌우하는 요소입니다.
6.1. 은닉층 기본 전략
- 일반적인 CNN/MLP라면
- 1차 선택: ReLU
- 학습이 잘 안 된다, 죽은 뉴런이 많다 → Leaky ReLU 혹은 ELU로 변경.
- 딥한 CNN + 성능 극대화 목표라면
- Swish(SiLU) 또는 Mish를 고려.
- 계산량이 늘어나는 대신 정확도가 몇 %씩 올라갈 수 있습니다.
- Transformer·LLM 구조라면
- GELU 또는 SwiGLU를 사용하는 것이 안전한 기본값입니다.
- 직접 구현하는 소형 Transformer에도 GELU를 넣는 것이 일반적입니다.
- 새로운 활성화 함수 테스팅 여유가 있다면
- TeLU 같은 최신 함수도 실험해볼 가치가 있습니다.
- 중요한 건, 항상 ReLU/GELU와 동일 조건에서 공정하게 비교하는 것입니다.
6.2. 출력층 선택 규칙 (최종 점검)
문제 유형만 정확히 알면 출력층 선택은 틀릴 일이 없습니다.
| 문제 유형 | 예시 | 추천 출력층 함수 |
|---|---|---|
| 회귀 (Regression) | 주가, 온도, 키/몸무게 예측 | Linear (None) |
| 이진 분류 (Binary) | 스팸/정상, 환자/정상 | Sigmoid |
| 다중 분류 (Multi-class) | 개/고양이/새/자동차 분류 | Softmax |
| 멀티라벨 분류 (Multi-label) | 뉴스 태그(정치+경제), 영화 장르 | Sigmoid (각 클래스별) |
이 패턴은 기계학습 교과서, 실무 튜토리얼, Do You Know?의 여러 AI 글에서도 공통적으로 등장하는 표준 조합입니다.
7. 마치며: 작은 선택이 만드는 성능의 차이
지금까지 활성화 함수의 역할과 종류, 그리고 올바른 선택 방법에 대해 알아보았습니다. “은닉층은 ReLU”라는 말이 아주 틀린 것은 아니지만, 모델의 구조와 데이터의 특성에 맞춰 활성화 함수를 섬세하게 조정하는 것만으로도 모델의 학습 안정성과 최종 성능을 크게 향상시킬 수 있습니다.
특히 출력층 활성화 함수는 문제의 정의와 직결되므로, 반드시 규칙에 맞춰 올바르게 선택해야 한다는 점을 기억해 주셨으면 합니다. 이 가이드가 여러분의 딥러닝 모델 성능을 한 단계 끌어올리는 데 도움이 되기를 바랍니다.
📚 함께 읽으면 좋은 글 (Do You Know?)
- 퍼셉트론과 신경망, 도대체 뭔가요?
- Transformer는 어떻게 언어를 이해하나요?
- 하이퍼파라미터 튜닝으로 성능 2배 올리기
- 소형 언어모델(SLM)과 온디바이스 AI
- 손실 함수 완벽 가이드
- 모델 평가 지표 완벽 가이드
- MLP는 죽었다? Kolmogorov-Arnold Networks (KAN) 완벽 해부! 학습 가능한 활성화 함수의 혁명
🔗 참고 자료
- Mish 논문: https://arxiv.org/abs/1908.08681
- TeLU 논문: https://arxiv.org/abs/2412.20269
- 위키독스 활성화 함수: https://wikidocs.net/250622
