1. 데이터 전처리


1.1. numpy, pandas 불러오기

import pandas as pd
import numpy as np

1.2. 작물 데이터 train set 읽어오기 : read_csv()

train = pd.read_csv("../input/jakjak/train.csv")
train


from PIL import Image
Image.open("../input/jakjak/train_imgs/10000.jpg")


1.3. 필요 없는 컬럼 삭제 : drop()

train = train.drop(columns=["uid","disease"])
train


1.4. 분석할 이미지 경로 재설정

train["img_path"] = "/kaggle/input/jakjak/" + train["img_path"]

1.5. disease_code 열을 string 으로 변환 : astype()

train["disease_code"] = train["disease_code"].astype("str")
train


1.6. 학습 데이터 셋, 테스트 셋 분리 : train_test_split 모듈

먼저, train / test 를 분리하는 목적을 정확히 알아야 한다.

정확히 말하면, train / test 가 아닌 train / validation 으로 볼 수 있다.

머신러닝 모델에 train 데이터를 100% 학습시킨 후 test 데이터에 모델을 적용했을 때 성능이 생각보다 안 나오는 경우가 많다.

이러한 현상을 보통 Overfitting 되었다라고 한다.

 

즉, 모델이 내가 가진 학습 데이터에 너무 과적합되도록 학습한 나머지, 이를 조금이라도 벗어난 케이스에 대해서는 예측율이 현저히 떨어지기 때문이라고 이해하면 된다. 그렇기 때문에 Overfitting을 방지하는 것은 전체적인 모델 성능을 따져보았을 때 매우 중요한 프로세스 중 하나이다.

 

 

위의 그림과 같이 기존 train / test로 구분 되어 있었던 데이터 셋을 train에서 train / validation으로 일정 비율 쪼갠 다음, 학습 시에는 train 셋으로 학습 후 중간중간 validation 셋으로 내가 학습한 모델 평가를 해주는 것이다.

 

만약, 모델이 과적합되었다면, validation 셋으로 검증시 예측율이나 오차율이 떨어지는 현상을 확인할 수 있으며, 이런 현상이 나타나면 학습을 종료한다.

 

그래서 머신러닝 모델의 하이퍼파라미터 튜닝 시, 특히 n_estimators의 값은 validation 셋의 오차율을 점검해 나가면서 튜닝을 진행해야 하며, 딥러닝 모델도 마찬가지로 validation_data를 지정해 줌으로써 매 epoch 마다 validation의 오차율을 확인하면서 과적합을 방지해야 좋은 성능의 모델을 만들 수 있다.

 

옵션 값 설명

더보기
더보기

test_size: 테스트 셋 구성의 비율을 나타낸다. train_size의 옵션과 반대 관계에 있는 옵션 값이며, 주로 test_size를 지정해 준다. 0.2는 전체 데이터 셋의 20%를 test (validation) 셋으로 지정하겠다는 의미이다. default 값은 0.25 이다.

 

shuffle: default=True 이다. split을 해주기 이전에 데이터를 섞을건지에 대한 여부이다. 보통은 default 값으로 놔둔다.

 

stratify: default=None 이다. classification을 다룰 때 매우 중요한 옵션값이다. stratify 값을 target으로 지정해주면 각각의 class 비율(ratio)을 train / validation에 유지해 준다. (한 쪽에 쏠려서 분배되는 것을 방지합니다) 만약 이 옵션을 지정해 주지 않고 classification 문제를 다룬다면, 성능의 차이가 많이 날 수 있다.

 

random_state: 세트를 섞을 때 해당 int 값을 보고 섞으며, 하이퍼 파라미터를 튜닝시 이 값을 고정해두고 튜닝해야 매번 데이터셋이 변경되는 것을 방지할 수 있다.

 

from sklearn.model_selection import train_test_split
X_train, X_valid = train_test_split(train, test_size = 0.2, random_state = 82, stratify = train["disease_code"])

train과 validation에 disease_code가 한쪽으로 쏠리지 않게 분배한다.


