본문 바로가기
Artificial Intelligence/Deep Learning

Hands-On Machine Learning(핸즈온 머신러닝) - 10장 연습문제

by EunjiBest 2022. 7. 19.

Hands-On Machine Learning(핸즈온 머신러닝) - 10장 연습문제

 

 

1장부터 9장까지는 머신러닝 내용이니, 머신러닝 카테고리

10장부터 19장까지는 딥러닝 내용이니, 딥러닝 카테고리에 포스팅을 하기로 하겠다.

 

 

 

 

1번

 

텐서플로 플레이그라운드를 방문해서 연습문제에 나온대로 사용해보세요.

 

 

 

Tensorflow — Neural Network Playground

Tinker with a real neural network right here in your browser.

playground.tensorflow.org

 

텐서플로우 플레이 그라운드는 딥러닝 신경망 시뮬레이터이다. 

복잡한 코드를 입력하지 않고, 클릭만으로 어떤 신경망들이 어떤 효과를 내는지 시각적으로 한눈에 볼 수 있다.

신경망의 레이어를 처음 배울 때 레이어의 작동 방식 등을 익히기 좋은 사이트같다.

 

 

지금까지는 큰 생각없이 이런저런 레이어를 쌓으면서 모델링을 했었는데,

여기서 시뮬레이션을 돌리면 어떻게 해야 모델링이 효과적인지 판단하는데에 큰 도움이 될 것같다.

 

 

 

 

 

 

3번

 

고전적인 퍼센트론보다 로직스틱 회귀 분류기를 일반적으로 선호하는 이유는 무엇인가? 퍼셉트론을 어떻게 수정하면 로지스틱 회귀 분류기와 동등하게 만들 수 있나?

 

퍼셉트론은 클래스 확률을 제공하지 않고, 고정된 임곗값을 기준으로 예측을 만든다.(360p)

퍼셉트론은 데이터셋이 선형적으로 구분될 때에만 수렴하고, 클래스 확률을 추정할 수 없다.

하지만 로지스틱 회귀는 데이터셋이 선형적이지 않아도 좋은 솔루션으로 수렴하고 클래스 확률을 출력한다.

 

퍼셉트론의 activation을 로지스틱 활성화 함수(softmax)로 바꾸고, 경사하강법이나 기타 최적화 알고리즘을 사용하여 훈련하면 로지스틱 회귀 분류기와 동일하게 사용할 수 있다.

 

 

 

 

4번

 

왜 초창기의 다층 퍼셉트론을 훈련할 때 로지스틱 활성화 함수가 핵심요소인가?

 

로지스틱의 활성화 함수의 도함수는 어디에서나 0이 아니기 때문에 미분이 가능하여 경사 하강법이 가능했다.

활성화 함수가 계단함수일 경우 수평선밖에 없어 계산할 그라디언트가 없다. (364p)

 

 

 

 

 

5번

 

인기 많은 활성화 함수 3개

 

 

 

1. 하이퍼볼릭 탄젠트 함수

 

로지스틱(sigmoid)처럼 모양이 s모양이여서 연속적이고 미분이 가능한다.

출력범위가 -1에서 1 사이기기때문에, 훈련 초기에 각 층의 출력을 원점으로 모의는 경향이 있다. 이는 빠르수렴을 도와주기도 한다.

 

 

2. ReLU

 

f(x)가 0일때 미분가능하지 않다.(기울기가 갑자기 변해서 경사 하강법이 다르곳으로 튈 수 있다.)

f(x)가 0보다 작을 때, 도함수는 0이지만 실제로 잘 작동하고 계산속도가 매우 빠르다는 점에서 가장 기본적으로 사용하는 활성화 함수이다. 가장 큰 장점은 출력에 최댓값이 없는 것이데 이는 경사하강법의 일부 문제를 완화해준다.

 

3. Sigmoid

 

로지스틱 회귀라고도 하며, 0과 1사이의 값을 출력한다.

미분이 되지 않는 지점에서 사용하는데 즉 계단형식의 함수를 미분이 가능하도록 곡선화를 해준다.

 

 

 

 

6번

 

통과 뉴런 10개로 구성된 입력층, 뉴런 50개로 구성된 은닉층, 뉴런 3개로 구성된 출력층으로 이루어진 다층 퍼셉트론이 있다고 하자. 모든 뉴런은 relu 활성화 함수를 사용한다.

 

1. 입력행렬 x의 크기는 얼마인가?

 

입력은 (N,10)이다. 여기서 N은 훈련배치의 크기이다.

 

2. 은닉층의 가중치 행렬 Wh와, 편향백터 bh의 크기는 얼마인가?

 

(10,50)이고 bias는 50이다.

