| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- TTS
- Python
- 트랜스포머
- 소프트웨어 개발
- 생성형 인공지능
- 머신러닝
- CLIP
- 에이전트
- Transformer
- 캐글
- ASR
- 객체지향
- python 기초
- LangGraph
- dementional reduction
- 자연어처리
- 기초
- CNN
- UMAP
- 데이터 시각화
- 데이터엔지니어
- 딥러닝
- RNN
- 정보처리기사
- SQL
- RDBMS
- 알고리즘
- python기초
- 랭그래프
- 힙정렬
- Today
- Total
수달이네 기술 블로그
8. Multi-class weather dataset(날씨 이미지 데이터셋)2 + 모델 학습 본문
모델 만들기
기초 모델
클래스로 모델을 만들면 가중치만 따로 저장하는 등의 모델로서의 기능을 사용할 수 있다.
class Model1(nn.Module):
def __init__(self):
super(Model1, self).__init__()
self.linear1 = nn.Linear(256*256*3, 4)
self.flatten = nn.Flatten()
def forward(self, x):
x = self.flatten(x)
x = self.linear1(x)
return x
_ init _: 생성자
- super로 부모 생성자의 원래 기능을 불러옴
- self.linear1 = nn.Linear(256 * 256 * 3, 4)
- 이미지를 입력 받자마자 출력하는 즉 선형 모델을 만들어버림(머신러닝급)
- self.flatten = nn.Flatten()
- 모든 변수를 일렬로 만들어줌
forward: 과정
- flatten: 일렬로
- linear1: 위에서 만든 선형모델
모듈 상속
모델 구성요소 관리: 레이어와 파라미터를 자동으로 관리해준다.
순전파 정의(Forward): forward()메서드로 간단하고 일관된 순전파 과정을 정의할 수 있다.
계층적 설계: 서브모듈을 활용해 복잡한 모델을 쉽게 설계할 수 있다.
유틸리티 제공: 파라미터 저장, 로드/ 학습, 추론 모드 전환 등의 기능
파이토치 호환성: 최적화, 데이터 로더 등의 파이토치의 다른 기능과 통합 가능
추상화: 저수준의 작업을 추상화하여 개발자의 생산성을 향상시켜준다.
학습 함수
def train():
start_time = time.time() # 실행시간 확인
print(f'[Epoch {epoch+1}] Training...')
model.train()
total = 0
running_loss = 0.0
running_correct = 0
for i, batch in enumerate(train_dataloader): # train_loader의 개수만큼 돈다
imgs, labels = batch
imgs, labels = imgs.cuda(), labels.cuda() # device를 cuda로 설정(gpu 설정)
outputs = model(imgs)
optimizer.zero_grad()
_, preds = torch.max(outputs, 1)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
total += labels.shape[0] # 라벨의 개수를 total에 누적
running_loss += loss.item() # loss값 누적
running_correct += (preds == labels).sum(preds == labels.data) # accuracy누적
if i % log_step == 0: # 출력
print(f'[Batch: {i + 1}] running train loss: {running_loss / total}, running train accuracy: {running_correct / total}')
print(f'train loss: {running_loss / total}, accuracy: {running_correct / total}')
print("elapsed time:", time.time() - start_time) # 연산시간 출력
return running_loss / total, (running_correct / total).item()
model.train() : 학습용임을 나타냄(평가용이 아님)
outputs = model(imgs): 모델에 이미지를 넣어 결과를 받음
_, preds = torch.max(outputs, 1) : 가장 큰 확률의 클래스를 결과로 받음
loss = criterion(outputs, labels) : 해당 결과로 실제값과 비교하여 loss계산
loss.backward() : 역전파
optimizer.step() : 적용
검증함수
검증함수의 내용은 학습 함수와 비슷하나, 일부 기울기를 계산하지 않거나, 평가모드로 설정하는 등의 세부사항이 다르다.
def validate():
start_time = time.time()
print(f'[Epoch {epoch+1}] Validating...')
model.eval() # 학습이 아닌 평가모드임
total = 0
running_loss = 0.0
running_correct = 0
for i, batch in enumerate(val_dataloader): # val_loader의 개수만큼 돈다
imgs, labels = batch # 이미지, 라벨 개수 64개
imgs, labels = imgs.cuda(), labels.cuda() #device를 cuda로 설정(gpu 설정)
with torch.no_grad(): #평가모드이므로 기울기 계산 안함
outputs = model(imgs) # 모델에 이미지를 넣어 예측
_, preds = torch.max(outputs, 1) # 예측값 중 가장 큰 확률의 클래스를 preds에 저장
loss = criterion(outputs, labels) # 예측값과 실제값의 loss 계산
total += labels.shape[0] # 라벨의 개수를 total에 누적
running_loss += loss.item()
running_correct += torch.sum(preds == labels.data)
if i % log_step == 0:
print(f'[Batch: {i + 1}] running val loss: {running_loss / total}, running val accuracy: {running_correct / total}')
print(f'val loss: {running_loss / total}, accuracy: {running_correct / total}')
print("elapsed time:", time.time() - start_time) # 연산 시간 출력
return running_loss / total, (running_correct / total).item()
model.eval() : 모델을 평가모드로 전환
with torch.no_grad(): : 평가모드 이므로 기울기 계산 안함 + 역전파또한 없음
테스트 함수
검증함수와 같다.
def test():
start_time = time.time()
print(f'Testing...')
model.eval() # 학습이 아닌 평가모드임
total = 0
running_loss = 0.0
running_correct = 0
for i, batch in enumerate(test_dataloader):
imgs, labels = batch # 이미지, 라벨 개수 64개
imgs, labels = imgs.cuda(), labels.cuda() #device를 cuda로 설정(gpu 설정)
with torch.no_grad(): #평가모드이므로 기울기 계산 안함
outputs = model(imgs) # 모델에 이미지를 넣어 예측
_, preds = torch.max(outputs, 1) # 예측값 중 가장 큰 확률의 클래스를 preds에 저장
loss = criterion(outputs, labels) # 예측값과 실제값의 loss 계산
total += labels.shape[0] # 라벨의 개수를 total에 누적
running_loss += loss.item()
running_correct += torch.sum(preds == labels.data)
if i % log_step == 0:
print(f'[Batch: {i + 1}] running test loss: {running_loss / total}, running test accuracy: {running_correct / total}')
print(f'test loss: {running_loss / total}, accuracy: {running_correct / total}')
print("elapsed time:", time.time() - start_time) # 연산 시간 출력
return running_loss / total, (running_correct / total).item()
위의 함수들을 만들면 model, criterion등이 노란 줄이 뜨는데, 해당 함수 실행 전에 정의하면 상관없다.
학습률 함수
def adjust_learning_rate(optimizer, epoch):
lr = learning_rate
if epoch >= 3:
lr /= 10
if epoch >= 7:
lr /= 10
for param_group in optimizer.param_groups:
param_group['lr'] = lr
return lr
처음 몇 에폭에선 lr을 크게 주어 빨리 수렴하도록 한다.
이후엔 점차 줄여 정확도를 높인다.
- param_group['lr'] = lr : 옵티마이저의 parameter들 중에 lr값을 현재 설정한 lr로 변경해준다.
옵티마이저
learning_rate = 0.01
log_step = 8
model = Model1().cuda()
criterion = nn.CrossEntropyLoss() # lossfunction
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)
옵티마이저는 위와 같이 설정한다.
- cuda를 사용하기 위해선 pytorch또한 cuda버전으로 다운로드 받아주어야 한다. 만약 안된다면 새로 설치해보자
optimizer.param_groups
# [{'params': [Parameter containing:
# tensor([[-1.8623e-03, -2.1910e-03, -4.8949e-04, ..., -5.3811e-04,
# 6.7743e-04, -2.0790e-03],
# [-7.6419e-04, -2.2354e-03, 1.3329e-03, ..., 1.0763e-03,
# -1.8846e-03, -4.0704e-04],
# [-8.4138e-04, -5.5695e-04, -1.6299e-03, ..., -1.5105e-03,
# -4.9726e-04, 1.7225e-03],
# [-2.0870e-03, -1.5302e-03, 4.9625e-05, ..., -1.2296e-03,
# 1.7425e-03, 2.4341e-04]], device='cuda:0', requires_grad=True),
# Parameter containing:
# tensor([0.0015, 0.0007, 0.0003, 0.0017], device='cuda:0', requires_grad=True)],
# 'lr': 0.01,
# 'momentum': 0.9,
# 'dampening': 0,
# 'weight_decay': 0,
# 'nesterov': False,
# 'maximize': False,
# 'foreach': None,
# 'differentiable': False,
# 'fused': None}]
해당 함수는 옵티마이저 내의 파라미터를 나타내는 함수이다.
- params: 파라미터(기울기, 편향 등)
- lr: 학습률 등등. (원래는 처음 설정할 때의 학습률로 설정된다.)
num_epochs = 20 # 에폭 수
best_val_acc = 0.0 # 가장 좋은 acc
best_epoch = -1 # 가장 좋았떤 epoch
history = []
accuracy = []
os.makedirs('weights/Model1', exist_ok=True) # 가중치 저장
학습
for epoch in range (num_epochs):
adjust_learning_rate(optimizer, epoch) # 현재 epoch에 맞게 learning rate 조정
train_loss, train_acc = train() # train 함수 호출
val_loss, val_acc = validate() # validate 함수 호출
history.append((train_loss, val_loss)) # epoch별 train loss와 val loss 저장
accuracy.append((train_acc, val_acc)) # epoch별 train accuracy와 val accuracy 저장
if val_acc > best_val_acc:
print('Saving best model...')
best_val_acc = val_acc
best_epoch = epoch
torch.save(model.state_dict(), f'weights/Model1/best_model_epoch_{epoch + 1}.pth')
torch.save(model.state_dict(), f'weights/Model1/final_model_epoch_{num_epochs}.pth')
# [Epoch 1] Training...
# [Batch: 1] running train loss: 0.023097557947039604, running train accuracy: 0.125
# [Batch: 9] running train loss: 0.22011838170389333, running train accuracy: 0.5920138955116272
# train loss: 0.235046521844718, accuracy: 0.6175243258476257
# elapsed time: 4.41102409362793
# [Epoch 1] Validating...
# [Batch: 1] running val loss: 0.4582744240760803, running val accuracy: 0.53125
# val loss: 0.43976463741726346, accuracy: 0.5666666626930237
# elapsed time: 1.1149239540100098
# Saving best model...
- 지금까지 정의한 함수들을 호출한 후
- 해당 accuracy를 확인해 가장 높은 accuracy를 적용하여 모델을 저장한다.
- pth파일을 통해 해당 모델을 저장하면 다른 곳에서도 학습없이 사용가능하다.
- 해당 pth파일을 통해 이후 다른 앱이나 사이트에 적용 가능하다.
학습을 마무리 하면
plt.plot([x[0] for x in accuracy], 'b', label='train')
plt.plot([x[1] for x in accuracy], 'r--',label='validation')
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend()
test_loss, test_accuracy = test()
print(f"Test loss: {test_loss:.8f}")
print(f"Test accuracy: {test_accuracy * 100.:.2f}%")
# Testing...
# [Batch: 1] running test loss: 0.18146856129169464, running test accuracy: 0.609375
# test loss: 0.13867560319140948, accuracy: 0.7566371560096741
# elapsed time: 1.695519208908081
# Test loss: 0.13867560
# Test accuracy: 75.66%
테스트 결과를 확인해본다. accuracy는 75.66%이다.
처음에 모델을 설정할때 단순 선형 모델로 했기 때문에 accuracy가 낮은것은 어쩔수 없다.

