Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/BowonKwon/AISA5
Browse files Browse the repository at this point in the history
  • Loading branch information
BowonKwon committed Aug 5, 2023
2 parents 779863f + 2a6b778 commit b083c37
Show file tree
Hide file tree
Showing 5 changed files with 538 additions and 0 deletions.
74 changes: 74 additions & 0 deletions 주말수업/5주차/1_inference_follow copy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 패키지 임포트
import os # 경로 설정을 위한 os 패키지 임포트
import torch # 파이토치 패키지 임포트
import torch.nn as nn # 파이토치의 nn 패키지 임포트
from PIL import Image # 이미지를 다루기 위한 PIL 패키지 임포트
from torchvision.transforms import Resize # 이미지 크기를 조절하는 함수 임포트
from torchvision.transforms import ToTensor # 이미지를 텐서로 변환하는 함수 임포트

# 타겟하는 학습 세팅을 설정
target_folder = '../../주중수업/5주차/results/1' # 타겟 폴더 설정
assert os.path.exists(target_folder), 'target folder does not exists' # 타겟 폴더가 존재하는지 확인

# 하이퍼파라미터 로드
with open(os.path.join(target_folder, 'hparam.txt'), 'r') as f: # hparam.txt 파일을 읽기 모드로 열기
data = f.readlines() # 파일의 모든 줄을 읽어서 리스트로 저장
print(data) # 읽어온 데이터 출력

lr = float(data[0].strip()) # 학습률 저장
image_size = int(data[1].strip()) # 이미지 사이즈 저장
num_classes = int(data[2].strip()) # 클래스 개수 저장
batch_size = int(data[3].strip()) # 배치 크기 저장
hidden_size = int(data[4].strip()) # 은닉층 크기 저장
epochs = int(data[5].strip()) # 에포크 수 저장
results_folder = data[6].strip() # 결과 폴더 저장

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # GPU 사용 여부에 따라 device 설정

# 모델 class 만들기
class MLP(nn.Module): # nn.Module을 상속받는 MLP 클래스 선언
def __init__(self, image_size, hidden_size, num_classes): # 클래스 초기화: MLP 레이어 정의
super().__init__() # 상속받은 상위 클래스의 초기화 메서드 호출
self.image_size = image_size # 이미지 사이즈 저장
self.mlp1 = nn.Linear(image_size * image_size, hidden_size) # 첫 번째 MLP 레이어 선언(입력층 -> 은닉층1)
self.mlp2 = nn.Linear(hidden_size, hidden_size) # 두 번째 MLP 레이어 선언(은닉층1 -> 은닉층2)
self.mlp3 = nn.Linear(hidden_size, hidden_size) # 세 번째 MLP 레이어 선언(은닉층2 -> 은닉층3)
self.mlp4 = nn.Linear(hidden_size, num_classes) # 네 번째 MLP 레이어 선언(은닉층3 -> 출력층)
def forward(self, x): # 순전파: 데이터가 레이어 통과하는 방식 지정
batch_size = x.shape[0] # 입력 텐서의 배치 크기 저장(x: [batch_size, 28, 28, 1])
x = torch.reshape(x, (-1, image_size * image_size)) # 28*28 픽셀 이미지를 1차원 벡터로 변환(펼치기)
# 순전파 수행: 입력 이미지를 순차적으로 MLP 레이어에 통과시킴
x = self.mlp1(x) # [batch_size, 500]
x = self.mlp2(x) # [batch_size, 500]
x = self.mlp3(x) # [batch_size, 500]
x = self.mlp4(x) # [batch_size, 10]
# 최종 출력 반환
return x

# 모델 선언
myMLP = MLP(image_size, hidden_size, num_classes).to(device)

# 저장된 모델 가중치 불러오기
ckpt = torch.load( # 저장된 모델 가중치 불러오기
os.path.join( # 경로 설정
target_folder, 'myMLP_best.ckpt' # 타겟 폴더 내의 myMLP_best.ckpt 파일 경로
)
)
myMLP.load_state_dict(ckpt) # 모델에 가중치 저장

