[TensorFlow]텐서플로우와 DNN

신동혁·2022년 9월 26일
0

TensorFlow

목록 보기
1/4
  • DNN(Deep Neural Network)이란?
    feature를 추출하기 위해(예를 들어 운동신경을 예측하기 위한 feature : 키, 몸무게 등등)Fully-Connected-Layer를 사용해 학습하는 모델을 의미한다.

1.텐서플로우 기본 흐름

간단한 DNN예제를 통해 텐서플로우 기본 흐름을 확인해본다.

1. 데이터 로딩

from tensorflow import keras

# keras에서 제공하는 데이터 중 보스턴 집값에 대한 데이터 로딩하기
(train_x, train_y),(test_x,test_y) = keras.datasets.boston_housing.load_data()

2. 전처리

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
x_train = scaler.fit_transform(train_x)
x_test = scaler.transform(test_x)

3. dataset 만들어주기

import tensorflow as tf

# train 데이터를 dataset 형식으로 만들고, train 데이터 개수만큼 섞기, 배치 개수 설정, 배치로 나눠지지 않은 나머지 데이터 처리 방식 설정 등을 해준다.
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, train_y)).shuffle(x_train.shape[0]).batch(100, drop_remainder=True)
test_dataset = tf.data.Dataset.from_tensor_slices((x_test, test_y)).batch(N_BATCHS)

4. 모델 구현

# bottom layer ( 뒤에 오는 layer을 top layers 라고 함)
model = keras.Sequential() # 순서대로 레이어를 쌓는 모델 생성

# input layer
# model.add(layers.InputLayer((13,))) # x_train.shape이 (404, 13) 이므로 input은 다음과 같다.
# 즉, input : (feature수, )

# hidden layer
model.add(layers.Dense(units=64, activation="relu", input_shape=(13,)))# 다음과 같은 코드로 input layer를 생략할 수도 있다.
# model.add(layers.ReLU()) 위에 relu 처리를 다음과 같이 할 수도 있음
model.add(layers.Dense(units=32, activation="relu"))
model.add(layers.Dense(units=16, activation="relu"))
# 관례적으로 Dense layer는 unit 수로를 줄여나간다!!!!!!!!!!!!!!!!!!!!!!!!!

# output layer
model.add(layers.Dense(units=1)) # unit은 예측하려는 값의 개수로 지정
# activation 함수로는 회귀에서는 보통 다음 함수를 사용한다. None, sigmoid, tanh 


model.summary() # 모델 구조 확인하기
keras.utils.plot_model(model, show_shapes=True) # 모델 구조

5. 컴파일하기

# optimizer 설정, 손실함수 설정, 평가지표 설정을 해준다.
model.compile(optimizer=keras.optimizers.Adam(learning_rate=0.001), loss="categorical_crossentropy", metrics=["accuracy"])
  • 손실함수
    • 이진분류 : binary_crossentropy
    • 다중분류 : categorical_crossentropy
  • 평가지표
    • 정확도 : accuracy

6. 학습하기

hist = model.fit(train_dataset, # 위에서 batch size는 따로 지정해 줘서 생략가능
                epochs=100,
                 validation_data=test_dataset # dataset을 사용할때는 validation_split말고 validation_data 사용한다.
                )

8. 확인하기

plt.subplot(1,2,1)
plt.plot(hist.epoch, hist.history["loss"], label="Train loss")
plt.plot(hist.epoch, hist.history["val_loss"], label="Validation loss")
plt.legend()

plt.subplot(1,2,2)
plt.plot(hist.epoch, hist.history["accuracy"], label="Train Accuracy")
plt.plot(hist.epoch, hist.history["val_accuracy"], label="Validation Accuracy")
plt.legend()

plt.tight_layout()
plt.show()

9. 평가하기

loss, acc = model.evaluate(test_dataset)
print(loss, acc)

2.기본용어

Epoch(애폭) : 전체 데이터셋을 몇바퀴 돌릴지에 대한 값.
Step(스탭) : 가중치를 업데이트하는 횟수. 즉, 애폭을 배치로 나눈 값과 같다.
Batch(배치) : 전체 데이터셋을 쪼개는 단위.

3.단계별 세부사항

전처리

  • image : float32타입으로 변환 후 0 ~ 1 로 정규화(255로 나누기)
  • label : one hot encoding

image

image의 경우 0부터 255의 수로 이루어져 있다. 그러므로 MinMaxScaler처럼 해당 수들을 0~1 사이로 정규화시켜주기 위해 255로 나눠준다. 하지만 이때 타입이 uint8인 상태로 나누기를 실행할 시 정수로 나오게 된다. 그러므로 255로 나누기 전에 미리 float32타입으로 소수가 나올 수 있도록 처리해준다.