1.7. 이미지 데이터 전처리 : ImageDataGenerator 모듈

keras에서는 이미지데이터 학습을 쉽게하도록 하기위해 다양한 패키지를 제공한다. 그 중 하나가 ImageDataGenerator 클래스이다. ImageDataGenerator 클래스를 통해 객체를 생성할 때 파라미터를 전달해주는 것을 통해 데이터의 전처리를 쉽게할 수 있다.

또한 이미지 데이터가 부족한 현상을 이미지 증식을 통해 데이터 부족 현상을 낮출 수 있다. 강아지 사진을 축소한다고 해서 고양이 사진이 되지는 않지만, 픽셀 데이터 상으로는 완전히 다른 데이터가 나오므로 이것을 이용해 데이터도 늘릴 겸 위치이동이나 회전에 대한 학습도 할 수 있다.

 

 

하지만 안그래도 용량 많이먹는 이미지를 전부 다 돌리고 늘리고 한 것들을 전부 저장한다면 하드든 메모리든 펑 하고 터져버릴 것이다.
그래서 메모리상엔 기본 이미지만 올려놓고 학습시 배치단위로 입력될 때 살짝 변조해서 데이터를 입력해주는 방식으로 큰 메모리 손실없이 많은 데이터를 학습하게 하는 생성기 역할도 한다.

 

예시 코드

idg = ImageDataGenerator(rescale =  1./255,          # 0과 1사이로 변경
                             zoom_range = 0.2,           # 확대축소 20%
                             width_shift_range = 0.2,    # 좌우이동 20%
                             height_shift_range = 0.2,   # 상하이동 20%
                             rotation_range = 30,        # 회전각도 30도 이내
                             horizental_flip = True)     # 좌우반전 True

 

옵션 값 설명

더보기
더보기

rotation_range : 랜덤하게 회전할 각도의 범위 (0~180)

width_shift & height_shift : 좌우 & 상하 랜덤 이동 범위 (원본 이미지에 대한 비율)

shear_range : shearing transformation 범위 (회전하면서 늘어지는거 같은데 잘 모르겠다)

zoom_range : 랜덤 확대 범위, 확대 축소 비율(0~1)

horizontal_flip, vertical_flip : 좌우상하반전여부 (50%확률로 뒤집는다. 뒤집어도 자연스러운 케이스에 사용하면 좋다고 함)

fill_mode : 빈 공간을 채우는 방식

 

이런식으로 제네레이터를 생성해 주면 된다.
끝 이면 좋겟지만 아직 좀 남았다.

 

이제 생성규칙 하나 만들어줬을 뿐이다.

진짜 제네레이터를 만드는건 3가지 함수가 있다.

 

예시 코드

generator = datagen.flow_from_dataframe(X_train,                # 데이터프레임
                                      directory = './image',  # 데이터 위치
                                      x_col = 'img_file',     # 파일위치 열이름
                                      y_col = 'class',        # 클래스 열이름
                                      target_size = (224,224),    # 이미지 사이즈
                                      color_mode= 'rgb',          # 이미지 채널수
                                      class_mode= 'categorical',  # Y값 변화방법
                                      batch_size= 32,         # 배치사이즈
                                      Shuffle = True,         # 랜덤 여부
                                      seed = 42,              # 랜덤엔 시드
                                      interpolation= 'nearest')# 이미지변경시 보완방법

generator = datagen.flow_from_directory('./image'       # 파일위치
                                      classes = []    # 리스트
                            )

 

batch size 더보기

더보기
더보기

batch size : 한번의 batch 마다 주는 데이터 샘플의 size.

여기서 batch(보통 mini-batch 라고 표현)는 나눠진 데이터 셋을 뜻한다.

 

batch size와 성능의 상관 관계는 아직 정확하게 규정되지는 않았다. task, 데이터에 따라 그 기준이 달라지기 때문​이다.

다만, 일반적으로 32, 64 크기의 mini-batch가 성능에는 가장 좋다고 알려져 있다.

 