# 추론 데이터를 가지고 오기
image_path = './test_image.jpg' # 추론할 이미지 경로
assert os.path.exists(image_path), 'target image does not exists' # 이미지가 존재하는지 확인
input_image = Image.open().convert('L') # 이미지를 흑백으로 변환

# 학습 과정에서 사용했던 전처리 과정을 그대로 실행
resizer = Resize(image_size) # 크기 맞추기: 이미지 크기를 조절하는 함수 선언
totensor = ToTensor() # 크기 맞추기: 이미지를 텐서로 변환하는 함수 선언
image = totensor(resizer(input_image)).to(device) # 이미지를 텐서로 변환 후 device로 이동

# 모델 추론 진행
output = myMLP(image) # 모델에 이미지 입력 후 출력값 저장
# 추론 결과를 우리가 이해할 수 있는 형태로 변환
output = torch.argmax(output).item() # 출력값 중 가장 큰 값의 인덱스를 추론 결과로 저장

print(f'Model says, the image is {output}') # 모델이 추론한 결과 출력
70 changes: 70 additions & 0 deletions 주말수업/5주차/2_inference_comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# 패키지 임포트
# 경로 설정을 위한 os 패키지 임포트
# 파이토치 패키지 임포트
# 파이토치의 nn 패키지 임포트
# 이미지를 다루기 위한 PIL 패키지 임포트
# 이미지 크기를 조절하는 함수 임포트
# 이미지를 텐서로 변환하는 함수 임포트

# 타겟하는 학습 세팅을 설정
# 타겟 폴더 설정
# 타겟 폴더가 존재하는지 확인

# 하이퍼파라미터 로드
# hparam.txt 파일을 읽기 모드로 열기
# 파일의 모든 줄을 읽어서 리스트로 저장
# 읽어온 데이터 출력

# 학습률 저장
# 이미지 사이즈 저장
# 클래스 개수 저장
# 배치 크기 저장
# 은닉층 크기 저장
# 에포크 수 저장
# 결과 폴더 저장

# GPU 사용 여부에 따라 device 설정

# 모델 class 만들기
# nn.Module을 상속받는 MLP 클래스 선언
# 클래스 초기화: MLP 레이어 정의
# 상속받은 상위 클래스의 초기화 메서드 호출
# 이미지 사이즈 저장
# 첫 번째 MLP 레이어 선언(입력층 -> 은닉층1)
# 두 번째 MLP 레이어 선언(은닉층1 -> 은닉층2)
# 세 번째 MLP 레이어 선언(은닉층2 -> 은닉층3)
# 네 번째 MLP 레이어 선언(은닉층3 -> 출력층)
# 순전파: 데이터가 레이어 통과하는 방식 지정
# 입력 텐서의 배치 크기 저장(x: [batch_size, 28, 28, 1])
# 28*28 픽셀 이미지를 1차원 벡터로 변환(펼치기)
# 순전파 수행: 입력 이미지를 순차적으로 MLP 레이어에 통과시킴
# [batch_size, 500]
# [batch_size, 500]
# [batch_size, 500]
# [batch_size, 10]
# 최종 출력 반환

# 모델 선언

# 저장된 모델 가중치 불러오기
# 저장된 모델 가중치 불러오기
# 경로 설정
# 타겟 폴더 내의 myMLP_best.ckpt 파일 경로
# 모델에 가중치 저장

# 추론 데이터를 가지고 오기
# 추론할 이미지 경로
# 이미지가 존재하는지 확인
# 이미지를 흑백으로 변환

# 학습 과정에서 사용했던 전처리 과정을 그대로 실행
# 크기 맞추기: 이미지 크기를 조절하는 함수 선언
# 크기 맞추기: 이미지를 텐서로 변환하는 함수 선언
# 이미지를 텐서로 변환 후 device로 이동

# 모델 추론 진행
# 모델에 이미지 입력 후 출력값 저장
# 추론 결과를 우리가 이해할 수 있는 형태로 변환
# 출력값 중 가장 큰 값의 인덱스를 추론 결과로 저장