XW+B =Y라는 식에 1번에서 받아온 입력10을 X에 넣고, 뉴런 50개를 W에 넣는다.따라서 shape은(10,50)이다.

B(bias)는 W와 같은 50이다.

파라미터의 개수를 계산하자면 10x50+50이 된다.

 

3. 출력층의 가중치 행렬 Wo와 편향벡터 bo의 크기는 얼마인가?

 

출력도 마찬가지로 (50,3)이 될 수 있고, B는 3이다.

 

4. 네트워크의 출력 행렬 Y의 크기는 얼마인가

 

최종 출력 Y 크기는 (N,3)이 된다.

 

 

 

 

7번

 

1. 스팸 메일을 분류하기 위해서는 출력층에 몇개의 뉴런이 필요할까?
출력층에는 어떤 활성화 함수를 활용해야할까?
2. MINST문제라면 출력층에 어떤 활성화 함수를 활용하고, 몇개의 뉴런이 필요할까?
3. 2장의 주택가격 예측 네트워크에 대해 같은 답을 찾아보자.

 

1. 스팸 메일의 경우, 이진분류 문제에 해당하기 때문에 출력층에 하나의 뉴런만 필요하다.

보통 이진 분류의 문제를 풀때에는 sigmoid 활성화 함수를 사용한다.

 

2. MINST 데이터셋은 10개의 카테고리를 가지고 있다. 따라서 다중분류로 구분이 되며, 활성화 함수는 softmax를 사용할 수 있다. 그리고 분류에 대한 출력은 10개이니 출력층에 10개의 뉴런이 필요하다.

 

3. 2장의 주택가격 예측문제는 회귀문제이다. 따라서 하나의 뉴런과 활성화 함수가 없는 출력층을 만들어야한다.

 

 

 

 

8번

 

역전파란 무엇이고 어떻게 작동을 할까?, 역전파와 후진 모드 자동 미분의 차이는 무엇인가?

 

역전파는 모든 모델의 파라미터에 대한 비용함수의 그래디언트를 계산하고, 그래디언트를 이용해서 경사하강법 스텝을 수행한다. 이때 모델 파라미터가 비용함수를 최소화하는 값으로 수렴할 때까지 수행된다.

 

그래디언트를 계산하기 위해서 후진 모드 자동 미분을 사용하는데 이는 계산 그래프의 정방향 계산에서 현재 훈련 배치에 대한 모든 노드의 값을 구한 후 역방향 계산에서 한번에 모든 그래디언트를 구해준다.

 

역전파 : 그래디언트 계산과 경사하강법 스텝을 여러번 수행해서 신경망을 훈련시키는 전체 프로세스 자체를 의미.

후진 모드 자동 미분 : 그래디언트를 계산해주는 하나의 역전파의 기법.

 

 

 

 

 

 

9번

 

다층 퍼셉트론에서 조정할 수 있는 하이퍼파라미터를 모두 나열해라.
훈련 데이터에 다층 퍼셉트론이 과대적합이 되었다면 이를 해결하기 위해서는 하이퍼파라미터를 어떻게 조정해야하나?

 

다층 퍼셉트론(MLP)에서 바꿀 수 있는 하이퍼파라미터는 

은닉층의 수와 활성화함수이다. 앞서 말했듯이 보통 Relu 활성화 함수를 기본값으로 사용하고

출력층 활성화 함수는 이진 분류에서 로지스틱(시그모이드), 다중 분류에서 소프트맥스, 회귀는 적용하지 않는다.

 

MLP가 과대적합 되었다면 위에서 말한 하이퍼파라미터를 줄이면 어느정도 해결이 될 수 있다.

 

 

 

 

 10번

 

문제: 심층 MLP를 MNIST 데이터셋에 훈련해보세요(keras.datasets.mnist.load_data() 함수를 사용해 데이터를 적재할 수 있습니다). 98% 이상의 정확도를 얻을 수 있는지 확인해보세요. 이 장에서 소개한 방법을 사용해 최적의 학습률을 찾아보세요(즉 학습률을 지수적으로 증가시키면서 손실을 그래프로 그립니다. 그다음 손실이 다시 증가하는 지점을 찾습니다). 모든 부가 기능을 추가해보세요. 즉, 체크포인트를 저장하고, 조기 종료를 사용하고, 텐서보드를 사용해 학습 곡선을 그려보세요.

 

(X_train_full, y_train_full), (X_test, y_test) = keras.datasets.mnist.load_data()

 

데이터를 가져온다.

shape을 찍어보면, x_train_full -> (60000,28,28) / dytype은 uint8 인것을 알 수 있다.

 

