TensorMSA User Guide

TensorMSA Easy to Use UI/UX

우리의 프레임웍은 크게 두가지 형태로 서비스를 제공하는데 기본적으로 대부분의 기능을 Rest API 형태로 구축하여 서버간의 연동을 통한 사용방법과 지금 설명하고자 하는 UI/UX 기반의 서비스 제공이다. 서버간의 데이터 수집 및 모델 갱신 과정을 연동을 통해 자동화 하고자 할때는 Rest API 를 통해 서비스를 구성하는 것이 효과적일 것이고, 사용자가 분석을 하려는 목적을 가지고 있다면 UI/UX 기능을 사용하는 것이 효과적일 것이다. 우리의 UI/UX 는 대표적인 파이프 라인에 대해서 데이터를 넣고 자동으로 최적의 하이퍼 파라메터를 탐색하는 프로세스를 지원하도록 되어 있으며, 커스텀 형태의 기능들은 현재는 지원하지 않고 있다.

Main Page

로그인 후 화면에 처음들어 오면 위와 같은 메인 페이지를 볼수가 있다. 우리가 제공하는 주요한 메뉴는 화면의 상단에서 확인 할 수 있는데 간략하게 설명하면 다음과 같다.

(1) Net Info : 우리는 알고리즘을 비지니스 단위-파이프라인 구성단위-데이터훈련 단위로 나누어 각각 Network – Version -Batch 라고 명명하여 관리하고 있는데, 본 화면은 비지니스 관리 단위로 현재 서버에 등록된 대상들을 출력합니다.
(2) Net Detail : 정의되어 훈련된 모델의 상세 정보를 출력합니다.
(3) Net Create : 새로운 신경망을 정의합니다.
(4) Monitoring : 전체 시스템에 수행중인 Task 와 서버의 부하를 모니터링
(5) Setting : 서버 정보, 권한 정보 등을 세팅합니다.
(6) Apps : Deep Learning Layer 와 연동하여 서비스 가능한 Plugin 관리

(1) Defined Neural Network List

정의된 신경망을 출력하여 보여주고 있습니다. 관리자 권한으로 로그인한 경우가 아니면 자신이 권한을 가지고 있는 신경망에 대해서만 조회가 가능합니다. 정의된 신경망의 그룹, 서브그룹, 제목, 요약 사용여부, 최종 정확도와 같은 정보들을 출력하고 있으며, 여기에서 신경망을 선택하면 상세 화면으로 이동할 수 있다.

(2) Detail Information Page

(1)번에서 신경망을 선택하면 위와 같은 화면이 나온다. 위의 화면에서 출력되는 내용은 크게 3가지  “버전 요약정보”, “Genetic Algorithm 진행 정보”, “버전별 상세 결과 정보” 로 구성된다.
(가) 버전 요약 정보 : 제네틱 알고리즘을 수행한 결과는 버전별로 성능이 평가가 되는데, 이러한 결과를 정확도 역순으로 출력하여 성능이 좋은 모델순으로 요약 정보를 조회 할 수 있도록 합니다. 이 정보는 AutoML 이 진행되면서 실시간으로 업데이트 됩니다.
(나) AutoML 정보 : 전체 지정한 세대에 대해서 진행중인 정보를 세대, 구성원 단위로 나눠서 진행 정보를 이해할 수 있도록 그래프 형태로 표현하여 줍니다.
(다) 버전별 상세 결과 정보 : Genetic Algorithm 입장에서 보면 각 세대의 구성원, 프레임웍의 관리 단위에서 보면 신경망 버전단위의 훈련 결과를 상세히 출력합니다. 좌측의 그래프의 경우 카테고리별 정확도를 출력하고 있으며, 우측의 그래프는 각 카테고리의 상세 예측 결과를 보여주고 있습니다.

(3) Create New Network Page

새로운 신경망을 정의하기 위해 사용하는 화면으로 다음과 같은 내용들을 정의하고 있다. “신경망에 대한 비지니스 관점의 정의”, “알고리즘의 선택”, “선택한 알고리즘 동작을 위한 파라메터 정의” 크게 3가지로 나눌 수가 있다.
(1) 비지니스 관점의 정의 : 비지니스 명, 비지니스 설명, 그룹, 서브그룹 등 정보
(2) 알고리즘 선택 :  우리는 아래와 같이 3개의 카테고리의 알고리즘을 제공한다.

알고리즘을 선택하면 크게 6개의 노드로 구성된 파라메터 구성을 볼 수 있는데, 그 구성은 아래와 같다.  “데이터 추출”, “데이터 전처리”, “알고리즘 하이퍼 파라메터”, “평가 데이터”, “평가 방법” 등을 입력하여 주어야 한다.  우리의 프레임웍은 AutoML 을 적용하고 있어 정확한 파라메터 값이 아닌 탐색하기를 원하는 범위만 지정하면 내부적으로 Genetic Algorithm 을 활용하여 최적의 값을 탐색한다.

Application Layer – ChatBot Builder

우리가 제공하는 Deep Learning Layer 는 데이터 기반 모델을 훈련하고 서비스하는 것에 중점을 두고 있지만, 우리가 해결해야 하는 문제들이 모델만 가지고 해결되는 간단한 문제만 있는 것은 아니다. 대부분의 경우 Rule Base 시스템이나 각종 스케줄 로직 등을 딥러닝 모델과 연결하여 앙상블할 필요가 있을 수 있다. 대표적인 예가 챗봇인데 우리는 Frame Based ChatBot 어플리케이션 레이어를 제공하고 있으며 이 레이어를 통해서 챗봇 서비스를 제공할 수 있도록 지원한다.

위의 화면이 챗봇을 정의하는 화면을 보여주고 있다. 향후 다양한 어플리케이션이 추가되면 우리가 생성한 딥러닝 레이어와의 연동을하는 다양한 서비스를 사용할 수 있게 될 것이다.

Plugin Application – ChatBot Service

위의 화면은 챗봇을 구성하고 실제로 클라이언트 서비스를 통해서 테스틀르 하는 화면을 보여주고 있다.

TensorMSA Service Architecutre

Overroll Service Architecutre

시스템 구성 관점에서의 Architecture 로 “Master”, “AP”, “Train”, “DB”, ”Cluster” 크게 5가지 형태의 Docker Container 를 제공한다. Master 는 전체 서버를 컨트롤하는 기능 수행, Train 은 주로 GPU 서버로 모델의 훈련을 수행, AP 는 훈련된 모델을 서비스로 연결하는 역할을 수행하며, DB와 Cluster 는 각 구성요소들을 연결하기 위한 역할을 수행하게 됩니다.  TensorMSA는 이러한 컴포넌트들을 종합적으로 연결하여 유기적인 서비스를 제공합니다.

Master Server

TensorMSA Master 는 전체 프레임웍의 구성요소들을 Control 하는 역할을 수행하며, 컨트롤 대상은 훈련을 담당하는 GPU서버, 서비스를 담당한는 AP 서버 그리고 각종 파라메터 관리를 위한 DB와 분산처리를 위한 Celery 구성요소 등이 있다. Master서버는 모델 훈련관리, 서버구성관리, 사용자관리, 연결 권한 관리, 연결 어플리케이션 레이어 관리 등을 수행하게 된다.

Train Server

Train Server 는 준비된 데이터와 정의된 파라메터를 기반으로 실질적인 훈련을 수행하게 된다. Train Server 는 훈련을 위한 준비, 과정, 결과를 다시 마스터 서버 및 서비스 서버와 연동하여 그 결과를 공유할 수 있도록 한다.

