이번 튜토리얼에서는 tf.keras.Layer
클래스 상속을 통해 모델을 구성하는 레이어를 직접 설정해보는 방법과 기존 정의되어 있는 레이어를 조합하여 모델을 구성하는 방법을 알아볼 것입니다.
#필요한 모듈 임포트하기
import warnings
warnings.filterwarnings(action='ignore')
import tensorflow as tf
머신러닝을 위한 코드를 작성하는 경우, 대부분 개별적인 연산과 변수를 조작하는 것보다는 주로 높은 수준의 추상화 도구를 사용합니다.
많은 머신러닝 모델은 비교적 단순한 레이어(layer)를 조합하고 쌓아서 표현할 수 있습니다. 텐서플로우는 여러 표준형 레이어을 제공하기때문에 처음부터 사용자 고유의 응용 프로그램에 특화된 레이어를 작성하거나 혹은 기존 레이어들을 이용하여 단순 조합만을 통해 쉽게 모델을 만들 수 있습니다.
텐서플로우는 케라스(Keras)의 모든 API를 tf.keras
패키지에 포함하고 있습니다. 케라스 레이어는 모델을 구축하는데 매우 유용합니다.
tf.keras.layers
패키지에서 층은 객체입니다. 레이어를 구성하기 위해 먼저 다음과 같이 간단히 객체를 생성해보겠습니다.
대부분의 layer는 첫번째 인수로 출력 차원(크기) 또는 채널을 가집니다.
layer = tf.keras.layers.Dense(100)
입력 차원의 수(input_shape)는 레이어를 처음 실행할 때 유추할 수 있기 때문에 필요하지 않을 수 있습니다.
그러나 일부 복잡한 모델에서는 수동으로 입력 차원의 수를 제공하는것이 유용할 수 있습니다.
layer = tf.keras.layers.Dense(10, input_shape=(None, 5))
# 층을 사용하려면, 간단하게 호출합니다.
layer(tf.zeros([10, 5]))
layer는 유용한 메서드를 많이 가지고 있습니다. 예를 들어, layer.variables
를 사용하여 층안에 있는 모든 변수를 확인할 수 있으며,
layer.trainable_variables
를 사용하여 훈련 가능한 변수를 확인할 수 있습니다.
완전 연결(fully-connected)층은 가중치(weight) 와 편향(biases) 을 위한 변수(variable)를 가집니다.
layer.variables
또한 변수는 객체의 속성을 통해 편리하게 접근 가능합니다.
layer.kernel, layer.bias
사용자 정의 레이어를 구현하는 가장 좋은 방법은 tf.keras.Layer
클래스를 상속하고 다음과 같이 구현하는 것입니다.
__init__
: 층에 필요한 매개변수를 입력 받습니다.build
: 입력 텐서의 크기를 얻고 남은 초기화를 진행할 수 있습니다.call
: 정방향 연산(forward computation)을 진행 할 수 있습니다.변수를 생성하기 위해 build
가 호출되길 기다릴 필요는 없으며, 변수를 __init__
에 생성할 수도 있습니다. build
에 변수를 생성할때의 장점은 레이어가 입력 크기 를 기준으로 변수를 생성할 수 있다는 것입니다. 반면에, __init__
에 변수를 생성하는 것은 변수 생성에 필요한 크기가 명시적으로 지정되어야 함을 의미합니다.
class MyDenseLayer(tf.keras.layers.Layer):
def __init__(self, num_outputs):
super(MyDenseLayer, self).__init__()
self.num_outputs = num_outputs
def build(self, input_shape):
self.kernel = self.add_variable("kernel",
shape=[int(input_shape[-1]),
self.num_outputs])
def call(self, input):
return tf.matmul(input, self.kernel)
layer = MyDenseLayer(10)
print(layer(tf.zeros([10, 5])))
print()
print(layer.trainable_variables)
머신러닝 모델의 대부분은 기존의 레이어를 조합하여 구현됩니다. 예를 들어, 레즈넷(resnet)이라는 모델의 Identity Block은 합성곱(convolution), 배치 정규화(batch normalization), 쇼트컷(shortcut) 등으로 구성되어 있습니다.
다른 레이어를 포함한 모델을 만들기 위해 사용하는 메인 클래스는 tf.keras.Model
입니다.
다음은 tf.keras.Model
을 상속(inheritance)하여 구현한 코드입니다.
class ResnetIdentityBlock(tf.keras.Model):
def __init__(self, kernel_size, filters):
super(ResnetIdentityBlock, self).__init__(name='')
filters1, filters2, filters3 = filters
self.conv2a = tf.keras.layers.Conv2D(filters1, (1, 1))
self.bn2a = tf.keras.layers.BatchNormalization()
self.conv2b = tf.keras.layers.Conv2D(filters2, kernel_size, padding='same')
self.bn2b = tf.keras.layers.BatchNormalization()
self.conv2c = tf.keras.layers.Conv2D(filters3, (1, 1))
self.bn2c = tf.keras.layers.BatchNormalization()
def call(self, input_tensor, training=False):
x = self.conv2a(input_tensor)
x = self.bn2a(x, training=training)
x = tf.nn.relu(x)
x = self.conv2b(x)
x = self.bn2b(x, training=training)
x = tf.nn.relu(x)
x = self.conv2c(x)
x = self.bn2c(x, training=training)
x += input_tensor
return tf.nn.relu(x)
block = ResnetIdentityBlock(1, [1, 2, 3])
print(block(tf.zeros([1, 2, 3, 3])))
print()
print([x.name for x in block.trainable_variables])
그러나 대부분의 경우에, 많은 레이어로 구성된 모델은 단순하게 순서대로 레이어를 하나씩 호출합니다. 이는 tf.keras.Sequential
을 사용하여 다음과 같은 간단한 코드로 구현 가능합니다.
my_seq = tf.keras.Sequential([tf.keras.layers.Conv2D(1, (1, 1), input_shape=(None, None, 3)),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Conv2D(2, 1, padding='same'),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Conv2D(3, (1, 1)),
tf.keras.layers.BatchNormalization()])
my_seq(tf.zeros([1, 2, 3, 3]))
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.