저번 시간에는 범주형 데이터를 인코딩하는 방식과 가중치를 초기화하는 방식에 대해서 각각 알아보았다.
이번엔 데이터를 Normalization하는 방법, 그리고 과잉적합과 과소적합에 대해 알아보고 이를 방지하는 전략까지 다루어볼 것이다.🤔
학습을 수행하기 전에 데이터를 정규화(Normalization)하는 것은 중요하다.
예를 들어 입력 x1, x2를 가지는 신경망이 하나 존재한다고 하자.
x1은 0~1의 값을 가지고, x2는 0~100의 값을 가진다.
신경망은 일련의 선형 조합과 비선형 활성화 함수를 통해 입력을 결합하여 학습하게 되므로 각 입력과 관련된 매개 변수도 서로 다른 범위를 가지면서 학습된다.
따라서 이것은 큰 범위의 특정 매개변수의 그래디언트에 더 중점을 둔 손실함수 모양이 될 것이다.❗❗❗
따라서 모든 입력을 정규화, 즉 같은 범위의 값으로 만들어주어야 한다.
가장 많이 사용되는 방법은 가우시안 정규화 기법이다.
고등학교 수학에서 배운 것같은데, 평균을 0, 값의 범위를 약 -1.0~1.0으로 제한되도록 수치데이터의 값을 바꾸어주는 것이다.
수식은 아래와 같다.
x' = (x - 평균) / 표준편차
sklearn의 MinMaxScaler 클래스는 0에서 1사이의 범위에 있도록 값들을 정규화해준다.
from sklearn.preprocessing import MinMaxScaler
data = [[-1, 2],
[-0.5, 6],
[0,10],
[1,18]]
scaler = MinMaxScaler() # 객체 생성
scaler.fit(data) # 데이터의 최소값과 최대값 구함
print(scaler.transform(data)) # 데이터 변환
Keras의 Normalization 클래스를 사용하였다.
이 객체의 adapt()메서드를 호출하면 케라스가 데이터를 분석하여 평균과 분산을 계산한다.
이후에 해당 클래스에 데이터를 넣어주면 정규화된 수치를 반환한다.
from tensorflow.keras.layers.experimental.preprocessing import Normalization
import numpy as np
# 정규화할 데이터의 범위
data = np.array([[1.],[2.],[3.],[4.],[5.]])
# 테스트로 넣어볼 데이터들
input_data = np.array([[1.],[2.],[3.]])
layer = Normalization() # 정규화 객체
layer.adapt(data)
print(layer(input_data))
이렇게 데이터를 넣어서 정규화하는 경우도 있지만, 직접 Normalization객체를 선언 시에 평균과 분산 값을 입력해줄 수도 있다.
과잉 적합(Over fitting): 지나치게 훈련 데이터에 특화되어 실제 적용 시 좋지 못한 결과가 나오는 것
훈련이 계속되어도 Test 데이터의 손실 수치가 감소하지 않으면 과잉 적합 가능성☝️☝️☝️
과소 적합(Under fitting): 신경망 모델이 충분히 훈련되지 않는 것
영화 리뷰를 분류하는 문제이다.
Tensorflow Keras의 imdb라는 데이터셋을 사용하였다.
아래의 코드에 대한 설명은 생략한다.
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
# 데이터 다운로드
imdb = tf.keras.datasets.imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
# 원-핫 인코딩
def one_hot_sequences(sequences, dimension=10000):
results = np.zeros((len(sequences), dimension))
for i, word_index in enumerate(sequences):
results[i, word_index]=1.
return results
train_data = one_hot_sequences(train_data)
test_data = one_hot_sequences(test_data)
# 신경망 모델 구축
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(16, activation="relu", input_shape=(10000,)))
model.add(tf.keras.layers.Dense(16, activation="relu"))
model.add(tf.keras.layers.Dense(1, activation="sigmoid"))
model.compile(loss="binary_crossentropy", optimizer = "adam", metrics=["accuracy"])
# 신경망 훈련, 검증 데이터 전달
history = model.fit(train_data,
train_labels,
epochs=20,
batch_size =512,
validation_data = (test_data, test_labels),
verbose=2)
# 훈련데이터의 손실함수값과 테스트데이터의 손실함수값을 그래프에 출력
history_dict = history.history
loss_values = history_dict['loss'] # 훈련 데이터 손실함수값
val_loss_values = history_dict['val_loss'] # 테스트 데이터 손실함수값
acc = history_dict['accuracy'] # 정확도
epochs = range(1, len(acc)+1) # 에포크 수
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title("Loss Plot")
plt.ylabel("loss")
plt.xlabel("epochs")
plt.legend(["train error", "val error"], loc = "upper left")
plt.show()

살펴보아야 할 점은 저 부분이다.
훈련 데이터가 학습되면서 손실 함수의 값이 떨어지는 것을 확인할 수 있는데,
반면에 일정 epoch부터 Test 데이터 즉 검증 데이터의 손실 함수값이 다시 증가하는 것을 확인할 수 있다.
즉 저 ephoch부터는 과잉 적합이 발생했다고 판단할 수도 있을 것이다.
사실 가장 단순하고 가장 좋은 방법은 양질의 훈련 데이터의 양을 늘리는 것이다.
하지만 훈련 데이터를 많이 확보하는 것은 한계가 존재한다.
이런 경우에 이를 방지할 수 있는 전략은 아래와 같다.
조기 종료: 검증 손실이 증가하면 훈련을 조기에 종료한다.

가중치 규제 방법(Weight Regularization)⭐: 가중치의 절대값을 제한한다.
# 신경망 모델 구축
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(16, kernel_regularizer=tf.keras.regularizers.l2(0.001), activation="relu", input_shape=(10000,)))
model.add(tf.keras.layers.Dense(16, kernel_regularizer=tf.keras.regularizers.l2(0.001), activation="relu"))
model.add(tf.keras.layers.Dense(1, activation="sigmoid"))
model.compile(loss="binary_crossentropy", optimizer = "adam", metrics=["accuracy"])
add()# 신경망 모델 구축
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(16, activation="relu", input_shape=(10000,)))
model.add(tf.keras.layers.Dropout(0.5))
model.add(tf.keras.layers.Dense(16, activation="relu"))
model.add(tf.keras.layers.Dropout(0.5))
model.add(tf.keras.layers.Dense(1, activation="sigmoid"))
이전과 달리 tf.keras.layers.Dropout(0.5)를 확인할 수 있을 것이다.
또한 아래처럼 손실함수값도 이전보다 훨씬 향상되었다.👍👍
데이터 정규화의 중요성, 과잉적합과 과소적합이 검증 데이터에 얼마나 큰 문제를 야기하는지 느낄 수 있었다.
과잉 적합으로 인해 증가하는 손실값이 크다는 것을 느꼈고, 적당한 Epoch값과 방지 전략들을 잘 활용해야겠다는 생각이 들었다🥺
특히 Dropout() 메서드! 잘 기억해주겠어😊
참고 자료
https://goodtogreate.tistory.com/entry/Neural-Network-%EC%A0%81%EC%9A%A9-%EC%A0%84%EC%97%90-Input-data%EB%A5%BC-Normalize-%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0
https://limjun92.github.io/assets/TensorFlow%202.0%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC/2.%20Keras%EB%A5%BC%20%EC%82%AC%EC%9A%A9%ED%95%9C%20ML%20basic/%5B%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC5%5D%EA%B3%BC%EB%8C%80%EC%A0%81%ED%95%A9%EA%B3%BC%20%EA%B3%BC%EC%86%8C%EC%A0%81%ED%95%A9/