Abstract

In this paper we describe a new mobile architecture, MobileNetV2, that improves the state of the art perfor- mance of mobile models on multiple tasks and bench- marks as well as across a spectrum of different model sizes. We also describe efficient ways of applying these mobile models to object detection in a novel framework we call SSDLite. Additionally, we demonstrate how to build mobile semantic segmentation models through a reduced form of DeepLabv3 which we call Mobile DeepLabv3.

is based on an inverted residual structure where the shortcut connections are between the thin bottle- neck layers. The intermediate expansion layer uses lightweight depthwise convolutions to filter features as a source of non-linearity. Additionally, we find that it is important to remove non-linearities in the narrow layers in order to maintain representational power. We demon- strate that this improves performance and provide an in- tuition that led to this design.

Finally, our approach allows decoupling of the in- put/output domains from the expressiveness of the trans- formation, which provides a convenient framework for further analysis. We measure our performance on ImageNet [1] classification, COCO object detection [2], VOC image segmentation [3]. We evaluate the trade-offs between accuracy, and number of operations measured by multiply-adds (MAdd), as well as actual latency, and the number of parameters.


본 논문에서는 다양한 모델 크기의 스펙트럼에서뿐만 아니라 여러 작업과 벤치마크에서 SOTA를 달성한 MobileNetV2를 소개한다.

우리는 또한 SSDLite라 부르는 새로운 프레임워크에서 이러한 모바일 모델을 객체 인식에 적용할 수 있는 효과적인 방법을 설명한다.

더하여서, 우리는 Mobile DeepLabv3이라고 부르는 축소된 DeepLabv3를 통해 어떻게 모바일 semantic segmentation을 빌드하는지 설명한다.

DeepLabv3는 shortcut connection이 병목 레이어 사이에 있는 inverted 잔차 연결 구조를 기반으로 한다.

중간 팽창 레이어는 lightweight depthwise convolutoin을 사용하여 비선형성으로서 feature들을 필터링한다.

또한, 우리는 표현력을 유지하기 위해서는 좁은 층에서 비선형성을 제거하는 것이 중요하다는 것을 알게 된다.

우리는 이것이 성능을 향상시키고 이러한 디자인을 이끌어낸 직관력을 제공한다는 것을 증명한다.

마지막으로, 우리의 방법은 추가 분석을 위한 편리한 프레임워크를 제공하는 변환의 표현성으로부터 input/output 도메인의 분리를 가능케 한다.

우리는 Imagenet 분류, COCO 객체인식, VOC 이미지 segmentation에서 실험하였다. 

우리는 정확도와 multiply-adds(MAdd)를 이용하여 측정한 연산의 수 뿐만 아니라 실제 지연시간과 파라미터수 간의 트레이드 오프를 평가했다. 

 

 

Reference

Sandler, M., Howard, A., Zhu, M., Zhmoginov, A., & Chen, L. C. (2018). Mobilenetv2: Inverted residuals and linear bottlenecks. In Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition (pp. 4510-4520).

이글은 다음 문서를 참조합니다.

www.tensorflow.org/guide/keras/functional

(번역은 자력 + 파파고 + 구글 번역기를 사용하였으니, 부자연스럽더라도 양해바랍니다.)

2019/03/29 - [ML/tensorflow2.0(keras)] - tensorflow 2.0 keras Functional API (1)


Extending the API by writing custom layers

tf.keras에는 수많은 layer들이 담겨있습니다.

  • Convolutional layers : Conv1D, Conv2D, Conv3D, Conv2DTranspose, etc.
  • Pooling layers : MaxPooling1D, MaxPooling2D, MaxPooling3D, AveragePooling1D, etc.
  • RNN layers : GRU, LSTM, ConvLSTM2D, etc.
  • BatchNormalization, Dropout, Embedding, etc.

만약 원하는 layer가 없을 경우 직접 정의하는 것도 가능합니다.

  • 모든 layer는 Layer 클래스의 하위호환입니다.
  • call method는 layer의 연산부분을 담당합니다. 
  • build method는 weights를 생성하는 부분입니다. (이는 관습적인 부분이며, __init__에서도 weight를 생성할 수 있습니다.)

Dense layer의 예를 보겠습니다.

