흐름 요약
1.데이터 전처리
- 데이터 EDA, 필요없는 데이터 제거, 라벨인코딩, 원핫 인코딩 등 데이터 가공
- 데이터를 알맞게 변환할 transform 객체 생성
- 데이터를 Train, Validation, Test 용으로 분류 + 데이터 셋 생성하기
- 데이터 로더 생성하기
2. 모델 학습
- 장치 설정
- 모델 클래스 만들기 + 모델 객체 생성
- loss함수, optimizer 객체 생성
- train 및 validation 루프 함수 생성
- epoch 설정 및 루프 설정
3. 테스트
- 테스트 데이터 로더 생성하기
- 테스트 실행 함수 생성하기 + 테스트 실행
4. 모델 저장
- 모델 가중치와 매개변수만 저장 + 불러오기
- 모델 저장 + 불러오기
1. 데이터 전처리
1. 데이터 EDA, 필요없는 데이터 제거, 라벨인코딩, 원핫 인코딩 등 데이터 가공
2. 데이터를 알맞게 변환할 transform 객체 생성
transform_train = transforms.Compose([ # 데이터에 여러효과를 순서대로 적용
transforms.Resize((256, 256)), # 크기 동일하게 맞추기
transforms.RandomHorizontalFlip(), # 랜덤으로 좌우반전. 확률 50% (데이터 증강)
transforms.ToTensor(), # 텐서형으로 바꾸기 + "데이터를 0-1 사이로 정규화 해줌!" + RGB 이미지(H, W, C)를 -> 변환 후 Tensor (C, H, W)가 됨. H:높이, W: 가로, C: 채널
transforms.Normalize( # tensor 정규화된 값의 평균과 표준편차를 0.5로 표준화. [0.0 ~ 1.0] -> [-1.0 ~ 1.0]변환. 이유? Relu 사용시 기울기를 좀 더 살릴 수 있다.
mean=[0.5, 0.5, 0.5],
std=[0.5, 0.5, 0.5]
)
])
# Relu 예시
# x = [0.2, 0.4, 0.7, 0.9] : 모두 양수이므로 Relu를 그대로 통과 [0.2, 0.4, 0.7, 0.9]
# x = [-0.8, -0.2, 0.3, 0.9] : Relu 통과 후 [0.0, 0.0, 0.3, 0.9]
transform_test = transforms.Compose([ # -> test는 데이터 증강을 하지 않아야 함. 원래 모습대로 시험 봐야하니까
transforms.Resize((256, 256)),
transforms.ToTensor(),
transforms.Normalize(
mean=[0.5, 0.5, 0.5],
std=[0.5, 0.5, 0.5]
)
])
3. 데이터를 Train, Validation, Test 용으로 분류 + 데이터 셋 생성하기
train_dataset = datasets.ImageFolder( # 이미지를 불러들여서 데이터셋을 만들어주는 메소드
root='train/', # 폴더경로 내부 데이터 모두 가져옴
transform = transform_train # 가져오면서 transform방법은 transform_train이걸 적용할 것이다.
)
dataset_size = len(train_dataset)
train_size = int(dataset_size * 0.8)
val_size = dataset_size - train_size
train_dataset, val_dataset = random_split(train_dataset, [train_size, val_size]) # random_split: 파이토치의 split 함수. (데이터, [나눌 사이즈])
test_dataset = datasets.ImageFolder(
root='test/',
transform=transform_test
)
4. 데이터 로더 생성하기
# 미니배치용 dataloader 만들기
train_dataloader = DataLoader(train_dataset, batch_size=64, shuffle=True)
val_dataloader = DataLoader(val_dataset, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_dataset, batch_size=64, shuffle=False) # 정답은 셔플이 필요 없음
2. 모델 학습
1. 장치 설정
# 장치 확인
device = 'cuda' if torch.cuda.is_available() else 'cpu'
print(device)
2. 모델 클래스 만들기 + 모델 객체 생성
class ConvNeuralNetwork(nn.Module):
def __init__(self):
super(ConvNeuralNetwork, self).__init__() # super(ClassName, self).__init__() 은 파이썬 2버전 표현법. 파이썬 3버전 표현인 super().__init__() 과 동일하다.
self.flatten = nn.Flatten()
self.classifier = nn.Sequential(
nn.Conv2d(1, 28, kernel_size=3, padding='same'),
nn.ReLU(),
nn.Conv2d(28, 28, kernel_size=3, padding='same'),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Dropout(0.25),
nn.Conv2d(28, 56, kernel_size=3, padding='same'),
nn.ReLU(),
nn.Conv2d(56, 56, kernel_size=3, padding='same'),
nn.ReLU(),
nn.MaxPool2d(kernel_size=2),
nn.Dropout(0.25)
)
self.Linear = nn.Linear(56 * 7 * 7, 3)
def forward(self, x):
x = self.classifier(x)
x = self.flatten(x)
output = self.Linear(x)
return output
model = ConvNeuralNetwork().to(device)
print(model)
3. loss함수, optimizer 객체 생성
loss = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
4. train 및 validation 루프 함수 생성
def train_loop(train_loader, model, loss_fn, optimizer):
sum_losses = 0
sum_accs = 0
for x_batch, y_batch in train_loader:
x_batch = x_batch.to(device)
y_batch = y_batch.to(device)
y_pred = model(x_batch)
loss = loss_fn(y_pred, y_batch)
optimizer.zero_grad()
loss.backward()
optimizer.step()
sum_losses += loss.item()
y_prob = nn.Softmax(1)(y_pred)
y_pred_index = torch.argmax(y_prob, axis=1)
acc = (y_batch == y_pred_index).float().sum() / len(y_batch) * 100
sum_accs = sum_accs + acc
avg_loss = sum_losses / len(train_loader)
avg_acc = sum_accs / len(train_loader)
return avg_loss, avg_acc
5. epoch 설정 및 루프 설정
epochs = 50
for i in range(epochs):
print(f"------------------------------------------------")
avg_loss, avg_acc = train_loop(loader, model, loss, optimizer)
print(f'Epoch {i:4d}/{epochs} Loss: {avg_loss:.6f} Accuracy: {avg_acc:.2f}%')
print("Done!")
3. 테스트
1. 테스트 데이터 로더 생성하기
# 테스트 데이터 로드
test_loader = DataLoader(
dataset=testset,
batch_size=32, # 시험 배치는 학습 배치와 상관없음
shuffle=True
)
2. 테스트 실행 함수 생성하기 + 테스트 실행
def test(model, loader):
model.eval() # model이 이제 테스트로 작동해서 학습하는 메모리를 꺼버림 (=grad저장 안하게됨)
sum_accs = 0
img_list = torch.Tensor().to(device)
y_pred_list = torch.Tensor().to(device)
y_true_list = torch.Tensor().to(device) # 텐서형 빈 자료형
for x_batch, y_batch in loader:
x_batch = x_batch.to(device)
y_batch = y_batch.to(device)
y_pred = model(x_batch)
y_prob = nn.Softmax(1)(y_pred)
y_pred_index = torch.argmax(y_prob, axis=1)
y_pred_list = torch.cat((y_pred_list, y_pred_index), dim=0)
y_true_list = torch.cat((y_true_list, y_batch), dim=0)
img_list = torch.cat((img_list, x_batch), dim=0)
acc = (y_batch == y_pred_index).float().sum() / len(y_batch) * 100
sum_accs += acc
avg_acc = sum_accs / len(loader)
return y_pred_list, y_true_list, img_list, avg_acc
y_pred_list, y_true_list, img_list, avg_acc = test(model, test_loader)
print(f'테스트 정확도는 {avg_acc:.2f}% 입니다.')
4. 모델 저장
1. 모델 가중치와 매개변수만 저장 + 불러오기
# 모델의 가중치와 매개변수만 저장
# 모델의 구조가 저장되지 않으므로 모델 클래스 정의가 없으면 복원할 수 없음
torch.save(model.state_dict(), 'model_weights.pth')
model2 = ConvNeuralNetwork().to(device) # 클래스로 새로운 객체를 만듦
print(model2)
model2.load_state_dict(torch.load('model_weights.pth'))
y_pred_list, y_true_list, img_list, avg_acc = test(model2, test_loader)
print(f'테스트 정확도는 {avg_acc:.2f}% 입니다.')
2. 모델 저장 + 불러오기
# 모델 전체를 저장
# 모델 클래스와 가중치가 함께 저장되므로, 복원 시 모델 구조를 별도로 정의할 필요 없음
torch.save(model, 'model.pth')
model3 = torch.load('model.pth', weights_only=False) # weights_only=False : 가중치만 불러오지 않겠다. model 전체를 불러오겠다
y_pred_list, y_true_list, img_list, avg_acc = test(model3, test_loader)
print(f'테스트 정확도는 {avg_acc:.2f}% 입니다.')'AI 활용 소프트웨어 개발 > AI, 머신러닝, 딥러닝' 카테고리의 다른 글
| Local GPU (Vscode) 환경 설정 및 사용하기 (0) | 2025.08.13 |
|---|---|
| YOLO 하이퍼파라미터 조정하기 (yaml 파일) (3) | 2025.08.11 |
| Resnet(Deep Residual Learning for Image Recognition)논문 요약 및 구현 (2) | 2025.08.05 |
| 딥러닝, 이미지 폴더 전처리하기. (3) | 2025.08.05 |
| AlexNet 논문 핵심 내용 요약 (1) | 2025.08.04 |