Dev Summit을 여는 첫 번째 동영상 Kenote는 이번 Dev Summit에서 텐서플로우가 무엇을 이야기할지 간략하게 정리해준다.

https://www.youtube.com/watch?v=_lsjCH3fd00&t=687s


- 코로나의 영향으로 온라인 라이브로 진행합니다.

- 2019년은 텐서플로우에게 매우 중요한 해였습니다. 바로 텐서플로우 2.x를 배포하였기 때문이죠. 또, 배포함과 동시에 사용자의 접근성을 계속해서 고려하고 있습니다.(아마 Pytorch를 의식하지 않았을까요?, Keras, Eager Execution을 통해 텐서플로우의 편리함을 강조하고 있습니다)

- 이제금 TensorFlow 2.2 버전이 제공됩니다. 좀 더 Stable한 버전이 될 것으로 기대합니다.

- 영상에서는 TensorFlow Ecosystem을 언급하는데, 다음 그림을 보면 무엇인지 바로 확인할 수 있습니다.
(JAX도 포함되어 있고, CoLab 등 우리에게 필요한 것이 전부 있습니다!)

- ecosystem은 연구자, 실제 환경에서의 사용자, 기타 사용자에게까지 모든 것을 편리하게 제공합니다.

- 텐서플로우는 Meena, T5와 같은 NLP 모델를 예시로 다양한 sub fields에서 활약하고 있다.
- 연구자는 텐서보드(Tensorboards)를 활용해서 많은 부분을 피드백받을 수 있도록 한다. 실제로 2019년에 많은 논문에서 텐서보드를 활용하여 실험 결과를 공유하고 있다고 합니다.

- 텐서플로우 2.x는 매우 단순하다.
(Eager Execution, NumPy array 지원, tf.data를 통한 data pipeline handling, TF Datasets 등을 통해 쉽게 접근할 수 있다)
- 또, JAX를 본격적으로 활용하면서 연구자들이 매우 환영할 것으로 기대한다(아마 traning의 시간에 매우 영향을 끼칠 것으로 판단됨).

- 머신러닝 모델을 실제 제품에 적용하는 것은 매우 어려운 일인데, 텐서플로우 Ecosystem을 활용하면 큰 도움을 받을 수 있다.

  1. 케라스 API를 활용하면 텐서플로우를 더욱 쉽게 활용할 수 있다.
  2. TensorFlow Hub를 활용하면 pre-trained 모델, 각 분야의 모델 Demo 등을 CoLab을 통해 쉽게 사용해 볼 수 있다.
    (개인적으로 매우 좋은 것 같습니다. pre-trained 모델을 쉽게 사용할 수 있는 것은 딥러닝의 매~~~~우 큰 장점이란 것을 아니까요)
  3. 구글 클라우드 플랫폼 파이프라인을 활용하면 end-to-end production을 쉽게 구축할 수 있습니다.
  4. 케라스를 통해 TPU를 쉽게 활용할 수 있습니다.

- TF Lite는 latency 수준을 매우 낮췄다!(밑 그림의 회색 bar를 확인하세요.)
- TF Lite의 사용을 더욱 쉽게 할 수 있고, Android Studio와도 연동이 더욱 수월하게 할 수 있도록 진행하는 것 같습니다.
- 뿐만 아니라, TensorFlow.js에서도 매우 훌륭한 성능을 제공하는 것을 보여줍니다.

- TensorFlow Runtime이 새롭게 개편되었습니다. 효율적이고 최적화를 진행했기 때문에 더욱 빠르게 연구할 수 있을 것으로 기대합니다.

- TensorFlow는 다양한 질문에 대비할 준비가 되어 있다.

- TensorFlow가 가지고 있는 커뮤니티의 힘은 매우 강력합니다.
(실제로 국내에서도 그렇죠. TensorFlow KR 또는 Keras KR with FaceBook을 찾아보세요!)

- TensorFlow를 학습하기 위한 다양한 course를 제공하고 있고, deeplearning.ai를 활용해도 좋습니다.
- TensorFlow 자격증이 생겼습니다!
(Tensorflow.org/certificate 를 참고하세요)

이 글은 다음 영상을 참조합니다.

https://www.youtube.com/watch?v=4iq-d2AmfRU&list=PLQY2H8rRoyvzIuB8rZXs7pfyjiSUs8Vza&index=2


Quantization이 무엇인가?

Quantization은 모델이 표현하는 바를 일부 제한시켜서 모델의 파라미터를 감소시키는 방법이다. 이 방법은 모델의 크기를 감소시켜서 프로그램을 빠르게하고, 파워 소비를 감소시킵니다. 또 마지막으로 메모리 요구를 감소시켜 하드웨어 측면에서도 이점을 취할 수 있습니다.

왜 어려운가?

장점이 많은만큼, 어렵다.
(1) 이 방법을 표현하기 어렵다. 표준이 없다는 이야기이다.
(2) 완전한 적용을 위한 메타 데이터가 충분하지 않다.
(3) 신경망의 고질적인 문제인 것처럼, 결과를 해석할 수 없다. 그래서 이 방법은 효과적이지만 정교하게 해석할 수 없기에 이를 목표로 잡고있다고 언급한다.

어떻게 사용하는가?

가장 쉬운 방법은 프로그램이 활용하는 수의 범위에서 min-max를 결정해서 clipping하는 것이다. 이 방법은 효과적일 수 있지만, 어떤 모델에서는 유용하고, 또 어떤 모델에서는 유용하지 않을 수 있기 때문에 주의해야 한다. 

이 방법은 주로 전처리 과정이나 또는 경우에 따라 사후 처리에서 사용해서 값의 범위를 제한시키고 모델에 입력시켰는데, 최근에는 모델의 학습 과정(예를 들면 backward)에서 사용한다.

학습 과정에서 사용하면 더욱 잘 adjust할 수 있지만, 재사용, 유지보수 불가, unstable, 다루기 어려움과 같은 주의점이 존재한다.

Neural connection pruning

우리가 흔히 하는 Model pruning과 동일한 이름인 것 같다. 이 방법은 신경망의 개별 connection을 끊어주는 것을 의미한다. 예를 들면, dense한 tensor에서 sparse한 tensor로 만들어주는 것이다.
sparse한 tensor가 되기 위해서는 기존의 값을 0으로 채워넣으면 되겠죠?

그래서 TensorFlow는 이를 위해 어떤 tool을 제공하는가?

텐서플로우는 2019년에 이를 위한 Model Optimization Toolkit을 배포했다.
(Quantization, Sparsity를 수행해서 이미지가 어떻게 변화하는지는 영상의 [15:14]에서 볼 수 있다.)

https://github.com/tensorflow/model-optimization

텐서플로우에서는 세 가지의 Quantization 방법을 제공한다.
- TensorFlow Lite용
- 학습 과정 중에 사용할 수 있는 방법
- 사후 처리 과정 중에 사용할 수 있는 방법

먼저 quantization 방법은 bit로 표현할 수 있는 범위를 제한시키는 것이 대표적인데,
텐서플로우는 float형태--> float + int 형태 --> only 8-bit int 형태의 quantization 방법을 제공한다.
(자세한 설명은 동영상을 참고하세요)

중요한 것은 keras API를 활용해서 쉽게 적용가능하다.

import tensorflow_model_optimization as tfmot

model = MyModel()

model_to_quantize = tfmot.quantization.keras.quantize(model)

model_for_pruning.fit()

왜 마지막 모델의 이름이 model_for_pruning 인지는 뒤에서 알 수 있다.

 

TF Lite에서도 매우 쉽게 활용할 수 있는 것을 보면, 감탄사가 나온다. 
convert하는 과정에서 converter의 옵션을 다음과 같이 설정하기만 하면 된다.

converter.optimizations = [tf.lite.Optimize.DEFAULT]

동영상에서는 CPU를 통해 얼마만큼의 속도 향상이 이루어졌는지 결과를 보여준다(무려 4배, RNN 계열은 3배).
보통 속도와 성능은 trade-off 관계인 것을 알고 있을 것이다. 동영상에서는 이에 대한 실험결과도 보여주는데 기본 baseline과 quantization을 수행한 결과 차이가 거의 업다!