class CustomDense(layers.Layer):

  def __init__(self, units=32):
    super(CustomDense, self).__init__()
    self.units = units

  def build(self, input_shape):
    self.w = self.add_weight(shape=(input_shape[-1], self.units),
                             initializer='random_normal',
                             trainable=True)
    self.b = self.add_weight(shape=(self.units,),
                             initializer='random_normal',
                             trainable=True)

  def call(self, inputs):
    return tf.matmul(inputs, self.w) + self.b
      
inputs = keras.Input((4,))
outputs = CustomDense(10)(inputs)

model = keras.Model(inputs, outputs)

또한, 직렬화기능을 사용하려면 get_config method를 정의해야한다고 합니다.

class CustomDense(layers.Layer):

  def __init__(self, units=32):
    super(CustomDense, self).__init__()
    self.units = units

  def build(self, input_shape):
    self.w = self.add_weight(shape=(input_shape[-1], self.units),
                             initializer='random_normal',
                             trainable=True)
    self.b = self.add_weight(shape=(self.units,),
                             initializer='random_normal',
                             trainable=True)

  def call(self, inputs):
    return tf.matmul(inputs, self.w) + self.b

  def get_config(self):
    return {'units': self.units}
    
    
inputs = keras.Input((4,))
outputs = CustomDense(10)(inputs)

model = keras.Model(inputs, outputs)
config = model.get_config()

new_model = keras.Model.from_config(
    config, custom_objects={'CustomDense': CustomDense})
    

코드와 본문내용으로 짐작해보면, CustomDense를 config를 얻어 from_config를 사용하면 재사용할 수 있다~ 뭐 이런 것 같습니다.

(또, 위 2개의 예제가 name parameter에서 에러가 뜹니다. 댓글좀 달아주세요. API에 보면 name of layers인데 이름 집어넣어도 에러가 뜹니다) -> 그래프 초기화가 안되서 그런것 같습니다, 그냥 input_shape[-1]을 4로 바꿔주시면 됩니다. 그리고 name = 'string' 아무거나 집어넣어주세요


When to use the Functional API

함수형 API를 써서 새 모델을 만들 것인지, Model의 하위클래스로서 만들것인지 어떻게 결정할까요?

일반적으로 함수형 API는 사용이 쉽고 안전하며, Model 클래스가 가지고 있지 않은 기능을 가지고 있습니다.

그러나 Model의 하위클래스로 작업을 할 경우 Tree-RNN과 같은 함수형 API로는 표현이 쉽지 않은 모델을 구축할 수 있습니다.

위의 말은 그냥 high-level과 low-level의 차이를 설명해놓은거네요. 당연하죠.


Here are the strengths of the Functional API:

함수형 API는 super(Myclass, self).__init__(...), def call(self, ...)과 같은 함수를 정의하지 않아도 됩니다.

단 몇줄이면 됩니다.

inputs = keras.Input(shape=(32,))
x = layers.Dense(64, activation='relu')(inputs)
outputs = layers.Dense(10)(x)
mlp = keras.Model(inputs, outputs)

subclass 버전과 비교해보세요

class MLP(keras.Model):
  
  def __init__(self, **kwargs):
    super(MLP, self).__init__(**kwargs)
    self.dense_1 = layers.Dense(64, activation='relu')
    self.dense_2 = layers.Dense(10)
    
  def call(self, inputs):
    x = self.dense_1(inputs)
    return self.dense_2(x)
 
# Instantiate the model.
mlp = MLP()
# Necessary to create the model's state.
# The model doesn't have a state until it's called at least once.
_ = mlp(tf.zeros((1, 32)))

여러분이 위 함수를 정의하는 동안 함수형 API는 여러분의 모델을 검증할 수 있습니다.

함수형 API는 plotting 및 검증이 가능합니다. - 모델을 그려볼 수도 있고, 아래와 같이 중간층도 출력하기 쉽습니다.

features_list = [layer.output for layer in vgg19.layers]
feat_extraction_model = keras.Model(inputs=vgg19.input, outputs=features_list)

Here are the weaknesses of the Functional API:

dynamic한 구조를 구축하기 어렵습니다(high-API의 단점), 전적으로 high-API의 단점을 가지고 있는거죠.


Mix-and-matching different API styles