# 모델이 추론한 결과 출력
144 changes: 144 additions & 0 deletions 주중수업/5주차/1_follow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# 패키지 임포트
import os # os 패키지 임포트
import torch # 파이토치 패키지 임포트
import torch.nn as nn # nn 패키지 임포트
from torchvision.datasets import MNIST # MNIST 데이터셋 불러오기
from torchvision.transforms import ToTensor # ToTensor 클래스 임포트
from torch.utils.data import DataLoader # DataLoader 클래스 임포트
from torch.optim import Adam # Adam 클래스 임포트

# hyperparameter 선언(학습률, 이미지 사이즈, 클래스 개수, 배치 사이즈, 은닉층 사이즈, 에포크 수, 결과 저장 폴더)
lr = 0.001
image_size = 28
num_classes = 10
batch_size = 100
hidden_size = 500
epochs = 3
results_folder = 'results'

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 디바이스 설정

# 저장
# 상위 저장 폴더가 없으면 상위 저장 폴더 생성
if not os.path.exists(results_folder):
os.makedirs(results_folder)
# 결과 저장할 하위 타깃 폴더 생성
target_folder_name = max([0] + [int(e) for e in os.listdir(results_folder)])+1 # 하위 타깃 폴더 이름
target_folder = os.path.join(results_folder, str(target_folder_name)) # 하위 타깃 폴더 경로
os.makedirs(target_folder) # 하위 타깃 폴더 생성
# 타깃 폴더에 하이퍼파라미터 저장
with open(os.path.join(target_folder, 'hparam.txt'), 'w') as f: # 타깃 폴더에 hparam.txt 파일 생성
f.write(f'{lr}\n')
f.write(f'{image_size}\n')
f.write(f'{num_classes}\n')
f.write(f'{batch_size}\n')
f.write(f'{hidden_size}\n')
f.write(f'{epochs}\n')
f.write(f'{results_folder}\n')

# 모델 설계도 그리기
class MLP(nn.Module): # nn.Module을 상속받는 MLP 클래스 선언
def __init__(self, image_size, hidden_size, num_classes): # 클래스 초기화: MLP 레이어 정의
super().__init__() # 상속받은 상위 클래스의 초기화 메서드 호출
self.image_size = image_size # 이미지 사이즈 저장
self.mlp1 = nn.Linear(image_size * image_size, hidden_size) # 첫 번째 MLP 레이어 선언(입력층 -> 은닉층1)
self.mlp2 = nn.Linear(hidden_size, hidden_size) # 두 번째 MLP 레이어 선언(은닉층1 -> 은닉층2)
self.mlp3 = nn.Linear(hidden_size, hidden_size) # 세 번째 MLP 레이어 선언(은닉층2 -> 은닉층3)
self.mlp4 = nn.Linear(hidden_size, num_classes) # 네 번째 MLP 레이어 선언(은닉층3 -> 출력층)
def forward(self, x): # 순전파: 데이터가 레이어 통과하는 방식 지정
batch_size = x.shape[0] # 입력 텐서의 배치 크기 저장(x: [batch_size, 28, 28, 1])
x = torch.reshape(x, (-1, image_size * image_size)) # 28*28 픽셀 이미지를 1차원 벡터로 변환(펼치기)
# 순전파 수행: 입력 이미지를 순차적으로 MLP 레이어에 통과시킴
x = self.mlp1(x) # [batch_size, 500]
x = self.mlp2(x) # [batch_size, 500]
x = self.mlp3(x) # [batch_size, 500]
x = self.mlp4(x) # [batch_size, 10]
# 최종 출력 반환
return x

# 설계도를 바탕으로 모델 만들기 <- hyperparmeter 사용
myMLP = MLP(image_size, hidden_size, num_classes).to(device)

# 데이터 불러오기
# dataset 설정(학습, 테스트 데이터)
train_mnist = MNIST(root='../../data/mnist', train=True, transform=ToTensor(), download=True)
test_mnist = MNIST(root='../../data/mnist', train=False, transform=ToTensor(), download=True)
# dataloader 설정(학습, 테스트 데이터)
train_loader = DataLoader(dataset=train_mnist, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_mnist, batch_size=batch_size, shuffle=False)

# Loss 선언
loss_fn = nn.CrossEntropyLoss()
# Optimizer 선언
optim = Adam(params=myMLP.parameters(), lr=lr)