예제 )

X_train = train_image.astype("float32")/255.
X_test = test_image.astype("float32")/255.

label

예제 )

y_train = keras.utils.to_categorical(train_label, num_classes=10)
y_test = keras.utils.to_categorical(test_label, num_classes=10)

위 코드는 label값인 y_train과 y_test가 범위형일 경우의 전처리 방식이다. 해당 코드를 통해 one-hot encoding이 이루어져서 y_train과 y_test의 shape이 다음과 같은 방식으로 바뀐다.
(60000,), (10000,)) ===> ((60000, 10), (10000, 10))
60000개의 train데이터와 10000개의 test데이터가 존재하고, y(label)에 대한 범위가 10가지 있다는 사실을 확인할 수 있다.

모델 구현

모델 구현 방식으로 3가지 정도 존재한다.

  • Sequential 방식: 순서대로 쌓아올린 네트워크로 이뤄진 모델을 생성하는 방식
  • Functional API 방식: 다양한 구조의 네트워크로 이뤄진 모델을 생성하는 방식
  • Subclass 방식: 네트워크를 정의하는 클래스를 구현.
# 모델 구현
def create_bigger_model():
    model = keras.Sequential()
    model.add(layers.Flatten(input_shape=(28,28)))
    model.add(layers.Dense(256, activation="relu"))
    model.add(layers.Dense(256, activation="relu"))
    model.add(layers.Dense(128, activation="relu"))
    model.add(layers.Dense(128, activation="relu"))
    model.add(layers.Dense(10, activation="softmax", name="output_layer"))
    
    model.compile(optimizer=optimizers.Adam(LEARNING_RATE), loss="categorical_crossentropy", metrics=["accuracy"])
    return model
    
# 모델 생성
model = create_bigger_model() 

4.성능개선 방법

Layer, Unit 개수 수정

layer나 unit이 많다면 더 복잡한 모델이 되어 과대적합(overfitting)이 발생할 수 있다. 반대로 layer나 unit이 적다면 단순한 모델이 되어 과속적합(underfitting)이 발생할 수 있다.

Epoch 수정

Epoch은 전체데이터를 얼마나 많이 돌리면서 학습시킬지 정하는 변수다. 그러므로 epoch가 너무 크면 과대적합(overfitting)이 발생할 수 있다. 반대로 epoch가 너무 작으면 과소적합(underfitting)이 발생할 수 있다.

Dropout Layer 추가

Dropout 이란 layer에서 모든 unit(노드)이 학습되지 않고, 일부는 학습되지 않도록 하는 방법을 의미한다. Dropout은 overfitting의 원인인 co-adaptation 현상을 감소/방지하는 효과가 있다.

co-adaptation 현상이란? : 학습을 진행할 때 올바르게 구해진 가중치와 잘못 구해진 가중치가 있을 때, 전체가 업데이트되면서 오히려 올바르게 구해진 가중치까지 함께 업데이트되어 버리는 현상을 의미한다.

예제 )

