[1]. CNN (Convolutional Neural Networks)
딥러닝에서 주로 이미지나 영상 데이터를 처리할 때 쓰인다.
CNN에서 C는 Convolution(합성곱)을 뜻하며, 이미지의 특징을 추출하는 전처리 역할을 한다.
{1}. 왜 쓰냐?
(1). 문제점
DNN(Deep Neural Network)의 문제점에서 시작되었다.
DNN는 이미지를 1줄로 펼쳐버리기 때문에 공간(차원)이라는 정보가 소멸된다.
예) :
"고양이 얼굴"을 이루는 건 눈, 코, 입의 위치 관계인데 픽셀을 한 줄로 펼치면 그 관계가 사라진다.
즉, 숫자만 남고 맥락은 없어지는 것이다.
(2). 핵심 아이디어
CNN은 이미지를 날것 그대로 받아서, 부분 부분 흝어가며 특징을 쌓아나간다.
그림 감정사를 예로 들어보자
DNN은 그림을 가위로 잘라 순서 없이 한 줄로 붙인 뒤 감정한다.
CNN은 그림 위에 돋보기를 옮겨가며 조금씩 훑는다.
선이 있네, 곡선이 있네, 눈 모양이네.. 이렇게 부분에서 전체 순서로 파악한다.
- 이미지 전체가 아닌 작은 영역을 슬라이딩하며 뤁는다.
- 이 과정에서 한 픽셀과 주변 픽셀의 공간적 관계가 살아있다.
즉, DNN이 이미지를 "해체 후 분석"한다면, CNN은 "구조를 유지한 채 훑으며 분석"한다.
{2}. CNN의 구성 요소
(1). Convolution 작동 원리
- 2차원 이미지는 픽셀 단위행렬로 표현된다
→ 예) : 30x30 이미지 ⇒ 30x30 행렬
- CNN에는 *필터(커널)가 존재한다. 이 필터를 이미지 행렬 위에 *슬라이딩하며 반복 적용한다.
- 필터와 이미지의 각 영역을 *Inner Product(내적)으로 연산한다.
? Inner Product(내적)이란
"같은 위치의 값을 곱한 뒤 전부 더하는 것"이다.
예를 들어
- 이미지 영역 (3x3)
1 2 3
4 5 6
7 8 9
- 필터 (3x3)
1 0 -1
1 0 -1
1 0 -1
이라면 내적을 했을 때
(1x1) + (2x0) + (3x-1)
(4x1) + (5x0) + (6x-1)
(7x1) + (8x0) + (9x-1)
⇒ -2 + -2 + -2 = -6 이 되어 이 하나가 해당 위치의 결괏값이 된다.
? 슬라이딩이란
필터가 입력 데이터(이미지) 위를 일정한 간격으로 이동하며
합성곱 연산을 수행하는 과정을 의미한다.
? Filter (커널)이란
"이 패턴이 여기 있나?"를 확인하는 작은 행렬
필터는 숫자로 채워진 작은 행렬이다.
예) 3x3 필터 :
1 0 -1
1 0 -1
1 0 -1
이 필터를 이미지 위에 슬라이딩하면서 내적을 계산하면 이 패턴과 유사한 영역일수록 결과값이 크게 나온다.
위 3x3 필터는 세로 경계선을 감지하는 필터이다. 왼쪽엔 양수, 오른쪽엔 음수가 있어서, 밝은 영역에서 어두운 영역으로 바뀌는 경계에서 반응이 강하게 나온다.
어두운 영역에서 밝은 영역 반응을 강하게 하려면 왼쪽엔 음수, 오른쪽에는 양수를 배치하면 된다.
쉽게 설명하면
필터 = 수배 전단지
경찰이 용의자를 잡으려고 수배 전단지를 들고 거리를 돌면서 용의자와 "얼마나 닮았는지 점수를 매기는 것"이 내적이다.
(2). Feature Map - Convolutaion 최종 결과물

