1. Alexnet
AlexNet은 2012년 ILSVRC(ImageNet Large Scale Visual Recognition Challenge)에서 우승한 딥러닝 모델로, 딥러닝의 대중화를 이끈 중요한 합성곱 신경망(CNN)입니다. 이 모델은 8개의 레이어(5개의 합성곱 레이어와 3개의 완전 연결 레이어)로 구성되어 있으며, ReLU 활성화 함수, 드롭아웃(dropout), 데이터 증강(data augmentation) 등을 사용해 과적합을 방지하고 학습 성능을 향상시켰습니다. AlexNet은 대규모 데이터셋과 GPU 병렬 연산을 활용해 1,000개의 클래스 분류 문제에서 top-1, top-5 error rates가 각각 37.5%, 17.5%로 뛰어난 성능을 보여, 컴퓨터 비전에서 딥러닝이 표준 기법으로 자리 잡는 데 기여했습니다. 이 성과는 당시 기준으로 매우 뛰어난 결과였습니다. 특히 AlexNet은 이전에 사용된 전통적인 머신러닝 방법론보다 훨씬 큰 차이로 성능을 끌어올리며, 딥러닝의 가능성을 보여주었습니다.
chrome-extension://efaidnbmnnnibpcajpcglclefindmkaj/https://papers.nips.cc/paper/2012/file/c399862d3b9d6b76c8436e924a68c45b-Paper.pdf