AP Server

Inference Server 는 실제 서비스를 제공하는 기능을 Restful API로 제공하며, 비지니스 종류별로 어떤 모델을 연결하고, 어떤 그래프 flow 를 갖는 버전을 사용할 것인지, 사용자 대상에 대한 권한 관리 및 점유 리소스 관리 등을 수행할 수 있으며, 간단한 조작으로 서비스를 수행할 수 있도록 한다.

Development Environment

Architecture

FrameWork Stack

1.Front End : React(ES6), SVG, D3, Pure CSS, Mobile(for Chatbot FW)
2.Back End : Django(Python 3.5), Restful Service(Micro Service Architecture), Tensorflow(v1.2), PostgreSQL, Memcache, Celery, Spqrk QL, HDF5, Ngix, Gensim, Konlpy
3.Methology : Agile (CI, TDD, Pair programming and Cloud)
4.Infrastructure : Docker

 

TensorMSA Guide – Seq2Seq

Seq2Seq  for Encoder & Decoder

concept of this algorithm

위 그림에 각 박스는 가장 일반적으로 GRU 쎌이거나 LSTM 쎌인 RNN 쎌을 나타낸다(RNN Tutorial를 참조하길 바란다). 인코더와 디코더는 가중치를 공유 할수 있거나, 더 일반적으로는 다른 매개변수 집합을 사용한다. 다중층 쎌들은 역시 시퀸스-투-시퀸스에서 성공적으로 사용되어 왔다. 예로 번역 Sutskever et al., 2014 (pdf)에서 알수 있다.

위에서 설명된 기본 모델에서, 모든 입력은 디코더에 전달되는 유일한 것이기 때문에 고정된 크기를 가진 상태 벡터로 인코딩 되어져야 한다. 디코더가 입력에 더 직접적인 접근을 가능케 하기 위해, 주의(attention) 메카니즘이 Bahdanau et al., 2014(pdf)에서 소개된다. 주의(attention) 메카나즘에 대해서 상세히 보지 않을 것이다(논문을 참고), 그것은 디코더가 모든 디코딩 단계에서 입력을 엿보게 해주는 것이라고 언급하는 것만으로도 충분하다. LSTM 쎌을 가진 여러층의 시퀸스-투-시퀸스 네트워크와 디코더 안에 어탠션 메카니즘은 이처럼 보인다.

[번역] 가장 대표적인 사용예는 번역이 될 것이다. 요즘 Google 번역기가 매우 좋아진 것도 바로 이런 이유이다.
Encode : 안녕하세요. 오늘 기분은 어떠세요?
Decode : Hello. How are you feel today?
위와 같이 데이터를 구성하고 아래의 Network 을 이용하여 훈련을 시키면 “안녕하세요. 오늘 기분은 어떠세요?” 라고 입력을 하였을때, “Hello. How are you feel today?”라는 답을 하는 네트워크가 구성되는 것이다.

[대화]번역뿐만 아니라 간단한 문/답에도 아래와 같이 적용해 볼 수 있을 것이다. (※단순 Seq2Seq 로 Alex 같은 것은 구현할 수 없다)
Encode : 안녕하세요!?
Decode : 잘가세요!?

[분류]Time Series 한 Classification 문제도 생각해 볼 수가 있다. 아래의 데이터를 주가의 흐름이라고 하자
Encode : 1900, 1800, 1700, 1600, 2000
Decode : Up/Down
예를 들면 종합 주가지수가 1900, 1800, 1700, 1600, 2000 와 같이 변동해 왔을때, 내일의 주가는 내려갈까요? 올라갈까요? 와 같은 형태의 질문도 훈련을 할 수가 있을 것이다.

APIs – Define Neural Network

import requests
import json, os

nn_id = 'seq2seq003'

####(1) 네트워크 생성 ####
resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/' + nn_id + '/',
                     json={
                         "biz_cate": "MES",
                         "biz_sub_cate": "M60",
                         "nn_title" : "test",
                         "nn_desc": "test desc",
                         "use_flag" : "Y",
                         "dir": "wdnn",
                         "config": "N"
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

####(2) 버전 생성 ####
resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/' + nn_id + '/version/',
                 json={
                     "nn_def_list_info_nn_id": "",
                     "nn_wf_ver_info": "test version info",
                     "condition": "1",
                     "active_flag": "Y"
                 })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

모든 네트워크가 공통적으로 사용하는 기능으로 비지니스를 정의하고 해당 비지니스에서 어떤 아키택쳐를 사용하고 어떤 파이프라인을 사용할 것인가에 따라서 버전을 정의할 수 있다. 상세한 정의 내용은 아래와 같다.
-nn_id : Neural Network ID
-biz_cate : Business 대분류
-biz_sub_cate : Business 소분류
-nn_title : Neural Network Title
-nn_desc : Neural Network Description
-use_flag : 사용여부
-dir : 문제유형
-config : Custom 여부

APIs – Create Graph Flow

