반응형

캐글 머신러닝 문제들을 풀면서 K-Fold Cross Validation (교차검증)를 자주 사용했었는데, 이번에 딥러닝에서 쓸 일이 있어서 Keras 에서 Image Data Generator와 함께 사용해봤다. 

K-Fold CV

 

교차검증 소개 글 (여러 교차검증 종류도 소개가 잘 되어있다~) : davinci-ai.tistory.com/18

 

머신러닝 (5) - Cross Validation(교차검증)

Writer: Harim Kang 머신러닝 - 5. End-to-End Machine Learning Project (4) 해당 포스팅은 머신러닝의 교과서라고 불리는 Hands-On Machine Learning with Scikit-Learn & Tensor flow 책을 학습하며 정리하..

davinci-ai.tistory.com

 

이진분류 문제에서 사용했는데, 데이터를 타켓값(y)의 기준으로 봤을 때 분포가 고르지 않아서 StratifiedKFold 를 사용했다.

StratifiedKFold는 KFold의 변형된 반복자로 각각 비율이 다른 클래스의 비율을 유지하면서 훈련과 테스트 세트를 분류하도록 해준다. (출처: https://davinci-ai.tistory.com/18 [DAVINCI - AI])

 

<예시 코드 from 사이킷런 공식 User Guide>

>>> import numpy as np
>>> from sklearn.model_selection import StratifiedKFold
>>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
>>> y = np.array([0, 0, 1, 1])
>>> skf = StratifiedKFold(n_splits=2)
>>> skf.get_n_splits(X, y)
2
>>> print(skf)
StratifiedKFold(n_splits=2, random_state=None, shuffle=False)
>>> for train_index, test_index in skf.split(X, y):
...     print("TRAIN:", train_index, "TEST:", test_index)
...     X_train, X_test = X[train_index], X[test_index]
...     y_train, y_test = y[train_index], y[test_index]
TRAIN: [1 3] TEST: [0 2]
TRAIN: [0 2] TEST: [1 3]

 

<코드>

1. StratifiedKFold, ImageDataGenerator 선언

Train data는 DataFrame 형식으로 만들었다 -> Column은 파일 이름이 포함된 "file" 칼럼과 라벨값(Y)이 포함된 "label" 값이 있음

train_data = pd.read_csv('data.csv')

Y = train_data[['label']]

skf = StratifiedKFold(n_splits=5, random_state=42, shuffle=True)

# train 용
idg = ImageDataGenerator(rescale=1./255,
                         zoom_range=0.2,
                         horizontal_flip=True,
                         fill_mode='nearest'
                         )

# validation 용
idg2 = ImageDataGenerator(rescale=1./255,
                         )

 

2. 

주의해야할 점은 딥러닝은 머신러닝과 다르게 모델 선언을 for 문 밖에서 해주면 그 전 학습을 계속 이어서 해주기 때문에 모델 선언을 for 문 안에서 해줘야하고, backend.clear_session()도 해줘야한다.

tf.keras.backend.clear_session

Keras manages a global state, which it uses to implement the Functional model-building API and to uniquify autogenerated layer names.

If you are creating many models in a loop, this global state will consume an increasing amount of memory over time, and you may want to clear it. Calling clear_session() releases the global state: this helps avoid clutter from old models and layers, especially when memory is limited.

VALIDATION_ACCURACY = []
VALIDAITON_LOSS = []
val_acc = 0

fold_var = 1 # weight 나 모델 저장용

for train_index, val_index in skf.split(train_data, train_data['label']): # Y의 분포 기준으로 나눔
    training_data = train_data.iloc[train_index] # train data
    validation_data = train_data.iloc[val_index] # valid data

    train_data_generator = idg.flow_from_dataframe(training_data, directory='이미지 경로',
                                                   x_col="file", y_col="label",
                                                   class_mode="categorical", shuffle=True) # Softmax
    valid_data_generator = idg2.flow_from_dataframe(validation_data, directory='이미지 경로',
                                                   x_col="file", y_col="label",
                                                   class_mode="categorical", shuffle=True)
    print(len(train_data_generator))
    print(len(valid_data_generator))

    # CREATE NEW MODEL
    model = Sequential()
    # EfficientNet 사용
    model.add(EfficientNetB0(include_top=False, pooling='avg', weights='imagenet'))
    model.add(Dense(2, activation='softmax'))

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

    # CREATE CALLBACKS
    checkpoint_path = "weight 저장할 경로" + str(fold_var) + ".ckpt"
    modelcheckpoint = ModelCheckpoint(checkpoint_path, monitor='val_loss', mode='min', save_best_only=True,
                                      save_weights_only=True)
    # learning rate scheduler
    reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=20, verbose=1)
    earlystopping = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=20)
    callbacks_list = [modelcheckpoint,earlystopping,reduce_lr]

    # FIT THE MODEL
    history = model.fit(train_data_generator,
                        epochs=100,
                        callbacks=callbacks_list,
                        validation_data=valid_data_generator)
	
    # 모델 저장
    model.load_weights(checkpoint_path)
    model_path = "모델 저장할 경로" + str(fold_var) + ".h5"
    model.save(model_path)

    results = model.evaluate(valid_data_generator)
    results = dict(zip(model.metrics_names, results))

    VALIDATION_ACCURACY.append(results['acc'])
    VALIDAITON_LOSS.append(results['loss'])

    tf.keras.backend.clear_session() ########

    fold_var += 1

    val_acc += results['acc']/5 # 평균 Acc
  
 
print(val_acc)

 

참고 자료 :

medium.com/the-owl/k-fold-cross-validation-in-keras-3ec4a3a00538

반응형