본 포스팅은 다음 과정을 정리 한 글입니다.
Custom Models, Layers, and Loss Functions with TensorFlow
www.coursera.org/specializations/tensorflow-advanced-techniques
지난 시간 리뷰
2021.03.26 - [Artificial Intelligence/Keras] - [Tensorflow 2][Keras] Week 2 - Custom lambda layers
안녕하세요 이번 시간에는 저번 시간에 이어 Custom Layer를 만드는 방법에 대해서 설명드리고자 합니다.
Lambda layer는 기본적이고 간단한 기능 및 프로토타이핑에 유용하지만, 더 advanced 한 기능, 예를 들면 학습 가능한 layer를 갖는 것은 lambda layer로는 불가능합니다.
다행히 Tensorflow의 keras layer들은 상속이 가능합니다. 학습 가능하고 기존 기능을 상속하여 복잡한 기능을 수행할 수 있는 custom layer를 만들 수 있는 것입니다.
아래 그림은 Tensorflow에서 지원하는 layer들의 유형입니다. 기본적으로 빨간 네모 안에 있는 layer들이 일반적으로 사용되고 있습니다.
convolutional layer, LSTM, GRU, Lambda, MaxPooling 등등 이미 많이 보셨던 layer들입니다.
그럼 layer란 무엇일까요?
일반적으로 신경망에서 layer의 목적을 달성하기 위해 state(상태)와 Computation(계산)을 캡슐화하는 매개 변수를 수집하는 클래스입니다.
Sequential이나 functional API 둘 중 무엇을 사용하든, 모든 모델 아키텍처는 layer를 디자인합니다.
State를 변수라고 간주하면 layer의 특정 인스턴스를 고유하게 만듭니다.
이러한 state는 model.fit을 수행 중에 Tensorflow가 더 나은 성능을 내기 위해 값을 조정하거나 학습이 불가능한 경우 다른 기능에 사용될 수 있습니다.
Computation은 입력 배치를 출력 배치로 변환하는 수단입니다. 일반적으로 신경망에서 순방향 전달이라고 하며 계산이 이루어지고 다음 계층으로 전달됩니다.
예를 들어, 신경망의 매우 단순한 Dense Layer의 경우 종종 커널이라고 하는 Weight와 Bias라고 하는 C, 2개의 매개 변수가 있습니다.
계산 Y는 WX + C와 같습니다. W와 C는 State이고 공식 Y는 Computation입니다.
다음으로 실제로 이와 같은 레이어를 만드는 방법을 살펴보겠습니다.
아래 코드는 완벽한 Layer Class코드이고 이 것을 SimpleDense라고 정의하겠습니다.
레이어를 생성할 때 이와 같이 클래스 이름 뒤에 괄호를 붙이고 괄호 안에 "Layer"를 그대로 넣어 Keras의 Layer를 상속합니다. 저 (Layer)는 그냥 Class Layer를 만드실 때 반드시 넣어야 된다고 생각하시면 됩니다.
우리는 클래스 안에 3가지 함수를 정의해줘야 합니다.
첫 번째는 init입니다. init은 매개 변수를 받는 클래스를 초기화하고 내부 변수를 설정합니다.
units숫자를 받아서 self.units에 저장하는 것을 볼 수 있습니다.
두 번째는 build입니다. build는 인스턴스가 생성될 때 실행됩니다. 이 것을 사용하여 layer의 state와 생성에 필요한 몇 가지 것들을 지정해 줍니다.
세 번째는 call입니다. call은 computation을 수행하고 학습 중에 이 셀에서 출력을 얻기 위해 호출됩니다.
다시 init으로 돌아가 보면, 가장 먼저 해야 할 일은 초기화를 기본 클래스로 다시 전달하는 것입니다. (super(SimpleDense, self).__init__()) 이것은 계층 클래스에서 상속되므로 일부 초기화도 거기에서 수행되어야 하며 super 키워드를 사용하여 수행됩니다.
그런 다음 units라는 매개 변수가 전달되고 그것을 인스턴스 변수인 self.units에 저장합니다. 아무것도 지정하지 않으면 layer는 units=32를 갖게 됩니다.
이제 빌드 내에서 state를 초기화하는 코드를 봅시다. state는 위에서 배운 것 같이 w와 b로 이루어져 있습니다.
Layer를 만들 때 단일 뉴런을 만드는 것이 아니라 단위 변수에 지정된 수만큼 뉴런을 만들어야 합니다.
모든 뉴런을 초기화해야 하며 Tensorflow는 값을 초기화하기 위해 여러 내장 함수를 지원합니다. tf.random_normal_initializer()는 이름에서 알 수 있듯이 정규 분포를 사용하여 무작위로 초기화하는 함수입니다.
self.w는 w의 state를 보유하고 tf.Variable로 생성하여 tensor로 있게 됩니다. inital_value로 w_init을 사용하여 초기화하며 나중에 추적할 수 있도록 kernel이라는 이름을 줍니다. 학습 가능하도록 trainable=True로 설정하여 model.fit을 수행할 때 w값이 학습되도록 해줍니다.
bias는 이름에서 알 수 있듯이 0으로 설정하는 tf.zeros_initializer() 함수를 사용하여 다르게 초기화합니다.
self.b는 Layer에 있는 self.units의 수만큼 0으로 초기화됩니다. 이 것 역시 trainable로 설정합니다.
call은 계산을 수행하고 self.w와 self.b는 tensor이므로 입력에 w를 tf.matmul로 곱한 다음 b를 더한 값을 반환할 수 있습니다. 여기서 input은 일반적인 x값으로 y = wx+b를 수행하는 것입니다.
이제 실제로 클래스를 생성해 봅시다!
my_dense 모델을 SimpleDense의 units을 1개로 만드는 클래스를 호출하여 선언합니다.
x는 간단한 (1,1) 짜리 1이고 y는 my_dense(x)를 넣어서 나오는 결과입니다.
my_dense의 변수들은 아래와 같습니다. w는 shape이(1,1)이고 random_normal_initializer로 초기화를 하였으니 랜덤 한 값이 들어가 있습니다. 또한 이름이 kernel로 설정된 것을 알 수 있습니다.
b 역시 이름이 bias로 되어있고 0으로 초기화하였으므로 0이 저장되어 있는 것을 확인할 수 있었습니다.
마지막으로 실제 코드를 돌려봅시다!
SimpleDense를 Sequential mode로 만들어서 model.fit까지 진행을 한 것입니다.
실제 18.981468이 결과로 나왔는데 정답인 19와 유사한 것을 알 수 있습니다. 정상적으로 잘 동작한다는 것이죠ㅎㅎ
그럼 다시 MNIST model 만들기로 돌아와서 아래 Dense Layer를 어떻게 바꿀 수 있을까요? 또한 저 relu는 어떻게 하면 될까요?
바로 tf.keras.layers.Dense(128, activation='relu')를 두 개로 나누면 됩니다.
tf.keras.layers.Dense(128)을 SimpleDense(128)로 변경하고 activation='relu'는 지난 시간에 배웠던 Lambda layer를 사용하여 연결해주면 됩니다.
이것으로 Custom Layers를 만들어서 연결하는 방법에 대해 살펴보았습니다.
언제든지 질문이 있으시면 댓글 남겨주시면 답변드리겠습니다.
감사합니다.
'Artificial Intelligence > Keras' 카테고리의 다른 글
[Tensorflow 2][Keras] Week 3 - Assignment: Custom Layers (0) | 2021.03.27 |
---|---|
[Tensorflow 2][Keras] Week 3 - Activating Custom Layers (0) | 2021.03.27 |
[Tensorflow 2][Keras] Week 3 - Custom lambda layers (0) | 2021.03.26 |
[Tensorflow 2][Keras] Week 2 - Programming Assignment: Creating a custom loss function (0) | 2021.03.25 |
[Tensorflow 2][Keras] Week 2 - Contrastive Loss (0) | 2021.03.21 |
댓글