중요한 것은, 기능 API 또는 모델 하위 분류 중 하나를 선택하는 것은 여러분을 한 범주의 모델로 제한하는 이항 결정이 아니라는 점이다. tf.keras API의 모든 모델은 시퀀셜 모델, 기능 모델 또는 처음부터 작성된 하위 분류 모델/레이어 등 각 모델과 상호 작용할 수 있다.

units = 32
timesteps = 10
input_dim = 5

# Define a Functional model
inputs = keras.Input((None, units))
x = layers.GlobalAveragePooling1D()(inputs)
outputs = layers.Dense(1, activation='sigmoid')(x)
model = keras.Model(inputs, outputs)


class CustomRNN(layers.Layer):

  def __init__(self):
    super(CustomRNN, self).__init__()
    self.units = units
    self.projection_1 = layers.Dense(units=units, activation='tanh')
    self.projection_2 = layers.Dense(units=units, activation='tanh')
    # Our previously-defined Functional model
    self.classifier = model

  def call(self, inputs):
    outputs = []
    state = tf.zeros(shape=(inputs.shape[0], self.units))
    for t in range(inputs.shape[1]):
      x = inputs[:, t, :]
      h = self.projection_1(x)
      y = h + self.projection_2(state)
      state = y
      outputs.append(y)
    features = tf.stack(outputs, axis=1)
    print(features.shape)
    return self.classifier(features)

rnn_model = CustomRNN()
_ = rnn_model(tf.zeros((1, timesteps, input_dim)))

위와 같이 함수형 API와 subclass version을 섞어서도 구성할 수 있습니다.

반대로 subclass version을 구현하여 함수형 API의 input, layer or output으로 사용할 수 있습니다. 다만, 이 방식을 사용할려면 다음과 같이 call method를 구현해야 합니다.

  • call(self, inputs, **kwargs) where inputs is a tensor or a nested structure of tensors (e.g. a list of tensors), and where **kwargs are non-tensor arguments (non-inputs).
  • call(self, inputs, training=None, **kwargs) where training is a boolean indicating whether the layer should behave in training mode and inference mode.
  • call(self, inputs, mask=None, **kwargs) where mask is a boolean mask tensor (useful for RNNs, for instance).
  • call(self, inputs, training=None, mask=None, **kwargs) -- of course you can have both masking and training-specific behavior at the same time.

다음은 예시입니다.

units = 32
timesteps = 10
input_dim = 5
batch_size = 16


class CustomRNN(layers.Layer):

  def __init__(self):
    super(CustomRNN, self).__init__()
    self.units = units
    self.projection_1 = layers.Dense(units=units, activation='tanh')
    self.projection_2 = layers.Dense(units=units, activation='tanh')
    self.classifier = layers.Dense(1, activation='sigmoid')

  def call(self, inputs):
    outputs = []
    state = tf.zeros(shape=(inputs.shape[0], self.units))
    for t in range(inputs.shape[1]):
      x = inputs[:, t, :]
      h = self.projection_1(x)
      y = h + self.projection_2(state)
      state = y
      outputs.append(y)
    features = tf.stack(outputs, axis=1)
    return self.classifier(features)

# Note that we specify a static batch size for the inputs with the `batch_shape`
# arg, because the inner computation of `CustomRNN` requires a static batch size
# (when we create the `state` zeros tensor).
inputs = keras.Input(batch_shape=(batch_size, timesteps, input_dim))
x = layers.Conv1D(32, 3)(inputs)
outputs = CustomRNN()(x)

model = keras.Model(inputs, outputs)

rnn_model = CustomRNN()
_ = rnn_model(tf.zeros((1, 10, 5)))

 

이글은 다음 문서를 참조합니다.

www.tensorflow.org/guide/keras/functional

(번역은 자력 + 파파고 + 구글 번역기를 사용하였으니, 부자연스럽더라도 양해바랍니다.)


The Keras Functional API in Tensorflow

!pip install -q pydot
!pip install graphviz(apt-get install graphviz)

pydot, graphviz를 설치해줍니다. 나중에 model_plot 그릴때 사용됩니다. (graphviz import error 는 밑쪽에)

 

Introduction

우리는 이미 keras.Sequential()을 이용하여 모델 만들기에 익숙해져있습니다. 함수형 API는 Sequential을 통한 모델 생성보다 더 유연하게 모델을 구축할 수 있습니다: 비선형 구조, 층 공유, 다중 입출력 모델을 다룰 수 있습니다.

 딥러닝은 DAG(directed acyclic graph) 아이디어로 구성되어있다. 함수형 API는 층에 대한 그래프를 만들기 위한 도구이다.

