● 케라스

  • 파이썬으로 작성된 고수준 신경망 API로 TensorFlow, CNTK, Theano와 함께 사용 가능
  • 사용자 친화성, 모듈성, 확장성을 통해 빠르고 간편한 프로토타이핑 가능
  • 컨볼루션 신경망, 순환 신경망, 둘의 조합까지 모두 지원
  • CPU와 GPU에서 매끄럽게 실행
import numpy as np
import tensorflow as tf

 

  - 레이어들을 import하는 방식(1)

  • 일일히 import 하지 않아도 됨
  • 코드가 다소 길어질 수 있음
# keras까지만 import 하여 이후 필요한 것은 keras.**으로 사용
from tensorflow import keras

keras.__version__

# 출력 결과
'2.11.0'
keras.layers.Dense(10, activation = 'sigmoid')

# 출력 결과
<keras.layers.core.dense.Dense at 0x1eaa357ecd0>
keras.Model()

# 출력 결과
<keras.engine.training.Model at 0x1eabdafa0d0>
keras.models.Sequential()

# 출력 결과
<keras.engine.sequential.Sequential at 0x1eabda0feb0>

 

  - 레이어들을 import하는 방식(2)

  • 일일히 import 해야함
  • 코드가 간결
# keras.layers, keras.models 등으로 사용할 레이어들을 한번에 import
from tensorflow.keras.layers import Dense, Input, Flatten, Activation
from tensorflow.keras.models import Sequential
from tensorflow.keras import Model
Dense(10, activation = 'relu')

# 출력 결과
<keras.layers.core.dense.Dense at 0x1eaa3455730>
Flatten(input_shape = [28, 28])

# 출력 결과
<keras.layers.reshaping.flatten.Flatten at 0x1eabdafae80>
X_train = np.random.randn(5500, 2)

Input(shape = X_train.shape[1:])

# 출력 결과
<KerasTensor: shape=(None, 2) dtype=float32 (created by layer 'input_1')>

 

 

1. 주요 레이어

  - Dense

  • Fully-Connected Layer
  • 노드수(유닛 수), 활성화 함수 등을 지정
  • name을 통한 레이어 간 구분 가능
  • 기본적으로 'Glorot uniform' 가중치(Xavier 분포 초기화), zeros bias로 초기화
    • kernel_initializer 인자를 통해 다른 가중치 초기화를 진행할 수 있음
dense = Dense(10, activation = 'relu', name = 'Dense Layer')
dense

# 출력 결과
<keras.layers.core.dense.Dense at 0x1eabdb1e760>
dense2 = Dense(15, activation = 'softmax')
dense2

# 출력 결과
<keras.layers.core.dense.Dense at 0x1eabdbd4a60>
  • 단 한줄로 레이어 선언이 끝남, keras의 장점

 

  - Activation

  • Dense layer에서 미리 활성화 함수를 지정할 수도 있지만 때에 따라서 따로 레이어를 만들어줄 수 있음
dense = Dense(10, kernel_initializer = 'he_normal', name = 'Dense Layer')
dense = Activation(dense)
dense

# 출력 결과
<keras.layers.core.activation.Activation at 0x1eabdb1e7c0>

 

  - Flatten

  • 배치 크기(또는 데이터 크기)를 제외하고 데이터를 1차원으로 쭉 펼치는 작업
  • 예시
(128, 3, 2, 2) -> (128, 12)
Flatten(input_shape = (28, 28))

# 출력 결과
<keras.layers.reshaping.flatten.Flatten at 0x1eabda5ddc0>

 

  - input

  • 모델의 입력을 정의
  • shape, dtype을 포함
  • 하나의 모델은 여러 개의 입력을 가질 수 있음
  • summary() 메소드를 통해서는 보이지 않음
input_1 = Input(shape = (28, 28), dtype = tf.float32)
input_2 = Input(shape = (8,), dtype = tf.int32)

input_1

# 출력 결과
<KerasTensor: shape=(None, 28, 28) dtype=float32 (created by layer 'input_2')>