# 평가함수 구현
# 전체 데이터에 대한 정확도를 계산하는 함수
def evaluate(model, loader, device): # 모델, 데이터 로더, 디바이스를 인자로 받음
with torch.no_grad(): # 그래디언트 계산 비활성화
model.eval() # 모델을 평가 모드로 설정
total = 0 # 전체 데이터 개수 저장 변수
correct = 0 # 정답 개수 저장 변수
for images, targets in loader: # 데이터 로더로부터 미니배치를 하나씩 꺼내옴
images, targets = images.to(device), targets.to(device) # 디바이스에 데이터를 보냄
output = model(images) # 모델에 미니배치 데이터 입력하여 결괏값 계산
output_index = torch.argmax(output, dim = 1) # 결괏값 중 가장 큰 값의 인덱스를 뽑아냄
total += targets.shape[0] # 전체 데이터 개수 누적
correct += (output_index == targets).sum().item() # 정답 개수 누적

acc = correct / total * 100 # 정확도(%) 계산
model.train() # 모델을 학습 모드로 설정
return acc # 정확도(%) 반환
# 클래스별 정확도를 계산하는 함수
def evaluate_by_class(model, loader, device, num_classes): # 모델, 데이터 로더, 디바이스, 클래스 개수를 인자로 받음
with torch.no_grad(): # 그래디언트 계산 비활성화
model.eval() # 모델을 평가 모드로 설정
total = torch.zeros(num_classes) # 클래스별 전체 데이터 개수 저장 변수
correct = torch.zeros(num_classes) # 클래스별 정답 개수 저장 변수
for images, targets in loader: # 데이터 로더로부터 미니배치를 하나씩 꺼내옴
images, targets = images.to(device), targets.to(device) # 디바이스에 데이터를 보냄
output = model(images) # 모델에 미니배치 데이터 입력하여 결괏값 계산
output_index = torch.argmax(output, dim = 1) # 결괏값 중 가장 큰 값의 인덱스를 뽑아냄
for _class in range(num_classes): # 클래스 개수만큼 반복
total[_class] += (targets == _class).sum().item() # 클래스별 전체 데이터 개수 누적
correct[_class] += ((targets == _class) * (output_index == _class)).sum().item() # 클래스별 정답 개수 누적

acc = correct / total * 100 # 클래스별 정확도(%) 계산
model.train() # 모델을 학습 모드로 설정
return acc # 클래스별 정확도(%) 반환

_max = -1 # 최대 정확도 저장 변수
# 학습을 위한 반복 (Loop) for / while
for epoch in range(epochs):
# 입력할 데이터를 위해 데이터 준비 (dataloader)
for idx, (images, targets) in enumerate(train_loader):
# 데이터와 타깃을 디바이스에 올리기
images = images.to(device)
targets = targets.to(device)
# 모델에 데이터를 넣기
output = myMLP(images)
# 모델의 출력과 정답을 비교하기 (Loss 사용)
loss = loss_fn(output, targets)
# 역전파 수행
loss.backward()
# 가중치 업데이트
optim.step()
# 그래디언트 초기화
optim.zero_grad()

# 100번 반복마다 loss 출력
if idx % 100 == 0:
print(loss)

acc = evaluate(myMLP, test_loader, device) # 전체 데이터에 대한 정확도 계산
# acc = evaluate_by_class(myMLP, test_loader, device, num_classes) # 클래스별 정확도 계산

# 정확도가 높아지면 모델 저장
if _max < acc : # acc가 높아지면
print('새로운 acc 등장, 모델 weight 업데이트', acc) # acc 출력
_max = acc # _max에 acc 저장
# 모델 저장
torch.save(
myMLP.state_dict(),
os.path.join(target_folder, 'myMLP_best.ckpt')
)
104 changes: 104 additions & 0 deletions 주중수업/5주차/2_comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# 패키지 임포트
# os 패키지 임포트
# 파이토치 패키지 임포트
# nn 패키지 임포트
# MNIST 데이터셋 불러오기
# ToTensor 클래스 임포트
# DataLoader 클래스 임포트
# Adam 클래스 임포트