에폭수를 더 늘리더라도 좋은 모델은 나오지 않을 것 같아보인다.
- accuracy가 늘어나지 않았으므로
새로운 모델
기존 선형 모델
class Model1(nn.Module):
def __init__(self):
super(Model1, self).__init__()
self.linear1 = nn.Linear(256 * 256 * 3, 4)
self.flatten = nn.Flatten()
def forward(self, x):
x = self.flatten(x)
x = self.linear1(x)
return x
- y = wx + b
- (x픽셀 * y픽셀 * 3차원(rgb) + bias) * 클래스 4개: (2562563+1)*4 = 786,436개의 파라미터
- 파라미터의 개수가 늘어날수록 표현할 수 있는 가짓수가 커지므로 더 상세하게 분류 가능하다.
2중 선형 모델
class Model2(nn.Module):
def __init__(self):
super(Model2, self).__init__()
self.linear1 = nn.Linear(256 * 256 * 3, 64) # 64개로 내주고
self.linear2 = nn.Linear(64, 4) # 4개로 다시 줄여준다.
self.flatten = nn.Flatten()
def forward(self, x):
x = self.flatten(x) # 평탄화 이후
x = self.linear1(x) #
x = self.linear2(x)
return x
- 위 함수는 2개의 선형 함수를 사용했으나, 활성화 함수를 사용하지 않았으므로, 사실상 선형함수이다
- 그러나 표현할 수 있는 파라미터의 개수는 (2562563+1)*64 + (64+1)*4 = 12,583,236 이다.
비선형성 모델(딥러닝)
class Model3(nn.Module):
def __init__(self):
super(Model3, self).__init__()
self.linear1 = nn.Linear(256 * 256 * 3, 128)
self.dropout1 = nn.Dropout(0.5)
self.linear2 = nn.Linear(128, 64)
self.dropout2 = nn.Dropout(0.5)
self.linear3 = nn.Linear(64, 32)
self.dropout3 = nn.Dropout(0.5)
self.linear4 = nn.Linear(32, 4)
self.flatten = nn.Flatten()
def forward(self, x):
x = self.flatten(x)
x = F.relu(self.linear1(x))
x = self.dropout1(x)
x = F.relu(self.linear2(x))
x = self.dropout2(x)
x = F.relu(self.linear3(x))
x = self.dropout3(x)
x = self.linear4(x)
return x
dropout(0.5)은 학습하는 것 중 절반(0.5)을 랜덤하게 꺼준다.
- 만약 파라미터 4 > 6개로 가면 24개의 파라미터지만 이중 절반 12개는 학습이 되지 않는다.
- 이를 통해 과적합을 방지하고, 일반화 성능을 높일 수 있다.
위에선 layer가 4개 dropout을 3개를 주었다.
forward
- 여기서 평탄화 > relu함수로 비선형성을 준 레이어 > dropout을 반복한다.
- relu함수는 0이하를 0으로 만들어 버리는 활성화 함수
Model2
os.makedirs("weights/Model2", exist_ok=True)
learning_rate = 0.01
log_step = 8
model = Model2()
model = model.cuda()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)
num_epochs = 20
best_val_acc = 0
best_epoch = 0
history = []
accuracy = []
for epoch in range(num_epochs):
adjust_learning_rate(optimizer, epoch)
train_loss, train_acc = train()
val_loss, val_acc = validate()
history.append((train_loss, val_loss))
accuracy.append((train_acc, val_acc))
if val_acc > best_val_acc:
print("[Info] best validation accuracy!")
best_val_acc = val_acc
best_epoch = epoch
torch.save(model.state_dict(), f"weights/Model2/best_checkpoint_epoch_{epoch + 1}.pth")
torch.save(model.state_dict(), f"weights/Model2/last_checkpoint_epoch_{num_epochs}.pth")
plt.plot([x[0] for x in accuracy], 'b', label='train')
plt.plot([x[1] for x in accuracy], 'r--',label='validation')
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend()
test_loss, test_accuracy = test()
print(f"Test loss: {test_loss:.8f}")
print(f"Test accuracy: {test_accuracy * 100.:.2f}%")
- model1의 구조와 같으나 모델만 바꿔줌
test loss: 0.12633993298606536, accuracy: 0.7654867172241211
elapsed time: 0.7122688293457031
Test loss: 0.12633993
Test accuracy: 76.55%