input_2

# 출력 결과
<KerasTensor: shape=(None, 8) dtype=int32 (created by layer 'input_3')>

 

 

2. 모델 구성 방법

  • Sequential()
  • 서브클래싱(Subclassing)
  • 함수형 API

 

  - Sequential()

  • 모델이 순차적으로 진행할 때 사용
  • 간단한 방법
    • Sequential 객체 생성 후, add를 통한 방법
    • Sequential 인자에 한번에 추가
  • 다중 입력 및 출력이 존재하는 등의 복잡한 모델을 구성할 수 없음
from tensorflow.keras.layers import Dense, Input, Flatten
from tensorflow.keras.models import Sequential, Model
from tensorflow.keras.utils import plot_model

model = Sequential()
# Input 레이어 - Dense 레이어(relu 활성화 함수) - Dense 레이어(relu 활성화 함수) - Dense 레이어(softmax 활성화 함수) 연결
model.add(Input(shape = (28, 28)))
model.add(Dense(300, activation = 'relu'))
model.add(Dense(100, activation = 'relu'))
model.add(Dense(10, activation = 'softmax'))
  • 모델 구조 확인(model 객체의 summary() 이용)
model.summary()

# 출력 결과
# Input 레이어는 나타나지 않으므로 추가한 Dense 레이어만 표시됨
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 dense_5 (Dense)             (None, 28, 300)           8700      
                                                                 
 dense_6 (Dense)             (None, 28, 100)           30100     
                                                                 
 dense_7 (Dense)             (None, 28, 10)            1010      
                                                                 
=================================================================
Total params: 39,810
Trainable params: 39,810
Non-trainable params: 0
_________________________________________________________________
plot_model(model)

# model의 레이어 한번에 정의하기
model = Sequential([Input(shape = (28, 28), name = 'Input'),
                    Dense(300, activation = 'relu', name = 'Dense1'),
                    Dense(100, activation = 'relu', name = 'Dense2'),
                    Dense(10, activation = 'softmax', name = 'Output')])
model.summary()

# 출력 결과
Model: "sequential_2"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 Dense1 (Dense)              (None, 28, 300)           8700      
                                                                 
 Dense2 (Dense)              (None, 28, 100)           30100     
                                                                 
 Output (Dense)              (None, 28, 10)            1010      
                                                                 
=================================================================
Total params: 39,810
Trainable params: 39,810
Non-trainable params: 0
_________________________________________________________________
plot_model(model)

 

  - 함수형 API

  • 가장 권장되는 방법
  • 모델을 복잡하고 유연하게 구성 가능
  • 다중 입출력을 다룰 수 있음
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Flatten, Dense
from tensorflow.keras.utils import plot_model

inputs = Input(shape = (28, 28, 1))

x = Flatten(input_shape = (28, 28, 1))(inputs)
x = Dense(300, activation = 'relu')(x)
x = Dense(100, activation = 'relu')(x)
x = Dense(10, activation = 'softmax')(x)

model = Model(inputs = inputs, outputs = x)
model.summary()

# 출력 결과
Model: "model_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_6 (InputLayer)        [(None, 28, 28, 1)]       0         
                                                                 
 flatten_3 (Flatten)         (None, 784)               0         
                                                                 
 dense_6 (Dense)             (None, 300)               235500    
                                                                 
 dense_7 (Dense)             (None, 100)               30100     
                                                                 
 dense_8 (Dense)             (None, 10)                1010      
                                                                 
=================================================================
Total params: 266,610
Trainable params: 266,610
Non-trainable params: 0
_________________________________________________________________
plot_model(model)

from tensorflow.keras.layers import Concatenate

# wide & deep 모델
# 입력 하나를 wide 모델과 deep 모델에 분산시켜야함
# 다중 입력 필요
input_layer = Input(shape = (28, 28))
hidden1 = Dense(100, activation = 'relu')(input_layer)
hidden2 = Dense(30, activation = 'relu')(hidden1)
concat = Concatenate()([input_layer, hidden2])
output = Dense(1)(concat)