▶ batch size를 줄임으로써 얻는 장점​

- 필요한 메모리 감소: 전체 데이터를 쪼개어 여러 번 학습하는 것이기 때문에 최소 요구 메모리량을 줄일 수 있음.

▶ batch size를 늘임으로써 얻는 장점

- 아래 graph를 보면 전체 데이터를 활용한 Batch의 경우(파란색 그래프)보다 batch size가 작은 Mini-batch의 경우(초록색 그래프)가 더 fluctuate 한 것을 확인할 수 있음.

(더 flucatuate 하다는 것은 학습이 불안정 해진다는 의미)

 

가용 메모리가 적을 때는 batch size를 상대적으로 작게,

보다 안정적으로 학습을 시키고 싶다면 batch size를 상대적으로 높게 설정해주면 된다.

batch size가 커질 수록 일반화 성능은 감소하는 경우가 다소 확인이 되었으니 그 점만 유의해주면 된다.

 

from tensorflow.keras.preprocessing.image import ImageDataGenerator
idg = ImageDataGenerator(horizontal_flip=True)
train_generator = idg.flow_from_dataframe(X_train, x_col = "img_path", y_col = "disease_code", target_size = (280,280), batch_size = 16)
train_generator

train 데이터 셋에서 200개의 이미지 데이터를 인식했고, 7개의 클래스로 분류하였다.

 

idg2 = ImageDataGenerator(horizontal_flip=True)
valid_generator = idg2.flow_from_dataframe(X_valid, x_col = "img_path", y_col = "disease_code", target_size = (280,280), batch_size = 16)

valid 데이터 셋에서 50개의 이미지 데이터를 인식했고, 7개의 클래스로 분류하였다.


2. 모델링


2.1. Early Stopping : EarlyStopping() 

너무 많은 Epoch 은 overfitting 을 일으킨다. 하지만 너무 적은 Epoch 은 underfitting 을 일으킨다. 

 

이런 상황에서 Epoch 을 어떻게 설정해야하는가? Epoch 을 정하는데 많이 사용되는 Early stopping 은 무조건 Epoch 을 많이 돌린 후, 특정 시점에서 멈추는 것이다. 그 특정시점을 어떻게 정하느냐가 Early stopping 의 핵심이라고 할 수 있다. 일반적으로 hold-out validation set 에서의 성능이 더 이상 증가하지 않을 때 학습을 중지시키게 된다.

 

 

Earlystopping 클래스의 구성 요소

  1. Performance measure: 어떤 성능을 monitoring 할 것인가?
  2. Trigger: 언제 training 을 멈출 것인가?

 

예시 코드

es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=50)

 

옵션값 설명

더보기
더보기

monitor = 'val_loss' : validation set 의 loss 를 monitoring 한다는 뜻이다. 

 

mode = 'min' : 만약 performance measure가 최소화 시켜야하는 것이면 mode를 min 으로, 최대화 시켜야하는 것이면 mode를 max로 지정한다. loss 의 경우, 최소화 시키는 방향으로 training 이 진행되므로 min 을 지정한다. 

 

verbose = 1 : mode 의 default 는 auto 인데, 이는 keras 에서 알아서 min, max 를 선택하게 된다. 여기까지가 가장 기본적인 Early stopping 의 사용법이다. performance measure를 정의하고, 이것을 최대화 할지, 최소화 할지를 지정하는 것이다. 그러면 keras 에서 알아서 적절한 epoch 에서 training 을 멈춘다. verbose=1 로 지정하면, 언제 keras 에서 training 을 멈추었는지를 화면에 출력할 수 있다.

 

patience = 50 : 성능이 증가하지 않는다고, 그 순간 바로 멈추는 것은 효과적이지 않을 수 있다. patience 는 성능이 증가하지 않는 epoch 을 몇 번이나 허용할 것인가를 정의한다. partience 는 다소 주관적인 기준이다. 사용한 데이터와 모델의 설계에 따라 최적의 값이 바뀔 수 있다. 


2.2. Model Choice : ModelCheckpoint()