예를 들어 Input 이미지를 3개의 채널로 분리한 뒤,
각 채널에 Filter를 Convolution한 결과를 모두 합산한 것이 Feature Map이다.
그림처럼 3채널 입력이면 채널별 Convolution 결과 3개가 나오고,
이를 element-wise로 더하면 하나의 Feature Map이 완성된다
필터 역할 :
- 수배 전단지 = 필터 (찾고자 하는 패턴)
- 거리를 돌아다니며 비교 = 슬라이딩
- 얼마나 닮았나 = 내적 결과값
- 많이 닮을수록 높은 점수 = 결과값이 크게 나옴
그리고 CNN은 필터가 여러 장으로
- 한 명은 수배 전단지로 "세로 경계선"을
- 한 명은 "눈 모양"
- 한 명은"얼굴 선"
을 찾는다. 각자 다른 걸 찾는 수사관들이 동시에 이미지를 훑는 것이다.
그리고 학습이 진행될수록 수배 전단지가 점점 정교해진다. 처음엔 대충 "선 같은 거"를 찾다가 나중엔 "이 각도의 이 굵기의 선"을 찾게 되는 식이 된다.
- 필터의 용도 : 이미지에서 특정 패턴을 감지
- 필터 값은 어떻게 정함? : 학습을 통해 자동으로 결정됨
- 필터가 여러 개인 이유 : 각 필터가 서로 다른 패턴을 담당하기 때문에
- 초반 레이어 필터 : 선, 경계, 색상 같은 단순한 패턴 감지
- 중간 레이어 필터 : 눈, 코, 바퀴 같은 복합 패턴 감지
- 후반 레이어 필터 : 얼굴, 자동차 같은 고수준 개념 감지
즉, 레이어가 쌓일수록 Feature Map은 픽셀 수준의 정보에서 의미 수준의 정보로 추상화된다.
CNN은 아래와 같은 과정으로 진행된다.
입력 이미지 → Pooling → Convolution ⇒ Feature Map → Pooling → Convolution ⇒ Feature Map ...
→ Fully Connected Layer ⇒ Result
Feature Map은 다음 레이어에서 입력 이미지 역할을 한다.
이 과정이 반복되면서 점점 추상화 된 Feature Map이 만들어지게 되고,
마지막 Fully Connected Layer를 거쳐 결과를 출력한다.
(3). Zero Padding - 사진 인화 테두리
- Convolution을 거치면 결괏값이 입력값보다 크기가 줄어드는 문제가 발생한다.
- 이미지 가장자리에 0으로 채운 테두리를 추가하면 해결할 수 있다.
- 그러면 입력값과 결괏값의 크기를 동일하게 유지할 수 있다.
⇒ 사진관에서 사진을 인화할 때, 가장자리가 잘릴까 봐 흰 여백을 추가하는 것과 같다.
(4). Stride - 보폭
필터가 이미지를 걸어 다니는 것을 stride라고 한다.
- stride 1 : 한 걸음씩 꼼꼼히 이동 ⇒ 결과물 크기가 큼
- stride 2 : 두 걸음씩 성큼성큼 이동 ⇒ 건너뛰니까 결과물 크기가 작아짐
꼼꼼히 볼수록 결과물이 많아지고, 대충 훑을수록 결과물이 줄어든다.
(5). Order-3 Tensor - 투명 필름 3장 겹치기
흑백 이미지가 필름 1장이라면, 컬러 이미지는 R-G-B 필름 3장을 겹쳐놓은 것이다.
그러면 필터도 당연히 3장짜리가 돼야 각 필름에 대응할 수 있다. 연산은 동일하게 하지만, 3장을 동시에 Inner Product 한 뒤 합산하는 것이다.
{3}. CNN 전체 네트워크 구조
CNN은 Convolution Layer → Pooling Layer를 반복한 뒤 마지막에 Fully-Connected Layer로 마무리된다.
(1). Convolutional Layer - 스케치 + 윤곽선 강조
- 입력 이미지에 여러 개의 필터를 적용해 *feature map을 생성한다.
- 그 후 *활성함수(Activation function)를 적용
→ convolution은 선형 연산이므로, 비선형성을 추가하기 위함이다.
쉽게 설명하면
- Convolution : 이미지에서 특징을 뽑아 스케치하는 과정
- Activation Fucntion : 스케치에서 중요한 선만 굵게 강조하는 과정
선형 연산만 쌓으면 아무리 깊어도 결국 직선 하나로 표현되는 것과 다를 바 없어서, 활성함수로 구불구불한 표현력을 추가하는 것이다.
즉, Convolutional Layer = Convolution(스케치) + Activation(강조)
? 활성함수 (다음 글에서 자세히 다룰 예정)
인공 신경망에서 이전 층의 가중치 합(입력 신호)을
다음 층으로 얼마나 전달할지 결정하는 비선형 변환 함수이다.
입력 신호란 Net Input Function이라는 위험 점수를 의미하는데,
이 위험 점수를 보고 경보(신호)를 얼마나 줄지를 정하는 게 활성함수이다.
선형 연산만 쌓으면 아무리 깊어도 결국 직선 하나와 다를 바 없어서,
활성함수로 비선형성을 추가해 복잡한 패턴을 표현할 수 있게 한다.
(2). Pooling Layer - 요약본 만들기
"Convolution 결과 feature map이 너무 많아지는 문제를 해결"
각 feature map의 차원을 축소하는 방법을 사용한다.
대표적인 방법은 아래 두 가지다.
- Max Pooling : 영역 내 최댓값 선택
- Average Pooling : 영역 내 평균값 선택
Pooling Layer는 단순 크기 축소를 하기 때문에 학습 가능한 매개변수가 없다.
쉽게 설명하면
책 한 권을 읽고 나서 핵심만 추려 요약본을 만드는 것과 같다.
- Max Pooling : 영역에서 가장 인상적인 내용(최댓값)만 남긴다.
- Average Pooling : 영역의 전체 분위기(평균값)를 남긴다.
요약하는 사람은 따로 공부(학습)할 필요가 없다. 그냥 규칙대로 추리는 것이기 때문에 학습 파라미터가 없다.
(3). 두 번 Convolutional Layer
첫 번째와 동일한 방식으로 한번 더 차원을 축소한다.
요약본을 다시 한 번 더 압축해 핵심 요약본의 요약본을 만드는 것이다.
(4). Flatten (Vectorization) - 2D → 1D 변환을 직관적으로 표현
Pooling을 거쳐 나온 텐서를 1차원 벡터로 펼친다.
이 시점의 데이터는 이미지 자체가 아니라 추출된 특징 데이터이므로, 1차원으로 변환해도 정보 손실이 없다.
쉽게 말해서
2차원 가계도를 시간 순서대로 한 줄 연표로 펼치는 것과 같다.
이미 "이미지"가 아니라 특징 목록이기 때문에 공간 구조를 유지할 필요가 없는 것이다.
(5). Fully-Connected Layer - 최종 심사위원
Flatten 된 벡터를 기존 *DNN 방식으로 처리한다.
마지막에 활성함수를 적용해 최종 출력한다.
- 다중 분류 : Softmax
- 이진 분류 : Sigmoid
쉽게 설명하면
앞에서 수사관들(필터)이 각자 특징을 뽑아왔다면, Fully-Connected Layer는 그 결과를 모두 취합해서 "이건 고양이다 / 아니다"를 판정하는 최종 심사위원이다.
(6). 정리
| 레이어 | 역할 | 비유 | 학습 파라미터 |
| COnvolutional Layer | 필터로 특징 추출 + 활성함수로 비선형성 추가 | 스케치 + 윤곽선 강조 | 있음 |
| Pooling Layer | feature map 차원 축소 | 요약본 만들기 | 없음 |
| Convolutional Layer | 한 번 더 특징 추출 + 차원 축소 | 요약본의 요약본 | 있음 |
| Flatten | 2D 텐서 → 1D 백테 변환 | 가계도 → 연표 | 없음 |
| Fully-Connected Layer | 추출된 특징으로 최종 분류 | 최종 심사위원 | 있음 |
내가 정리한 5개의 레이어는 CNN을 이해하기 위한 최소 구조이다.
실제 CNN에서 추가될 수 있는 레이어는 아래와 같다.
- Batch Normalization Layer : 학습 안정화
- Dropout Layer : 과적합 방지
- ReLU Layer : 활성함수를 별도 층으로 분리
- 1x1 Convolution Layer : 채널 수 조절
Global Average Pooling : Flatten 대신 사용하기도 함
핵심만 말하면
기본 구조 :
- Conv → Pooling → Conv → Flatten → Full-Connected
실제 모델 :
- Conv → Batch Normalization → ReLU → Pooling → Dropout → Conv를 모델에 따라서 반복 → Full-Connected
{4}. Parameter vs Hyper-parameter - 요리사와 레시피
| 구분 | 정의 | 예시 |
| Parameter | 모델 내부, 데이터로부터 학습되는 값 | 필터의 가중치 |
| Hyper-parameter | 모델 외부, 사람이 직접 설정하는 값 | 필터 개수, stride, learning rate |
딥러닝의 목표는 Parameter를 최적값으로 빠르고 정확하게 수렴시키는 것이다.
Hyper-parameter를 최적하는 것을 "Tuning"이라고 한다.
쉽게 설명하자면
- Parameter는 요리하면서 자연스럽게 완성되는 손맛 (학습이 자동으로 결정)
- Hyper-parameter는 요리 전에 사람이 미리 정하는 레시피 설정값(불 세기, 시간, 재료 비율)
튜닝 = 더 맛있는 요리를 위해 레시피를 조금씩 바꿔보는 것
(1). 주요 Hyper-parameter 목록
- COnvolutional Layer : 필터 개수, 필터 크기, stride, zero-padding 유무
- Pooling Layer : MaxPool / AvgPool 선택, pool 크기, pool stride
- Fully-Connected Layer : 층의 너비(width)
- Activation Function : ReLU, Softmax, Sigmoid
- Loss function : Cross-entropy(분류), L1/L2(회귀)
- 최적화 알고리즘 : SGD, Momentum, AdaGrad, RMSprop
- 초기화 방식 : Gaussian / Uniform
[2]. 실습
{1}. 코드
# ======================================================
# CNN으로 CIFAR-10 이미지 분류 (Google Colab용)
# 비행기, 자동차, 새, 고양이, 사슴, 개, 개구리, 말, 배, 트럭
# 총 10종류의 컬러 이미지를 분류하는 CNN 구현
# ======================================================
# ── 1. 라이브러리 임포트 ────────────────────────────
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
import numpy as np
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"사용 디바이스: {DEVICE}")
# CIFAR-10 클래스 이름
CLASSES = ['비행기', '자동차', '새', '고양이', '사슴',
'개', '개구리', '말', '배', '트럭']
# ── 2. 데이터 로드 ──────────────────────────────────
# MNIST와 차이:
# MNIST : 흑백 28x28 (채널 1개)
# CIFAR-10: 컬러 32x32 (채널 3개 RGB)
transform_train = transforms.Compose([
transforms.RandomHorizontalFlip(), # 좌우 반전 (데이터 증강)
transforms.RandomCrop(32, padding=4), # 랜덤 크롭 (데이터 증강)
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) # RGB 3채널 정규화
])
transform_test = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
train_dataset = datasets.CIFAR10(root="./data", train=True, download=True, transform=transform_train)
test_dataset = datasets.CIFAR10(root="./data", train=False, download=True, transform=transform_test)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=128, shuffle=True, num_workers=2)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=128, shuffle=False, num_workers=2)
print(f"학습 데이터: {len(train_dataset)}장")
print(f"테스트 데이터: {len(test_dataset)}장")
# ── 3. CNN 모델 정의 ────────────────────────────────
# MNIST CNN과 차이:
# MNIST : 입력 채널 1개 (흑백)
# CIFAR-10: 입력 채널 3개 (RGB)
# + Batch Normalization 추가 → 학습 안정화
# + Dropout 추가 → 과적합 방지
class CNN(nn.Module):
def __init__(self):
super().__init__()
# ── 특징 추출부 ──────────────────────────────
self.features = nn.Sequential(
# Block 1: 32x32 → 16x16
nn.Conv2d(3, 32, kernel_size=3, padding=1), # 입력 3채널 (RGB)
nn.BatchNorm2d(32),
nn.ReLU(),
nn.Conv2d(32, 32, kernel_size=3, padding=1),
nn.BatchNorm2d(32),
nn.ReLU(),
nn.MaxPool2d(2), # 32x32 → 16x16
nn.Dropout(0.25), # 과적합 방지
# Block 2: 16x16 → 8x8
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.Conv2d(64, 64, kernel_size=3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(2), # 16x16 → 8x8
nn.Dropout(0.25),
# Block 3: 8x8 → 4x4
nn.Conv2d(64, 128, kernel_size=3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.Conv2d(128, 128, kernel_size=3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.MaxPool2d(2), # 8x8 → 4x4
nn.Dropout(0.25),
)
# ── 분류부 ───────────────────────────────────
self.classifier = nn.Sequential(
nn.Linear(128 * 4 * 4, 512), # Flatten 후 FC Layer
nn.ReLU(),
nn.Dropout(0.5),
nn.Linear(512, 10) # 10개 클래스 출력
)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1) # Flatten: (B, 128, 4, 4) → (B, 2048)
return self.classifier(x)
# ── 4. 모델 / 손실함수 / 옵티마이저 초기화 ─────────
model = CNN().to(DEVICE)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.5)
# scheduler: 10 에폭마다 학습률을 절반으로 줄임 → 학습 안정화
# ── 5. 학습 함수 ────────────────────────────────────
def train(epoch):
model.train()
total_loss, correct, total = 0, 0, 0
for imgs, labels in train_loader:
imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)
optimizer.zero_grad()
outputs = model(imgs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
total_loss += loss.item()
correct += (outputs.argmax(1) == labels).sum().item()
total += labels.size(0)
acc = 100 * correct / total
print(f"[Epoch {epoch:>3}] Loss: {total_loss/len(train_loader):.4f} Train Acc: {acc:.2f}%", end=" ")
# ── 6. 평가 함수 ────────────────────────────────────
def evaluate():
model.eval()
correct, total = 0, 0
with torch.no_grad():
for imgs, labels in test_loader:
imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)
outputs = model(imgs)
correct += (outputs.argmax(1) == labels).sum().item()
total += labels.size(0)
acc = 100 * correct / total
print(f"Test Acc: {acc:.2f}%")
return acc
# ── 7. 학습 루프 ────────────────────────────────────
print("학습 시작!")
best_acc = 0
for epoch in range(1, 31):
train(epoch)
acc = evaluate()
scheduler.step()
if acc > best_acc:
best_acc = acc
torch.save(model.state_dict(), "best_model.pth")
print(f"\n최고 정확도: {best_acc:.2f}%")
# ── 8. 결과 시각화 ──────────────────────────────────
def show_predictions(num=16):
model.eval()
imgs, labels = next(iter(test_loader))
imgs, labels = imgs[:num], labels[:num]
with torch.no_grad():
outputs = model(imgs.to(DEVICE))
preds = outputs.argmax(1).cpu()
# [-1,1] → [0,1] 변환
imgs = imgs * 0.5 + 0.5
fig, axes = plt.subplots(2, 8, figsize=(16, 5))
axes = axes.flatten()
for i in range(num):
img = imgs[i].permute(1, 2, 0).numpy() # (C,H,W) → (H,W,C)
axes[i].imshow(img)
axes[i].axis('off')
pred = CLASSES[preds[i]]
label = CLASSES[labels[i]]
color = 'blue' if preds[i] == labels[i] else 'red'
axes[i].set_title(f"예측: {pred}\n정답: {label}", fontsize=8, color=color)
plt.suptitle("파란색 = 정답 / 빨간색 = 오답", fontsize=12)
plt.tight_layout()
plt.show()
show_predictions()
# ── 9. 클래스별 정확도 분석 ─────────────────────────
def class_accuracy():
model.eval()
correct = [0] * 10
total = [0] * 10
with torch.no_grad():
for imgs, labels in test_loader:
imgs, labels = imgs.to(DEVICE), labels.to(DEVICE)
outputs = model(imgs)
preds = outputs.argmax(1)
for i in range(10):
mask = (labels == i)
total[i] += mask.sum().item()
correct[i] += (preds[mask] == i).sum().item()
print("\n클래스별 정확도:")
for i in range(10):
acc = 100 * correct[i] / total[i]
bar = "█" * int(acc // 5)
print(f" {CLASSES[i]:>4} : {acc:>6.2f}% {bar}")
class_accuracy()
{2}. 결과

저해상도라 많이.. 흐릿하긴 하지만 클래스별 정확도는 아래와 같이 높게 나왔다.
클래스별 정확도:
- 비행기 : 89.10%
- 자동차 : 95.20%
- 새 : 74.50%
- 고양이 : 67.40%
- 사슴 : 87.00%
- 개 : 78.40%
- 개구리 : 95.30%
- 말 : 88.80%
- 배 : 93.00%
- 트럭 : 92.50%
[3]. CNN 한계
{1}. 데이터 의존성
CNN은 학습 데이터가 많아야 제대로 작동한다.
데이터 적음 → 필터가 제대로 학습 안 됨 → 성능 저하
비유하자면 수사관이 수배 전단지를 만들려면 용의자 사진이 많아야 한다.
사진이 몇 장 없으면 전단지가 부정확해지기 때문이다.
{2}. 과적합
학습 데이터에만 너무 맞춰져서 새로운 데이터에서 성능이 떨어지는 현상이다.
- 학습 데이터 정확도 : 99%
- 테스트 데이터 정확도 : 50% → 과적합
시험 문제를 통째로 외운 학생이 똑같은 문제는 100점인데 문제가 조금만 바뀌면 못 푸는 것이다.
{3}. 높은 계산 비용
층이 깊어질수록 연산량과 메모리가 폭발적으로 증가한다.
LeNet-5 (2층) → 일반 CPU로 가능
ResNet-152 (152층) → 고성능 GPU 필수
{4}. 공간 정보 손실 (Pooling)
Pooling 과정에서 위치 정보가 사라진다.
"눈이 있다"는 CNN이 감지할 수 있다. 근데
"눈이 얼굴 위쪽에 있다"는 Pooling 후 사라질 수 있다.
요약본을 만들다 보면 "어느 페이지에 있던 내용인지"가 사라지는 것처럼 핵심은 남지만 위치 맥락은 잃어버린다.
{5}. 평행 이동에만 강함
CNN은 평행 이동(Translation)에는 강하지만, 회전이나 크기 변화에는 약하다.
고양이가 왼쪽에 있든 오른쪽에 있든 잘 인식한다.
하지만 고양이가 거꾸로 있거나 크기가 다르면 인식률이 떨어진다.
수배 전단지가 정면 사진이면 용의자의 측면이나 뒤통수를 보고는 못 잡는 것이다.
{6}. 정리
| 한계 | 내용 |
| 데이터 의존성 | 학습 데이터 많아야 함 |
| 과적합 | 새로운 데이터에 성능 저하 |
| 높은 계산 비용 | 깊어질수록 GPU 필수 |
| 공간 정보 손실 | Pooling 후 위치 정보 사라짐 |
| 변환 취약성 | 회전/크기 변화에 약함 |
CNN은 이미지를 한 줄로 펼치던 DNN의 한계를 극복하고, 필터로 공간 구조를 유지하며 특징을 계측적으로 학습한다.
단순한 선과 경계에서 시작해 눈, 코, 얼굴까지 쌓아가는 이 구조가 이미지 인식 AI의 핵심이다.
이후 정리할 Xceptioin, GradCAM, Attribution 모두 CNN을 기반으로 동작한다.
출처 :
'AI > AI' 카테고리의 다른 글
| XAI 기법 - LIME (1) | 2026.05.02 |
|---|---|
| Attention Mechanism (0) | 2026.05.02 |
| Saliency Map (0) | 2026.04.30 |
| Activation Function (활성화 함수) (0) | 2026.04.29 |
| XAI (eXplainable AI) - 설명가능한 AI (0) | 2026.04.17 |