model = Model(inputs = [input_layer], outputs = [output])
model.summary()

# 출력 결과
Model: "model_2"
__________________________________________________________________________________________________
 Layer (type)                   Output Shape         Param #     Connected to                     
==================================================================================================
 input_8 (InputLayer)           [(None, 28, 28)]     0           []                               
                                                                                                  
 dense_12 (Dense)               (None, 28, 100)      2900        ['input_8[0][0]']                
                                                                                                  
 dense_13 (Dense)               (None, 28, 30)       3030        ['dense_12[0][0]']               
                                                                                                  
 concatenate_1 (Concatenate)    (None, 28, 58)       0           ['input_8[0][0]',                
                                                                  'dense_13[0][0]']               
                                                                                                  
 dense_14 (Dense)               (None, 28, 1)        59          ['concatenate_1[0][0]']          
                                                                                                  
==================================================================================================
Total params: 5,989
Trainable params: 5,989
Non-trainable params: 0
__________________________________________________________________________________________________
plot_model(model)

# 다중 입력
input_1 = Input(shape = (10, 10), name = 'input_1')
input_2 = Input(shape = (10, 28), name = 'input_2')

hidden1 = Dense(100, activation = 'relu')(input_2)
hidden2 = Dense(10, activation = 'relu')(hidden1)
concat = Concatenate()([input_1, hidden2])
output = Dense(1, activation = 'sigmoid', name= 'output')(concat)

model = Model(inputs = [input_1, input_2], outputs = [output])
model.summary()

# 출력 결과
Model: "model_3"
__________________________________________________________________________________________________
 Layer (type)                   Output Shape         Param #     Connected to                     
==================================================================================================
 input_2 (InputLayer)           [(None, 10, 28)]     0           []                               
                                                                                                  
 dense_17 (Dense)               (None, 10, 100)      2900        ['input_2[0][0]']                
                                                                                                  
 input_1 (InputLayer)           [(None, 10, 10)]     0           []                               
                                                                                                  
 dense_18 (Dense)               (None, 10, 10)       1010        ['dense_17[0][0]']               
                                                                                                  
 concatenate_3 (Concatenate)    (None, 10, 20)       0           ['input_1[0][0]',                
                                                                  'dense_18[0][0]']               
                                                                                                  
 output (Dense)                 (None, 10, 1)        21          ['concatenate_3[0][0]']          
                                                                                                  
==================================================================================================
Total params: 3,931
Trainable params: 3,931
Non-trainable params: 0
__________________________________________________________________________________________________
plot_model(model)

# 다중 출력
input_ = Input(shape = (10, 10), name = 'input_')

hidden1 = Dense(100, activation = 'relu')(input_)
hidden2 = Dense(10, activation = 'relu')(hidden1)

output = Dense(1, activation = 'sigmoid', name = 'main_output')(hidden2)
sub_out = Dense(1, name = 'sum_output')(hidden2)

model = Model(inputs = [input_], outputs = [output, sub_out])
model.summary()

# 출력 결과
Model: "model_4"
__________________________________________________________________________________________________
 Layer (type)                   Output Shape         Param #     Connected to                     
==================================================================================================
 input_ (InputLayer)            [(None, 10, 10)]     0           []                               
                                                                                                  
 dense_20 (Dense)               (None, 10, 100)      1100        ['input_[0][0]']                 
                                                                                                  
 dense_21 (Dense)               (None, 10, 10)       1010        ['dense_20[0][0]']               
                                                                                                  
 main_output (Dense)            (None, 10, 1)        11          ['dense_21[0][0]']               
                                                                                                  
 sum_output (Dense)             (None, 10, 1)        11          ['dense_21[0][0]']               
                                                                                                  
==================================================================================================
Total params: 2,132
Trainable params: 2,132
Non-trainable params: 0
__________________________________________________________________________________________________
plot_model(model)