다음 모델을 고려해보자:

(input: 784-dimensional vectors)
       ↧
[Dense (64 units, relu activation)]
       ↧
[Dense (64 units, relu activation)]
       ↧
[Dense (10 units, softmax activation)]
       ↧
(output: probability distribution over 10 classes)

3개의 단순한 층으로 이루어진 그래프이다.

함수형 API로는 다음과 같이 만들 수 있고, 입력 노드는 다음과 같다.

from tensorflow import keras

inputs = keras.Input(shape=(784,))

우리의 데이터가 784차원임을 나타내준다. 배치 크기가 항상 생략할 수 있고, 우리는 그저 각 데이터의 구체적인 shape만 알려주면 된다. 만약 데이터가 (32, 32, 3)으로 이루어져 있다면 다음과 같을 것이다.

img_inputs = keras.Input(shape=(32, 32, 3))

Input 함수의 반환은 input data의 dtype과 shape에 관한 정보를 포함합니다.

inputs.shape = TensorShape([None, 784])
inputs.dtype = tf.float32

 

층 그래프에 inputs object로 새로운 노드를 다음과 같이 만들 수 있습니다.

(층 그래프란 것은 쉽게 말해서 텐서플로우에서 Session안에 층을 구성하면 한 그래프에 층이 쌓이게(stack) 됩니다. 그래프는 통이고 층은 내용물이라고 생각하면 쉽겠네요.)

from tensorflow.keras import layers

dense = layers.Dense(64, activation='relu')
x = dense(inputs)

"layer call"은 우리가 만든 layer로 inputs에서 화살표를 그리는 것과 같습니다. dense layer에 입력을 통과시키고 x를 얻습니다.

더 추가해봅시다.

x = layers.Dense(64, activation='relu')(x)
outputs = layers.Dense(10, activation='softmax')(x)

입력과 출력을 지정하여 Model을 만들 수 있습니다.

model = keras.Model(inputs=inputs, outputs=outputs)

복습합시다. 전체 과정은 다음과 같습니다.

inputs = keras.Input(shape=(784,), name='img')
x = layers.Dense(64, activation='relu')(inputs)
x = layers.Dense(64, activation='relu')(x)
outputs = layers.Dense(10, activation='softmax')(x)

model = keras.Model(inputs=inputs, outputs=outputs, name='mnist_model')

여러분이 만든 모델은 model.summary()를 이용하여 파라미터 수와 층이 어떻게 구성되어있는지 확인할 수 있습니다.

model.summary()

또한, keras.utils.plot_model(model, 'my_first_model.png')를 사용하면 예쁘게 그림도 그려주고 저장도 해줍니다.

 

ImportError: You must install pydot and graphviz for `pydotprint` to work.

-> 저는 pip말고 brew install graphviz로 설치하니까 되더군요.

keras.utils.plot_model()

선택적으로 shape도 보여줍니다.

keras.utils.plot_model(model, 'my_first_model_with_shape_info.png', show_shapes=True)

 

이러한 그림들과 코드는 사실상 동일함을 나타냅니다. 코드에서 연결화살표는 함수 호출을 의미합니다.

"graph of layers"는 딥러닝 모델을 직관적으로 나타내는 이미지이며, 함수형 API는 이러한 것을 나타내는데 도움을 줍니다.


Training, evaluation, and inference

훈련, 평가, 추론은 Sequential 모델에서 작동하듯이 함수형 API에서도 똑같이 작동합니다.

바로 예시를 보죠.

MNIST 데이터가 있고, validation_spilit을 통해 모니터링하면서 fit시킨 후 평가합니다.

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test = x_test.reshape(10000, 784).astype('float32') / 255

model.compile(loss='sparse_categorical_crossentropy',
              optimizer=keras.optimizers.RMSprop(),
              metrics=['accuracy'])
history = model.fit(x_train, y_train,
                    batch_size=64,
                    epochs=5,
                    validation_split=0.2)
test_scores = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', test_scores[0])
print('Test accuracy:', test_scores[1])


Saving and Serialization

이 기능 또한 함수형 API에서도 사용할 수 있습니다.

