Deeplearning-chapter4

심준보·2023년 4월 11일
post-thumbnail

신경망 시작하기: 분류와 회귀

영화 리뷰 분류 : 이진 분류 예제

  • IMDB 데이터셋

from tensorflow.keras.datasets import imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(
    num_words=10000)

imdb.load_data() : 함수는 IMDB 데이터셋을 로드하는 함수로, 이 함수는 훈련 데이터셋과 테스트 데이터셋을 각각 튜플로 반환합니다. 튜플의 첫 번째 원소는 데이터(data)이고, 두 번째 원소는 레이블(label)입니다.

num_words=10000 : 인자는 데이터셋에서 가장 자주 사용되는 단어 1만 개만 선택하겠다는 것을 의미

train_data.shape

train_data : shape을 알려주는것

max([max(sequence) for sequence in test_data[40:70]]) 

: 테스트 데이터셋에서 40번째부터 69번째까지의 샘플에 대해, 시퀀스(sequence) 중 가장 큰 정수값을 구하는 코드

리뷰를 다시 텍스트로 디코딩하기]

word_index = imdb.get_word_index()

reverse_word_index = dict(
    [(value, key) for (key, value) in word_index.items()])
decoded_review = " ".join(
    [reverse_word_index.get(i - 3, "?") for i in train_data[0]])   
  • word_index = imdb.get_word_index(): IMDB 데이터셋으로부터 단어와 해당 단어의 정수 인덱스를 가져옵니다. word_index는 딕셔너리 형태이며, key는 단어, value는 해당 단어의 정수 인덱스입니다.

  • reverse_word_index = dict([(value, key) for (key, value) in word_index.items()]): word_index의 key와 value를 뒤집은 딕셔너리 reverse_word_index를 생성합니다. 이를 통해, 정수 인덱스를 이용해 단어를 찾을 수 있게 됩니다.

  • decoded_review = " ".join([reverse_word_index.get(i - 3, "?") for i in train_data[0]]): 텍스트 데이터를 디코딩합니다. 이 코드에서는 첫 번째 훈련 데이터의 정수 시퀀스를 디코딩하는 것을 예시로 들고 있습니다. 정수 시퀀스는 train_data[0]에 저장되어 있습니다. reverse_word_index를 이용하여, 각 정수 인덱스를 해당하는 단어로 바꾸고, 이를 공백 문자열을 기준으로 이어붙입니다. 이 결과, decoded_review는 정수 시퀀스에 해당하는 텍스트 데이터가 됩니다. 여기서 get() 함수의 두 번째 인자인 ?는 만약 정수 인덱스가 reverse_word_index에 없을 경우 대신 사용할 값입니다. i - 3은 인덱스를 3씩 감소시켜주는 것으로, IMDB 데이터셋에서 정의한 규칙에 따라 특수 문자를 나타내는 0, 1, 2를 제외하기 위한 조치

데이터 준비


import numpy as np
def vectorize_sequences(sequences, dimension=10000):  
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        for j in sequence:
            results[i, j] = 1.
    return results
x_train = vectorize_sequences(train_data)  
x_test = vectorize_sequences(test_data) 
  • def vectorize_sequences(sequences, dimension=10000):: 정수 시퀀스를 입력으로 받아, 이를 고정된 크기의 벡터로 변환하는 함수입니다. dimension은 결과 벡터의 차원 수를 의미합니다. 기본값은 10000입니다.

  • results = np.zeros((len(sequences), dimension)): 결과를 저장할 2차원 배열 results를 생성합니다. len(sequences)는 입력 시퀀스의 개수를 나타내며, dimension은 결과 벡터의 차원 수입니다. 이 배열은 모든 값이 0인 배열로 초기화됩니다.

  • for i, sequence in enumerate(sequences):: 입력 시퀀스의 개수만큼 반복합니다. enumerate() 함수는 리스트나 배열의 값과 인덱스를 동시에 반환하는 함수입니다.

  • for j in sequence: results[i, j] = 1.: 시퀀스의 각 정수 인덱스 j에 대해, results 배열에서 i번째 행과 j번째 열에 해당하는 값에 1을 할당합니다. 이는 해당하는 단어가 시퀀스에 포함되었음을 의미합니다.

  • x_train = vectorize_sequences(train_data): 훈련 데이터를 벡터화합니다. train_data는 정수 시퀀스의 리스트이며, vectorize_sequences() 함수를 이용하여 벡터화된 훈련 데이터를 x_train에 할당합니다.