# 다중 입력, 다중 출력
input_1 = Input(shape = (10, 10), name = 'input_1')
input_2 = Input(shape = (10, 28), name = 'input_2')

hidden1 = Dense(100, activation = 'relu')(input_2)
hidden2 = Dense(10, activation = 'relu')(hidden1)
concat = Concatenate()([input_1, hidden2])
output = Dense(1, activation = 'sigmoid', name = 'main_output')(concat)
sub_out = Dense(1, name = 'sum_output')(hidden2)

model = Model(inputs = [input_1, input_2], outputs = [output, sub_out])
model.summary()

# 출력 결과
Model: "model_5"
__________________________________________________________________________________________________
 Layer (type)                   Output Shape         Param #     Connected to                     
==================================================================================================
 input_2 (InputLayer)           [(None, 10, 28)]     0           []                               
                                                                                                  
 dense_26 (Dense)               (None, 10, 100)      2900        ['input_2[0][0]']                
                                                                                                  
 input_1 (InputLayer)           [(None, 10, 10)]     0           []                               
                                                                                                  
 dense_27 (Dense)               (None, 10, 10)       1010        ['dense_26[0][0]']               
                                                                                                  
 concatenate_6 (Concatenate)    (None, 10, 20)       0           ['input_1[0][0]',                
                                                                  'dense_27[0][0]']               
                                                                                                  
 main_output (Dense)            (None, 10, 1)        21          ['concatenate_6[0][0]']          
                                                                                                  
 sum_output (Dense)             (None, 10, 1)        11          ['dense_27[0][0]']               
                                                                                                  
==================================================================================================
Total params: 3,942
Trainable params: 3,942
Non-trainable params: 0
__________________________________________________________________________________________________
plot_model(model)

 

  - 서브클래싱(Subclassing)

  • 커스터마이징에 최적화된 방법
  • Model 클래스를 상속받아 Model이 포함하는 기능을 사용할 수 있음
    • fit(), evaluate(), predict()
    • save(), load()
  • 주로 call() 메소드 안에서 원하는 계산 가능
    • for, if, 저수준 연산 등
  • 권장되는 방법은 아니지만 어떤 모델의 구현 코드를 참고할 때 해석할 수 있어야 함
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Flatten, Dense
from tensorflow.keras.utils import plot_model

class MyModel(Model):
    def __init__(self, units = 30, activation = 'relu', **kwargs):
        super(MyModel, self).__init__(**kwargs)

        self.dense_layer1 = Dense(300, activation = activation)
        self.dense_layer2 = Dense(100, activation = activation)
        self.dense_layer3 = Dense(units, activation = activation)

        self.output_layer = Dense(10, activation = 'softmax')
    
    def call(self, inputs):
        x = self.dense_layer1(inputs)
        x = self.dense_layer2(x)
        x = self.dense_layer3(x)
        x = self.output_layer(x)
        return x

 

 

3. 모델 가중치 확인

from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Flatten, Dense
from tensorflow.keras.utils import plot_model

inputs = Input(shape = (28, 28, 1))

x = Flatten(input_shape = (28, 28, 1))(inputs)
x = Dense(300, activation = 'relu')(x)
x = Dense(100, activation = 'relu')(x)
x = Dense(10, activation = 'softmax')(x)

model = Model(inputs = inputs, outputs = x)
model.summary()

# 출력 결과
Model: "model_7"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_9 (InputLayer)        [(None, 28, 28, 1)]       0         
                                                                 
 flatten_4 (Flatten)         (None, 784)               0         
                                                                 
 dense_28 (Dense)            (None, 300)               235500    
                                                                 
 dense_29 (Dense)            (None, 100)               30100     
                                                                 
 dense_30 (Dense)            (None, 10)                1010      
                                                                 
=================================================================
Total params: 266,610
Trainable params: 266,610
Non-trainable params: 0
_________________________________________________________________
  • 모델의 레이어들이 리스트로 표현됨
model.layers

