Python/Deep learning

다층 퍼셉트론을 향상시키는 방법 - 1

noodle-dev 2020. 1. 21. 23:06

Advanced Multi-Layer Perceptron

Advanced techniques for training neural networks

  • Weight Initialization
  • Nonlinearity (Activation function)
  • Optimizers
  • Batch Normalization
  • Dropout (Regularization)
  • Model Ensemble

Weight Initialization

SGD에서 w 초기값?

Sigmoid에서 문제 -

sigmoid 함수의 변수범위를 참고하여 -4~4로 초기화-> 대부분 출력값이 0, 1이 대부분이라. 학습이 안 됨

w값이 큰 게 문제다 -> N(0, 0.1) 정규분포로 초기화 -> sigmoid 분포

weight값은 +,-범위에 굉장히 작은 값이어야 한다.

Xavier Initialization

이전 노드와 다음 노드의 개수에 의존하여 표준편차 계산

ReLU에서 문제 - He Initialization

Xavier 방법이 비효율적이라서.

기본적으로 w값이 매우 작아야(sd작아야) 발산하는 경우가 없음

X_train.shape
# (60000, 28, 28)
X_train.shape[0]
#개수 60000개
# reshaping X data: (n, 28, 28) => (n, 784)
# X set 2차원을 1차원으로
X_train = X_train.reshape((X_train.shape[0], -1))
X_test = X_test.reshape((X_test.shape[0], -1))

reshape에서 두번째 parameter를 -1로 설정하는 것은

앞의 조건을 지키고 나머지 영역은 알아서 묶어달라는 의미

위는 3차원을 2차원으로 바꾸는데 n만 지키고 나머지 영역을 묶어 한 차원으로 바꾸라는 의미

train_test_split

# use only 33% of training data to expedite the training process
X_train, _ , y_train, _ = train_test_split(X_train, y_train, test_size = 0.67, random_state = 7)

train_test_split: 자주 쓰는 함수라서. split하여 (1-p), p 순으로 리턴

# converting y data into categorical (one-hot encoding)
y_train = to_categorical(y_train)
y_test = to_categorical(y_test)

one-hot encoding: 1차원 벡터->2차원 벡터
0 -> 1 0 0 이 한 줄이 one binary class
1 -> 0 1 0 행렬로 구하면 빨라
2 -> 0 0 1

model.add(Dense(50, input_shape = (784, )))
model.add(Activation('sigmoid'))
model.add(Dense(50))
model.add(Activation('sigmoid'))
model.add(Dense(50))
model.add(Activation('sigmoid'))
model.add(Dense(50))
model.add(Activation('sigmoid'))
model.add(Dense(10))
model.add(Activation('softmax'))  #출력층

출력층: binary 땐 sigmoid 썼지만
multiple는 softmax 사용. binary와 똑같지만 여러번 처리
softmax: sigmoid와의 차이점은 정규화해줌 (값의 합 1로 scaling)
출력갯수 10개, class가 10개니까

# optimzer="adam" 은 디폴트값밖에 못 써. 아래처럼 사용하면 learning rate 설정 가능
sgd = optimizers.SGD(lr = 0.001) #Adam하면 금방 올라감
model.compile(optimizer = sgd, loss = 'categorical_crossentropy', metrics = ['accuracy'])
history = model.fit(X_train, y_train, batch_size = 256, validation_split = 0.3, epochs = 200, verbose = 0)

validation_split: train data를 내부적으로 또 나눠.
70개는 학습, 30개는 validation data set으로 사용하겠다
내가 학습을 제대로 하고 있는지 검증하는 또다른 test set. overfitting 검사가능

training data set: 학습 인식률

validation data set: test 인식률

// 테스트 인식률이 더 좋을 수는 없다. 항상 training data 인식률이 test data 인식률보다 더 높아

  • if validation_split 옵션 지우면

validation data set이 없으니까 (전체 set을 학습으로만 사용하니까) validation data 인식률은 나올 수 없지

-> loss function 하나만 확인 가능

-> validation value 조금이라도 주는 게 좋아

# from now on, create a function to generate (return) models
def mlp_model():
    model = Sequential()

    model.add(Dense(50, input_shape = (784, ), kernel_initializer='he_normal'))     # use he_normal initializer
    model.add(Activation('sigmoid'))    
    model.add(Dense(50, kernel_initializer='he_normal'))                            # use he_normal initializer
    model.add(Activation('sigmoid'))    
    model.add(Dense(50, kernel_initializer='he_normal'))                            # use he_normal initializer
    model.add(Activation('sigmoid'))    
    model.add(Dense(50, kernel_initializer='he_normal'))                            # use he_normal initializer
    model.add(Activation('sigmoid'))    
    model.add(Dense(10, kernel_initializer='he_normal'))                            # use he_normal initializer
    model.add(Activation('softmax'))

    sgd = optimizers.SGD(lr = 0.001)
    model.compile(optimizer = sgd, loss = 'categorical_crossentropy', metrics = ['accuracy'])

    return model

model = mlp_model()
history = model.fit(X_train, y_train, validation_split = 0.3, epochs = 100, verbose = 0)

어느 순간에 초기화를 잘 해서 쭉 올라가.
정확도가 45퍼센트로 확 뜀
초기값을 적절히 잘 세팅해야 해.

Nonlinearity (Activation function)

def mlp_model():
    model = Sequential()

    model.add(Dense(50, input_shape = (784, )))
    model.add(Activation('relu'))    # use relu
    model.add(Dense(50))
    model.add(Activation('relu'))    # use relu
    model.add(Dense(50))
    model.add(Activation('relu'))    # use relu
    model.add(Dense(50))
    model.add(Activation('relu'))    # use relu
    model.add(Dense(10))
    model.add(Activation('softmax'))

    sgd = optimizers.SGD(lr = 0.001)
    model.compile(optimizer = sgd, loss = 'categorical_crossentropy', metrics = ['accuracy'])

    return model

model = mlp_model()
history = model.fit(X_train, y_train, validation_split = 0.3, epochs = 100, verbose = 0)

ReLU (비선형 함수) 사용, 초기값 설정 안 해도 성능 좋아

마지막 값이 아니라, 그 중에서 validation value 가장 좋았던 값을 저장.

선형함수 쓰면 2차원 곡선 형태밖에 안 나와

비선형 함수로 activation하면 굴곡이 더 생겨