현재 대학원 졸업을 위해 시각화 실험을 하고 있다.
나의 목적은 t-SNE를 사용한 학습된 모델의 시각화가 목적이었다.
따라서 분류 레이어 이전까지(gap 전까지)의 레이어만을 사용해 결과물을 확보하고자 하였다.
그러던 중 발견했던 에러와 해결방법을 공유하고자 한다.
진행사항 전부를 나열했으니 해결방법을 바로 보고 싶다면,
[03. 해결방법]부터 보면 된다.
나의 모델 구성이다.
졸업논문 내용이라 모델 코드를 공개할 수 없는 점 양해 부탁드린다.
(대부분의 내용을 삭제한 모델 코드이며, 포스팅에 지장은 없다.)
class Model(tf.keras.Model):
  def __init__(self, num_classes):
    super().__init__()
    
    self.conv = Sequential([
      
    ])
    
    self.module =     # tensorflow.keras.layers가 아닌 custom layer
    
    self.gap = GlobalAveragePooling1D()
    self.dropout = Dropout(0.2)
    self.classifier = Dense(num_classes, activation='softmax')
    
    
  def call(self, inputs):
    x = inputs
    
    x = self.conv(x)
    x = self.module(x)
    
    gap = self.gap(capsule)
    drop = self.dropout(gap)
    
    output_softmax = self.classifier(drop)
    return output_softmax다음과 같은 코드를 사용해 레이어 슬라이싱을 진행했다.
# 이미 학습된 모델을 불러온다.
origin = Model(len(CLASS_LABELS))
origin.build(input_shape=x_test.shape)
origin.load_weights(h5_path)
model = tf.keras.Model(inputs=origin.layers[0].input, outputs=origin.layers[-4].output)    # error그랬더니 마지막 줄에서 에러가 발생했다.
(나머지는 고정된 문자열이고, 'module'은 본인이 설정한 레이어의 변수 이름으로 값이 바뀐다.)
AttributeError: Layer module has no inbound nodes.
stackoverflow, tensorflow github issue page를 살펴보니,
tensorflow-2.x 버전에서 비슷한 문제를 겪은 사람들이 많이 있었다.
발견했던 몇 가지 해결 방법은 다음과 같다.
origin.layers[-4].output을 origin.get_output_at(-4)로 대체RuntimeError: The layer model has never been called and thus has no defined output.K.Model([origin.layers[0].input], [origin.layers[-4].output])RuntimeError: The layer model has never been called and thus has no defined output.상기 언급된 해결방법은 keras의 레이어라면 해결 가능하다고 한다.
from tensorflow.keras.layers
그러나 직접 구성한 custom layer라면 이 방법은 통하지 않았다.
내가 참고한 자료들은 다음과 같다.
1. Saving & loading only the model's weights values
2. How do I get the weights of a layer in Keras?
우선 다음 두 API를 살펴보자.
get_weights()로부터 반환된 numpy 배열에서 레이어의 가중치 설정다시 말해,
get_weights()로 가중치와 바이어스 값을 구해서,
set_weights()로 가중치와 바이어스 값을 덮어 씌우면 된다.
### 원본 모델
class Model(tf.keras.Model):
  def __init__(self, num_classes):
    super().__init__()
    
    self.conv = Sequential([
      
    ])
    
    self.module =     # tensorflow.keras.layers가 아닌 custom layer
    
    self.gap = GlobalAveragePooling1D()
    self.dropout = Dropout(0.2)
    self.classifier = Dense(num_classes, activation='softmax')
    
    
  def call(self, inputs):
    x = inputs
    
    x = self.conv(x)
    x = self.module(x)
    
    gap = self.gap(capsule)
    drop = self.dropout(gap)
    
    output_softmax = self.classifier(drop)
    return output_softmax
   
## 슬라이싱을 위한 모델 구조 선언
## module 이후의 레이어가 전부 지워진 모습을 볼 수 있다.
class Model2(tf.keras.Model):
  def __init__(self, num_classes):
    super().__init__()
    
    self.conv = Sequential([
      
    ])
    
    self.module =     # tensorflow.keras.layers가 아닌 custom layer
    
    
  def call(self, inputs):
    x = inputs
    
    x = self.conv(x)
    x = self.module(x)
    
    return xload_weights()는 가중치만 저장되어 있다.fit()하거나 predict()를 하려면 위와 같이 모델 구조를 똑같이 구성해야 한다.model.build(input_shape)를 반드시 해줘야 함.origin = Model(len(CLASS_LABELS))
origin.build(input_shape=data.shape)
origin.load_weights(h5_path)get_weights() 사용layer[0].get_weights()와 같이 코드를 작성하면 0번째 위치에 있는 레이어의 가중치를 얻을 수 있다.def get_layers_weights(origin_model, until):
    """get weights of model
    Args:
        origin_model (keras.Model): Original model (+weights)
        until (int): Index of wanted final layer
    Returns:
        list: weights for each layer
    """
    
    ret = []
    
    copy_layers = origin_model.layers[:until]
    for cur_layer in copy_layers:
        ret.append(cur_layer.get_weights())
    
    return ret
    
origin_layers_weights = get_layers_weights(origin, until=-3)test_model = Model2(len(CLASS_LABELS))
test_model.build(input_shape=data.shape)test_model_layers = test_model.layers
for i, cur_test_layer in enumerate(test_model_layers):
    cur_test_layer.set_weights(origin_layers_weights[i])predictions = test_model(x_test, training=False)
print(predictions)
모델의 뼈대는 vscode에서 Tensorflow 2.0 Snippets extention을 설치하면 매우 간단히 만들 수 있다.
## tf:ctrl:model   이걸 입력하면 윈도우 박스에 model block이 보일 것이다.
## enter 키를 입력하면 아래와 같은 구조가 만들어진다.
class MyModel(tf.keras.Model):
  def __init__(self):
    super(MyModel, self).__init__()
    self.dense1 = tf.keras.layers.[Dense Like Layer]
  def call(self, inputs):
    x = self.dense1(inputs)
    return x