def create_dropout_model(dropout_rate=0.5):
    model = keras.Sequential()
    model.add(layers.Flatten(input_shape=(28,28)))
    
    model.add(layers.Dropout(dropout_rate)
    model.add(layers.Dense(256, activation="relu"))
              
    model.add(layers.Dropout(dropout_rate)          
    model.add(layers.Dense(256, activation="relu"))
              
    model.add(layers.Dropout(dropout_rate)          
    model.add(layers.Dense(128, activation="relu"))
              
    model.add(layers.Dropout(dropout_rate)          
    model.add(layers.Dense(128, activation="relu"))
              
    model.add(layers.Dropout(dropout_rate)          
    model.add(layers.Dense(10, activation="softmax", name="output_layer"))
    
    model.compile(optimizer=optimizers.Adam(LEARNING_RATE), loss="categorical_crossentropy", metrics=["accuracy"])
    return model

dropout layer는 위 코드와 같이 dropout을 적용해줄 layer마다 앞에 추가로 넣어주는 형태로 사용한다. 또한 얼마나 dropout할지에 대한 dropout rate값을 지정해준다.

!주의! : dropout layer는 학습과정에서만 동작해야한다. tensorflow의 keras에서는 알아서 dropout layer가 학습과정에서만 동작하도록 설정되어 있지만, pytorch 같은 다른 라이브러리를 사용할 때는 해당 설정을 따로 해줘야 할 수도 있다.

배치 정규화

A데이터셋과 B데이터셋이 같은 종류의 데이터셋인지 아닌지를 구분하기 위해서는 두 데이터셋의 분포를 비교한다. 분포가 비슷하면 같은 데이터셋일 확률이 높은 것이다. 이런 원리로 각 layer들의 입력분포를 비슷하게 만들어 계속해서 같은 종류의 데이터셋(정규 분포)을 입력으로 넣는 느낌을 내는 것이다. 이를 통해 성능을 높일 수 있다.

예제 )

def create_batchnormalizaion_model(dropout_rate=0.5):
    model = keras.Sequential()
    model.add(layers.Flatten(input_shape=(28,28)))
    
    # 다음과 같은 형식으로 중간에 배치 정규화를 시켜준다.
    model.add(layers.Dropout(dropout_rate)) # 1번
    model.add(layers.Dense(256)) # 2번
    model.add(layers.BatchNormalization()) # 3번 (배치 정규화)
    model.add(layers.ReLU()) # 4번
              
    model.add(layers.Dropout(dropout_rate))
    model.add(layers.Dense(256))
    model.add(layers.BatchNormalization()) 
    model.add(layers.ReLU()) 
              
    model.add(layers.Dropout(dropout_rate))
    model.add(layers.Dense(128)) 
    model.add(layers.BatchNormalization())
    model.add(layers.ReLU()) 
              
    model.add(layers.Dropout(dropout_rate)) 
    model.add(layers.Dense(128))
    model.add(layers.BatchNormalization())
    model.add(layers.ReLU()) 
              
    model.add(layers.Dropout(dropout_rate))          
    model.add(layers.Dense(10))
    model.add(layers.BatchNormalization())
    model.add(layers.Softmax())
    
    model.compile(optimizer=optimizers.Adam(LEARNING_RATE), loss="categorical_crossentropy", metrics=["accuracy"])
    return model

Learning Rate 수정

  • learning rate decay
    초반 epoch에는 learning rate를 크게 설정하고 epoch가 진행됨에 따라 learning rate를 줄여주는 방향으로 학습한다.

예제 )

# learning_scheduler 생성
lr_scheduler = optimizers.schedules.ExponentialDecay(
    initial_learning_rate=0.001, # 첫 learning rate 설정
    decay_steps=len(train_dataset), # 몇 스탭마다 learning rate 수정할 지. 현재코드는 1 epoch 당 업데이트를 하기 위해 train_dataset의 전체 스탭수를 업데이트 단위로 설정한 것이다.(1epoch=전체데이터셋수)
    decay_rate=0.8, # learning rate 변화율
    staircase=True # learing rate를 계단식(디지털식)으로 변화시킬건지, 이어지는식(아날로그식)으로 변화시킬건지 설정
)

# 생성한 learning_scheduler로 compile시키기
model.compile(optimizer=optimizers.Adam(learning_rate=lr_scheduler), loss="categorical_crossentropy", metrics=["accuracy"])
  • callback
    특정 구간에서 성능이 높아지지 않으면 learning rate를 변경하는 방향으로 학습한다.
# callback 객체 생성
lr_cb = keras.callbacks.ReduceLROnPlateau(
        monitro="val_loss", # 모니터링할 평가지표
        factor=0.5, # learning rate 조정비율(디폴트:0.1)로 현재학습률*조정비율로 변경해준다
        patience=3, # 에폭구간을 설정한 값으로 해당 epoch 동안 성능개선이 안되면 학습률을 변경한다
        verbose=2, # 학습률이 변경될 때마다 로그를 남긴다.(0:로그안남김, 1:간단한로그, 2:조금더상세한로그)
        )

# 학습시킬 때 미리 만들어 놓은 callback호출
hist = model.fit(train_dataset, epochs=N_EPOCHS, validation_data=test_dataset,
                callbacks=[lr_cb])

그 외 하이퍼파라미터 조정

  • Parameters
    • 모델이 학습하여 데이터에 가장 적합한 값을 찾아내는 파라미터
      • Weights WW
      • Bias bb
  • Hyper parameters
    • 모형의 구조를 결정하거나 optimization 방법을 결정하는 변수들로 개발자가 직접 설정하는 파라미터
    • Optimizer의 종류
    • learning rate(α\alpha)
    • Hidden layer의 수
    • Hidden unit의 수
    • Iteration의 수
    • Activation function의 종류
    • Minibatch size
    • Regularization
    • dropout rate
    • etc..
  • 다양한 조합의 hyper parameter를 시도해서 loss 함수가 빠르게 감소하는 hyper parameter를 찾아내는 시도가 필요
profile
개발취준생

0개의 댓글