# hyperparameter 선언(학습률, 이미지 사이즈, 클래스 개수, 배치 사이즈, 은닉층 사이즈, 에포크 수, 결과 저장 폴더)

# 디바이스 설정

# 상위 저장 폴더가 없으면 상위 저장 폴더 생성
# 결과 저장할 하위 타깃 폴더 생성
# 하위 타깃 폴더 이름
# 하위 타깃 폴더 경로
# 하위 타깃 폴더 생성
# 타깃 폴더에 하이퍼파라미터 저장
# 타깃 폴더에 hparam.txt 파일 생성

# 모델 설계도 그리기
# nn.Module을 상속받는 MLP 클래스 선언
# 클래스 초기화: MLP 레이어 정의
# 상속받은 상위 클래스의 초기화 메서드 호출
# 이미지 사이즈 저장
# 첫 번째 MLP 레이어 선언(입력층 -> 은닉층1)
# 두 번째 MLP 레이어 선언(은닉층1 -> 은닉층2)
# 세 번째 MLP 레이어 선언(은닉층2 -> 은닉층3)
# 네 번째 MLP 레이어 선언(은닉층3 -> 출력층)
# 순전파: 데이터가 레이어 통과하는 방식 지정
# 입력 텐서의 배치 크기 저장(x: [batch_size, 28, 28, 1])
# 28*28 픽셀 이미지를 1차원 벡터로 변환(펼치기)
# 순전파 수행: 입력 이미지를 순차적으로 MLP 레이어에 통과시킴
# [batch_size, 500]
# [batch_size, 500]
# [batch_size, 500]
# [batch_size, 10]
# 최종 출력 반환

# 설계도를 바탕으로 모델 만들기 <- hyperparmeter 사용

# 데이터 불러오기
# dataset 설정(학습, 테스트 데이터)
# dataloader 설정(학습, 테스트 데이터)

# Loss 선언
# Optimizer 선언

# 평가함수 구현
# 전체 데이터에 대한 정확도를 계산하는 함수
# 모델, 데이터 로더, 디바이스를 인자로 받음
# 그래디언트 계산 비활성화
# 모델을 평가 모드로 설정
# 전체 데이터 개수 저장 변수
# 정답 개수 저장 변수
# 데이터 로더로부터 미니배치를 하나씩 꺼내옴
# 디바이스에 데이터를 보냄
# 모델에 미니배치 데이터 입력하여 결괏값 계산
# 결괏값 중 가장 큰 값의 인덱스를 뽑아냄
# 전체 데이터 개수 누적
# 정답 개수 누적
# 정확도(%) 계산
# 모델을 학습 모드로 설정
# 정확도(%) 반환

# 클래스별 정확도를 계산하는 함수
# 모델, 데이터 로더, 디바이스, 클래스 개수를 인자로 받음
# 그래디언트 계산 비활성화
# 모델을 평가 모드로 설정
# 클래스별 정답 개수 저장 변수
# 클래스별 전체 데이터 개수 저장 변수
# 데이터 로더로부터 미니배치를 하나씩 꺼내옴
# 디바이스에 데이터를 보냄
# 모델에 미니배치 데이터 입력하여 결괏값 계산
# 결괏값 중 가장 큰 값의 인덱스를 뽑아냄
# 클래스 개수만큼 반복
# 클래스별 전체 데이터 개수 누적
# 클래스별 정답 개수 누적
# 클래스별 정확도(%) 계산
# 모델을 학습 모드로 설정
# 클래스별 정확도(%) 반환

# 최대 정확도 저장 변수

# 학습을 위한 반복 (Loop) for / while
# 입력할 데이터를 위해 데이터 준비 (dataloader)
# 데이터와 타깃을 디바이스에 올리기
# 모델에 데이터를 넣기
# 모델의 출력과 정답을 비교하기 (Loss 사용)
# 역전파 수행
# 가중치 업데이트
# 그래디언트 초기화

# 100번 반복마다 loss 출력

# 전체 데이터에 대한 정확도 계산
# 클래스별 정확도 계산

# 정확도가 높아지면 모델 저장
# acc가 높아지면
# acc 출력
# _max에 acc 저장
# 모델 저장
Loading

0 comments on commit b083c37

Please sign in to comment.