X_valid, X_train = X_train_full[:5000] / 255., X_train_full[5000:] / 255.
y_valid, y_train = y_train_full[:5000], y_train_full[5000:]
X_test = X_test / 255.

 

valid와 train셋으로 나눠주고 0~1범위로 스케일링해준다.

x_train[0]을 찍어보니 아래와 같은 7이라고 추정되는 숫자가 나오고

y_train[0]을 찍어보니 7이라고 라벨링 되어있는 것을 확인할 수 있다.

y_train은 0~9까지의 수이다.

 

 

K = keras.backend

class ExponentialLearningRate(keras.callbacks.Callback):
    def __init__(self, factor):
        self.factor = factor
        self.rates = []
        self.losses = []
    def on_batch_end(self, batch, logs):
        self.rates.append(K.get_value(self.model.optimizer.lr))
        self.losses.append(logs["loss"])
        K.set_value(self.model.optimizer.lr, self.model.optimizer.lr * self.factor)

 

위 코드는 콜백함수이다.

반복마다 학습률을 증가시키기 위해서 학습률과 손실을 기록해주는 역할을 한다.

 

keras.callbacks에는 다양한 콜백의 종류가 많으니 필요에 따라서 사용할 수 있다.

 

 

model = keras.models.Sequential([
    keras.layers.Flatten(input_shape=[28, 28]),
    keras.layers.Dense(300, activation="relu"),
    keras.layers.Dense(100, activation="relu"),
    keras.layers.Dense(10, activation="softmax")
])

 

간단하게 모델 생성을 해준 후,

 

model.compile(loss="sparse_categorical_crossentropy",
              optimizer=keras.optimizers.SGD(learning_rate=1e-3),
              metrics=["accuracy"])
expon_lr = ExponentialLearningRate(factor=1.005)

 

컴파일을 시켜주는데

optimizer의 학습률을 1e-3에서 시작하여 반복마다 0.5%씩 증가하게 한다.

 

 

history = model.fit(X_train, y_train, epochs=1,
                    validation_data=(X_valid, y_valid),
                    callbacks=[expon_lr])

 

model을 fit시킬 때, callbacks 옵션을 넣어준다.

 

plt.plot(expon_lr.rates, expon_lr.losses)
plt.gca().set_xscale('log')
plt.hlines(min(expon_lr.losses), min(expon_lr.rates), max(expon_lr.rates))
plt.axis([min(expon_lr.rates), max(expon_lr.rates), 0, expon_lr.losses[0]])
plt.grid()
plt.xlabel("Learning rate")
plt.ylabel("Loss")

 

plt를 이용해서 손실 그래프를 그릴 수 있다.

 

그래프를 보면, 6e-1을 지날 때 손실이 급격하게 올라가는 것을 볼 수 있다.

때문에, learning_rate를 약간 올려주어 다시 학습한다.

 

keras.backend.clear_session()
np.random.seed(42)
tf.random.set_seed(42)

 

메모리를 아끼기 위해서 기본 설정을 다시해준다.

 

model = keras.models.Sequential([
    keras.layers.Flatten(input_shape=[28, 28]),
    keras.layers.Dense(300, activation="relu"),
    keras.layers.Dense(100, activation="relu"),
    keras.layers.Dense(10, activation="softmax")
])

model.compile(loss="sparse_categorical_crossentropy",
              optimizer=keras.optimizers.SGD(learning_rate=3e-1),
              metrics=["accuracy"])

 

모델을 생성하고, 컴파일 시키는데 이때 learning_rate를 3e-1로 바꿔주었다.

 

run_index = 1
run_logdir = os.path.join(os.curdir, "my_mnist_logs", "run_{:03d}".format(run_index))
run_logdir


early_stopping_cb = keras.callbacks.EarlyStopping(patience=20)
checkpoint_cb = keras.callbacks.ModelCheckpoint("my_mnist_model.h5", save_best_only=True)
tensorboard_cb = keras.callbacks.TensorBoard(run_logdir)

history = model.fit(X_train, y_train, epochs=10,
                    validation_data=(X_valid, y_valid),
                    callbacks=[checkpoint_cb, early_stopping_cb, tensorboard_cb])
                    
model = keras.models.load_model("my_mnist_model.h5") # rollback to best model
model.evaluate(X_test, y_test)

 

조기종료를 할 수 있는 콜백 함수를 사용하여 fit을 해보았다.

처음과 같이 모델을 학습시키고 모델 저장 후 예측값까지 뽑아보았다.

Epoch 26/100
1719/1719 [==============================] - 4s 2ms/step - loss: 3.6531e-05 - accuracy: 1.0000 - val_loss: 0.0869 - val_accuracy: 0.9874

 

정확도가 98퍼센트까지 나온 것을 확인할 수 있다.

반응형

댓글