ImageNet LSVRC
- ImageNet LSVRC는 Large Scale Visual Recognition Challenge의 약자로, 이미지 인식 및 분류 기술을 겨루는 대회입니다. 2010년부터 매년 개최되었으며, ImageNet이라는 대규모 이미지 데이터셋을 기반으로 참가자들이 다양한 모델을 설계하고 경쟁했습니다.
- ImageNet 데이터셋: 약 1400만 장의 이미지를 포함하며, 1000개의 클래스(예: 고양이, 강아지, 자동차 등)로 분류된 대규모 이미지 데이터셋입니다.
- 목적: 컴퓨터 비전 및 딥러닝 기술의 발전을 촉진하고, 이미지 인식 분야에서 혁신적인 기술을 발견하는 것이 목표였습니다.
- LSVRC-2010: 이 대회에서 AlexNet이 2012년에 처음으로 딥러닝 기반 접근법을 사용해 뛰어난 성능을 보여줌으로써 딥러닝의 새로운 시대를 열었습니다.
Error Rate
이미지 분류 모델의 성능을 평가하는 지표로, 모델이 이미지를 얼마나 정확히 분류했는지를 나타냅니다.
- Top-1 Error Rate
- 모델이 예측한 가장 높은 확률의 클래스(Top-1)가 정답이 아닐 확률입니다. 예를 들어, 이미지에 "고양이"가 있고, 모델이 가장 높은 확률로 "강아지"라고 예측했다면, 이건 Top-1 에러입니다.
- Top-5 Error Rate
- 모델이 예측한 상위 5개의 클래스 중 하나라도 정답에 포함되지 않았을 확률입니다. 예를 들어, 이미지가 "고양이"인데 모델이 "강아지", "토끼", "고양이", "호랑이", "여우"를 상위 5개로 예측했다면, 이건 정답으로 간주됩니다.
- Top-5를 사용하는 이유: 사람이 보기에 유사한 클래스(예: 치타와 표범)를 분류하는 것은 어렵기 때문에, 상위 5개 중에 정답이 있는지를 확인하는 방식으로 보다 실용적인 성능을 평가합니다.
2. CIFAR 데이터셋
CIFAR 데이터셋은 torchvision 라이브러리에서 제공하는 이미지 데이터셋으로, 주로 딥러닝 모델의 학습 및 평가에 사용됩니다. CIFAR-10과 CIFAR-100 두 종류가 있으며, 각각 10개와 100개의 클래스에 대해 32x32 크기의 컬러 이미지로 구성됩니다. CIFAR-10은 클래스당 6,000개(총 60,000개)의 이미지로 이루어져 있으며, CIFAR-100은 클래스당 600개(총 60,000개)로 구성됩니다. PyTorch는 torchvision.datasets 모듈을 통해 이 데이터셋을 쉽게 불러올 수 있으며, 학습/테스트 데이터셋 분리, 데이터 증강(transforms), 정규화 등의 전처리를 지원합니다. 이 데이터셋은 이미지 분류 알고리즘을 실험하고 비교하는 데 널리 사용됩니다.
Datasets — Torchvision 0.21 documentation
Shortcuts
pytorch.org
3. Alexnet 직접 구현(CIFAR 데이터셋 사용)
import numpy as np
import matplotlib.pyplot as plt
import torch
from torch.utils.data import DataLoader
from torch import nn
from torchvision import datasets
from torchvision.transforms import transforms
from torchvision.transforms.functional import to_pil_image
# to_pil_image : 이미지에 효과 주는거
train_img = datasets.CIFAR10(
root='data',
train=True,#train용 데이터만 다운
download=True,#파일 다운로드
transform=transforms.ToTensor()
)
test_img = datasets.CIFAR10(
root='data',
train= False,#test용 데이터만 다운
download=True,#파일 다운로드
transform=transforms.ToTensor()
)
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to data/cifar-10-python.tar.gz
100%|██████████| 170M/170M [00:04<00:00, 41.7MB/s]
Extracting data/cifar-10-python.tar.gz to data
Files already downloaded and verified
# 실질적으로 데이터에 대해 맞춤형으로 표준화 시키기 위해서 이렇게 해줌
# 표준화 시킬때 쓸 변수
mean = train_img.data.mean(axis=(0,1,2)) / 255 # 이미지 분포도에 따라서 다르게 적용
std = train_img.data.std(axis=(0,1,2)) / 255 # 이미지 범위에 따라서 변동
print(f'평균:{mean}, 표준편차:{std}')
평균:[0.49139968 0.48215841 0.44653091], 표준편차:[0.24703223 0.24348513 0.26158784]
transform_train = transforms.Compose([
transforms.ToTensor(),#텐서형으로 정규화
transforms.RandomCrop(size=train_img.data.shape[1], padding=4),# RandomCrop 이미지 랜덤하게 잘라줌 size=train_img.data.shape[1]:이미지 쉐이프의 두번째 크기대로
transforms.RandomHorizontalFlip(),# 수평으로 반전
transforms.Normalize(mean, std),#아까 준 평균 표준편차로 표준화
])
transform_test = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean, std),
])
train_img = datasets.CIFAR10(
root = 'data',
train = True,
download = True,
transform = transform_train,
)
test_img = datasets.CIFAR10(
root = 'data',
train = False,
download = True,
transform = transform_test,
)
Files already downloaded and verified
Files already downloaded and verified
EPOCH = 10
BATCH_SIZE = 128
LEARNING_RATE = 1e-3
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print("Using Device:", DEVICE)
Using Device: cuda
1e-3
0.001
train_loader = DataLoader(train_img, batch_size = BATCH_SIZE, shuffle = True) # 데이터셋,배치사이즈,셔플
test_loader = DataLoader(test_img, batch_size = BATCH_SIZE, shuffle = False)
print(train_img, '\n------------------\n', test_img)
Dataset CIFAR10
Number of datapoints: 50000
Root location: data
Split: Train
StandardTransform
Transform: Compose(
ToTensor()
RandomCrop(size=(32, 32), padding=4)
RandomHorizontalFlip(p=0.5)
Normalize(mean=[0.49139968 0.48215841 0.44653091], std=[0.24703223 0.24348513 0.26158784])
)
------------------
Dataset CIFAR10
Number of datapoints: 10000
Root location: data
Split: Test
StandardTransform
Transform: Compose(
ToTensor()
Normalize(mean=[0.49139968 0.48215841 0.44653091], std=[0.24703223 0.24348513 0.26158784])
)
train_img[0]
(tensor([[[-1.9892, -1.9892, -1.9892, ..., -1.9892, -1.9892, -1.9892],
[-1.9892, -1.9892, -1.9892, ..., -1.9892, -1.9892, -1.9892],
[-1.9892, -1.9892, -1.9892, ..., -1.9892, -1.9892, -1.9892],
...,
[-1.9892, 0.7412, 0.2967, ..., 0.1539, 1.0111, 1.3604],
[-1.9892, 1.2175, 0.9794, ..., 0.7254, 1.4239, 0.9635],
[-1.9892, 1.4397, 1.0746, ..., 1.2334, 1.2810, -0.0207]],
[[-1.9802, -1.9802, -1.9802, ..., -1.9802, -1.9802, -1.9802],
[-1.9802, -1.9802, -1.9802, ..., -1.9802, -1.9802, -1.9802],
[-1.9802, -1.9802, -1.9802, ..., -1.9802, -1.9802, -1.9802],
...,
[-1.9802, 0.0813, -0.5629, ..., -0.3374, 0.5806, 0.9349],
[-1.9802, 0.5484, 0.0974, ..., 0.1296, 0.9672, 0.5162],
[-1.9802, 0.8222, 0.2102, ..., 0.7095, 0.8061, -0.4824]],
[[-1.7070, -1.7070, -1.7070, ..., -1.7070, -1.7070, -1.7070],
[-1.7070, -1.7070, -1.7070, ..., -1.7070, -1.7070, -1.7070],
[-1.7070, -1.7070, -1.7070, ..., -1.7070, -1.7070, -1.7070],
...,
[-1.7070, -0.5677, -1.4372, ..., -1.0474, -0.4027, 0.0020],
[-1.7070, -0.4777, -1.3172, ..., -0.6576, -0.1179, -0.3428],
[-1.7070, -0.4027, -1.4671, ..., -0.1779, -0.1329, -0.9724]]]),
6)
train_features, train_labels = next(iter(train_loader)) # 피쳐 라벨 분할해서 받음 이터로 데이터 로더 돌려서 배치하나 꺼래서 찍어주기
print(f"Feature batch shape: {train_features.size()}")
print(f"Labels batch shape: {train_labels.size()}")
Feature batch shape: torch.Size([128, 3, 32, 32])
Labels batch shape: torch.Size([128])
labels_map = {
0: "plane",
1: "car",
2: "bird",
3: "cat",
4: "deer",
5: "dog",
6: "frog",
7: "horse",
8: "ship",
9: "truck",
}
- view란?
- PyTorch에서 view는 텐서의 크기(shape)를 변경할 때 사용하는 함수입니다. NumPy의 reshape와 유사하게 작동합니다.
# 노말라이즈 되어있는 상태에서 맵플로리 찍으면 이상하게 나와서 다시 노말라이즈 반대로해서 멀쩡하게 시각화하려고 쓰는거
def denormalize(img, mean, std):
mean = torch.tensor(mean).view(3, 1, 1) # view(3, 1, 1): 이미지 채널수,높이,채널
std = torch.tensor(std).view(3, 1, 1)
return img * std + mean

