페이지

2022년 7월 25일 월요일

3.6 주택 가곅 예측: 회귀 문제

 앞의 두 예제는 분류 문제입니다. 입력 데이터 포인트의 개별적인 레이블 하나를 예측하는 것이 목적입니다. 또 다른 종류의 머신 러닝 문제는 개별적인 레이블 대신에 연속적인 값을 예측하는 회귀(regression)입니다. 예를 들어 기상 데이터가 주어졌을 때 내일 기온을 예측하거나, 소프트웨어 명세가 주어졌을 때 소프트웨어 프로젝트가 완료될 시간을 예측하는 것입니다.

회귀와 로지스틱 회귀(logistic regression)알고리즘을 혼동하지 마세요. 로지스틱 회귀는 회귀 알고리즘이 아니라 분류 알고리즘입니다.


3.5.9 정리

 다음은 이 예제에서 배운 것들 입니다.

1) N개의 클래스로 데이터 포인트를 분류하려면 네트워크의 마지막 Dense층의 크기는 N이어야 합니다.

2) 단일 레이블, 다중 분류 문제에서는 N개의 클래스에 대한 확률 분포를 출력하기 위해 softmax 활성화 함수를 사용해야 합니다.

3) 이런 문제에는 항상 범주형 크로스엔트로피를 사용해야 합니다. 이 함수는 모델이 출력한 확률 분포와 타깃 분포 사이의 거리를 최소화합니다.

4) 다중 분류에서 레이블을 다루는 두 가지 방법이 있습니다.

    - 레이블을 범주형 인코딩(또는 원-핫 인코딩)으로 인코딩하고 categorical_crossentropy손실 함수를 사용합니다.

    - 레이블을 정수로 인코딩하고 sparse_categorical_crossentropy 손실 함수를 사용합니다.

5)많은 수의 범주를 분류할 때 중간층의 크기가 너무 작아 네트워크에 정보의 병목이 생기지 않도록 해야 합니다.

3.5.8 추가 실험

 1) 더 크거나 작은 층을 사용해 보세요. 32개의 유닛, 128개의 유닛 등

2) 여기에서 2개의 은닉 층을 사용했습니다. 1개나 3개의 은닉 층을 사용해 보세요.

3.5.7 충분히 큰 중간층을 두어야 하는 이유

 앞서 언급한 것 처럼 마지막 출력이 46차원이기 때문에 중간층의 히든 유닛이 46개보다 많이 적어선느 안 됩니다. 46차원보다 훨씬 작은 중간층(예를 들어 4차원)을 두면 정보의 병목이 어떻게 나타나는지 확인해 보겠습니다.

    model = models.Sequential()

    model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))

    model.add(layers.Dense(4, activation='relu'))

    model.add(layers.Dense(46, activation='softmax'))


    model.compile(optimizer='rmsprop',

                        loss='categorical_crossentropy',

                        metrics=['accuracy'])

    model.fit(partial_x_train,

                partial_y_train,

                epochs=20,

                batch_size=128,

                validation_data=(x_val, y_val))

검증 정확도의 최고 값은 약 71%로 8% 정도 감소되었습니다. 이런 손실의 원인 대부분은 많은 정보(클래스 46개의 분할 초평면을 복원하기에 충분한 정보)를 중간층의 저 차원 표현 공간으로 압축하려고 했기 때문입니다. 이 네트워크는 필요한 정보 대부분을 4차원 표현 안에 구겨 넣었지만 전부는 넣지 못했습니다.

2022년 7월 23일 토요일

3.5.6 레이블과 손실을 다루는 다른 방법

 앞서 언급한 것처럼 레이블을 인코딩하는 다른 방법은 다음과 같이 정수 텐서로 변환하는 것입니다.

    y_train = np.array(train_labels)

    y_test = np.array(test_labels)

