2021년 3월 28일 일요일

Ubuntu에서 Celery

 [설치]

$ sudo apt install python-celery-common -y
$ sudo apt-get install redis-server -y
$ pip install celery
$ pip install redis

[코딩]

# tasks.py
from celery import Celery

BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
app = Celery('tasks', broker=BROKER_URL, backend=CELERY_RESULT_BACKEND)

@app.task
def add(x, y):
  return x + y


[실행]

$ celery -A tasks worker --loglevel=info

[호출]

>>> from tasks import add
>>> add.delay(4, 4)
>>> result = add.delay(4, 4)
>>> result.ready()
>>> result.get()


[참고]

1. 비동기 처리




2021년 2월 22일 월요일

Django RestFramework 스터디

 (1) OneQ 웹 프레임워크 Django(python) 개념 정리

- 프레임워크: lib는 사용자가 호출. framework는 framework이 사용자 코드를 호출


(2) OneQ 웹 프레임워크 Django 실습


(3) [T24] 장고 01강_웹프로그래밍과 Django


-여기 까지는 DJango에 대한 부분으로 상기한 링크 자료만 학습하면 됨. 

아래는 Django REST framework에 대한 부분으로 실습 해보아야 됨.

- DJango 학습 시에 유의할 사항은 django project(1개만 있음) 하에서 여러 app이 존재할 수 있다는 것을 이해. 

app은 user관리, 결제처리, 등등... 필요에 따라 추가할 수 있으며 folder단위로 관리됨, 재 사용도 가능하다. 


(4) [이 부분이 가장 중요] REST API Guide - Productionizing a Machine Learning model by creating a REST API with Python Django and Django REST Framework 


(5) Django  REST framework Quickstart


[참고] 자주 나오는 Serializer 클래스는 Model 데이터를 json으로 바꾸는 역할을 한다. 이 클래스를 만들고 model 데이터를 이 클래스 객체에 던져주면 json으로 바뀌어서 리턴된다. 


[References]

1. Database 연동하기 - Model설계, Migration 



2020년 11월 8일 일요일

가장 짧게 transformer 설명

어떤 시계열 데이터가 있는데, 시계열 길이는 32이고 속성 수는 16개라 가정하자.  

그러면 데이터 shape은 original=(bs, slen=32, nfeat=16)이다. bs는 batch_size이다. 여기서, 첫번째 데이터인 (32,16) 행렬만 추출하여 tansformer연산을 해보자.


1. (32,16)을 속성 수가 16이 아닌 8로 만드는 linear층을 적용한다. 물론 8은 바꿀수 있다. 

그러면 데이터는 (32,8)이된다. 그리고 속성은 더이상 origianl이 아닌 latent텐서가 된다. 


2. transformer의 self attention사용할 예정이므로 1에 설명된 방법으로 original로부터 (32,8)인 query, key, value 텐서 3개를 만든다. 


3. 먼저 query와 key에 대해 attention(가중치) 연산을 수행한다 (self attention연산 이해는 이미지를 활용한 아래 사례를 참조한다). 

query*key'=(32,8)x(8,32)을 하면 (32,32)크기가 나온다. 이것은 시간 t=i에서 8개 속성과 t=j에서 8개 속성을 유사도 비교 연산한 것이다. 

즉, 서로 다른 시간에서 신호 속성들의 유사도를 따지는 것이다. 현 신호는 이전 어떤 시간대에서 관련성이 있는지를 평가한다. 


따라서 (32,32)행렬 첫 행은 t=1(8속성)과 t=1,2,3,...,32까지를 비교한 값들이고, 이 값을 정규화(softmax)하여 저장한 것이다. 

이 값을 value의 첫번째 속성인 (32,1)에다 곱해준다: a1*v1+a2*v2+a3*v3+...+a32*v32


또, (32,32)행렬의 두번째 행은 t=2(8속성)와 t=1,2,3,...,32까지 속성을 비교한 것이다. 이 값도 마찬가지로 

value의 두번째 속성인(32,2)에 있는 32개 벡터와 차례로 곱해준다: a1*v1+a2*v2+...+a32*v32