y_train = np.asarray(train_labels).astype("float32")  # y: label 깂
y_test = np.asarray(test_labels).astype("float32")
  • y_train = np.asarray(train_labels).astype("float32"): train_labels 리스트를 NumPy 배열로 변환하고, 이를 y_train 변수에 할당합니다. astype("float32")는 배열의 데이터 타입을 실수형(float32)으로 변환하는 메소드입니다

np.asarray : p.asarray() 함수는 입력 데이터를 NumPy 배열로 변환하는 함수입니다. 이 함수는 파이썬 리스트, 튜플, 배열 등 다양한 객체를 입력으로 받아 해당 객체를 NumPy 배열로 변환합니다

신경망 모델 만들기


model = keras.Sequential([
    layers.Dense(16, activation="relu"),
    layers.Dense(16, activation="relu"), 

    layers.Dense(1, activation="sigmoid")  
  • 첫 번째 층(layers.Dense(16, activation="relu"))은 16개의 뉴런을 가지며, 활성화 함수로 ReLU(Rectified Linear Unit) 함수를 사용합니다. 입력 데이터의 차원은 모델에 따라 자동으로 결정되므로, 이 층에서는 입력 데이터의 차원을 명시적으로 지정하지 않습니다.

  • 두 번째 층(layers.Dense(16, activation="relu"))은 첫 번째 층과 동일한 구조를 가집니다. 이전 층에서 출력된 16개의 특성(feature)을 입력으로 받아 다시 16개의 특성을 출력합니다. 활성화 함수로는 여전히 ReLU 함수가 사용됩니다.

  • 세 번째 층(layers.Dense(1, activation="sigmoid"))은 하나의 출력 뉴런을 가지며, 활성화 함수로 Sigmoid 함수를 사용합니다. Sigmoid 함수는 이진 분류 문제(binary classification)에서 사용하는 일반적인 활성화 함수입니다. 출력값이 0.5보다 크면 1, 작으면 0으로 분류합니다.

  • ReLU 함수 : 입력값이 0보다 작을 경우에는 0을 출력하고, 0보다 큰 경우에는 입력값 그대로 출력합니다. 이 함수는 다음과 같은 장점이 있습니다.

반면, 출력층에서는 활성화 함수를 목적에 맞게 선택하여 사용합니다. 예를 들어, 이진 분류 문제에서는 Sigmoid 함수를, 다중 분류 문제에서는 Softmax 함수를 사용합니다. Sigmoid 함수는 출력값을 [0, 1] 범위로 변환하며, 이진 분류 문제에서 출력값이 0.5보다 크면 1, 작으면 0으로 분류합니다. Softmax 함수는 출력값을 확률로 해석할 수 있도록 변환합니다.

모델 컴파일하기


model.compile(optimizer="rmsprop",  
              loss="binary_crossentropy",
              metrics=["accuracy"])  
  • optimizer: 최적화 알고리즘을 선택합니다. 여기에서는 RMSprop 알고리즘을 사용합니다.

  • loss: 손실 함수를 선택합니다. 이진 분류 문제에서는 binary_crossentropy를 사용합니다. 이 손실 함수는 실제값과 예측값 간의 차이를 계산하여 모델을 학습하는 데 사용됩니다.

  • metrics: 모델의 성능을 평가하는 지표를 선택합니다. 이진 분류 문제에서는 accuracy(정확도)를 사용합니다. 정확도는 전체 샘플 중 맞게 분류한 샘플의 비율을 의미합니다.

다중 분류 문제에서는 categorical_crossentropy 손실 함수를 사용하는 것이 일반적입니다.

훈련 검증

검증 세트 준비하기


x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]
  • x_val: 검증 데이터의 입력값으로 사용할 x_train의 첫 10,000개 샘플을 할당합니다.
  • partial_x_train: 검증 데이터로 사용하지 않을 나머지 훈련 데이터를 할당합니다.
  • y_val: 검증 데이터의 출력값으로 사용할 y_train의 첫 10,000개 샘플을 할당합니다.
  • partial_y_train: 검증 데이터로 사용하지 않을 나머지 훈련 데이터의 출력값을 할당합니다.

모델 훈련하기


history = model.fit(partial_x_train,
                    partial_y_train,
                    epochs=20,
                    batch_size=512,
                    validation_data=(x_val, y_val)) 

model.fit() 메서드는 다음과 같은 파라미터를 받습니다.

partial_x_train: 훈련 데이터셋의 입력값 중 검증 데이터를 제외한 부분입니다.
partial_y_train: 훈련 데이터셋의 출력값 중 검증 데이터를 제외한 부분입니다.
epochs: 훈련 과정에서 전체 데이터셋을 몇 번 반복할 것인지를 결정합니다.
batch_size: 한 번에 처리할 데이터의 개수를 결정합니다.
validation_data: 검증 데이터셋을 지정합니다.

history.history

  • history.history는 딕셔너리 타입으로, 훈련 과정에서 기록된 손실과 정확도를 나타냅니다. 딕셔너리의 키는 'loss', 'accuracy', 'val_loss', 'val_accuracy'입니다.
  • 'loss': 각 epoch마다 훈련 데이터셋에 대한 손실값을 저장한 리스트
  • accuracy': 각 epoch마다 훈련 데이터셋에 대한 정확도를 저장한 리스트
  • 'val_loss': 각 epoch마다 검증 데이터셋에 대한 손실값을 저장한 리스트
  • 'val_accuracy': 각 epoch마다 검증 데이터셋에 대한 정확도를 저장한 리스트

history_dict.keys()
  • history_dict.keys()는 딕셔너리의 키(key)들을 리스트 형태로 반환합니다.

훈련과 검증 손실 그리기


import matplotlib.pyplot as plt 
history_dict = history.history
loss_values = history_dict["loss"]
val_loss_values = history_dict["val_loss"]
epochs = range(1, len(loss_values) + 1)
plt.plot(epochs, loss_values, "bo", label="Training loss")
plt.plot(epochs, val_loss_values, "b", label="Validation loss")
plt.title("Training and validation accuracy")
plt.xlabel("Epochs")
plt.ylabel("accuracy")
plt.legend()
plt.show()
                    
  • plt.title() 함수는 그래프의 제목을 설정하며, "Training and validation accuracy"로 설정합니다.
  • plt.xlabel()과 plt.ylabel() 함수는 각각 x축과 y축의 레이블을 설정합니다.
  • 마지막으로 plt.legend() 함수는 그래프에 범례를 표시합니다. plt.show() 함수는 그래프를 출력합니다.

훈련과 검증 정확도 그리기

plt.clf()
acc = history_dict["accuracy"]
val_acc = history_dict["val_accuracy"]
plt.plot(epochs, acc, "bo", label="Training acc")
plt.plot(epochs, val_acc, "b", label="Validation acc") #blue -> b
plt.title("Training and validation accuracy")
plt.xlabel("Epochs")
plt.ylabel("Accuracy")
plt.legend()
plt.show()

  • plt.clf(): 현재 figure에 그려진 모든 그래프를 지우고 새로운 그래프를 그리기 위해 초기화합니다.

  • acc = history_dict["accuracy"]: 모델이 학습한 학습 데이터에 대한 정확도 값을 acc 변수에 저장합니다.

  • plt.plot(epochs, acc, "bo", label="Training acc"): epochs와 acc 값을 이용해 학습 데이터에 대한 정확도 그래프를 그립니다. 'bo'는 파란색 동그라미를 의미합니다. label="Training acc"는 이 그래프가 학습 데이터에 대한 정확도 그래프임을 나타내는 레이블(label)입니다.

  • result : 에폭이 커질수록 , train의 loss는 줄어들고 accuracy는 커지는 것을 볼 수 있다.
    하지만 , val의 loss는 오히려 커지고 , val의 accuracy는 작아지는 것을 볼 수 있다. 이로써 최적값을 찾아야한다.

모델을 처음부터 다시 훈련하기


model = keras.Sequential([
    layers.Dense(16, activation="relu"),
    layers.Dense(16, activation="relu"),
    layers.Dense(1, activation="sigmoid")
])
model.compile(optimizer="rmsprop",
              loss="binary_crossentropy",  #cross-emtropy -
              metrics=["accuracy"])
model.fit(x_train, y_train, epochs=4, batch_size=512)  
results = model.evaluate(x_test, y_test)

  • Sequential 모델 객체를 생성하고, add 메서드를 이용하여 레이어를 추가합니다.
  • compile 메서드를 이용하여 모델을 컴파일합니다. 여기서는 rmsprop 옵티마이저를 사용하고, 이진 분류 문제에서는 binary_crossentropy 손실 함수를 사용하는 것이 일반적입니다.
  • fit 메서드를 이용하여 모델을 훈련합니다. 여기서는 훈련 데이터셋인 x_train과 - - y_train을 사용하며, 총 4번의 에포크(epoch)로 학습을 진행합니다. 한 번에 512개의 샘플씩 묶어서 학습(batch_size)합니다.
  • evaluate 메서드를 이용하여 모델을 평가합니다. 여기서는 테스트 데이터셋인 x_test와 y_test를 사용합니다. 이 때, 손실값과 정확도가 반환됩니다.

model = Sequential()
model.add(Dense(16, activation='relu', input_shape=(10000,)))

이렇게 해서 , layer를 추가할 수도 있다 -> add 메소드 사용

훈련된 모델로 새로운 데이터에 대해 예측하기

model.predict(x_test)
  • predict () 함수 중요

뉴스 기사 분류: 다중 분류 문제

레이블 인코딩하기

#1

def to_one_hot(labels, dimension=46):
    results = np.zeros((len(labels), dimension))
    for i, label in enumerate(labels):
        results[i, label] = 1.
    return results
y_train = to_one_hot(train_labels)
y_test = to_one_hot(test_labels)
  • one-hot encoding을 구현한 함수인 to_one_hot을 정의하고, 이를 통해 train_labels와 test_labels에 대한 one-hot encoding된 label 데이터를 생성
  • labels: one-hot encoding을 수행하고자 하는 라벨 데이터가 입력됩니다.
  • dimension: one-hot encoding 결과물의 차원을 정의하는 값입니다. 기본값은 46으로 설정되어 있습니다.
  • to_one_hot 함수는 np.zeros를 사용하여 results 변수를 0으로 채워진 shape가 (len(labels), dimension)인 2차원 numpy 배열로 초기화합니다. 이후 enumerate를 사용하여 labels에서 라벨을 하나씩 꺼내와 results 배열의 해당 라벨 위치를 1로 설정하여 one-hot encoding을 수행합니다.

enumerate(labels)는 labels라는 iterable 객체를 받아 해당 객체의 각 원소를 순회하면서 해당 원소의 인덱스와 값을 동시에 반환하는 iterator를 생성

#2

from tensorflow.keras.utils import to_categorical
y_train = to_categorical(train_labels)
y_test = to_categorical(test_labels)
  • tensorflow.keras 패키지에서 제공하는 to_categorical 함수를 사용하여, 다중 클래스 분류 문제를 위해 label 데이터를 one-hot encoding하는 과정
 

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)
hits_array.mean()
  • test_labels와 동일한 shape을 가지는 test_labels_copy 배열을 생성하고, 이를 무작위로 섞은 뒤 test_labels와의 일치 여부를 판단하여 정확도를 계산하는 과정

  • copy 모듈에서 copy 함수를 import하고, test_labels를 복사하여 test_labels_copy를 생성합니다.

  • np.random.shuffle 함수를 사용하여 test_labels_copy 배열의 원소들을 무작위로 섞습니다