model.save() 를 통해 모델을 저장할 수 있고, 코드가 있지 않아도 같은 구조의 모델을 load할 수 있습니다.

이 파일에는 다음과 같은 내용이 포함됨: - 모델의 아키텍처 - 모델의 weights 값(교육 중에 학습됨) - 모델의 training config(model.compile) 구성(편집하기 위해 전달된 내용), 있는 경우 - optimizer와 해당 상태(이 경우, 중단한 곳에서 교육을 다시 시작할 수 있음)

model.save('path_to_my_model.h5')
del model
# Recreate the exact same model purely from the file:
model = keras.models.load_model('path_to_my_model.h5')

 

Using the same graph of layers to define multiple models

함수형 API는 구체적으로 입출력을 지정할 수 있습니다. 이는 다중 입출력 모델 또한 구성 가능하다는 것을 뜻합니다.

아래 예시는 2 Model로 auto-encoder를 구성하는 것을 나타냅니다.

encoder_input = keras.Input(shape=(28, 28, 1), name='img')
x = layers.Conv2D(16, 3, activation='relu')(encoder_input)
x = layers.Conv2D(32, 3, activation='relu')(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation='relu')(x)
x = layers.Conv2D(16, 3, activation='relu')(x)
encoder_output = layers.GlobalMaxPooling2D()(x)

encoder = keras.Model(encoder_input, encoder_output, name='encoder')
encoder.summary()

x = layers.Reshape((4, 4, 1))(encoder_output)
x = layers.Conv2DTranspose(16, 3, activation='relu')(x)
x = layers.Conv2DTranspose(32, 3, activation='relu')(x)
x = layers.UpSampling2D(3)(x)
x = layers.Conv2DTranspose(16, 3, activation='relu')(x)
decoder_output = layers.Conv2DTranspose(1, 3, activation='relu')(x)

autoencoder = keras.Model(encoder_input, decoder_output, name='autoencoder')
autoencoder.summary()

(꼭 summary()를 확인하세요!)

 

이러한 구성은 input_shape를 가진 output을 만들어내기 위해 필요합니다.

Conv2D의 반대는 Conv2DTranspose(가중치 학습 가능), MaxPooling2D의 받내는 UpSampling2D(가중치 학습 x)

All models are callable, just like layers

어떠한 모델이던 다른 층의 출력이나 입력을 층으로서 활용이 가능합니다. 이때, 모델 구조를 재사용하는 것이 아닌 가중치를 재사용한다는 것을 명심하세요

encoder_input = keras.Input(shape=(28, 28, 1), name='original_img')
x = layers.Conv2D(16, 3, activation='relu')(encoder_input)
x = layers.Conv2D(32, 3, activation='relu')(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation='relu')(x)
x = layers.Conv2D(16, 3, activation='relu')(x)
encoder_output = layers.GlobalMaxPooling2D()(x)

encoder = keras.Model(encoder_input, encoder_output, name='encoder')
encoder.summary()

decoder_input = keras.Input(shape=(16,), name='encoded_img')
x = layers.Reshape((4, 4, 1))(decoder_input)
x = layers.Conv2DTranspose(16, 3, activation='relu')(x)
x = layers.Conv2DTranspose(32, 3, activation='relu')(x)
x = layers.UpSampling2D(3)(x)
x = layers.Conv2DTranspose(16, 3, activation='relu')(x)
decoder_output = layers.Conv2DTranspose(1, 3, activation='relu')(x)

decoder = keras.Model(decoder_input, decoder_output, name='decoder')
decoder.summary()

autoencoder_input = keras.Input(shape=(28, 28, 1), name='img')
encoded_img = encoder(autoencoder_input)
decoded_img = decoder(encoded_img)
autoencoder = keras.Model(autoencoder_input, decoded_img, name='autoencoder')
autoencoder.summary()

(꼭 summary()를 확인하세요!)

 

모델 앙상블링은 다음과 같이 구성됩니다.

def get_model():
  inputs = keras.Input(shape=(128,))
  outputs = layers.Dense(1, activation='sigmoid')(inputs)
  return keras.Model(inputs, outputs)

model1 = get_model()
model2 = get_model()
model3 = get_model()