4. 이런 식으로 연산을 하면 결과 행렬식 (32,8)이 생기는데, 이것이 한개의 self-attention head이다. 


5. attention head는 보통 여러개가 되고, 이를 함께 연결하여(concat) 큰 행렬 하나로 묶어 내고, 이를 linear층을 통과시켜 original data와 크기가 같은 (32,16) 행렬을 만든다. 


6. original 입력(32,16)은 attention head 출력(32,16)과 더해주는데 이는 original data의 크기값(scale)이 Attention Head 출력에 잘 반영되도록 하기 위함이다.



(사례)



그림은 Input sequence에 대한 Transformer 연산을 좀 더 쉽게 이해하기 위해 dog and dog 이미지를 이용하여 self attention 방법을 보여준다. 이미지를 4개의 patch로 분할하여 patch가 나타난 순서대로 일렬로 세워서 벡터로 만들고 이를 곱해준다. 

곱한 결과인 softmax($QK^T$) 행렬을 보면, 


- 자기 자신 patch끼리의 상관성 높음 (대각방향)    

- Noisy한 배경 끼리의 상관성은 낮음 (비대각 방향)

- Patch 2와 Patch3은 둘 다 dog이므로 상관성 높음 ($a_3^2$와 $a_2^3$ 높음)

- $V$와 곱하면 Output 2, 3 만 높음 (attention 됨). dog가 있는 patch가 attention 되었음. 

- 입력에서 반복 출현하는 유의미(salient) 객체는 상관성 높음 (자기 상관성이던 다른 dog와 상관성이던 배경보다 높아짐)

 

Output행렬의 첫 행을 보면 t=1~4의 4개의 데이터 $V$에 attention(가중치) 값 $a_j^i$값이 곱해진 형태이다. 이것은 sequence 데이터(t=1~4)에 가중치 weight($a_j^i$)가 곱해진 것이며, fully connected net이나 convolution연산과 모양이 동일하다.  

Transformer는 학습되고 나면 고정된 가중치를 가지는 FCN이나 CNN구조와 달리, 위 그림에서 나타나는 가중치 $a_j^i$처럼 Input의 함수이다. 달라지는 Input에 따라 고정된 값이 아니라 바뀌는 값이다. 따라서 FCN이나 CNN에 비해 inductive bias가 휠씬 적게 된다 [1]. 



Reference

1. PR-297 Youtube

2. ViT pytorch 코드 리뷰 (github 원본)

2019년 5월 12일 일요일

신경망 훈련을 위한 처방

Andrej Karpathy가 그의 블로그에 올린 신경망 학습에 관한 유용한 내용이 있어 해당 글을 편역한다. 딥 신경망을 학습할 때 인자 선정과 조정 기준으로 사용해 볼 만한 내용이다. 


Karpathy가 올린 "가장 흔한 신경망 실수"라는 twitter이 있는데, 신경망 훈련과 관련된 몇 가지 흔한 실수들을 열거하였다. twitter은 예상보다 훨씬 많이 조회 되었고, 많은 사람들이 단순히 "어떻게 conv넷이 작동하는가"와 "자신의 convnet이 실제 최고 결과를 성취하는가" 사이에 큰 차이가 있음을 알게 되었다.

아래 글에서는 흔히 나타나는 다양한 오류를 열거하는 것에서 벗어나, 기존 오류에 대해 더 깊이 파고들어 어떻게 하면 오류를 방지하고 수정할지에 대해 살펴 본다. 잘 계획된 일련의 절차을 따른다면 오류를 방지할 수 있지만, 불행히도 이런 방법을 보여주는 문서를 찾기가 쉽지 않다.
먼저 두 가지 중요한 관찰로부터 시작해보자.

1) 신경망 훈련은 누수된 추상화

많은 초보자들은 신경망 훈련이 아주 쉽다고 말한다. 수많은 라이브러리와 프레임웍은 사용자가 가진 데이터 문제를 한번에 해결하는 30줄도 안되는 기적같은 코드 조각을 자랑하고 있으며, 활용법도 마치 Plug&Play 같은 느낌을 준다. 흔히 볼 수 있는 예는 다음과 같다.

>>> your_data = # 여기에 사용자가 가진 멋진 데이터 셋 연결
>>> model = SuperCrossValidator(SuperDuper.fit, your_data, ResNet50, SGDOptimizer)
# 사용법이 너무 너무 쉬워요

데모 라이브러리와 예제들은 매우 간결하고 명확하다. 이는 산뜻한 API와 추상화를 제공하는 기존의 표준 소프트웨어와 유사하다. 유사한 예를 들자면 웹 개발자에게 익숙한 Request library 데모를 보자.

>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
>>> r.status_code
200

얼마나 간결하고 멋진가? 이를 작성한 유능한 개발자는 Query 문자열, URL, GET/POST 요청, HTTP 연결 등 내부 시스템을 이해하고 구현하는 부담을 대부분 떠 안아 주었고, 몇 줄의 코드 뒤에 있는 복잡성을 대부분 감추어 주었다. 이런류의 예제는 기존 사용자인 우리에게 매우 익숙한 것으로 딥러닝에서도 기대하는 것들이다.

그러나 불행히도 신경망은 우리 기대를 져버린다. ImageNet 분류기를 훈련하는 것에서 약간 벗어나자마자 더 이상 "기존" 기술이 아니다. 역전파기법을 살펴본 후 "backprop을 이해해야 한다"는 글을 블로그에 올리는 건 쉽지만, 상황은 훨씬 더 끔찍하다. backprop+SGD 최적화만으로는 테스트하는 넷이 마법처럼 작동하지 않는다. batch norm이 마법처럼 넷을 더 빨리 수렴하게 하지도 않고, RNN은 마법처럼 당신에게 "플러그인" 타입처럼 텍스트를 처리하지도 않는다. 만약 신경망이 어떻게 작동하는지 이해하지 않고 기술 사용을 고집한다면 사용자는 실패할 가능성이 높다.

2) 신경망 학습은 조용히 실퍠한다

코딩 시에 문법 오류나 구성이 틀리면, 종종 예외 발생을 만난다. 예외나 문법 오류는 단순한 것이고 디버깅의 시작에 불과하다.

문법은 제대로지만 코드 내에는 여전히 정돈되지 않은 것이 있고 구별이 어려운 것도 있다. 오류 발생 가능성은 항상 크고 단위 테스트도 까다롭다.
예를 들어 data augmentation 중 왼쪽에서 오른쪽으로 이미지를 반전시킬 때 레이블을 뒤집는 것을 잊었지만 넷은 여전히 잘 작동할 수 있다. 왜냐하면 넷은 내부적으로 뒤집힌 이미지를 감지하는 것을 배울 수 있기 때문이다.
또는 pre-trained checkpoint로부터 weight를 초기화했지만 original mean을 사용하지 않은 경우, 또는 정규화 강도, 학습율, 감쇠율, 모델 크기 등에 대한 설정을 잘못할 수도 있다. 잘못 구성된 신경망은 운이 좋을 때만 예외를 던질 것이다. 대부분의 경우 학습은 진행되지만 조용히 실패한다.

더 이상 강조하기 어려운 사실은 신경망 훈련에 "빠르게 돌파하는" 접근법은 효과가 없고 고통만 초래한다. 어떻게 접근하던 난관이야 만나겠지만, 기본적으로는 가능한 모든 것의 시각화에 집착하고, 방어적이고, 편집증 환자처럼 매달림으로써 어려움을 완화할 수 있다. 신경망 훈련 성공은 인내심과 세부사항에 대한 높은 주의력이다.


The recipe

1. Become one with the data

학습 첫 단계는 학습 코드를 건드리지 않는 것이다. 대신 데이터를 철저히 검사하는 것에서 시작한다. 이 단계는 매우 중요하다. 수천 개 데이터를 스캔하고, 분포를 이해하고 패턴을 찾는 데 많은 시간을 보내야 한다. 다행히, 사람 뇌는 이것을 꽤 잘한다. 자료에서 중복된 샘플을 발견할 수도 있고, 손상된 이미지/라벨을 찾을 수도 있다. 또한 자료 불균형과 바이어스를 찾기도 한다. 보통 데이터 분류를 위한 프로세스에 주의를 기울이는데, 이는 탐구할 아키텍처 종류를 암시한다. 예를 들어 - 매우 국부적인 기능이 필요한지, 아니면 글로벌 컨텍스트가 필요한지, 어느 정도 차이가 있고 어떤 형태를 취하고 있는지, 어떤 변형이 비논리적이며 미리 전 처리될 수 있는지, 공간적 위치가 중요한가, 아니면 평균적으로 풀링하고 싶은지, 세부사항이 얼마나 중요하고 얼마나 이미지들을 축소할 수 있는지, 라벨이 얼마나 노이지한지 등이다.