figure = plt.figure(figsize = (8, 8))
cols, rows = 5, 5
for i in range(1, cols * rows +1):
sample_idx = torch.randint(len(train_img), size=(1,)).item()
img, label = train_img[sample_idx]
img = denormalize(img, mean, std) # Normalize 복원
figure.add_subplot(rows, cols, i)
plt.title(labels_map[label])
plt.axis('off')
plt.imshow(to_pil_image(img))
#to_pil_image: 이미지 값이 혹시라도 넘어가면 값이 이상해지는거 방지
# 이미지 객체로 변환하는데 사용 텐서형태의 이미지를 시각화할때 사용 PIL이미지로 변환
# 0~255 또는 0~1범위를 가져야함
plt.show()

# 나중에 이미지 큰걸로 1025*1025 로 구해서 알렉스 재구현하기
class AlexNet(nn.Module):
def __init__(self, num_classes=10): # 클래스 초기값 10
super(AlexNet, self).__init__() # 부모생성자 현재 클래스이름으로 호출
#레이어 만들기
self.features = nn.Sequential(
nn.Conv2d(3, 96, kernel_size=3, stride=1, padding=1), # Conv1
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2), # MaxPool1
nn.Conv2d(96, 256, kernel_size=3, padding=1), # Conv2
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2), # MaxPool2
nn.Conv2d(256, 384, kernel_size=3, padding=1), # Conv3
nn.ReLU(inplace=True),
nn.Conv2d(384, 384, kernel_size=3, padding=1), # Conv4
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, padding=1), # Conv5
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=2, stride=2), # MaxPool3
)
#사이즈 4*4*256 로 나옴 4096으로 넘기기
#딥러닝
self.classifier = nn.Sequential(
nn.Linear(256 * 4 * 4, 4096), # FC1 (Flatten 크기 조정)
nn.Dropout(0.5),
nn.ReLU(inplace=True),
nn.Linear(4096, 4096), # FC2
nn.Dropout(0.5),
nn.ReLU(inplace=True),
nn.Linear(4096, num_classes), # FC3
)
def forward(self, x):
x = self.features(x)
x = x.view(x.size(0), -1) # Flatten메소드 쓰는거랑 같은 효과
x = self.classifier(x)
return x
# Model instance 생성
model = AlexNet().to(DEVICE)
print(model)
AlexNet(
(features): Sequential(
(0): Conv2d(3, 96, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace=True)
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(3): Conv2d(96, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): ReLU(inplace=True)
(5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(6): Conv2d(256, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(7): ReLU(inplace=True)
(8): Conv2d(384, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(9): ReLU(inplace=True)
(10): Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU(inplace=True)
(12): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(classifier): Sequential(
(0): Linear(in_features=4096, out_features=4096, bias=True)
(1): Dropout(p=0.5, inplace=False)
(2): ReLU(inplace=True)
(3): Linear(in_features=4096, out_features=4096, bias=True)
(4): Dropout(p=0.5, inplace=False)
(5): ReLU(inplace=True)
(6): Linear(in_features=4096, out_features=10, bias=True)
)
)
loss = nn.CrossEntropyLoss()
# Optimizer
optimizer = torch.optim.Adam(model.parameters(), lr = LEARNING_RATE)
#train 메소드만들기
def train(train_loader, model, loss_fn, optimizer):
model.train()
size = len(train_loader.dataset)
for batch, (X, y) in enumerate(train_loader): #batch: 인덱스, X: 트레인 이미지, y:라벨
X, y = X.to(DEVICE), y.to(DEVICE)
pred = model(X) #예측하기
# 손실 계산
loss = loss_fn(pred, y)
# 역전파
optimizer.zero_grad() #초기화
loss.backward() #역전파
optimizer.step() #기울기 적용
if batch % 100 == 0:
loss, current = loss.item(), batch * len(X)
print(f'loss: {loss:>7f} [{current:>5d}]/{size:5d}') # 소수점 정수 조절
def test(test_loader, model, loss_fn):#학습안하니까 옵티마이저 없애고
model.eval()# 테스트모더 전환
size = len(test_loader.dataset)
num_batches = len(test_loader) #테스트로더 길이만큼
test_loss, correct = 0, 0
with torch.no_grad(): #테스트모드 구간
for X, y in test_loader:
X, y = X.to(DEVICE), y.to(DEVICE)
pred = model(X) #모델 예측
test_loss += loss_fn(pred, y).item() #로스값 누적
correct += (pred.argmax(1) == y).type(torch.float).sum().item() # 정확도누적
test_loss /= num_batches
correct /= size
print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:8f}\n")
for i in range(EPOCH) :
print(f"Epoch {i+1} \n------------------------")
train(train_loader, model, loss, optimizer)
test(test_loader, model, loss)
print("Done!")
Epoch 1
------------------------
loss: 2.303909 [ 0]/50000
loss: 2.018820 [12800]/50000
loss: 1.623372 [25600]/50000
loss: 1.333367 [38400]/50000
Test Error:
Accuracy: 48.1%, Avg loss: 1.415564
Epoch 2
------------------------
loss: 1.434085 [ 0]/50000
loss: 1.430048 [12800]/50000
loss: 1.306728 [25600]/50000
loss: 1.213363 [38400]/50000
Test Error:
Accuracy: 57.7%, Avg loss: 1.155766
Epoch 3
------------------------
loss: 1.202227 [ 0]/50000
loss: 1.119649 [12800]/50000
loss: 1.292675 [25600]/50000
loss: 1.101037 [38400]/50000
Test Error:
Accuracy: 62.4%, Avg loss: 1.051404
Epoch 4
------------------------
loss: 1.166812 [ 0]/50000
loss: 1.221898 [12800]/50000
loss: 1.238492 [25600]/50000
loss: 1.008275 [38400]/50000
Test Error:
Accuracy: 66.1%, Avg loss: 0.963088
Epoch 5
------------------------
loss: 1.109681 [ 0]/50000
loss: 0.952144 [12800]/50000
loss: 1.089079 [25600]/50000
loss: 1.168941 [38400]/50000
Test Error:
Accuracy: 68.5%, Avg loss: 0.883785
Epoch 6
------------------------
loss: 0.813554 [ 0]/50000
loss: 1.198962 [12800]/50000
loss: 0.921174 [25600]/50000
loss: 0.768648 [38400]/50000
Test Error:
Accuracy: 71.7%, Avg loss: 0.808662
Epoch 7
------------------------
loss: 0.775716 [ 0]/50000
loss: 0.712997 [12800]/50000
loss: 0.902851 [25600]/50000
loss: 0.859272 [38400]/50000
Test Error:
Accuracy: 72.4%, Avg loss: 0.795650
Epoch 8
------------------------
loss: 0.580189 [ 0]/50000
loss: 0.777371 [12800]/50000
loss: 0.851962 [25600]/50000
loss: 0.628824 [38400]/50000
Test Error:
Accuracy: 74.1%, Avg loss: 0.741952
Epoch 9
------------------------
loss: 0.859118 [ 0]/50000
loss: 0.653804 [12800]/50000
loss: 0.983239 [25600]/50000
loss: 0.785648 [38400]/50000
Test Error:
Accuracy: 74.5%, Avg loss: 0.748219
Epoch 10
------------------------
loss: 0.851629 [ 0]/50000
loss: 0.790893 [12800]/50000
loss: 0.587940 [25600]/50000
loss: 0.741709 [38400]/50000
Test Error:
Accuracy: 76.5%, Avg loss: 0.691485
Done!
4. itertools
파이썬 표준 라이브러리 모듈로 반복과 관련된 효율적이고 고성능의 도구를 제공합니다. 다양한 반복 가능한 객체나 순열, 조합을 생성하거나 조작하는 함수들을 포함하고 있습니다.
from itertools import product, permutations, combinations, islice
# 데카르트 곱
color = ['red','blue']
size = ['S','M','L']
result = list(product(color, size))
print(result)
[('red', 'S'), ('red', 'M'), ('red', 'L'), ('blue', 'S'), ('blue', 'M'), ('blue', 'L')]
#순열
number =[1,2,3]
perm = list(permutations(number,2)) # 길이가 2인 순열 생성
print(perm)
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
#조합
letter = ['A','B','C']
comb = list(combinations(letter,2)) # 중복없이 해당 길이만큼 특정 조합 생성
print(comb)
[('A', 'B'), ('A', 'C'), ('B', 'C')]
# 슬라이싱
number = range(10)
sliced = list(islice(number,2,8,2))#2부터 7까지, 간격을 2로 설정
print(sliced)
[2, 4, 6]
import itertools
# cm : 행렬 target_names: 클래스 이름 cmap: 색상 맵
def plot_confusion_matrix(cm, target_names=None, cmap=None,
normalize=True, labels=True, title='Confusion matrix'):
accuracy = np.trace(cm) / float(np.sum(cm))
# np.trace: 혼돈행렬의 대각선 요소의 합 = 맞춘 샘플 수
misclass = 1 - accuracy
if cmap is None:
cmap = plt.get_cmap('Blues')
if normalize:
# [:, np.newaxis]:차원 하나 늘이기 []이거 하나 더 씌우기
# (3,) -> (3,1)
cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]
plt.figure(figsize=(8, 6))
# interpolation='nearest' : 픽셀간의 간격을 최소화해서 이미지 깔끔하게 보여줌
plt.imshow(cm, interpolation='nearest', cmap=cmap)
plt.title(title)
plt.colorbar() # 범례 추가
thresh = cm.max() / 1.5 if normalize else cm.max() / 2 # normalize에 따라 임계값 설정
if target_names is not None:
tick_marks = np.arange(len(target_names))
plt.xticks(tick_marks, target_names)
plt.yticks(tick_marks, target_names)
# 모든 경우에 결과 보여주기 (히트맵 처럼)
if labels:
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
if normalize:
plt.text(j, i, "{:0.4f}".format(cm[i, j]),
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
else:
plt.text(j, i, "{:,}".format(cm[i, j]),
horizontalalignment="center",
color="white" if cm[i, j] > thresh else "black")
plt.tight_layout()
plt.ylabel('True label')
plt.xlabel('Predicted label\naccuracy={:0.4f};\
misclass={:0.4f}'.format(accuracy, misclass))
plt.show()
from sklearn.metrics import confusion_matrix
model.eval()
ylabel = []
ypred_label = []
for batch_idx, (inputs, targets) in enumerate(test_loader):
inputs, targets = inputs.to(DEVICE), targets.to(DEVICE)
outputs = model(inputs)
_, predicted = outputs.max(1)
ylabel = np.concatenate((ylabel, targets.cpu().numpy()))
ypred_label = np.concatenate((ypred_label, predicted.cpu().numpy()))
ylabel
array([3., 8., 8., ..., 5., 1., 7.])
cnf_matrix = confusion_matrix(ylabel, ypred_label)
cnf_matrix
array([[806, 24, 41, 12, 9, 1, 7, 24, 59, 17],
[ 9, 931, 2, 2, 1, 3, 6, 3, 18, 25],
[ 67, 5, 620, 43, 85, 41, 76, 45, 14, 4],
[ 22, 6, 54, 578, 53, 104, 114, 48, 13, 8],
[ 24, 3, 45, 58, 731, 15, 45, 72, 7, 0],
[ 11, 4, 30, 193, 39, 609, 27, 83, 2, 2],
[ 8, 2, 30, 22, 33, 20, 864, 9, 11, 1],
[ 19, 2, 22, 41, 34, 23, 5, 850, 1, 3],
[ 60, 24, 16, 9, 2, 3, 1, 5, 873, 7],
[ 37, 95, 7, 12, 0, 2, 8, 26, 27, 786]])
plot_confusion_matrix(cnf_matrix,
target_names=labels_map.values(),
title='Confusion matrix, trained by AlexNet')
# 다항이어도 다 계산해서 히트맵처럼 만들수 있으니까 이런식으로 눈으로도 데이터가 잘 학습되었는지 확인해 봐야함

'인공지능 > 딥러닝' 카테고리의 다른 글
CNN (0) | 2025.03.04 |
---|---|
Multi-class Weather Dataset (0) | 2025.03.03 |
딥러닝: 퍼셉트론과 다층 퍼셉트론 (0) | 2025.03.03 |
손글씨 데이터셋 (0) | 2025.02.18 |
파이토치로 구현한 논리 회귀 (0) | 2025.02.01 |