inputs = keras.Input(shape=(128,))
y1 = model1(inputs)
y2 = model2(inputs)
y3 = model3(inputs)
outputs = layers.average([y1, y2, y3])
ensemble_model = keras.Model(inputs=inputs, outputs=outputs)

Manipulating complex graph topologies

Models with multiple inputs and outputs

함수형 API는 다중 입출력을 구성할 수 있습니다. 

다음 예제를 보겠습니다. 

티켓 우선순위에 따라 올바른 부서에 전달하는 시스템을 구축하고 있다고 생각합시다.

우리는 3개의 input을 가집니다.

  • Title of the ticket (text input)
  • Text body of the ticket (text input)
  • Any tags added by the user (categorical input)

또한, 2가지 output을 가집니다.

  • Priority score between 0 and 1 (scalar sigmoid output)
  • The department that should handle the ticket (softmax output over the set of departments)

코드를 볼까요.

num_tags = 12  # Number of unique issue tags
num_words = 10000  # Size of vocabulary obtained when preprocessing text data
num_departments = 4  # Number of departments for predictions

title_input = keras.Input(shape=(None,), name='title')  # Variable-length sequence of ints
body_input = keras.Input(shape=(None,), name='body')  # Variable-length sequence of ints
tags_input = keras.Input(shape=(num_tags,), name='tags')  # Binary vectors of size `num_tags`

# Embed each word in the title into a 64-dimensional vector
title_features = layers.Embedding(num_words, 64)(title_input)
# Embed each word in the text into a 64-dimensional vector
body_features = layers.Embedding(num_words, 64)(body_input)

# Reduce sequence of embedded words in the title into a single 128-dimensional vector
title_features = layers.LSTM(128)(title_features)
# Reduce sequence of embedded words in the body into a single 32-dimensional vector
body_features = layers.LSTM(32)(body_features)

# Merge all available features into a single large vector via concatenation
x = layers.concatenate([title_features, body_features, tags_input])

# Stick a logistic regression for priority prediction on top of the features
priority_pred = layers.Dense(1, activation='sigmoid', name='priority')(x)
# Stick a department classifier on top of the features
department_pred = layers.Dense(num_departments, activation='softmax', name='department')(x)

# Instantiate an end-to-end model predicting both priority and department
model = keras.Model(inputs=[title_input, body_input, tags_input],
                    outputs=[priority_pred, department_pred])

 

loss 또한, 각각 output에 대해 적절한 함수를 적용할 수 있습니다.

추가로 가중치를 줘서 각각 loss값이 total loss에 미치는 영향도를 조절할 수도 있습니다.

model.compile(optimizer=keras.optimizers.RMSprop(1e-3),
              loss=['binary_crossentropy', 'categorical_crossentropy'],
              loss_weights=[1., 0.2])

이름도 붙여 줄 수 있습니다.

model.compile(optimizer=keras.optimizers.RMSprop(1e-3),
              loss={'priority': 'binary_crossentropy',
                    'department': 'categorical_crossentropy'},
              loss_weights=[1., 0.2])

 

넘파이 배열을 이용하여 fit 시켜보겠습니다.

import numpy as np

# Dummy input data
title_data = np.random.randint(num_words, size=(1280, 10))
body_data = np.random.randint(num_words, size=(1280, 100))
tags_data = np.random.randint(2, size=(1280, num_tags)).astype('float32')
# Dummy target data
priority_targets = np.random.random(size=(1280, 1))
dept_targets = np.random.randint(2, size=(1280, num_departments))

model.fit({'title': title_data, 'body': body_data, 'tags': tags_data},
          {'priority': priority_targets, 'department': dept_targets},
          epochs=2,
          batch_size=32)

data, label을 fit시킬 떄는 두 가지 방법이 가능합니다.

  1. ([title_data, body_data, tags_data], [priority_targets, dept_targets])
  2.  ({'title': title_data, 'body': body_data, 'tags': tags_data}, {'priority': priority_targets, 'department': dept_targets})

A toy resnet model

함수형 API는 resnet과 같은 비선형적 모델 구조를 구성하기 쉽습니다.

잔차 연결의 예시를 봅시다.

inputs = keras.Input(shape=(32, 32, 3), name='img')
x = layers.Conv2D(32, 3, activation='relu')(inputs)
x = layers.Conv2D(64, 3, activation='relu')(x)
block_1_output = layers.MaxPooling2D(3)(x)

