페이지

2022년 7월 26일 화요일

3.6.4 K-겹 검증을 사용한 훈련 검증

 (훈련에 사용할 에프크의 수 같은) 매개변수들을 조정하면서 모델을 평가하기 위해 이전 예제에서 했던 것처럼 데이터를 훈련 세트와 검증 세트로 나눕니다. 데이터 포인트가 많지 않기 때문에 검증 세트도 매우 작아집니다(약 100개의 샘플). 결국 검증 세트와 훈련 세트로 어떤 데이터 포인트가 선택되었는지에 따라 검증 점수가 크게 달라집니다. 검증 세트의 분할에 대한 검증 점수의 분산이 높습니다. 이렇게 되면 신뢰 있는 모델 평가를 할 수 없습니다.

이런 상황에서 가장 좋은 방법은 K-겹 교차 검증(K-flod cross-validation)을 사용하는 것입니다. 데이터를 K개의 분할(즉 폴드(fold))로 나누고(일반적으로 K = 4 또는 5), K개의 모델을 각각 만들어 K - 1개의 분할에서 훈련하고 나머지 분할에서 평가하는 방법입니다. 모델의 검증 점수는 K개의 검증 점수 평균이 됩니다. 코드로 보면 이해하기 쉽습니다.    

    import numpy as np

    num_val_samples = len(train_data) // k

    num_epochs = 100

    all_scores = []

    for i in range(k):

        print('처리중인 폴드 #', ㅑ)

        val_data = train_Data[i * num_val_samples: (i +1) * num_val_samples]

        ..... 검증 데이터 준비 k번째 분할

        val_targets = train_targets[ i * num_val_samples: (i + 1) * num_val_samples]

    

        partial_train_data = np.concatenate( .....  훈련 데이터 준비:다른 분할 전체

            [train_data[:i * num_val_samples],

                train_data[(i +1) * num_val_samples:]],

            axis = 0)

        partial_train_targets = np.concatenate(

            [train_targets[:i * num_val_samples],

                train_targets[(i +1) * num_val_samples:]],

            axis = 0)

        model = build_model() ..........케라스 모델 구성(컴파일 포함)

        model.fit(partial_Train_Data, partial_train_target, 

                        .....모델 훈련(verbose=0이므로 훈련 과정이 출력되지 않습니다.)

                    epochs=num_epochs, batch_size=1, verbose=0)

        val_mse, val_mae = model.evaluate(val_data, val_targets, verbose=0)

            .......  검증 세트로 모델 평가

        all_scores.append(val_mae)

num_epochs = 100으로 실행하면 다음 결과를 얻습니다.

>>> all_scores

[2.0956787838794217m 2,220593797098292, 2.859968412040484, 2.4053704039111]

>>> np.mean(all_scores)

2.3953995083523267

검증 세트가 다르므로 확실히 검증 점수가 2.1에서 2.9까지 변화가 큽니다. 평균값(2.4)이 각각의 점수보다 훨씬 신뢰할 만합니다. 이것이 K-겹 교차 검증의 핵심입니다. 이 예에서는 평균적으로 2,400달러 정도가 납니다. 주택 가격의 범위가 1만 달러에서 5만 달러 사이인 것을 감안하면 비교적 큰 값입니다.

신경망을 조금 더 오래 500 에포크 동안 훈련해 보죠. 각 에포크마다 모델이 얼마나 개선되는지기록하기 위해 훈련 루프를 조금 수정해서 에포크의 검증 점수를 로그에 저장하겠습니다.

    num_epochs = 500

    all_mae_histories = []

    for i in range(k):

        print('처리중인 폴드 #', i)

        val_data = train_data[i * num_val_samples: (i +1) * num_val_samples] 

            ......... 검증 데이터 준비: k번째 분할

        val_targets = train_targets[i * num_val_samples: (i + 1) * num_val_samples]

        partial_train_Data = np.concatenate( ............ 훈련 데이터 준비: 다른 분할 전체

            [train_Data[:i * num_val_samples],

                train_data[(i +1) * num_val_samples:]],

            axis=0)

        partial_train_targets = np.concatenate(    

            [train_targets[:i * num_val_samples],

                train_targets[(i +1) * num_val_samples:]],

            axis=0)

        model = build_model() ............케라스 모델 구성(컴파일 푸함)

        history = model.fit(partial_train_Data, partial_train_targets, 

            ...... 모델 훈련(verbose=0이므로 훈련 과정이 출력되지 않습니다)

                        validation_data=(val_data, val_targets),

                        epochs=num_epochs, batch_size=1, verbose=0)

        mae_hostory = history.history['val_mean_absolute_error']

        all_mae_histories.append(mae_history)

그다음 모든 폴드에 대해 에포크의 MAE 점수 평균을 계산합니다.

    average_mae_history = [

        np.mean([x[i] for x in all_mae_histories]) for i in range(num_epochs)]

그래프로 나타내면 그림 3-12와 같습니다.

    import matplotlib.pyplot as plt

    plt.plot(range(1, len(average_mae_history) + 1), average_mae_hjistory)

    plt.xlabel('Epochs')

    plt.ylabel('Validation MAE')

    plt.show()

이 그래프는 범위가 크고 변동이 심하기 때뮤ㅜㄴ에 보기가 좀 어렵습니다. 다음과 같이 해 보죠.

1) 곡선의 다른 부분과 스케일이 많이 다른 첫 10개의 데이터 포인트를 제외시킵니다.

2) 부르더운 곡선을 얻기 위해 각 포인트를 이전 포인트의 지수 이동 평균(exponential moving average)으로 대체합니다.


    def smooth_curve(points, factor=0.9):

        smoothed_point=[]

        for point in points:

            if smoothed_points:

                previous = smoothed_points[-1]

                smoothed_points.append(previous *  factor + point * (1 - factor))

            else:

                smoothed_points.append(point)

        return smoothed_points

    smooth_mae_history = smooth_curve(average_mae_history[1-:])


    plt.plot(range(1, len(smooth_mae)history) + 1), smooth_mae_history)

    plt.xlabel('Epochs')

    plt.ylabel('Validation MAE')

    plt.show()

이 그래프를 보면 검증 MAE가 80번째 에포크 이후에 줄어드는 것이 멈추었습니다. 이 지점 이후로는 과대적합이 시작됩니다.

모델의 여러 매개변수에 대한 튜닝이 끝나면(에포크 수뿐만 아니라 은닉 층의 크기도 조절할 수 있습니다) 모든 훈련 데이터를 사용하고 최상의 매개변수로 최종 실전에 투입될 모델을 훈련시킵니다. 그다음 테스트 데이터로 성능을 확인합니다.

    model = build_model() ..............새롭게 컴파일된 모델을 얻습니다.

    model.fit(train_data, train_targets, ................. 전체 데이터로 훈련시킵니다.

                epochs=80, batch_size=16, verbose=0)

    test_mse_score, test_mae_score = model.evaluate(test_data, test_Targets)

최종 결과는 다음과 같습니다.

>>> test_mae_score

2.675027286305147

아직 2.675달러 정도 차이가 나네요

        

댓글 없음: