블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2018. 8. 16. 15:06 AI Deep Learning/Read Paper

Data2Vis는 seq2seq를 통해 입력되는 데이터를 기반으로 출력으로 차트를 자동생성한다.




개념


해당 논문을 이해하기 위해 다음과 같은 단어의 개념을 이해해야 한다. 소스에서도 같은 용어를 쓰기 때문에 소스이해를 위해서도 중요하다. 


 - Data2Vis의 데모 사이트에 가면 간략한 설명이 나와 있다.


    

  

  - Attention mechanism을 이용한 encoder-decoder 아키텍쳐 모델이다.  

  - key/value 쌍의 데이터를 입력으로 하고 Vega-Lite기반의 출력을 생성한다. Vega-Lite는 JSON기반으로 차트를 생성해주는 스펙이다. 

  - 특징

     + encoder는 최종 context vector 하나로 만든다. 이것을 C 라고 표현한다. 위이 그림에서 가운데 위치한 C이다. 

     + decoder는 학습할 때 encoder의 "C"와 "<go>답안"을 입력받아 "답안<eos>"를 출력하는 학습을 한다. (참조)

     + encoder, decoder의 길이를 정해야 한다. 무한정일 수 없다.

     + 여기서 encoder, decoder는 동시에 학습할 수 있다. (참조)

     + 정답이 있는 데이터만 S2S 학습이 가능하다.

     + 단어들에 대한 벡터화한 수치 사전이 필요하다. (참조)

  - beam search

     + RNN의 학습 과정에서 트리 탐색 기법으로 쓰임

     + 최고우선탐색(Best-First-Search)기번을 기본으로 회되 기억해야 하는 노드 수를 제한해 효율성을 높이는 방식

     + beam : 사용자가 기억해야 하는 노드 수

  - LSTM

     + Backward Propagation(역전파)할 때에 Gradient Vanishing이나 Exploding되는 현상을 막기 위해 LSTM을 사용한다. 

     + 역전파할 때 미분한다. Gradient는 결국 기울기 이고, 미분또한 기울기를 구하는 것으로 역전파를 할 때 미분의 값이 작을 때 Gradient Vanshing이 발생하고, 클때 exploding이 발생한다.

     + Gradient Vanishing에 대한 자세한 설명은 영덕의 연구소를 참조한다.  





소스 설치 및 실행


소스를 깃헙에서 클론한다.

$ git clone https://github.com/victordibia/data2vis.git


환경 설정

  - Anacoda를 설치

  - Python v3.6.5 사용

  - Tensorflow v1.9.0 사용 (Anaconda Navigator UI에서 설치하지 않고 conda CLI로 버전을 지정해서 설치한다.)

$ conda install -c conda-forge tensorflow=1.9.0


모듈 설치

  - requirements.txt는 node.js의 package.json역할

$ cd data2vis

$ pip install -r requirements.txt


실행하기 

$ python webserver.py


브라우져에서 http://localhost:5016/  호출


디버깅하기

MS Code에서 다음 항목을 추가한다.

  - port: listen 포트

  - model_dir: 모델이 있는곳, 이곳에 seq2seq의 환경파일인 train_options.json 파일이 존재해야 한다. 

     해당 파일은 training 시킨 결과를 통해 자동으로 생성된다. 훈련시키는 방법에 대해서는 두번째 글 참조.

  - beam_width: 사용자가 기억해야 하는 노드수 5개