Early stopping 객체에 의해 트레이닝이 중지되었을 때, 그 상태는 이전 모델에 비해 일반적으로 validation error 가 높은 상태일 것이다. 따라서, Earlystopping 을 하는 것은 특정 시점에 모델의 트레이닝을 멈춤으로써, 모델의 validation error 가 더 이상 낮아지지 않도록 조절할 수는 있겠지만, 중지된 상태가 최고의 모델은 아닐 것이다.

 

따라서 가장 validation performance 가 좋은 모델을 저장하는 것이 필요한데, keras 에서는 이를 위해 ModelCheckpoint 라고 하는 객체가 존재한다.

 

이 객체는 validation error 를 모니터링하면서, 이전 epoch 에 비해 validation performance 가 좋은 경우, 무조건 이 때의 parameter 들을 저장한다. 이를 통해 트레이닝이 중지되었을 때, 가장 validation performance 가 높았던 모델을 반환할 수 있다. 

예시 코드

mc = ModelCheckpoint('best_model.h5', monitor='val_loss', mode='min', save_best_only=True)

hist = model.fit(train_x, train_y, nb_epoch=10,  
                 batch_size=10, verbose=2, validation_split=0.2,   
                 callbacks=[es, mc])

위 ModelCheckpoint instance와 EarlyStopping instance를 callbacks 파라미터에 넣어줌으로써, 가장 validation performance 가 좋았던 모델을 저장할 수 있게된다.


2.3. ReduceLROnPlateau

모델의 개선이 없을 경우, Learning Rate를 조절해 모델의 개선을 유도하는 콜백함수이다.

 

예시 코드

rl = ReduceLROnPlateau(monitor='val_loss', 
                                 factor=0.1, 
                                 patience=10, 
                                 verbose=0, 
                                 mode='auto', 
                                 min_delta=0.0001, 
                                 cooldown=0, 
                                 min_lr=0, 
                                 **kwargs )

 

옵션값 설명

더보기
더보기

1. monitor : ReduceLROnPlateau의 기준이 되는 값을 입력합니다.
만약 'val_loss'를 입력하면 val_loss가 더이상 감소되지 않을 경우 ReduceLROnPlateau을 적용합니다.
이외에도 다양한 값을 입력할 수 있습니다.

 

2. factor : Learning rate를 얼마나 감소시킬 지 정하는 인자값입니다.
새로운 learning rate는 기존 learning rate * factor입니다.예를 들어 현재 lr이 0.01이고 factor가 0.8일 때, 콜백함수가 실행된다면 그 다음 lr은 0.008이 됩니다.또다른 예로 현재 lr이 0.3이고 factor가 0.1일 때, 콜백함수가 실행된다면 그 다음 lr은 0.03이 됩니다.

 

3. patience : Training이 진행됨에도 더이상 monitor되는 값의 개선이 없을 경우, 최적의 monitor 값을 기준으로 몇 번의 epoch을 진행하고, learning rate를 조절할 지의 값입니다. 

예를 들어 patience는 3이고, 30에폭에 정확도가 99%였을 때,
만약 31번째에 정확도 98%, 32번째에 98.5%, 33번째에 98%라면 모델의 개선이 (patience=3)동안 개선이 없었기에,  ReduceLROnPlateau 콜백함수를 실행합니다.

 

4. verbose :  0 또는 1
1일 경우, EarlyStopping이 적용될 때, 화면에 적용되었다고 나타냅니다.
0일 경우, 화면에 나타냄 없이 종료합니다.

 

5. mode : "auto" 또는 "min" 또는 "max"monitor되는 값이 최소가 되어야 하는지, 최대가 되어야 하는지 알려주는 인자입니다.

예를 들어, monitor하는 값이 val_acc 즉 정확도일 경우, 값이 클수록 좋기때문에 "max"를 입력하고, val_loss일 경우 작을수록 좋기 때문에 "min"을 입력합니다."auto"는 모델이 알아서 판단합니다.

 