x = layers.Conv2D(64, 3, activation='relu', padding='same')(block_1_output)
x = layers.Conv2D(64, 3, activation='relu', padding='same')(x)
block_2_output = layers.add([x, block_1_output])

x = layers.Conv2D(64, 3, activation='relu', padding='same')(block_2_output)
x = layers.Conv2D(64, 3, activation='relu', padding='same')(x)
block_3_output = layers.add([x, block_2_output])

x = layers.Conv2D(64, 3, activation='relu')(block_3_output)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dense(256, activation='relu')(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(10, activation='softmax')(x)

model = keras.Model(inputs, outputs, name='toy_resnet')
model.summary()

(꼭 summary()를 확인하세요!)

plot_image도 꼭 확인하세요!

train 시켜 보겠습니다.

(x_train, y_train), (x_test, y_test) = keras.datasets.cifar10.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
y_train = keras.utils.to_categorical(y_train, 10)
y_test = keras.utils.to_categorical(y_test, 10)

model.compile(optimizer=keras.optimizers.RMSprop(1e-3),
              loss='categorical_crossentropy',
              metrics=['acc'])
model.fit(x_train, y_train,
          batch_size=64,
          epochs=1,
          validation_split=0.2)


Sharing layers

함수형 API는 공유 층을 사용하기에도 좋습니다.

밑의 예시는 한가지 임베딩 층에 두가지 입력을 넣어 재사용성을 높였고, 여러 입력을 학습합니다.

공유 계층은 이러한 서로 다른 입력에 걸친 정보의 공유를 가능하게 하고, 그러한 모형을 더 적은 데이터로 훈련시킬 수 있게 하기 때문에 유사한 공간(예: 유사한 어휘를 특징으로 하는 두 개의 다른 텍스트)에서 오는 입력을 인코딩하는 데 자주 사용된다. 입력 중 하나에서 특정 단어가 보이는 경우, 공유 계층을 통과하는 모든 입력의 처리에 도움이 될 것이다.

# Embedding for 1000 unique words mapped to 128-dimensional vectors
shared_embedding = layers.Embedding(1000, 128)

# Variable-length sequence of integers
text_input_a = keras.Input(shape=(None,), dtype='int32')

# Variable-length sequence of integers
text_input_b = keras.Input(shape=(None,), dtype='int32')

# We reuse the same layer to encode both inputs
encoded_input_a = shared_embedding(text_input_a)
encoded_input_b = shared_embedding(text_input_b)

 

--> 2019/03/30 - [ML/tensorflow2.0(keras)] - tensorflow 2.0 keras Funtional API (2)

ex) 맥북에서 우분투에 있는 파일 다운로드 받기

scp server_name@server_ip:file_directory my_directory

 

ex) 맥북에서 우분투에 있는 폴더 다운로드 받기

-r만 추가하면 됨

scp -r server_name@server_ip:folder_directory my_directory

 

이 방법을 사용하면 가벼운 맥북으로도 무거운 서버의 gpu를 사용할 수 있습니다.(gpu관련글은 아님.)--


1. config 파일 만들기

cmd에서 jupyter notebook --generate-config

를 사용하면 jupyter_notebook_config.py가 만들어집니다. 


2. key 획득하기

위의 sha~ 부분을 다음과 같이 붙여줍니다. c.Notebook이런건 찾으시면 다 있으니 cmd(ctrl)+f기능을 활용하세요


3. jupyter_config 에서 몇 가지 더 수정하기

위에서 했던 것처럼 전부 찾아서 아래와 같이 바꿔주시면 됩니다.

c.NotebookApp.ip = '*'

c.NotebookApp.password_required = True

c.NotebookApp.port = 원하는 포트번호(5554)

c.NotebookApp.open_browser = False


4. 포트 등록하기

iptables를 사용하여 포트를 등록하면 됩니다. 혹시 permission 에러가 뜬다면 sudo!

cmd에 

(sudo) iptables -I(i입니다) Input 1 -p tcp --dport 5554 -j ACCEPT

이렇게 해주면 등록이 끝났습니다.


5. 사용하기

먼저 쥬피터 노트북을 no-browser모드로 실행시켜놓아야 합니다. 

jupyter notebook --ip=server_ip --no-browser

로 켜놓고 맥북에서

server_ip:port로 실행시켜주면 성공!