# Work Flow 틀을 구성하도로고 지시한다. (정해진 틀을 강제로 생성)
resp = requests.post('http://' + url + '/api/v1/type/wf/target/init/mode/simple/' + nn_id +'/wfver/1/',
                     json={
                         "type": 'seq2seq_csv'
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

Simple Type 으로 정해진 그래프 플로우를 강제로 생성합니다.  위의 경우에는 csv type 의 데이터를 받아서 seq2seq 로 처리하는 플로우를 만들겠다로 이해하시면 됩니다.

APIs – Upload local data

import os

return_dict = {}
return_dict['test'] = open('../../data/seq2seq.csv', 'rb')

resp = requests.post('http://' + url + '/api/v1/type/wf/state/framedata/src/local/form/raw/prg/source/nnid/'+nn_id+'/ver/1/node/data_csv_node/',
                     files = return_dict)

data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

간단하게 로컬 데이터를 업로드하여 훈련에 사용한다.

APIs – Data Configuration

resp = requests.put('http://' + url + '/api/v1/type/wf/state/framedata/src/local/form/raw/prg/source/nnid/'+nn_id+'/ver/1/node/data_csv_node/',
                     json={
                         "type": "csv",
                         "source_server": "local",
                         "source_sql": "all",
                         "preprocess":  "none"
                     })

데이터를 로딩하기 위한 파라메터를 세팅한다.

APIs – Data Feeder Configuration

# (2) Network 에 데이터를 Feed하는 Node 의 속성을 정의 
resp = requests.post('http://' + url + '/api/v1/type/wf/state/pre/detail/feed/src/frame/net/seq2seq/nnid/'+nn_id+'/ver/1/node/feed_fr2seq/',
                     json={
                         "encode_column" : "encode",
                         "decode_column" : "decode",
                         "encode_len" : 10,
                         "decode_len" : 10,
                         "preprocess": "mecab",
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

데이터를 어떻게 이해하고 가공하여 신경망 훈련에 사용할 것인지 지정한다.

-encode_column : Csv 파일에서 Encode 에 사용할 컬럼 명
-decode_column : Csv 파일에서 Decode 에 사용할 컬럼 명
-max_sentence_len : 문장의 길이를 최대 어디까지 인지할 것인지 지정
-preprocess : 사용할 Pos Tagger 를 지정 (mecab, kkma, twiter 등)

APIs – Network Configuration

# update source_info
resp = requests.put('http://' + url + '/api/v1/type/wf/state/netconf/detail/seq2seq/nnid/'+nn_id+'/ver/1/node/netconf_node/',
                     json={
                         "encoder_len" : 10,
                         "decoder_len" : 10,
                         "encoder_depth" : 2,
                         "decoder_depth" : 2,
                         "cell_type" : "lstm",   #vanila, lstm, gru
                         "cell_size" : 500,
                         "drop_out" : 0.8,
                         "word_embed_type" : "onehot",   #w2v, onehot
                         "word_embed_id" : "",
                         "vocab_size" : 200,
                         "batch_size" : 74,
                         "iter" : 100,
                         "early_stop" : 0.9,
                         "learning_rate" : 0.001
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

Seq2Seq 알고리즘을 사용하기 위한 파라메터를 지정한다.

-encoder_len : 인코더 부분의 길이 지정
-decoder_len : 디코더 부분의 길이 지정
-encoder_depth : 인코더 Hidden Layer 깊이
-decoder_depth : 디코더 Hidden Layer 깊이
-cell_type : vanila, lstm, gru
-cell_size : cell 의 Vector size
-drop_out : Train 시 Drop Out Rate
-word_embed_type : onehot encoder or word2vector를 사용할 것
-word_embed_id : Word2Vector인 경우 사용한 기 훈련된 Network ID 를 지정해야 함
-batch_size : 한번에 훈련할 데이터 건수
-iter : 반복해서 훈련할 횟수
-early_stop : 지정횟수 이전에 훈련을 종료하기 위한 적중률 기준
-learning_rate : Weight 값 갱신시 사용한 Hyper Parameter

APIs – Run Train

resp = requests.post('http://' + url + '/api/v1/type/runmanager/state/train/nnid/'+nn_id+'/ver/1/')
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

지금까지 정의한 파이프라인을 실행한다.

APIs – Predict Service

resp = requests.post('http://' + url + '/api/v1/type/service/state/predict/type/seq2seq/nnid/'+nn_id+'/ver/active/',
                     json={"input_data" : "[회의] 를 [이름] [이름] 참석자로 예약해줘" , "num": 0, "clean_ans":True}
                     )
data = json.loads(resp.json())
print("evaluation result(7) : {0}".format(data))
evaluation result(2) : [['@', '2/SN', 'SF'], ['-1', '-1', '-1'], ['-1', '-1', '-1'], ['-1', '-1', '-1']]

 

TensorMSA Guide – Word2Vector

Word2Vec for word representation

concept of this algorithm

기본적으로 컴퓨터가 어떤 단어에 대해 인지할 수 있게 하기 위해서는 수치적인 방식으로 단어를 표현할 수 있어야 한다. 그러나 앞서 말했듯이, 수치화를 통해 단어의 개념적 차이를 나타내기가 근본적으로 힘들었다. 이 한계를 극복하기 전의 NLP는 ‘one-hot encoding’ 방식을 많이 사용했다. 예를 들어, 내가 어떤 단어들이 있는지에 대한 단어 n개짜리 ‘사전’ (Dictionary)이 있다고 해보자. 이 때, 어떤 단어를 표현하기 위해서 길이 n짜리 벡터를 하나 만들고, 그 단어가 해당되는 자리에 1을 넣고 나머지 자리들에는 0을 넣는 것이다. 사전이 [감자, 딸기, 사과, 수박] 이라면 사과를 표현하는 벡터는 [0, 0, 1, 0] 이 되는 식이다.
Naive Bayes를 이용한 스팸 분류기가 이 방법을 사용하는 전형적인 예시라고 생각할 수 있겠다. 단어 자체를 벡터화한 것은 아니지만, 이 경우 이메일 전체를 보면서 어떤 단어가 있으면 1, 없으면 0으로 나타내는 식으로 이메일 하나에 대한 벡터를 만든다. 이 방식은 당시에는 나름 좋은 성능을 내었고, 지금까지도 사용하는 사람들이 있지만 컴퓨터 자체가 ‘단어가 본질적으로 다른 단어와 어떤 차이점을 가지는 지 이해할 수가 없다’ 는 아주 큰 단점이 존재한다.
이러한 단점을 존재하기 위해 연구자들은 단어 자체가 가지는 의미 자체를 다차원 공간에서 ‘벡터화’ 하는 방식을 고안하게 되었다. 단어의 의미 자체를 벡터화할 수 있게 된다면, 기본적으로 이것을 사용해서 할 수 있는 일들이 굉장히 많아진다.
그렇다면, ‘어떻게 각 단어를 벡터화해야 하는가?’ 에 대한 문제가 관건이 될 것이다. 놀랍게도 이렇게 단어를 벡터화하는 방법 자체는 정말 예전부터 이루어져왔던 연구이다. 현재 ‘CBOW’와 ‘Skip-gram’ 이라는 아키텍쳐로 다시 한번 발전하여 현재 word2vec의 모양새로 이어지게 되었다.

Word2Vec 는 기본적으로 유사한 의미를 갖는 단어는 비슷한 문맥에서 등장한다는 이론을 바탕에 두고 있다. 예를들면 <음식>을 먹는다. 형태의 문맥이 있다고 하면 “사과를 먹는다. 포도를 먹는다. 밥을 먹는다. ” 모든 문장은 먹는다와 근처에서 발생하게 된다. 이러한 특징을 바탕으로 백터를 훈련하면 유사한 의미를 갖는 단어들은 유사한 백터 분포를 갖는다라고 말한다.  Word Embedding 기법은 모든 자연어 처리 알고리즘에 있어서 가장 중요한 전처리 작업으로 최근에는 전체 도큐먼트의 발생 빈도를 고려하는 Glove나 Ngram 방법을 접목한 FastText 등이 주로 사용되고 있으며, 순수한 Word2Vector 알고리즘 자체는 잘 사용하지 않는 추세이긴 하지만 매우 중요한 개념이라는 것은 변함 없다.

APIs – Define Neural Network

import requests
import json, os

url = "{0}:{1}".format(os.environ['HOSTNAME'] , "8000")

nn_id = "w2v0014"
nn_wf_ver_id ="1"

# Seq - 1
resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/' + nn_id + '/',
                     json={
                         "biz_cate": "MES",
                         "biz_sub_cate": "M60",
                         "nn_title" : "test",
                         "nn_desc": "test desc",
                         "use_flag" : "Y",
                         "dir": "word2vec",
                         "config": "N"
                     })
data = json.loads(resp.json())
print("1.evaluation result : {0}".format(data))

resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/' + nn_id + '/version/',
 json={
 "nn_def_list_info_nn_id": "",
 "nn_wf_ver_info": "test version info",
 "condition": "1",
 "active_flag": "Y"
 })
data = json.loads(resp.json())
print("2.evaluation result : {0}".format(data))

네트워크를 정의하고 버전 정보를 정의하는 작업은 공통적인 작업이다.
nn_id : Neural Network ID
biz_cate : Business 대분류
biz_sub_cate : Business 소분류
nn_title : Neural Network Title
nn_desc : Neural Network Description
use_flag : 사용여부
dir : 문제유형
config : Custom 여부

APIs – Initialize Graph Flow

resp = requests.post('http://' + url + '/api/v1/type/wf/target/init/mode/simple/'+ nn_id + '/wfver/1/',
                     json={
                         "type": "word2vec"
                     })
data = json.loads(resp.json())
print("3.evaluation result : {0}".format(data))

그래프 플로우를 초기화 하고 파이프라인 구조를 생성하는 작업이다.
심플타입으로 진행하기 때문에 정해진 파이프라인이 강제로 생성되며, 사용자가 정의한 파이프 라인을 읽어오는 기능, 신규 파이프라인 생성 기능 등 기타 기능을 제공한다.

APIs – Data Upload

return_dict = {}
return_dict['test'] = open('../../data/novel_1.txt', 'rb')

resp = requests.post('http://' + url + '/api/v1/type/wf/state/textdata/src/local/form/raw/prg/source/nnid/'+nn_id+'/ver/1/node/data_node/',
                     files = return_dict)

data = json.loads(resp.json())

훈련하고자 하는 데이터를 로컬에서 업로드한다.

APIs – Data Configuration

resp = requests.put('http://' + url + '/api/v1/type/wf/state/textdata/src/local/form/raw/prg/source/nnid/'+ nn_id + '/ver/1/node/data_node/',
                     json={
                         "source_server": "local",
                         "source_sql": "all",
                         "max_sentence_len" : 10,
                         "preprocess":  "None",
                     })
data = json.loads(resp.json())
print("5.evaluation result : {0}".format(data))

데이터 소스에 대한 정의로 로컬 파일을 사용하는 경우 별다른 설정은 사실상 필요하지 않다. 타입만 로컬만 넣어 주면 된다. 실제 소스 서버를 명시하는 경우 접속정보 등을 바탕으로 해당 서버에서 데이터를 ETL 작업을 수행한 후 후속 프로세스를 수행하지만사전에 데이터를 업로드해 놓은 상태이기 때문에 실제 ETL  작업은 Skip 된다.

APIs – Word2Vector configuration

resp = requests.put('http://' + url + '/api/v1/type/wf/state/netconf/detail/w2v/nnid/' + nn_id + '/ver/' + nn_wf_ver_id + '/node/netconf_node/',
                     json={
                        "window_size" : 5,
                        "vector_size" : 100,
                        "batch_size" : 100,
                        "iter" : 5,
                        "min_count" : 1,
                        "preprocess" : "None"
                     })
data = json.loads(resp.json())
print("9.evaluation result : {0}".format(data))

Word2Vector 알고 리즘을 수행하기 위한 하이퍼 파라메터를 정의한다.
– WindowSize : 문장내에서 기준단어에서 어느정도 범위까지 탐색할 것인지
– min_count : Dict 에 등록하기 위한 최소 발생 빈도
– preprocess : mecab 등 lexical Analysis 를 수행 후 훈련 할 수 있다

APIs – Execute train

resp = requests.post('http://' + url + '/api/v1/type/runmanager/state/train/nnid/'+nn_id+'/ver/'+nn_wf_ver_id+'/')
data = json.loads(resp.json())
print("14.evaluation result : {0}".format(data))

위와 같이 정의된 프로세스에 따라 훈련을 실행한다.

APIs – Inference Test

resp = requests.post('http://' + url + '/api/v1/type/service/state/predict/type/w2v/nnid/' + nn_id + '/ver/active/',
                     json={
                         "type": "vector",
                         "val_1":["관심"],
                         "val_2":[]
                        }
                     )
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

아래 예와 같이 단순히 해당 단어에 대한 백터를 출력할 수도 있고, 해당 단어와 백터간의 유사도가 높은 단어를 찾거나 해당 단어의 인덱스를 찾는 등 다양한 기능을 type 을 바꿔서 실행 할 수 있다.  아래는 “관심”이라는 단어에 대한 백터 출력 결과

evaluation result : [[-0.020525163039565086, 0.04692612960934639, 0.05030370131134987, -0.012286012060940266, -0.0037592644803225994, -0.030842192471027374, 0.01674736849963665, -0.054970309138298035, -0.08577895909547806, 0.1255255788564682, -0.02777358889579773, 0.03695392981171608, 0.044458433985710144, -0.007728930562734604, 0.08414790034294128, 0.058133892714977264, 0.04944032430648804, 0.01613127626478672, -0.040425531566143036, 0.004654400981962681, -0.03939636051654816, -0.0019560905639082193, -0.009940450079739094, -0.06451232731342316, 0.0569504015147686, -0.014093209989368916, 0.09073378145694733, 0.09947685152292252, 0.006592847406864166, -0.008854197338223457, 0.12631729245185852, 0.04848669841885567, 0.06378431618213654, -0.04620460793375969, 0.008887161500751972, -0.030518099665641785, -0.01516534760594368, 0.044853076338768005, -0.05782085284590721, -0.08027826994657516, 0.014025202952325344, 0.044981539249420166, 0.004896924365311861, -0.028371311724185944, -0.05109790712594986, -0.07373176515102386, -0.10512163490056992, 0.08453123271465302, -0.013461959548294544, 0.021848665550351143, -0.008970526047050953, -0.04527459293603897, -0.017793165519833565, 0.01753085106611252, 0.02533436194062233, 0.035888779908418655, 0.026869671419262886, 0.07286906987428665, -0.09840452671051025, 0.08030493557453156, 0.020363574847579002, 0.05747954919934273, -0.04360934719443321, -0.007815506309270859, 0.05689325928688049, 0.05190270394086838, -0.018432151526212692, 0.009586657397449017, -0.08955849707126617, -0.015274081379175186, 0.06507446616888046, -0.04223490506410599, -0.047457266598939896, -0.05493870750069618, 0.03036578930914402, -0.012590847909450531, 0.10204384475946426, -0.07904526591300964, -0.0001657690154388547, -0.09601821005344391, 0.018075214698910713, 0.05400990694761276, 0.0034184586256742477, 0.002286079805344343, 0.02704218029975891, -0.044543638825416565, 0.07505488395690918, 0.04921184480190277, -0.05573805049061775, 0.0022162178065627813, 0.03275308758020401, -0.11974544078111649, 0.0004437191819306463, -0.01948268711566925, 0.03747180849313736, 0.006018102169036865, -0.02106001414358616, -0.0002090744092129171, -0.01121156569570303, 0.012898841872811317]]

 

TensorMSA Guide – AutoEncoder

Use AutoEncoder for Anomaly Detection

concept of this algorithm

AutoEncoder 를  정형 데이터 적용하기 위한 알고리즘을 제공한다. AutoEncoder는  Unsupervised 형태의 훈련 알고리즘으로 별도의 레이블 값 없이 Encoder 와 Decoder 형태의 모델로 인풋 데이터와 같은 아웃풋을 다시 생성해 내는 것을 목표로 하는 알고리즘이다.Anomlay Detection 의 경우 데이터의 분포가  매우 불균형한 바이너리 클레시피케이션 문제를 풀기 위한 방법의 하나이다. AutoEncoder 로  Anomlay Detection 문제를 접근 할 수 있는데, 풍부한 데이터 레이블을 기준으로 훈련하여  해당 데이터를 잘 설명 할 수 있도록 훈련하여 자신의 데이터를 잘 복월할 수 있도록 훈련한다. 모델을 사용시에는 Feed Worwarding 하여 Decoder 에서 복원된 데이터와 입력한 데이터의 백터간의 유사도 차이가 기준치보다 복원을 잘 못할 경우 비정상 데이터로 판별하는 방법으로 사용할 수 있다.

APIs – Define Neural Network

import requests
import json, os

nn_id = 'nn992798' 

####(1) 네트워크 생성 ####
resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/' + nn_id + '/',
                     json={
                         "biz_cate": "MES",
                         "biz_sub_cate": "M60",
                         "nn_title" : "test",
                         "nn_desc": "test desc",
                         "use_flag" : "Y",
                         "dir": "autoencoder_csv",
                         "config": "N"
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

####(2) 버전 생성 ####
resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/' + nn_id + '/version/',
                 json={
                     "nn_def_list_info_nn_id": "",
                     "nn_wf_ver_info": "test version info",
                     "condition": "1",
                     "active_flag": "Y"
                 })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

신경망에 대한 정의를 하는 작업은 모든 종류의 알고리즘이 동일하다.

APIs – Define Graph Flow

# Work Flow 틀을 구성하도로고 지시한다. (정해진 틀을 강제로 생성)
resp = requests.post('http://' + url + '/api/v1/type/wf/target/init/mode/simple/' + nn_id +'/wfver/1/',
                     json={
                         "type": 'autoencoder_csv'
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

심플 타입으로 그래프 플로우를 생성하는 경우 별도의 세팅은 필요하지 않다

APIs – upload train file

return_dict = {}
return_dict['test'] = open('../../data/seq2seq_mansearch_3.csv', 'rb')

resp = requests.post('http://' + url + '/api/v1/type/wf/state/framedata/src/local/form/raw/prg/source/nnid/'+nn_id+'/ver/1/node/datasrc/',
                     files = return_dict)

data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

훈련에 사용할 데이터를 간단하게 로컬에서 REST API 를 통해 업로드 가능하다

APIs – data parameter set up

resp = requests.put('http://' + url + '/api/v1/type/wf/state/framedata/src/local/form/raw/prg/source/nnid/'+nn_id+'/ver/1/node/datasrc/',
                     json={
                         "type": "csv",
                         "source_server": "local",
                         "source_sql": "all",
                         "preprocess":  "none",
                     })

데이터를 이해하기 위한 (소스정보, 접속정보 등)을 정의한다.
로컬 파일이기 때문에 별도의 ETL 을 위한 설정은 필요하지 않다.

APIs – data feeder parameter set up

resp = requests.post('http://' + url + '/api/v1/type/wf/state/pre/detail/feed/src/frame/net/autoencoder/nnid/'+nn_id+'/ver/1/node/feed_train/',
 json={ 
 "encode_column" : ["PRODUCT_CD","CUR_FAC_OP_CD","MC_NO","CAST_STR_NUM","SM_STEEL_GRD","CC_UNCOND_SF_MTH"],
 "vocab_size" : 10,
 "preprocess": "frame",
 "embed_type" : 'onehot'
 })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

데이터를 이해하기 위한 정보를 정의한다.
-encode_column : Data Frame 에서 분석에 실제로 사용하고자 하는 컬럼을 지정한다.
-vocab_size : 카테고리형 데이터는 자동으로 벡터로 변환한다. 그때 최대 버킷사이즈
-embed_type : 카테고리 데이터 임배딩시 백터 표현 방법

APIs – network  parameter set up

resp = requests.put('http://' + url + '/api/v1/type/wf/state/netconf/detail/autoencoder/nnid/' + nn_id + '/ver/1/node/netconf_node/',
                     json={
                        "learning_rate" : 0.01,
                        "iter" : 10,
                        "batch_size" : 10,
                        "examples_to_show" : 10,
                        "n_hidden" : [200, 100] 
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

오토인코더의 경우 기본적인 하이퍼 파라메터 외에 히든 사이즈가 중요하게 생각되는데 간단하게 Array 형태로 지정하여 사용할 수 있다. 배열의 사이즈가 히든사이즈의 Depth 이며 그 값이 각 레이어의 퍼셉트론의 수가 되겠다.

APIs – Run Train

resp = requests.post('http://' + url + '/api/v1/type/runmanager/state/train/nnid/'+nn_id+'/ver/1/')
data = json.loads(resp.json())

print("evaluation result : {0}".format(data))

지금까지 정의한 파이프라인에 따라 Job을 실행한다.

TensorMSA Guide – CharCNN

Use CharCNN for train model

Concept of this algorithm

워드 임베딩이 인기를 끌고 그 성능 또한 검증된 이후, 단어 결합이나 n-gram으로부터 높은 수준의 피처를 추출해내는 효율적인 함수의 필요성이 증대됐다. 이러한 추상화된 피처들은 감성분석, 요약, 기계번역, 질의응답(QA) 같은 다양한 NLP 문제에 사용될 수 있다. 콘볼루션 신경망은 컴퓨터 비전 분야에서 뛰어난 성능으로 인해 자연스런 선택이었다(Krizhevsky et al., 2012; Sharif Razavian et al., 2014; Jia et al., 2014). 문장 모델링에서 CNN을 활용하는 것은 Colobert and Weston(2008)로 거슬러 올라간다. 이 연구는 다범주 예측 결과를 출력하기 위해 multi-task learning을 사용했다. 품사태깅, 청킹, 개체명인식, 의미역결정, 의미적으로 유사한 단어 찾기, 랭귀지모델 같은 NLP 과제 수행을 위해서다. 참조테이블(look up table)은 각 단어를 사용자가 정의한 차원의 벡터로 변형해 사용된다. 따라서 n개의 단어로 이뤄진 입력문장 {s1,s2,..,sn}은 참조테이블을 활용해 벡터들의 나열인 {ws1,ws2,…,wsn}으로 변환된다. (그림 5)

이는 학습 과정에서 단어 벡터(가중치)가 학습되는 초기 단어 임베딩 기법의 아이디어로 생각할 수 있다. Collobert et al. (2011)은 넘쳐나는 NLP 문제를 해결하기 위해 그의 이전 업적을 확장해 일반적인 CNN 기반의 프레임워크를 제안했다. Colobert and Weston(2008)과 Collobert et al. (2011)은 NLP 연구자들 사이에 CNN이 큰 인기를 끌도록 촉발시켰다. CNN이 이미 컴퓨터 비전 태스크에서 괄목할 만한 성능을 보인 상황에서 사람들이 CNN의 성능을 믿는 것은 쉬웠다. CNN은 문장의 잠재적인 semantic represention을 만들어내기 위해 입력 문장으로부터 핵심적인 n-gram 피처를 추출하는 능력을 갖고 있다. 이 분야의 선구적인 업적은 Collobert et al. (2011), Kalchbrenner et al. (2014), Kim(2014)이다(본 블로그). 이들은 후속 연구에서 CNN 기반의 네트워크가 크게 확산되도록 했다.

APIs – Define Neural Networks

import requests
import json, os

nn_id = 'wcnntest97' 

####(1) 네트워크 생성 ####
resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/' + nn_id + '/',
                     json={
                         "biz_cate": "MES",
                         "biz_sub_cate": "M60",
                         "nn_title" : "test",
                         "nn_desc": "test desc",
                         "use_flag" : "Y",
                         "dir": "purpose?",
                         "config": "N"
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

####(2) 버전 생성 ####
resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/' + nn_id + '/version/',
                 json={
                     "nn_def_list_info_nn_id": "",
                     "nn_wf_ver_info": "test version info",
                     "condition": "1",
                     "active_flag": "Y"
                 })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

신경망을 정의하는 작업은 모든 종류의 알고리즘이 동일하게 사용한다.

APIs – Set Up Graph

# Work Flow 틀을 구성하도로고 지시한다. (정해진 틀을 강제로 생성)
resp = requests.post('http://' + url + '/api/v1/type/wf/target/init/mode/simple/' + nn_id +'/wfver/1/',
                     json={
                         "type": 'wcnn'
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

Graph Flow 를 정의하는 작업을 수행한다. 여기서는 정해진  Simple Flow  를 생성한다

APIs – Data Upload

import os

return_dict = {}
return_dict['test'] = open('/hoya_model_root/aug/pattern.csv', 'rb')

resp = requests.post('http://' + url + '/api/v1/type/wf/state/framedata/src/local/form/raw/prg/source/nnid/'+nn_id+'/ver/1/node/data_node/',
                     files = return_dict)

data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

훈련하고자 하는 데이터를 업로드 합니다.

APIs – Data Configuration

# (1) Train Data Node 의 속성을 정의
# 어디서 Source 를 어떻게 가지고 올것인지 파라메터 정의 
resp = requests.put('http://' + url + '/api/v1/type/wf/state/framedata/src/local/form/raw/prg/source/nnid/'+nn_id+'/ver/1/node/data_node/',
                     json={
                         "type": "csv",
                         "source_server": "local",
                         "source_sql": "all",
                     })

# 전처리는 어떤 것을 할지 정의
resp = requests.put('http://' + url + '/api/v1/type/wf/state/framedata/src/local/form/raw/prg/pre/nnid/'+nn_id+'/ver/1/node/data_node/',
                      json={
                          "preprocess":  "none",
                      })
# 전처리가 완료된 데이터는 어디에 저장을 할지 
resp = requests.put('http://' + url + '/api/v1/type/wf/state/framedata/src/local/form/raw/prg/store/nnid/'+nn_id+'/ver/1/node/data_node/',)

data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

데이터를 어디서 어떻게 가지고 올 것인지 정의합니다.

APIs – Data Feeder Configuration

# (2) Network 에 데이터를 Feed하는 Node 의 속성을 정의 
resp = requests.post('http://' + url + '/api/v1/type/wf/state/pre/detail/feed/src/frame/net/wcnn/nnid/'+nn_id+'/ver/1/node/pre_feed_train/',
                     json={
                         "encode_column" : "encode",
                         "decode_column" : "decode",
                         "channel" : 1,
                         "encode_len" : 15,
                         "preprocess": "none",
                         "vocab_size" : 100,
                         "char_encode" : False, 
                         "char_max_len" : 5,
                         "lable_size" : 22, #총 label 수에서 3개 더해야함 
                         "embed_type" : 'onehot'
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

데이터를 어떤 형태로 이해하고 가공해서 신경망에 제공할 것인지를 정의합니다

APIs – Neural Network configuration

resp = requests.put('http://' + url + '/api/v1/type/wf/state/netconf/detail/wcnn/nnid/'+nn_id+'/ver/1/node/netconf_node/',
                     json={
                         "param":{"epoch": 200 #Train Iteration
                                  ,"traincnt": 1
                                  ,"batch_size":64
                                  ,"predictcnt": 10
                         },
                         "config": {"num_classes":22,
                                    "learnrate": 0.001,
                                    "eval_type":"category",
                                    "optimizer":"AdamOptimizer" 
                                     }
                         ,"layers": 
                                    {"active": "relu",
                                     "cnnfilter": [2, 3, 4, 2, 3], 
                                     "droprate": "0.5",
                                    }
                         ,"out": {
                                    "active": "softmax",
                                    "padding": "SAME"
                                 }
                         ,"labels":[]
                        })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

신경망의 구조를 정의하고, 필요한 하이퍼 파라메터를 정의합니다.

APIs – Run Train

# Run All Workflow
resp = requests.post('http://' + url + '/api/v1/type/runmanager/state/train/nnid/'+nn_id+'/ver/1/')
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

지금까지 정의한 데이터, 파라메터, 그래프 플로우를 바탕으로 실제 훈련을 수행합니다.

APIs – Predict Service

expected_intent_no = "1"
intent_array= [ "tagname 의 tagsuper"  ]

for intent in intent_array :    
    resp = requests.post('http://' + url + '/api/v1/type/service/state/predict/type/wcnn/nnid/'+nn_id+'/ver/active/', json={"input_data" : intent })
    data = json.loads(resp.json())
    print( intent + "\t\t\t\t\t evaluation result("+ expected_intent_no + ") : {0}".format(data))

훈련이 끝나면 위와 같은 형태로 예측 서비스를 사용할 수 있습니다.

TensorMSA Guide – Residual Neural Network

Use Residual Neural Network

Concept of this algorithm

ILSVRC의 winning 네트워크들의 추세를 봐도 알수 있는 사실이지만 네트워크의 레이어를 층층이 쌓아서 깊게 구현하면 더 좋은 성능을 낸다. 하지만 레이어를 깊게 쌓는 것이 항상 좋은 결과를 낼 까? 네트워크를 깊게 쌓으면 gradient vanishing/exploding 현상이 발생할 수 있기 때문에 네트워크는 학습의 초기 단계부터 saturated되어 버릴 우려가 있다. 하지만 이 문제는 BN, Xavier 초기화(PReLU-net 참조) 등을 이용하면 수십개의 레이어까지는 해결이 된 상태이다. 하지만 네트워크가 더 깊어지면 degradation 이라 불리는 문제가 발생한다. 네트워크는 깊어지는데 정확도는 saturated 되는 현상이다. 사실 이는 overfit을 생각하면 당연하다고 생각 할 수 있지만 놀랍게도 degradation은 overfit에 의한 것이 아닌 애초에 트레이닝 에러 자체가 높아지는 현상이다.
아래 그림은 degradation의 예시를 보여준다.

일반적인(Plain) 네트워크는 위와 같은 레이어 구조를 가진다. 이 때 두 레이어를 거친 후 매핑된 결과는 H(x) 로 표현하며 아래와 같이 표현 H(x)=F(x,{Wi}) 여기서 위 네트워크는 2개의 레이어를 가지고 있기 때문에 F=W2σ(W1x) 이다. x 는 입력 벡터이며 σ 는 ReLU activation을 의미한다. 식을 간단히 쓰기 위해서 바이어스는 생략하였다. residual 네트워크는 일반적인 네트워크와는 달리 몇개의 레이어 (여기에서는 2개의 레이어)를 건너 뛴 shortcut을 활용한 것이 특징이다. H(x) 는 H(x)=F+x 으로 표현할 수 있다.

APIs – Single Train Process

resp = requests.put('http://' + url + '/api/v1/type/wf/state/netconf/detail/renet/nnid/'+nn_id+'/ver/'+wf_ver_id+'/node/netconf_node/',
                 json={
                     "param":{"traincnt": 1
                              ,"epoch": 1
                              ,"batch_size":200
                              ,"predictcnt": 2
                              ,"predictlog": "N" 
                              ,"augmentation": "Y"
                     },
                     "config": {"num_classes":1,
                                "learnrate": 0.001,
                                "layeroutputs":18, #18, 34, 50, 101, 152, 200
                                "optimizer":"adam", #
                                "eval_type":"category"
                                 }
                     ,"labels":[]
                    })

resp = requests.put('http://' + url + '/api/v1/type/wf/state/imgdata/src/local/form/file/prg/source/nnid/'+nn_id+'/ver/'+wf_ver_id+'/node/datasrc/',
                     json={"preprocess": {"x_size": 32,
                           "y_size": 32,
                           "channel":3,
                           "filesize": 1000000,
                           "yolo": "n"}
            })
dataconf = json.loads(resp.json())

훈련하고자 하는 데이터에 대한 속성과 Residual Net의 하이퍼파라메터를 정의하는 작업으로 AutoML 형태가 아니기 때문에 정해진 값을 세팅하는 형태로 진행도고 있다.
특성있는 파라메터로는 아래와 같은 예들이 있다.
1. augmentation : 데이터 불리기 여부 (Rgb, Rotation, Cropping 등 복합적 사용)
2. layeroutputs : ResNet Depth (18, 34, 50, 101, 152, 200 중에 선택)
3. channel : 3인 경우 컬러, 1인 경우 흑백으로 판단
4. x_size, y_size : 이미지 전처리 사이즈 (동일한 사이즈로 변환 해주어야 함)
5. yolo : Object Detction 을 통한 Cropping 적용 여부

resp = requests.post('http://' + url + '/api/v1/type/runmanager/state/train/nnid/'+nn_id+'/ver/'+wf_ver_id+'/')
data = json.loads(resp.json())

정의된 세팅 값에 맞춰서 훈련을 시작합니다. 훈련을 시작하면 정해진 Graph Flow에 맞춰서 작업이 자동으로 실행되고 주어진 데이터를 가공하고, 훈련하고, 평가하는 프로세스가 실행됩니다.

APIs – Predict

files = {'files000001':  open('/home/dev/hoyai/demo/data/airplane/1air.jpg','rb')
    ,'files000002':  open('/home/dev/hoyai/demo/data/airplane/2air.jpg','rb')}
resp = requests.post('http://' + url + '/api/v1/type/service/state/predict/type/renet/nnid/'+nn_id+'/ver/'+wf_ver_id+'/',
                     files=files)

예측하고자 하는 파일을 서버로 업로드하여 예측결과를 리턴 받습니다.

FileName = 2air.jpg
['Bolt', 'Air Filter']
[100.0, 0.0]

FileName = 1air.jpg
['Bolt', 'Air Filter']
[100.0, 0.0]

 

Example – Jupyter

http://IP:8888/notebooks/chap20_hoayi_api_guide/02.image/04_resnet_train_predict.ipynb

TensorMSA Guide – AutoML

Use AutoML for train model

Concept

신경망을 훈련하는데 있어서 최적의 성능을 갖는 하이퍼 파라메터의 조합을 찾는 일은 매우 중요하지만 매우 반복적이며, 많은 시간이 소요되는 작업이다. 우리는 이러한 작업을 사용자의 개입없이 시스템상에서 자동으로 할 수 있도록 하기 위해서 Hyper Parameter Random Search 와 Approximation 을 위한 Genetic Algorithm 그리고 빠른 연산을 위한 복수의 GPU 활용을 위한 분산처리까지 복합적으로 사용하여 사용자의 일을 최소화 하고 있습니다. 실제로 사용자가 해야할 일은 데이터에 대한 인사이트를 가지오 데이터를 정의하고 사용할 알고리즘과 필요하다면 하이퍼 파라메터의 범위를 조정하는 정도의 작업만하면 나머지는 우리의 프레임웍이 자동으로 처리하여 줍니다.

Hyper Parameter Random Search

우리가 하이퍼 파라메터를 탐색하는 방법은 크게 3가지로 나눌수가 있는데, 첫번째는 사용자가 자신의 노하우와 감을 가지고 파라메터를 수작업으로 탐색하는 방법. 두번째는 그리드 서치 방식으로 메트릭스를 구성하고 자동으로 탐색하는 방법. 마지막으로 랜덤으로 하이퍼 파라메터를 탐색하는 방법이 있다. 2012년에 발표된 Random Search for Hyper-Parameter Optimization 을 보면 히든 레이어가 3개 이하인 경우 Grid Search 에 비해서 무조건 월등한 성능을 보여주며, 그보다 복잡한 신경망의 경우 성능이 떨어져 비슷비슷한 결과를 보여준다고 한다. 우리는 랜덤 서치 방식을 채택하여 AutoML에 접목하였다.

Genetic Algorithm

하이퍼 파라메터를 전부 대입하여 딥러닝을 훈련하여 최선의 하이퍼 파라메터를 찾는 다고 생각하면 얼마나 많은 리소스가 소요될지 알 수가 없다. 딥러닝은 기존의 머신러닝 알고리즘 대비 훨씬더 많은 리소스가 필요한 알고리즘으로 전수조사를 한다는 것은 굉장히 비효율적인 접근이 될 것이다. 예를들어 5개의 경우의 수를 갖는 5개의 하이퍼 파라메터를 전수조사로 튜닝을 한다고 생각해보자. 한번의 훈련 및 테스트를 진행하기 위하여 1시간이 소요된다고 생각해 보자. 그러면 전체적으로 소요되는 시간은 5*(5승)*1시간이 될 것이다. 그러면 유전자 알고리즘을 적용한다고 생각해보자. 우리가 수행하려고하는 유전자 알고리즘은 총 5세대, 세대 구성원은 5, 각 세대에서 살아남는 구성원은 2라고 생각해보자. 그러면 총 연산 소요 시간은 5 + 3*4 가 된다. 전수조사에서 찾는 최고의 하이퍼파라메터 셋을 찾을 수는 없지만 그에 근사한 최적의 하이퍼 파라메터를 찾을 수 있다고 기대한다면, 훨씬더 적은 자원을 투자하고 원하는 결과를 얻을 수 있을 것이다.

Gpu Clustering

마지막으로 복수의 GPU 서버를 사용하여 전체 연산 시간을 줄이고자 하였다. 이는 Genetic Algorithm 이 동작하는 방식과 굉장히 효과적으로 접목할 수 있는 개념으로 우리는 GPU 서버의 Job 들을 효과적으로 관리하기 위하여 Celery 라는 솔루션을 내부적으로 연동하고 있다.

APIs – Business Define

import requests
import json, os

nn_id = 'auto_wcnn037'  # put some key value you want to test

####(1) 네트워크 생성 ####
resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/' + nn_id + '/',
                     json={
                         "biz_cate": "MES",
                         "biz_sub_cate": "M60",
                         "nn_title" : "test",
                         "nn_desc": "test desc",
                         "use_flag" : "Y",
                         "dir": "wcnn",
                         "automl_parms" : {},
                         "config": "N"
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

비지니스를 정의하는 작업은 싱글로 수행을 할때와 동일하게 사용자가 정의해주어야 할 필요가 있다. 비지니스를 정의하는 API 는 싱글로 실행할 때와 다른점이 없다.
이때 주의하여야 할 파라메터는 dir Flag 로 어떤 알고리즘을 사용하고자 하는지 지정하는 작업으로 어떤 파라메터를 정의했느냐에 따라 다른 알고리즘이 기동되게 된다.

APIs – See Parameter Format

resp = requests.get('http://' + url + '/api/v1/type/automl/state/rule/graph_id/wcnn/')
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

AutoML 을 사용하여 하이퍼파라메터를 자동으로 서치한다고 하더라도, 하이퍼 파라메터의 범위는 지정을 해주어야 할 필요가 있다. 그리고 정상적으로 동적하게 만들기 위해서는 알고리즘 별로 정해진 형태의 파라메터 포맷을 지정해 줄 필요가 있다. 위의 API 를 통해서 기준으로 정의되어 있는 파라메터 포맷을 조회할 수 있는데, 조심해야하는 것은 graph_id/<type> 부분에 원하는 타입을 지정해 주어야 한다는 점이다.

APIs – Set Parameter range for defined network

{"datasrc": {"type": {"auto": False, "type": "sel", "option": "imgdata"}, 
 "preprocess": {"yolo": {"auto": False, "type": "sel", "option": "N"}, 
 "x_size": {"auto": False, "type": "int", "option": 32}, 
 "y_size": {"auto": False, "type": "int", "option": 32}, 
 "channel": {"auto": False, "type": "int", "option": 3}, 
 "filesize": {"auto": False, "type": "int", "option": 1000000}}}, 
 "evaldata": {"type": {"auto": False, "type": "sel", "option": "imgdata"}, 
 "preprocess": {"yolo": {"auto": False, "type": "sel", "option": "N"}, 
 "x_size": {"auto": False, "type": "int", "option": 32}, 
 "y_size": {"auto": False, "type": "int", "option": 32}, 
 "channel": {"auto": False, "type": "int", "option": 3}, 
 "filesize": {"auto": False, "type": "int", "option": 1000000}}}, 
 "netconf_node": {"param": {"epoch": {"auto": [1, 3, 1], "type": "int", "option": None}, 
 "traincnt": {"auto": [1, 4, 2], "type": "int", "option": None}, 
 "batch_size": {"auto": [1, 2, 1], "type": "int", "option": None}, 
 "predictcnt": {"auto": False, "type": "int", "option": 5}, 
 "predictlog": {"auto": False, "type": "sel", "option": "N"}, 
 "augmentation": {"auto": False, "type": "sel", "option": "Y"}}, 
 "config": {"learnrate": {"auto": [0.0001, 0.1, 0.001], "type": "int", "option": None}, 
 "optimizer": {"auto": False, "type": "sel", "option": "adam"}, 
 "num_classes": {"auto": False, "type": "int", "option": 2}, 
 "layeroutputs": {"auto": [1, 152, 10], "type": "int", "option": 18},
 "eval_type": {"auto": False, "type": "str", "option": 'category'}}, 
 "labels": {"auto": False, "type": "list", "option": ['cat','dog']}}}

위에서 조회한 파라메터 값을 수정하여 실제 우리가 정의한 신경망에 set 을 하여준다.

APIs – Genetic Algorithm Hyperparameter

resp = requests.post('http://' + url + '/api/v1/type/automl/state/parm/nnid/' + nn_id + '/',
                     json={
                         "generation": 3,
                         "population": 3,
                         "survive" : 2
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

신경망의 하이퍼파라메터를 찾기위한 유전자 알고리즘 또한 하아퍼 파라메터를 갖게 된다. 크게 4~5가지 필요한 파라메터가 있을 수 있다.
세대수 : 몇 세대를 진화하여 최적의 하이퍼 파라메터 조합을 찾을 것인가
인구수 : 한 세대에 몇 개의 개체가 존재하는가
생존 : 한 세대에 몇개의 개체가 생존하는가
변형 : 버리는 개체중 몇 퍼센트를 뮤테이션하고 몇 퍼센트를 기존의 우성인자로 조합
클러스터 수 : 최대 사용가능한 GPU 클러스터의 수를 지정한다.

APIs – Run AutoML

resp = requests.post('http://' + url + '/api/v1/type/automl/state/train/nnid/' + nn_id + '/')
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

사전에 필요한 정보에 대한 정의 작업이 끝났으면, AutoML을 실제로 실행하여 준다.

APIs – Monitor Process

resp = requests.get('http://' + url + '/api/v1/type/automl/state/stat/nnid/' + nn_id + '/')
data = json.loads(resp.json())

print("[Best] final result of genetic process")
for raw in data['best'] : 
    print(raw)
    print('\n')
    
print("[All] all result by generations")
for idx,raw in enumerate(data['bygen']) : 
    print("===Generation : [{0}]===".format(idx))
    for idx, l in enumerate(raw) :
        print(l)
    print('\n')

Genetic Algorithm 을 실행하면 세대별로 실행이 하나씩 되는데 이 작업의 진행 정보를 위의 API 를 통해서 조회할 수 있다. 정보는 하나의 세대가 종료될 때 업데이트가 됩니다.

TensorMSA Guide – Define Neural Network

Set Up Master Configurations

모델관리 구조

TensorMSA 에서는 딥러닝 및 머신러닝의 훈련 및 서비스를 위한 데이터 및 모델을 위와 같은 구조로 관리하여 최종적으로 서비스까지 연결하고 있다. 구축하고자 하는 대상자체를 정의 – 파이프라인의 구성 및 하이퍼 파라메터 – 훈련에 따른 배치 단위 모델과 같은 구조로 관리하여 사용자가 원하는 버전을 활성화하여 서비스 할 수 있다.

등록된 신경망 리스트 확인 API

import requests
import json, os

url = "{0}:{1}".format(os.environ['HOSTNAME'] , "8000")

resp = requests.get('http://' + url + '/api/v1/type/common/target/nninfo/nnid/%/' )
data = json.loads(resp.json())
return_list = []
for row in data :
    return_list.append(row['nn_id'])
print (return_list)

현재 시스템이 등록되어 있는 딥러닝, 머신러닝 서비스 리스트를 조회할 수 있다. 조회는 자신이 권한을 가지고 있는 대상만 조회 가능하며, TensorMSA 에서 제공하는 화면을 사용할 경우 더 편하게 데이터를 조회 할 수 있다.

새로운 신경망의 정의

resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/nn00016/',
                     json={
                         "nn_id": "nn00016",
                         "biz_cate": "Category",
                         "biz_sub_cate": "Sub Category",
                         "nn_title" : "Title",
                         "nn_desc": "Description for neural network",
                         "use_flag" : "Y",
                         "dir": "type of model",
                         "config": "status flag (1,2,3) not necessary"
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

우리의 프레임웍에서 신경망의 정의라함은, 비지니스 레벨에서의 정의를 의미한다. 아이디의 경우 입력하지 않으면 랜덤 번호가 발번되며, 향후 모든 프로세스 및 서비스는 해당 아이디를 기준으로 발생하게 된다. 나머지 정보의 경우 카테고리, 서브카테고리, 제목, 설명등의 정보를 위한 항목과 서비스 여부, 사용 알고리즘, 상태값 등을 나타낸다. 이러한 생성행위는 당연히 UI/UX 통해서 제공이 되지만, 경우에 따라 서버간의 연동을 통해 자동적인 생성이 필요한 경우라면 권한을 부여 받아 해당 API를 사용할 수도 있다.

등록된 정보 확인

resp = requests.get('http://' + url + '/api/v1/type/common/target/nninfo/nnid/nn00016/')
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

위에서 등록한 정보를 위의 API 를 통해서 확인 할 수 있다.

버전 등록

resp = requests.post('http://' + url + '/api/v1/type/common/target/nninfo/nnid/nn00016/version/',
                     json={
                         "nn_def_list_info_nn_id": "",
                         "nn_wf_ver_info": "test version info",
                         "condition": "1",
                         "active_flag": "Y"
                     })
data = json.loads(resp.json())
print("evaluation result : {0}".format(data))

AutoML 을 사용하는 경우 버전 등록 과정부터 전체 과정이 자동으로 실행되기 때문에 별도의 조작이 필요 없지만, 단일로 훈련을 진행하기 원하는 경우 위와 같은 API 를 통해서 특정 버전을 강제로 생성하고 훈련을 진행할 수 있다.