6. min_delta : 개선된 것으로 간주하기 위한 최소한의 변화량입니다. 
예를 들어, min_delta가 0.01이고, 30에폭에 정확도가 0.8532라고 할 때,
만약 31에폭에 정확도가 0.8537라고 하면 이는 0.005의 개선이 있었지만 min_delta 값 0.01에는 미치지 못했으므로 개선된 것으로 보지 않습니다.

 

7. cooldown : Learning rate가 감소한 후, ReduceLROnPlateau 콜백함수를 다시 실행하기 전에 대기 할 Epoch 수입니다. 
예를 들어, factor가 3이고, cooldown이 5일 때, 만약 ReduceLROnPlateau이 적용되어 learning rate가 감소되었다고 합시다. 감소된 이후에도, 3에폭 연속 monitor 값의 개선이 없다고 해도, ReduceLROnPlateau는 실행되지 않습니다. cooldown이 적용되고 있기 때문입니다. cooldown 값인 5 에폭 실행 후, 3번 연속 moniort 값의 개선이 없을 시, ReduceLROnPlateau이 다시 적용됩니다.

 

8. min_lr : Learning rate의 하한선을 지정합니다.
예를 들어 현재 lr이 0.1이고 factor가 0.5이고, min_lr이 0.03이라면,
첫 번째로 콜백함수가 적용될 시, lr은 0.05(0.1*0.5)이 됩니다.
두 번째로 콜백함수가 적용된다면 0.025(0.1*0.5*0.5)이지만, min_lr이 0.03이기 때문에, 새로운 learning rate는 0.025가 아닌, 0.03이 됩니다.


2.4. Sequential Model 생성하기

model = Sequential()

keras에서는 모델을 만드는데 두 가지 방법이 있는데 Sequential 모델은 순차적으로 레이어 층을 더해주기 때문에 순차모델이라 불리고 만들기도 쉽다.


2.5. Model의 Node 구성하기

add 함수를 사용해서 model에 node를 추가할 수 있다.

해당 함수를 사용하면 이미 model 내부에 있는 node들과 현재 추가하는 노드를 연결시킬 수도 있다. 


2.5.1 EfficientNet

 


2.5.2 Dense

Dense 함수는 input과 output을 모두 연결해주는 NN layer이다. keras는 Dense를 class로 구현하였으며

Dense로 만들어준 node는 weight와 bias 변수를 각각 갖게 된다.

 

Dense 예시 코드

model.add(Dense(5, input_dim=1, activation='relu'))

 

옵션값 설명

더보기
더보기

input_dim = 1, 입력 차원이 1이라는 뜻이며 입력 노드가 한개라고 생각하면 됩니다.

만약 x배열의 데이터가 2개라면 2, 3개라면 3으로 지정을 해줍니다.

그 다음, 만든 시퀀스 오브젝트 model에 5개의 노드를 Dense레이어를 통해 연결해줍니다. 여기서 add를 통해 하나의 레이어를 추가해주는 것입니다.

 

Dense 레이어는 입력과 출력을 모두 연결해주며 입력과 출력을 각각 연결해주는 가중치를 포함하고 있습니다. 입력이 3개 출력이 4개라면 가중치는 총 3X4인 12개가 존재하게 됩니다. Dense레이어는 머신러닝의 기본층으로 영상이나 서로 연속적으로 상관관계가 있는 데이터가 아니라면 Dense레이어를 통해 학습시킬 수 있는 데이터가 많다는 뜻이 됩니다.

 

Dense의 첫번째 인자 : 출력 뉴런(노드)의 수를 결정

Dense의 두번째 인자 : input_dim은 입력 뉴런(노드)의 수를 결정, 맨 처음 입력층에서만 사용

Dense의 세번째 인자 : activation 활성화 함수를 선택

 

활성화 함수 종류

  relu 은닉 층으로 학습
'relu' 는 은닉층으로 역전파를 통해 좋은 성능이 나오기 때문에 마지막 층이 아니고서야 거의 relu 를 이용한다.
  sigmoid yes or no 와 같은 이진 분류 문제
  softmax 확률 값을 이용해 다양한 클래스를 분류하기 위한 문제

 