케라스를 활용하여 사용하는 과정은 다음과 같다.

  1. 케라스 모델을 구성한다.
  2. 텐서플로우에서 제공하는 optimization API를 활용해서 pruning을 적용한다.
  3. 학습한다.
  4. 모델은 sparse한 tensor 보유를 통해 크기가 감소할 것이다.

적용 과정을 더욱 구체적으로 살펴보자면,

import tensorflow_model_optimization as tfmot

model = MyModel()

pruning_schedule = tfmot.sparsity.keras.PolynomialDecay(
				inital_sparsity = 0.0, final_sparsity = 0.5,
                begin_step = 2000, end_step = 4000)
                
model_for_pruning = tfmot.sparsity.keras.prune_low_magnitude(model,
								pruning_schedule=pruning_schedule)

여기서 final_sparsity 인자값을 강조하고 있다. 이 인자를 통해 각 layer에서 weight를 얼마나 감소시킬 것인지를 결정할 수 있는데, 여기서는 0.5이므로 50%를 선택한 것이다.
인자값의 선택은 0.5 ~ 0.8 즉, 50% ~ 80% 정도가 가장 효율적이라고 실험을 통해 설명한다.

 

 

 

https://www.youtube.com/watch?v=kVEOCfBy9uY&list=PLQY2H8rRoyvzIuB8rZXs7pfyjiSUs8Vza&index=2


tf.data

이 동영상은 tf.data에 관한 동영상입니다. 본 영상은 여러 언어적 관점에서 다루지만 글은 Python view에서 나오는 내용만 적었습니다.

dataset = tf.data.TFRecordDataset(files)
dataset = dataset.shuffle(buffer_size = X)
dataset = dataset.map(lambda record: parse(record))
dataset = dataset.batch(batch_size = Y)

for element in datset:
	...

기존 tf 1.x와 다르게 매우 간단하게 정리되었습니다. eager execution이 본격적으로 사용되는 것처럼 위에서도 for-loop를 사용하여 데이터를 전달받을 수 있습니다. 

기존의  tf 1.x에서는 iterator를 초기화 한 후 사용해야 하는 등 좀 더 복잡한 과정을 거쳤었습니다.

전체적으로는 다음의 프로세스를 가진다. 'tfrecord -> shuffle -> map -> batch'

C++의 요소를 넣어 performance 측면에서 이득을 취했고, 그 결과 다시 다음의 코드를 만나볼 수 있다.

dataset = tf.data.TFRecordDataset(files) 
dataset = dataset.shuffle(buffer_size = X) 
dataset = dataset.map(lambda record: parse(record), num_parallel_cells =…) 
dataset = dataset.batch(batch_size = Y) 
dataset = dataset.prefetch(buffer_size=…)

for element in datset: …

 

supporting non-tensor types

텐서 타입이 아닌 타입을 다루기 위해서는 다음 이미지에 나오는 코드로 변환하여 tf.data를 사용할 수 있게 된다.

map이나 tensor_slice와 같은 함수는 기본적으로 tf.data Structure을 거쳐서 output 또는 input으로 반환되는 것을 볼 수 있다.

 

Static Optimizations

이 부분은 자세히 설명해주지는 않았지만, 대충 최적화를 위한 함수들이 있는 곳이라고 생각하면 될 것 같다. 다음과 같이 여러개의 함수가 존재한다.

  • map + batch fusion
  • map + filter fusion
  • map + map fusion
  • map parallelization
  • map vectorization
  • noop elimination
  • shuffle + repeat fusion

그리고 다음과 같이 사용한다.

(이 다음으로 C++ 측면에서 내부적으로 어떻게 흘러가는지 보여주지만 글에서는 생략한다.)

Dynamic optimization

아래 퀴즈에서 시작한다. 얼마나 많은 시간이 소요되겠는가?