신경망은 데이터 셋에 대한 효과적 압축/복호화 버전이기 때문에 네트워크(오류) 예측을 보면 이것이 어디에서 올 수 있는지 이해할 수 있을 것이다. 만약 네트워크가 데이터에서 본 것과 일치하지 않는 예측을 한다면, 뭔가 잘못된거다.

일단 넷을 평가할 수 있는 정성적인 감각을 얻으면, 가능한 방법(예: 라벨의 종류, 주석 크기, 주석 수 등)으로 검색/필터/구분을 할 수 있는 간단한 코드를 작성하고 그 분포와 축을 따라 특이치를 시각화하는 것도 좋은 생각이다. 특이치는 특히 데이터 품질이나 사전 처리에서 항상 일부 버그를 발견하게 해준다.

2. Set up the end-to-end training/evaluation skeleton + get dumb baselines

이제 데이터를 이해했으니, 초특급 멀티 스케일 ASPP FPN ResNet에 접속하여 멋진 모델을 학습할 수 있는가? 아니다, 그게 고통의 길이다.
해야 할 다음 단계는 완전한 학습+평가 골격을 설정하고 실험을 통해 정확성에 대한 신뢰를 얻는 것이다. 이 단계는 망쳐도 되는 간단한 모델을 선택하는 것이 좋다. 예를 들어 선형 분류기나 아주 작은 ConvNet 같은 것이다. 이를 훈련시키고, 손실과 기타 지표(예: 정확성)들을 시각화하며, 예측을 모델링하고, 그 과정에서 다양한 가설 삭제(ablation) 실험을 수행한다.

이 단계에서 팁 및 트릭을 몇가지 살펴보자.

Fix random seed.
코드를 두 번 실행해도 동일한 결과를 얻을 수 있도록 항상 고정된 랜덤 seed를 사용. 변동 요소를 제거하여 작업을 쉽게하는데 도움을 줄 것이다.

Simplify.
불필요 기능은 반드시 비 활성화한다. 예를 들어, 이 단계에서 모든 데이터 증강 기능을 해제한다. 데이터 증강은 나중에 통합할 수 있는 정규화 전략이지만, 현재는 멍청한 버그를 도입하는 기회를 줄 뿐이다.

Add significant digits to your eval.
Test loss를 그릴 때 전체 Test 샘플을 하나하나 평가한다. 배치 단위로 Test loss를 표시하지 말고, 텐서보드에서 평활화를 이용한다. 정확성 추구가 중요하며, 많은 시간을 들일 준비가 되어야 한다.

loss@init.
손실이 올바른 값으로 시작되었는지 확인한다. 예를 들어 최종 계층을 올바르게 초기화할 경우 초기화 시 softmax라면 -log(1/n_classes)를 예측해야 한다. L2 회귀 분석, 후버 손실 등에 대해서도 동일한 기본값을 도출할 수 있다.

Init well.
최종 학습층 가중치를 올바르게 초기화 한다. 예를 들어 mean이 50인 어떤 값을 regression 시킬 경우 최종 bias를 50으로 초기화한다. 비율 1:10의 pos:neg의 불균형 데이터 셋의 경우, 넷 초기화 시 0.1 확률을 예측하도록 logits에 bias를 설정한다. 제대로 설정한다면 수렴 속도가 빨라지고 넷이 단지 bias를 배우는 것에 지나지 않는 "하키 스틱" 손실 곡선을 피할 수 있을 것이다.