{

    "version": "0.2.0",

    "configurations": [

        {

            "name": "Python: Data2Vis - Flask (0.11.x or later)",

            "type": "python",

            "request": "launch",

            "program": "${workspaceFolder}/webserver.py",

            "env": {

                "FLASK_APP": "${workspaceFolder}/webserver.py",

                "FLASK_ENV": "development"

            },

            "args": [

                "--port=5016",

                "--model_dir=vizmodel",

                "--beam_width=15"

            ]

        },

        {

            "name": "Python: Current File",

            "type": "python",

            "request": "launch",

            "program": "${file}"

        },

        .....

}


샘플 실행

  - 좌측 examples 메뉴를 클릭하고 입력창에 1이상의 값을 넣고, "Generate Examples" 버튼을 클릭하면 차트가 생성된다. 





seq2seq 모듈


구글이 개발한 tf-seq2seq 모듈 소스을 data2vis 폴더에 그대로 copy해 놓은 상태이다.  모델을 학습하고 검증하는 것은 실제 seq2seq가 하므로 tf-seq2seq 사용방법을 알아야 한다. 

   - tf-seq2seq 소개 블로그: Goolge NMT 논문 필수

   - seq2seq에 대한 기본 설명은 Arxiv의 Neural Machine Translation 논문을 참조한다. 

   - Tensorflow의 seq2seq 사용법



Configuration Training

  - 환경파일에는 Input data, model, training parameter를 정의한다.

  - vismodel의 train_options.json 파일을 사용한다.

  - optimizer 종류와 learning_rate등을 지정. Adam 옵티마이저를 사용.

  - vocab_target, vocab_source 임베딩을 위한 벡터 카운트를 만들기 위해 파일 지정

  - decoder, encoder class와 params을 설정. 둘 다 LSTMCell 사용

  - attention class와 params 설정

  - inference, bridge, embedding 설정

  - source/target.max_seq_len 으로 string의 크기 지정

  - 모델 옵션 설명

  - 인코더 옵션 설명

  - 디코더 옵션 설명


{

    "model_class": "AttentionSeq2Seq",

    "model_params": {

        "optimizer.name": "Adam",

        "decoder.class": "seq2seq.decoders.AttentionDecoder",

        "inference.beam_search.beam_width": 5,

        "decoder.params": {

            "rnn_cell": {

                "dropout_input_keep_prob": 0.5,

                "num_layers": 2,

                "cell_params": {

                    "num_units": 512

                },

                "dropout_output_keep_prob": 1.0,

                "cell_class": "LSTMCell"

            },

            "max_decode_length": 2000

        },

        "optimizer.learning_rate": 0.0001,

        "source.reverse": false,

        "source.max_seq_len": 500,

        "attention.params": {

            "num_units": 512

        },

        "attention.class": "seq2seq.decoders.attention.AttentionLayerDot",

        "vocab_target": "sourcedata/vocab.target",

        "target.max_seq_len": 500,

        "optimizer.params": {

            "epsilon": 8e-07

        },

        "bridge.class": "seq2seq.models.bridges.ZeroBridge",

        "vocab_source": "sourcedata/vocab.source",

        "encoder.params": {

            "rnn_cell": {

                "dropout_input_keep_prob": 0.5,

                "num_layers": 2,

                "cell_params": {

                    "num_units": 512

                },

                "dropout_output_keep_prob": 1.0,

                "cell_class": "LSTMCell"

            }

        },

        "encoder.class": "seq2seq.encoders.BidirectionalRNNEncoder",

        "embedding.dim": 512

    }

}



Training 

  - 모델과 교육데이터가 갖추어져 있으면 훈련을 수행한다.

  - /sourcedata안에 source, target의 trainig data가 존재한다.

  - utils/data_gen.py에서 /examples 폴더의 vega spec을 읽어와 training data를 만들고 있다. 



Prediction

  - 모델 Training을 받은 후 예측을 시작할 수 있다. 

  - DecodeText 클래스를 사용하고, Input pipeline은 ParallelTextInputPipeline을 사용함. 

    + DecodeText는 모델 예측을 가져와 표준 출력으로 추력하는 작업을 수행함

    + DumpAttention과 DumpBeams을 이용해 모델 수행시 디버깅을 할 수 있다. 파일로 쓰는 것임.

    + input pipline은 데이터를 읽는 방법을 정의한다.



Decoding with Beam Search

  - 빔 검색은 번역 성능을 향상시키는 일반적으로 사용되는 디코딩 기술이다. 

  - 빔 검색은 메모리에 가설 또는 빔(beam)을 놓고 가장 높은 점수인 것을 선택한다. 



Evaluating specific checkpoint

  - Training을 통해 다양한 모델의 체크포인트를 저장한다.

  - BLEU (bilingual evaluation understudy)를 통해 번역 성능 평가. 

 


Checkpoint에 대한 설명

- Saving

  + model 을 만드는 코드 의존적인 포멧을 갖는다.

  + 체크포인트는 training하며 생성된 모델의 버전이다.

  + Estimator가 checkpoint를 model_dir 위치에 저장한다. 

  + events 파일은 tensorboard가 시각시에 사용한다. 

  + Saver를 통해 체크포인트를 Saving/Restoring 한다. 


checkpoint

events.out.tfevents.timestamp.hostname

graph.pbtxt

model.ckpt-1.data-00000-of-00001

model.ckpt-1.index

model.ckpt-1.meta

model.ckpt-200.data-00000-of-00001

model.ckpt-200.index

model.ckpt-200.meta


- Restoring

  + Estimator는 train()을 호출하면 model의 그래프를 model_fn()을 호출해서 생성한다. 

  + Estimator는 최근의 checkpoint를 통해 새로운 모델의 weight을 초기화 한다. 






webserver.py 이해


파이썬 웹서비스는 Flask를 이용한다.  data2vis/static 과 templates가 Flask운영을 위해 사용된다. 


webserver.py 실행 순서

- port, vizmodel, beam_width를 아규먼트를 받는다.

- vizmodel/train_options.json을 기반으로 TrainOption 오브젝트를 생성

train_options = training_utils.TrainOptions.load(model_dir_input)


- model params을 사용해 model class를 생성함. AttensionSeq2Seq.py (attension_seq2seq.py)

model_params = _deep_merge_dict(model_params, _maybe_load_yaml(model_params))

model = model_cls(params=model_params, mode=tf.contrib.learn.ModeKeys.INFER)


- inference task 생성. DecodeText 생성

if (str(tdict["class"]) == "DecodeText"):

        task = task_cls(tdict["params"], callback_func=_save_prediction_to_dict)


- ParallelTextInputPipeline pipeline 생성

input_pipeline_infer = input_pipeline.make_input_pipeline_from_def(

    fl_input_pipeline,

    mode=tf.contrib.learn.ModeKeys.INFER,

    shuffle=False,

    num_epochs=1)


- inference를 사용하는 (Tensorflow) graph 생성.

  + seq2seq/inference/inference.py에서 pipeline과 batch_size를 통해 input function을 만들고

  + input function의  feature와 label을 model의 파라미터로 사용해서 model의 build를 호출한다. 

predictions, _, _ = create_inference_graph( model=model, input_pipeline=input_pipeline_infer, batch_size=batch_size)


- Listen을 하고, Flask의 routing을 설정한다. "Generate Examples" 버튼 클릭시 호출 

  + test data를 사용한다. 

  + normalize를 해준다. (foward_norm, backward_norm)

  + decode result를 가지고 vega spec을 만들어 return한다. 

@app.route("/examplesdata")

def examplesdata():

    source_data = data_utils.load_test_dataset()

    f_names = data_utils.generate_field_types(source_data)

    data_utils.forward_norm(source_data, destination_file, f_names)


    run_inference()

    

    decoded_string_post = data_utils.backward_norm(decoded_string[0], f_names)


    try:

        vega_spec = json.loads(decoded_string_post)

        vega_spec["data"] = {"values": source_data}

        response_payload = {"vegaspec": vega_spec, "status": True}

    except JSONDecodeError as e:

        response_payload = {

            "status": False,

            "reason": "Model did not produce a valid vegalite JSON",

            "vegaspec": decoded_string

        }

    return jsonify(response_payload)





<참조>


  - Data2Vis 소개글, 깃헙 소스, Arxiv 링크

  - deeep 블로그
     seq2seq 에 대한 쉬운 설명글

     Attention 메카니즘설명 (소개한 Arxiv 링크)

  - ratsgo 블로그
     RNN과 LSTM 이해

     seq2seq를 이용한 뉴스 제목 추출하기
     설명에 대한 소스 (2018년 tensorflow 버전에 맞지않다)

     beam search 이해 in Recursive Neural Network

  - 구글 제공
     seq2seq 문서

  - Tensorflow의 seq2seq 한글 설명, 2014년 Arxiv에 소개된 seq2seq pdf

  - 라온피플 블로그
     RNN, LSTM, GRU 소개

  - 영덕의 연구소 블로그
     Gradient Vanishing 문제 개념

  - Naivsphere 블로그

    SGD (Stochastic Gradient Descent)에 대한 글

  - 카카오 IT 브런치
     BLEU: NMT 평가 방식 설명

  - skymind.ai

  - epoch, batch_size 용어 이해 (MNIST epoch, batch 설명)

posted by 윤영식