2.5.3 compile

모델을 학습 시키기 전에 compile 함수를 사용하여, 학습 과정에 필요한 여러 설정들을 해준다.

loss function과 optimization 기법 등을 정의해줄 수 있다. 

 

예시 코드

model.compile(optimizer = "adam", loss = "categorical_crossentropy", metrics = ['acc'])

 

옵션값 설명

더보기
더보기

compile 함수는 인자를 총 세가지 받을 수 있다.

 

첫번째 인자는 optimizer로 학습 과정에서의 최적화 방식을 설정해준다. 'adam' 이나 'sgd' 처럼 문자열로 선언할 수도 있다. 

 

두번째 인자는 loss로 loss function을 설정하는 인자이다. regression의 경우 mean_squared_error(평균 제곱 오차)를 사용할 수 있고, 

multi class classification의 경우 categorical_crossentropy (범주형 교차 엔트로피) 등을 사용할 수 있다. keras는 다양한 loss function을 지원하는데, 이에 관해서는 keras tutorial 홈페이지를 참고하면 좋겠다. 

 

세번째 인자는 metircs로 학습을 모니터링하기 위한 지표라 생각하면 되고, 딱히,, 뭔가 설정할 필요가 없다면 그냥 default로 두자. 

 


2.5.4 fit

 

 

from tensorflow.keras import *
from tensorflow.keras.layers import *
from tensorflow.keras.callbacks import * # earlystopping, modelcheckpoint
from tensorflow.keras.applications.efficientnet import EfficientNetB3
es = EarlyStopping(patience = 10, verbose = 1)
mc = ModelCheckpoint("best.h5",save_best_only = True, verbose = 1)
rl = ReduceLROnPlateau(patience = 8, verbose = 1, factor = 0.25)
model = Sequential()
model.add(EfficientNetB3(include_top = False, weights = "imagenet", pooling = "avg"))
model.add(Dense(7,activation = "softmax"))
model.compile(metrics = ['acc'], optimizer = "adam", loss = "categorical_crossentropy")
model.fit(train_generator, validation_data = valid_generator, epochs = 100, callbacks = [es,mc,rl], verbose = 1)
model.load_weights("best.h5")

test

test = pd.read_csv("../input/jakjak/test.csv")
test["img_path"] = "/kaggle/input/jakjak/" + test["img_path"]
test = test.drop(columns = "uid")

idg3 = ImageDataGenerator()
test_generator = idg3.flow_from_dataframe(test,x_col = "img_path",y_col = None, target_size = (280,280), batch_size = 16, class_mode = None, shuffle = False)

result = model.predict(test_generator, verbose = 1, workers = 4)

result.argmax(1)

sub = pd.read_csv("../input/jakjak/sample_submission.csv")
sub["disease_code"] = result.argmax(1)
sub

sub.to_csv("sub2.csv",index=False)

Ref.

train_test_split : https://teddylee777.github.io/scikit-learn/train-test-split

ImageGenerator : https://aruie.github.io/2019/06/28/keras-generator.html

batch size : https://blog.naver.com/qbxlvnf11/221449595336

epoch : https://blog.naver.com/qbxlvnf11/221449297033

Early Stopping : https://3months.tistory.com/424

ReduceLROnPlateau :  https://deep-deep-deep.tistory.com/56 

Model 학습시키기 : https://hyuna-tech.tistory.com/entry/Keras-Sequential-Model-%EC%88%9C%EC%B0%A8%EB%AA%A8%EB%8D%B8-%EC%82%AC%EC%9A%A9-%EC%98%88%EC%A0%9C-%EB%8B%A8%EC%9D%BC-layer

.

'💡 AI > Dacon | Kaggle' 카테고리의 다른 글

Kaggle - Home Credit Default Risk  (0) 2022.06.09
kaggle notebook의 첫 코드는 뭘까?  (0) 2022.03.27
복사했습니다!