딥러닝 모델을 작성하는 방법
1. Sequential
2. Functional
3. Model Subclassing
model = keras.Sequential()
이라고 선언해준 후 차곡차곡 레이어를 쌓아가는 형태이다.
import tensorflow as tf
from tensorflow import keras
model = keras.Sequential()
model.add(__넣고싶은 레이어__)
model.add(__넣고싶은 레이어__)
model.add(__넣고싶은 레이어__)
model.fit(x, y, epochs=10, batch_size=32)
keras.Model
을 사용하여 더 자유로운 모델을 만들 수 있다.
import tensorflow as tf
from tensorflow import keras
inputs = keras.Input(shape=(__원하는 입력값 모양__))
x = keras.layers.__넣고싶은 레이어__(관련 파라미터)(input)
x = keras.layers.__넣고싶은 레이어__(관련 파라미터)(x)
outputs = keras.layers.__넣고싶은 레이어__(관련 파라미터)(x)
model = keras.Model(inputs=inputs, outputs=outputs)
model.fit(x,y, epochs=10, batch_size=32)
Subclassing
은 이 세가지 방법 중 가장 자유롭게 모델링할 수 있는 방식이다.
keras.Model
을 상속받은 모델 클래스를 만든다.init
메소드 안에서 레이어 구성을 정의한다.call
메소드 안에서 레이어간 forward propagation을 구현한다.import tensorflow as tf
from tensorflow import keras
class CustomModel(keras.Model):
def __init__(self):
super(CustomModel, self).__init__()
self.__정의하고자 하는 레이어__()
self.__정의하고자 하는 레이어__()
self.__정의하고자 하는 레이어__()
def call(self, x):
x = self.__정의하고자 하는 레이어__(x)
x = self.__정의하고자 하는 레이어__(x)
x = self.__정의하고자 하는 레이어__(x)
return x
model = CustomModel()
model.fit(x,y, epochs=10, batch_size=32)
import tensorflow as tf
from tensorflow import keras
import numpy as np
mnist = keras.datasets.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train/255.0, x_test/255.0
x_train = x_train[..., np.newaxis]
x_test = x_test[..., np.newaxis]
print(len(x_train), len(x_test)) # 60000 10000
Spec:
1. 32개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
2. 64개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
3. Flatten 레이어
4. 128개의 아웃풋 노드를 가지고, activation function이 relu인 Fully-Connected Layer(Dense)
5. 데이터셋의 클래스 개수에 맞는 아웃풋 노드를 가지고, activation function이 softmax인 Fully-Connected Layer(Dense)
model = keras.Sequential()
model.add(tf.keras.layers.Conv2D(32, 3, activation='relu'))
model.add(tf.keras.layers.Conv2D(64, 3, activation='relu'))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(128, activation='relu'))
model.add(tf.keras.layers.Dense(10, activation='softmax'))
# 모델학습
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test, verbose=2)
Spec:
0. (28X28X1) 차원으로 정의된 Input
1. 32개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
2. 64개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
3. Flatten 레이어
4. 128개의 아웃풋 노드를 가지고, activation function이 relu인 Fully-Connected Layer(Dense)
5. 데이터셋의 클래스 개수에 맞는 아웃풋 노드를 가지고, activation function이 softmax인 Fully-Connected Layer(Dense)
inputs = keras.Input(shape=(28, 28, 1))
x = keras.layers.Conv2D(32, 3, activation='relu')(inputs)
x = keras.layers.Conv2D(64, 3, activation='relu')(x)
x = keras.layers.Flatten()(x)
x = keras.layers.Dense(128, activation='relu')(x)
outputs = keras.layers.Dense(10, activation='softmax')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
# 모델 학습
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test, verbose=2)
Spec:
0. keras.Model 을 상속받았으며, __init__()
와 call()
메소드를 가진 모델 클래스
1. 32개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
2. 64개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
3. Flatten 레이어
4. 128개의 아웃풋 노드를 가지고, activation function이 relu인 Fully-Connected Layer(Dense)
5. 데이터셋의 클래스 개수에 맞는 아웃풋 노드를 가지고, activation function이 softmax인 Fully-Connected Layer(Dense)
6. call의 입력값이 모델의 Input, call의 리턴값이 모델의 Output
class CustomModel(keras.Model):
def __init__(self):
super().__init__()
self.conv1 = keras.layers.Conv2D(32, 3, activation='relu')
self.conv2 = keras.layers.Conv2D(64, 3, activation='relu')
self.flatten = keras.layers.Flatten()
self.dense1 = keras.layers.Dense(128, activation='relu')
self.dense2 = keras.layers.Dense(10, activation='softmax')
def call(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = self.flatten(x)
x = self.dense1(x)
x = self.dense2(x)
return x
model = CustomModel()
# 모델 학습 설정
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test, verbose=2)
import tensorflow as tf
from tensorflow import keras
cifar100 = keras.datasets.cifar100
(x_train, y_train), (x_test, y_test) = cifar100.load_data()
x_train, x_test = x_train/255.0, x_test/255.0
print(len(x_train), len(x_test)) # 50000 10000
Spec:
1. 16개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
2. pool_size가 2인 MaxPool 레이어
3. 32개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
4. pool_size가 2인 MaxPool 레이어
5. 256개의 아웃풋 노드를 가지고, activation function이 relu인 Fully-Connected Layer(Dense)
6. 데이터셋의 클래스 개수에 맞는 아웃풋 노드를 가지고, activation function이 softmax인 Fully-Connected Layer(Dense)
model = keras.Sequential([
keras.layers.Conv2D(16, 3, activation='relu'),
keras.layers.MaxPool2D((2,2)),
keras.layers.Conv2D(32, 3, activation='relu'),
keras.layers.MaxPool2D((2,2)),
keras.layers.Flatten(),
keras.layers.Dense(256, activation='relu'),
keras.layers.Dense(100, activation='softmax')
])
# 모델 학습
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test, verbose=2)
Spec:
0. (32X32X3) 차원으로 정의된 Input
1. 16개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
2. pool_size가 2인 MaxPool 레이어
3. 32개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
4. pool_size가 2인 MaxPool 레이어
5. 256개의 아웃풋 노드를 가지고, activation function이 relu인 Fully-Connected Layer(Dense)
6. 데이터셋의 클래스 개수에 맞는 아웃풋 노드를 가지고, activation function이 softmax인 Fully-Connected Layer(Dense)
inputs = keras.Input(shape=(32, 32, 3))
x = keras.layers.Conv2D(16, 3, activation='relu')(inputs)
x = keras.layers.MaxPool2D((2, 2))(x)
x = keras.layers.Conv2D(32, 3, activation='relu')(x)
x = keras.layers.MaxPool2D((2, 2))(x)
x = keras.layers.Flatten()(x)
x = keras.layers.Dense(256, activation='relu')(x)
outputs = keras.layers.Dense(100, activation='softmax')(x)
model = keras.Model(inputs=inputs, outputs=outputs)
# 모델 학습
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test, verbose=2)
Spec:
0. keras.Model 을 상속받았으며, init()와 call() 메소드를 가진 모델 클래스
1. 16개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
2. pool_size가 2인 MaxPool 레이어
3. 32개의 채널을 가지고, 커널의 크기가 3, activation function이 relu인 Conv2D 레이어
4. pool_size가 2인 MaxPool 레이어
5. 256개의 아웃풋 노드를 가지고, activation function이 relu인 Fully-Connected Layer(Dense)
6. 데이터셋의 클래스 개수에 맞는 아웃풋 노드를 가지고, activation function이 softmax인 Fully-Connected Layer(Dense)
7. call의 입력값이 모델의 Input, call의 리턴값이 모델의 Output
class CustomModel(keras.Model):
def __init__(self):
super().__init__()
self.conv1 = keras.layers.Conv2D(16, 3, activation='relu')
self.maxpool1 = keras.layers.MaxPool2D((2,2))
self.conv2 = keras.layers.Conv2D(32, 3, activation='relu')
self.maxpool2 = keras.layers.MaxPool2D((2,2))
self.flatten = keras.layers.Flatten()
self.fc1 = keras.layers.Dense(256, activation='relu')
self.fc2 = keras.layers.Dense(100, activation='softmax')
def call(self, x):
x = self.conv1(x)
x = self.maxpool1(x)
x = self.conv2(x)
x = self.maxpool2(x)
x = self.flatten(x)
x = self.fc1(x)
x = self.fc2(x)
return x
model = CustomModel()
model.fit()
의 실제 수행 과정은
tf.GradientTape
는 순전파로 진행된 모든 연산의 중간 레이어값을 tape에 기록하고, 이를 이용해 gradient를 계산한 후 tape를 폐기한다.
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
↓↓↓ 위 스텝을 아래와 같이 바꿀 수 있다.
loss_func = tf.keras.losses.SparseCategoricalCrossentropy()
optimizer = tf.keras.optimizers.Adam()
def train_step(features, labels):
with tf.GradientTape() as tape:
predictions = model(features)
loss = loss_func(labels, predictions)
gradients = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(gradients, model.trainable_variables))
return loss
model.fit(x_train, y_train, epochs=5, batch_size=32)
↓↓↓ 위 스텝을 아래와 같이 바꿀 수 있다.
import time
def train_model(batch_size=32)
start = time.time()
for epoch in range(5):
x_batch = []
y_batch = []
for step, (x, y) in enumerate(zip(x_train, y_train)):
if step % batch_size == batch_size - 1:
x_batch.append(x)
y_batch.append(y)
loss = train_step(np.array(x_batch, dtype=np.float32), np.array(y_batch, dtype=np.float32))
x_batch = []
y_batch = []
print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))
print("It took {} seconds".format(time.time() - start))
train_model()
그럼 이렇게 바꿔서 무엇이 좋을까?
tf.GradientTape()
를 활용하면 model.compile()
과 model.fit()
안에 감추어져 있던 한 스텝의 학습 단계(위 예제에서는 train_step 메소드)를 끄집어내서 자유롭게 재구성할 수 있게 된다.tf.GradientTape()
를 사용할 줄 알아야한다.