모든 작업이 순차적으로 이루어지기 때문에 그렇다고 한다. 
그렇다면 다음 작업은 얼마나 걸리겠는가에 대한 퀴즈를 또 한번 낸다.

첫 번째 질문과의 차이는 num_parallel_calls의 차이이다. background에서 서로 다른 커널에서 수행되는 것 같은데, 감이 잘 안온다. 아무튼 여러가지의 스레드를 만들어서 동시작업을 행한다고 생각하면 편하다. 
하지만 맨 처음 element를 처리하는데 걸리는 시간은 첫 번째 문제와 같다는 것.

num_parallel_calls의 수가 늘어날 수록 output latency도 줄어든다. 하지만 그 수가 늘어난다고 해서 매우 많은 수의 thread를 만든다는 의미는 아니고, 여러 작업의 schedule을 동시에 처리해서 그 시간을 줄인다는 의미인 것 같다.

이 글은 다음 텐서플로우 유튜브 동영상을 공부하면서 끄적끄적한 글입니다.

https://www.youtube.com/watch?v=IzKXEbpT9Lg&list=PLQY2H8rRoyvzIuB8rZXs7pfyjiSUs8Vza


일단 이 동영상은 전체적으로 텐서플로우 내부의 흐름을 다루고, 이를 예를 들어 설명하고 있습니다.

 

Base API에서 사용되던 tf.cond, tf.while_loop는 Higher-level이나 Low-level API에서 따로 통용되는 함수가 존재합니다.

하지만, tf 2.0으로 넘어오면서 "Functional" ops로 변경되어 If나 While문과 같이 파이썬 문법처럼 사용할 수 있게 되었습니다.
(Eager Execution, Autograph)

첫번쨰로 Control flow v1이라고 해서 low-ops에 대해 설명합니다. 

영상에서는 tf.cond(x < y, lambda: tf.add(x, z), lambda: tf.square(y))와 몇 개의 예를 들면서 low-ops에서의 흐름을 설명합니다. 쉽게 예에 대해서 그래프의 흐름을 설명해주고 있습니다. 이를 구성하기 위해 대표적으로 Switch와 Merge의 표현을 사용하게 됩니다.

이것의 장점은 Pruning이 가능하고, dataflow만 잘 만들면된다. 하지만 분석이 어렵고 매우 복잡하다. 이를 매우 nested하다 라고 표현하고 있습니다. 

결과적으로 tf 내부적으로 어떻게 control flow가 구성되는지 tf.cond(), tf.while_loop()를 통해 설명하고 있는겁니다. 다음 사이트가 이를 잘 설명해주고 있습니다.

https://towardsdatascience.com/tensorflow-control-flow-tf-cond-903e020e722a

두번째로는 Control flow v2를 설명합니다. 

여기에서는 그래프가 좀 더 함수처럼 동작하는 것을 보여주고 있습니다. 특별한 점은 없으며 텐서플로우의 기본적인 표현입니다. 각각의 함수가 텐서 인풋과 텐서 아웃풋을 별개로 가지고 있고, 매우 simple해 졌습니다. 또한, v1에서는 true와 false가 매치되어 있다면, v2에서는 별개의 함수로 작용하는 것처럼 구성되어 있습니다. 

세번째, Gradient입니다.

tf.cond, tf_while_loop를 예로 들며, 이에 대해 내부적으로 gradient가 어떻게 만들어지는지 설명합니다. 

Control flow v2의 장점은 v1의 단점을 보완한다는 것입니다. 단순, 디버깅, 통합 등등. 하지만 이 때문에 성능적으로 좀 떨어진다는 단점이 생깁니다. 따라서 이에 대한 해결방법은 표현을 v2로 쓰되, 내부적으로 v1의 기능을 사용하여 성능과 속도를 동시에 잡는 것입니다. 이를 Lowering이라고 표현하고 있습니다. 

또한, 향후에는 control flow v1과 같은 표현을 되도록이면 제거하면 좋겠다고 말하네요. 이를 위해 세션을 제거하고, TensorArray를 재구성했다고 합니다. 모든 것을 Simple하게 바꾸면서도 efficient하게 하려는 작업인 것 같습니다.