- accuracy는 76.55로 사실상 거의 비슷하다.
- 어차피 선형이기 때문에 accuracy가 비슷함을 알 수 있다.
Model3
os.makedirs("weights/Model3", exist_ok=True)
learning_rate = 0.01
log_step = 20
model = Model3()
model = model.cuda()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)
num_epochs = 20
best_val_acc = 0
best_epoch = 0
history = []
accuracy = []
for epoch in range(num_epochs):
adjust_learning_rate(optimizer, epoch)
train_loss, train_acc = train()
val_loss, val_acc = validate()
history.append((train_loss, val_loss))
accuracy.append((train_acc, val_acc))
if val_acc > best_val_acc:
print("[Info] best validation accuracy!")
best_val_acc = val_acc
best_epoch = epoch
torch.save(model.state_dict(), f"weights/Model3/best_checkpoint_epoch_{epoch + 1}.pth")
torch.save(model.state_dict(), f"weights/Model3/last_checkpoint_epoch_{num_epochs}.pth")
plt.plot([x[0] for x in accuracy], 'b', label='train')
plt.plot([x[1] for x in accuracy], 'r--',label='validation')
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend()
test_loss, test_accuracy = test()
print(f"Test loss: {test_loss:.8f}")
print(f"Test accuracy: {test_accuracy * 100.:.2f}%")
test loss: 0.010391020735280703, accuracy: 0.73893803358078
elapsed time: 0.7321090698242188
Test loss: 0.01039102
Test accuracy: 73.89%

- 안정적인 학습성능을 보인다.
- 그러나 막 드라마틱한 accuracy변화는 없었다.
- 딥러닝을 사용하고, 레이어수를 늘렸는데도 변화가 없다는 것은.
그러나 위의 모델들은 모두 평탄화(1열로 바꿔줌)이후 학습을 진행했다.
따라서 이미지의 지역성을 파악하기 힘들다. 그렇기 때문에 CNN등의 2차원 학습 모델을 사용하면 성능이 좋아질 것이다.
'AI공부 > 딥러닝' 카테고리의 다른 글
| 10. CNN 구현 (0) | 2026.02.06 |
|---|---|
| 9. CNN(Convolutional Neural Network) (0) | 2026.02.05 |
| 7. Multi-class weather dataset(날씨 이미지 데이터셋) + 이미지 데이터 처리 (0) | 2026.02.03 |
| 6. 다층 퍼셉트론 (0) | 2026.02.01 |
| 5. ANN과 퍼셉트론 (0) | 2026.01.31 |