Human baseline.
Loss 값은 직관적 분석이 어려우므로 해석가능하고 확인할 수 있는 지표를 사용하여(예: accuracy) 모니터링한다. 언제나 확인가능한 정확성을 평가하고 비교하라. 대안으로 test data에 prediction과 GT 주석을 붙인체 확인하라.

Input-independent baseline.
입력과 상관없는 독립적인 기준으로 학습해 본다(예: 모든 입력을 0으로 설정하는 것이 가장 쉽다). 이것은 실제 데이터일 때보다 더 나쁜 성능을 보일 것이다. 실제 그런지 확인하라. 즉, 모델이 입력에서 정보를 추출하는 것을 배우는가?

Overfit one batch.
최소의 학습 샘플(예: 2개 배치 정도의 작은 경우)만을 준비한 단일 배치를 과적합 시킨다. 과적합을 만들려면 모델 용량만 늘리면 된다(예: 레이어 또는 필터 추가). 학습 시 달성 가능한 최저 손실(예: 0)에 도달할 수 있는지 확인한다.

이 때 라벨과 예측값을 같이 시각화하여 최소 손실에 도달하면 완벽하게 정렬되는지 확인한다. 만약 그렇지 않다면, 어딘가에 버그가 있고 다음 단계로 진행하면 안된다.

Verify decreasing training loss.
현재 단계는 Toy 모델로 작업 중이기 때문에 데이터 세트에 under-fitting할 것이다. 이 때 조금만 모델 용량을 늘려본다. 손실이 예상처럼 주는지 확인한다.

넷 직전 입력 확인.
데이터를 명확하게 시각화할 수 있는 정확한 위치는 모델로 데이터가 들어가기 직전 위치인 y = model(x) 바로 앞에 있다. 즉, 넷으로 들어가는 것을 정확하게 시각화 한다 - raw tensor 데이터 및 레이블을 시각화로 확인한다. 이 부분이 유일한 진실의 원천이다.

이를 확인함으로써 수 많은 개발 사례에서 데이터 처리와 증강에서 문제점을 찾을 수 있었다.

Visualize prediction dynamics.
학습 동안 고정된 test batch로 넷 예측치를 시각화하라. 예측이 어떻게 움직이는가에 대한 "동적거동"은 학습이 어떻게 진행 되는지에 대한 믿을 수 없을 정도로 좋은 직관력을 줄 것이다.

넷이 어떤 식으로든 너무 많이 흔들려 불안정성이 드러나면 데이터에 맞추기 위해 "고군분투"하는 것을 느낄 수 있는 경우가 많다. 너무 낮거나 높은 학습율은 jitter 양으로도 쉽게 눈에 띈다.

Use backprop to chart dependencies.
딥러닝 코드는 복잡하고, 벡터화된, 다양한 연산을 포함한다. 몇 번 마주친 비교적 흔한 버그는 사람들이 문제를 잘못 이해하고(예: 어딘가에서 transpose/permute 대신 view를 사용한다) 무심코 batch의 dimension을 섞어버린다는 것이다.

넷은 또 다른 샘플을 통해 몇몇 데이터를 무시하도록 학습할 수 있으므로 여전히 잘 훈련될 것이라는 것은 우울한 사실이다.

이(와 기타 관련 문제)를 디버깅하는 한 가지 방법은 어떤 예에 대한 손실을 1.0로 설정하고, 입력까지 역방향 패스를 실행하며, i번째 예에서만 0이 아닌 구배를 얻도록 하는 것이다.

일반적으로 말하면 gradients는 네트워크 내용에 따라 무엇이 달라지는지에 대한 정보를 제공하며 debugging에 유용하다.

Generalize a special case.
일반적인 코딩 팁이지만 사람들은 씹을 수 있는 것보다 더 많이 물어뜯을 때 버그를 만들어 내는 것을 종종 보았다.

코딩 시 세부적인 기능을 먼저 작성하고, 일단 작동하게 한 다음, 나중에 같은 결과를 얻도록 일반화하 하라. 이는 종종 벡터화 코드에도 적용된다. 먼저 완전한 루프 버전을 작성한 후, 그 다음 벡터화 코드로 변환한다.


To be continued ...

2019년 1월 20일 일요일

RTX Titan FP16 comparison