np.argmax(predictions[5]) 
  • 가장 큰 값을 가지는 인덱스를 반환해준다.

주택 가격 예측 : 회귀 문제

데이터 정규화하기

 mean = train_data.mean(axis=0)  
train_data -= mean
std = train_data.std(axis=0)
train_data /= std
test_data -= mean
test_data /= std
  • train_data.mean(axis=0)를 통해 훈련 데이터 각 픽셀의 평균값을 계산
  • train_data 배열에서 mean 값을 뺀 후, train_data.std(axis=0)를 통해 각 픽셀의 표준편차를 계산

  • train_data 배열에서 mean 값을 뺀 후, std 값으로 나누어주는 과정을 거쳐, 훈련 데이터와 테스트 데이터를 모두 정규화(normalize)합니다.

result : 정규화된 데이터를 모델의 입력값으로 사용하면, 모델이 더욱 빠르고 정확하게 학습할 수 있습니다.

k -겹 검증을 사용한 훈련 검증

k = 4
num_val_samples = len(train_data) // k
num_epochs = 100
all_scores = []
for i in range(k):
    print(f"#{i}번째 폴드 처리중")
    val_data = train_data[i * num_val_samples: (i + 1) * num_val_samples]
    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_targets,
              epochs=num_epochs, batch_size=16, verbose=0)
    val_mse, val_mae = model.evaluate(val_data, val_targets, verbose=0)
    all_scores.append(val_mae)
  • k 값이 4로 설정되어 있으므로, 전체 학습 데이터셋인 train_data와 train_targets를 4개의 폴드(fold)로 나누어서 교차 검증을 수행

  • all_scores 리스트에는 모든 폴드에서 검증 세트의 평균 절대 오차(MAE)가 저장


plt.plot(range(1, len(average_mae_history) + 1), average_mae_history)  
plt.xlabel("Epochs")
plt.ylabel("Validation MAE")
plt.show()

                    
  • average_mae_history : 각 에폭마다 검증 세트 MAE 값을 저장하고 있는 리스트이다.
                
profile
밑거름이라고생각합니다

0개의 댓글