# 출력 결과
[<keras.engine.input_layer.InputLayer at 0x1b51b66a0a0>,
 <keras.layers.reshaping.flatten.Flatten at 0x1b51d577c10>,
 <keras.layers.core.dense.Dense at 0x1b51d54a250>,
 <keras.layers.core.dense.Dense at 0x1b51d54a970>,
 <keras.layers.core.dense.Dense at 0x1b51d5997c0>]


# 위의 레이어 충 2번 인덱스의 레이어의 이름 출력
hidden_2 = model.layers[2]
hidden_2.name

# 출력 결과
'dense_28'
  • 위의 layer name 참고
# hidden_2(두번째 레이어)의 이름이 dense_28인지 확인
model.get_layer('dense_28') is hidden_2

# 출력 결과
True
# hidden_2에서 계산된 가중치(weights)와 편향(biases) 출력
weights, biases = hidden_2.get_weights()
weights

# 출력 결과
array([[-0.04896989,  0.00405482,  0.02683295, ..., -0.07056625,
        -0.04177827,  0.00787882],
       [-0.05326419, -0.0303001 ,  0.00274137, ..., -0.02837748,
         0.05391636, -0.04700017],
       [-0.05597277,  0.03437241, -0.00236335, ...,  0.04641164,
         0.04785167, -0.02015593],
       ...,
       [ 0.04056622, -0.05879534,  0.01665498, ...,  0.02095272,
         0.05407439, -0.069397  ],
       [-0.02786053, -0.02436828, -0.03833799, ...,  0.06946112,
        -0.02327226,  0.04145432],
       [ 0.00797608, -0.07426289,  0.04644973, ...,  0.02902658,
        -0.04708448, -0.02754754]], dtype=float32)


biases

# 출력 결과
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
       0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)


print(weights.shape)
print(biases.shape)

# 출력 결과
# hidden_2 레이어의 units를 300으로 지정했으므로 가중치와 편향도 각각 300개
(784, 300)
(300,)

 

 

4. 모델 컴파일(compile)

  • 모델을 구성한 후, 사용할 손실함수(loss), 옵티마이저(optimizer)를 지정
model.compile(loss = 'sparse_categorical_crossentropy',
              optimizer = 'sgd',
              metrics = ['accuracy'])

 

  - 참고1

  - loss

  • keras.losses.square_categorical_crossentropy등과 같이 지정 가능
    • sparse_categorical_crossentropy클래스가 배타적
      즉, MNIST 예제에서 (0, 1, 2, ..., 9)와 같은 방식으로 구분되어 있을 때 사용
    • categorical_crossentropy클래스가 원-핫 인코딩 방식으로 되어있을 때 사용
    • binary_crossentropy 이진 분류를 수행할 때 사용

  - optimizer

  • kera.optimizer.SGD() 등과 같이 사용
    • 보통 옵티마이저의 튜닝을 위해 따로 객체를 생성하여 컴파일
optimizer = keras.optimizer.SGD(learning_rate = 1e-5)
model.compile(...,
                      optimizer = optimizer,
                      ...)
  • keras.optimizer.Adam()도 많이 사용

  - metrics

  • 모니터링할 지표
  • 주로 'accuracy', 'acc'로도 가능

 

  - 참고2-컴파일 설정 예시

  • 평균 제곱 오차 회귀 문제
model.compile(loss = 'mse',
                      optimizer = RMSpop(),
                      metrics = ['mae'])
  • 이진 분류
model.compile(loss = 'binary_crossentropy',
                      optimizer = RMSpop(),
                      metrics = ['accuracy'])
  • 다항 분류
model.compile(loss = 'categorical_crossentropy',
                      optimizer = RMSpop(),
                      metrics = ['accuarcy'])

 

 

5. 모델 훈련, 평가 및 예측

  • fit() 함수
    • train_data(학습 데이터), train_label(데이터의 정답)
    • epochs
    • batch_size
    • validation_data
  • evaluate() 함수
    • 테스트 데이터
  • predict() 임의의 데이터를 인자로 넣어 예측 가능

+ Recent posts