Environment
-Baseline: cifar10 example[1], CEloss, DPN structure
-No test used, only training
-Scratch Initialization, 1-epoch only
-With data augmentation
-i7, 32gb cpu memory under windows10
-Anaconda env., pytorch1.0, python 3.7, cuda10, cudnn 7.4.2[3]

* RTX titan has 24Gb memory size, but video display shares it and occupies about 3 Gb,
so about 21 Gb mem can be used for dnn training.
* Turing architecture(rtx series) does not support cuda 9.x versions.


(1) Baseline(fp32) computation according to changes of batch_size
batch_size=128
--------------------------------
Epoch: 0
2019-01-21 11:15:03.973084
0 391 Loss: 2.436 | Acc: 6.250% (8/128)
50 391 Loss: 2.351 | Acc: 14.982% (978/6528)
100 391 Loss: 2.168 | Acc: 20.707% (2677/12928)
150 391 Loss: 2.065 | Acc: 23.996% (4638/19328)
200 391 Loss: 1.988 | Acc: 26.877% (6915/25728)
250 391 Loss: 1.922 | Acc: 29.451% (9462/32128)
300 391 Loss: 1.867 | Acc: 31.452% (12118/38528)
350 391 Loss: 1.817 | Acc: 33.224% (14927/44928)
2019-01-21 11:18:36.301463 ==>  3min 33sec.

batch_size=256
----------------------
Epoch: 0
2019-01-21 11:21:24.807364
0 196 Loss: 2.315 | Acc: 10.156% (26/256)
50 196 Loss: 2.201 | Acc: 17.831% (2328/13056)
100 196 Loss: 2.018 | Acc: 24.760% (6402/25856)
150 196 Loss: 1.905 | Acc: 29.134% (11262/38656)
2019-01-21 11:24:48.638777 ==> 3min 24sec.


batch_size=512: Memory error!!
----------------------------------



(2) FP16 for baseline 
-Change batch_size with fixed static_loss_scale(128.0)[2].
-Check GPU memory for increasing batch_size

batch_size=128
--------------------------------
Epoch: 0
2019-01-21 11:10:35.342605
0 391 Loss: 2.371 | Acc: 7.812% (10/128)
50 391 Loss: 2.421 | Acc: 13.480% (880/6528)
100 391 Loss: 2.242 | Acc: 18.162% (2348/12928)
150 391 Loss: 2.115 | Acc: 21.797% (4213/19328)
200 391 Loss: 2.029 | Acc: 24.662% (6345/25728)
250 391 Loss: 1.951 | Acc: 27.596% (8866/32128)
300 391 Loss: 1.891 | Acc: 29.893% (11517/38528)
350 391 Loss: 1.831 | Acc: 31.987% (14371/44928)
2019-01-21 11:13:24.088977 : 2min 49sec

batch_size=256 ==> 13Gb occupied in GPU memory
--------------------------------
Epoch: 0
2019-01-21 11:37:30.438707
0 196 Loss: 2.406 | Acc: 7.031% (18/256)
50 196 Loss: 2.273 | Acc: 15.709% (2051/13056)
100 196 Loss: 2.078 | Acc: 22.625% (5850/25856)
150 196 Loss: 1.947 | Acc: 27.491% (10627/38656)
2019-01-21 11:39:59.184161 ==> 2min 30sec

batch_size=512 ==>  21.87Gb occupied in GPU
--------------------------------
Epoch: 0
2019-01-21 11:27:54.565118
0 98 Loss: 2.329 | Acc: 13.086% (67/512)
50 98 Loss: 2.182 | Acc: 17.601% (4596/26112)
2019-01-21 11:30:14.626127 ==> 2min 20sec


batch_size=512+128 ==> Memory Error!!
--------------------------------


(3) For changes of static_loss_scale with fixed batch_size(512)

static_loss_scale=64.0
-----------------------------------------------
Epoch: 0
2019-01-21 11:45:43.910621
0 98 Loss: 2.337 | Acc: 11.914% (61/512)
50 98 Loss: 2.167 | Acc: 18.624% (4863/26112)
2019-01-21 11:48:03.947331 ==> 2min 20sec