이 방식을 사용하려면 손실 함수 하나만 바꾸면 됩니다. 코드 3-21에 사용된 손실 함수 categorical_crossentropy는 레이블이 범주형 인코딩되어 있을 것이라고 기대합니다. 정수 레이블을 사용할때는 sparse_categorical_crossentropy 를 사용해야 합니다.

    model.comile(optimizer='rmsprop',

                    loss='sparse_categorical_crossentropy',

                    metrics=['acc'])

이 손실 함수는 인터페이스만 다를 뿐이고 수학적으로 categorical_crossentropy와 동일합니다.

3.5.5 새로운 데이터에 대해 예측하기

 모델 객체의 predict 메서드는 46개의 토픽에 대한 확률 분포를 반환합니다. 테스트 데이터 전체에 대한 토픽을 예측해 보겠습니다.

    predictions = model.predict(x_test)

predictions의 각 항목은 길이가 46인 벡터입니다.

>>> predictions[0].shape

(46,)

이 벡터의 원소 합은 1입니다.

>>> np.sum(predictions[0])

1.0

가장 큰 값이 예측 클래스가 됩니다. 즉 가장 확률이 높은 클래스입니다.

>>> np.argmax(predictions[0])

3


3.5.4 훈련 검증

 훈련 데이터에서 1,000개의 샘플을 따로 떼어서 검증 세트로 사용하겠습니다.

    x_val = x_train[:1000]

    partial_x_train = x_train[1000:]


    y_val = one_hot_train_labels[:1000]

    partial_y_train = one_hot_train_labels[1000:]

이제 20번의 에포크로 모델을 훈련시킵니다.

    history = model.fit(partial_x_train,

                            partial_y_train,

                            epochs=20,

                            batch_size=512,

                            validation_data=(x_val, y_val))

마지막으로 손실과 정확도 곡선을 그립니다.

    import matplotlib.pyplot as plt

    loss = history.history]['loss']

    val_loss = history.history['val_loss']


    epochs = range(1, len(loss) + 1)

    plt.plot(epochs, loss, 'bo', label='Training loss')

    plt.plot(epochs, val_loss, 'b', label='Validation loss')

    plt.title('Training and validation loss')

    plt.xlabel('Epochs')

    plt.ylabel('Loss')

    plt.legend()

    plt.show()


    plt.clf()  ............... 그래프를 초기화합니다.


    acc = history.history['acc']

    val_acc = history.history['val_acc']


    plt.plot(epochs, acc, 'bo', label='Training acc')

    plt.plot(epochs, val_acc, 'b', label='Validation acc')

    plt.title('Training and validation accuracy')

    plt.xlabel('Epochs')

    plt.ylabel('Accuracy')

    plt.legend()

    plt.show()


이 모델은 아홉 번째 에포크 이후에 과대 적합이 시작됩니다. 아홉 번의 엨포크로 새로운 모델을 훈련하고 테스트 세트에서 평가하겠습니다.


    model = modles.Sequential()

    model.add(layers.Dense(64, activation='relu', input_shape=(1000, )))

    model.add(layers.Dense(64, activation='relu'))

    model.add(layers.Dense(46, activation='softmax'))

    

    model.compile(optimizer='rmsprop',

                    loss='categorical_crossentropy',

                    metrics=['accuracy']

    model.fit(partial_x_train,

                paartial_y_train,

                epochs=9,

                batch_size=512,

                validation_data=(x_val, y_val))

    results = model.evaluate(x_test, on_hot_test_labels)

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

>>> results

[1.022498257544459, 0.7756010686194165]

대략 78%의 정확도를 달성했씁니다. 균형 잡힌 이진 분류 문제에서 완전히 무작위로 분류하면 50%의 정확도를 달성합니다. 이 문제는 불균형한 데이터셋을 사용하므로 무작위로 분류하면 18%정도를 달성합니다. 여기에 비하면 이 결과는 꽤 좋은 편입니다.

>>> import copy

>>> test_labels_copy = copy.copy(test_labels)

>>> np.random.shuffle(test_labels_copy)

>>> hits_array = np.array(test_labels) == np.array(test.labels_copy)

>>> float(np.sum(hits_array)) / len(test_labels)

0.182546749777382