static_loss_scale=256.0
-------------------------------------------
Epoch: 0
2019-01-21 11:49:50.158676
0 98 Loss: 2.413 | Acc: 8.789% (45/512)
50 98 Loss: 2.224 | Acc: 16.885% (4409/26112)
2019-01-21 11:52:10.582739 ==> 2min 20sec



References
1. pytorch cifar10
2. NVIDIA apex
3. cuDNN support matrix














2018년 8월 9일 목요일

MnasNet

Mobile platform에 최적인 넷 구조를 NAS로 찾는다.

1. 최적화할 목적함수를 accuracy와 실제 폰에서 측정한 latency(지연시간,연산시간) 2개를 합쳐 사용한다.
1-1. 실측 이유는 연산시간은 폰 의존적이고 폰 사양은 매우 다양하다. 필드에서 직접 관찰이 중요하다. 실험에 쓴 구글 픽셀 one 폰은 단일 쓰레드 CPU 환경이다.
1-2. accuracy와 latency 둘 다를 목적함수 하나로 합치기 위해 Pareto optimal을 사용한다. hard와 soft constraint 2가지를 정의하고 soft를 사용했다.

2. 기존 NAS는 동일 cell 타입을 층으로 쌓았다. 같은 3x3 conv라도 입출력 shape이 달라지면 지연량이 다름을 고려치 않았다. MnasNet은 block별로 구조나 연결이 다른 넷을 구성한다.

3. 후보 샘플링->넷 구성->reward 계산->RNN 학습. 절차는 기존 sampling기반 NAS와 동일하다.




넷 구조 형성에는 Factorized Hierarchical Search 공간을 정의하고 탐색한다.
CNN은 Net 앞 단이 더 큰 data를 처리하므로, 동일한 Block(또는 cell) 구조를 누적 사용할 경우, 뒷 단 보다 latency에 끼치는 영향이 크다.  Block에 들어가는 data 크기에 따라 구조나 연결이 달라야 한다.
MnasNet은 data shape에 따라 Block 구조도 달라진다.


References
[1] MnasNet paper
[2] Google AI BLog: MnasNet
[3] Pytorch-MnasNet





2018년 8월 2일 목요일

DARTS

Differentiable Architecture Search(DARTS)는 NAS 알고리즘 일종으로 기존 NAS에서 사용하던 강화학습 기반의 discrete한 후보 선택 방법을 미분 가능하고 연속적인 최적화 방법으로 바꾸었다.

입력 $x=[64,3,32,32]$에 연산자 $op$를 적용한다. $op$ 후보가 8개라 가정하자. 이 중 1번만 적용하고 나머지 7개는 무시하면 $x'=op_1(x)$이다.

만일 2번, 5번 연산자를 동일한 가중치로 적용하고 나머지를 무시하면
$x'=0.5 \cdot op_2(x)+0.5 \cdot op_5(x)$
이다. 단, 이 연산이 성립하려면 $op_2(x)$와 $op_5(x)$는 같은 shape를 가져야 한다.

8개 모두 적용 시
$x'=\sum w_i \cdot op_i(x)$
이다.
DARTS는 $w_i(i=0...7)$ 탐색을 통해 $x'$가 연결되어 만든 net의 validation loss 최소화로 NAS 해결방법을 찾았다.


이는 $x'$가 만드는 loss를 $w_i$에 대해 편미분해 구한다.
통상 CNN에서 층(layer)이라 함은 Conv나 ReLu 등 연산을 선택 후, 이 $op$에 관련된 학습 가중치를 net loss가 최소화되게 구하는 것이다.
그런데, 이종의 $op$가 결합되어 층 하나를 구성한다면 어떤 연산을 지배적으로 사용할건지를 나타내는 연산 가중치 $w_i$ 결정과 각 연산에 들어 있는 학습 가중치 결정 2가지 문제를 함께 풀어야 한다.


두 타입 인자 결정을 동시에 할 수는 없다. $op$ 가중치 최적화, CNN 학습 가중치 최적화를 차례로 수행해야 한다. DARTS는 두 단계 수행 방법을 설명한다.


Reference
[1] DARTS paper
[2] pytorch-DARTS