728x90

Pytorch에서 DDP로 multi-GPU training을 신나게 돌리다가, 종종 에러가 발생한다.

 

 

구글링 결과, anaconda 관련 문제인 것 같았다.

 

main.py 및 DDP loading 과 관련된 문젱는 아니었다.

 

상당히 비슷한 문제가 아래의 링크에 포함되어 있는데,

 

https://github.com/conda/conda/issues/9589

 

Warning about leaked semaphore under Python 3.8 · Issue #9589 · conda/conda

Current Behavior Under Python 3.8, there is a warning printed when running most conda commands: ~/miniconda3/lib/python3.8/multiprocessing/resource_tracker.py:216: UserWarning: resource_tracker: Th...

github.com

 

이들은 모두 conda의 version, 그리고 python version 문제라고 하였다.

 

그래서 나는 우선 conda를 최신으로 업데이트 하였다.

 

conda update --all

 

위의 명령어를 통해서 업데이트 이후, deactivate, 다시 activate 하였다.

 

우선은 다시 돌리고 있는 중인데, 만약 이와 같은 문제가 또 생겼을 경우 python 버전을 3.7로 낮춰서 해봐야 할 것 같다.

728x90
728x90

이번에 리뷰할 논문은 Almost Unsupervised Text to Speech and Automatic Speech Recognition [1]이며, ICLR 2019에 억셉되었다.

 

Overview

- 음성 및 텍스트 영역 모두에서 언어 이해 및 모델링 기능을 구축하기 위해 짝을 이루지 않는 음성 및 텍스트 데이터에 대한 self-supervised learning 아이디어를 활용함

- 특히, 인코더-디코더 프레임 워크에서 손상된 음성 및 텍스트를 재구성하기 위해 Denoising Auto-Encoder를 사용함

- 역 번역의 개념인 Dual transformation을 사용하여 텍스트를 음성으로 (TTS) 및 음성을 텍스트로 (ASR) 변환하는 기능을 제안함

- 음성 및 텍스트 시퀀스가 ​​일반적으로 Neural Machine Translation과 같은 다른 시퀀스--시퀀스 학습 작업보다 길다는 점을 고려하면 오류 전파로 인해 더 많은 어려움을 겪을텐데, 이는 생성된 시퀀스의 오른쪽 부분이 일반적으로 왼쪽 부분보다 나쁘다는 문제를 나타냄

- 특히 Supervised 데이터가 부족하여 리소스가 없거나 리소스가 부족한 설정에서(즉 데이터가 부족한 상황) 자주 나타나는 현상임

- 따라서 Denoising Auto-Encoder Dual Transformation을 기반으로 텍스트와 음성 모두에 대해 양방향 시퀀스 모델링을 추가로 활용하여 오류 전파 문제를 완화하는 것을 제안함

 

Intro & Related works

- 최근, 최첨단 성능의 TTS ASR 시스템은 대부분 Neural Networks 기반이며, 모두 대규모 데이터를 많이 사용하므로, 쌍을 이루는 음성 및 텍스트 데이터셋이 부족한 언어에는 문제가 발생함

- 비지도 ASR에 초첨을 맞춘 작업에서는 TTS의 추가 정보를 활용하지 않는데(2019년 기준), 이는 ASR의 이중 작업이며, ASR의 성능을 향상시킬 수 있는 큰 잠재력임

- 게다가 비지도 ASR은 일반적으로 음성 파형을 단어 또는 음소로 먼저 분할하고, 세그먼트 수준에서 텍스트 데이터와 음성을 정렬하는 일부 작업별 알고리즘을 활용함

- 그러나 TTS는 일반적으로 음성 파형을 Mel-spectrogram 또는 MFCC로 변환하여 프레임 수준에서 처리함

- 따라서 비지도 ASR 용으로 설계된 알고리즘을 TTS에 쉽게 적용하기 힘듬

- 샘플이 거의 없는 특정 화자의 음성을 합성하려는 작업은 일반적으로 전이 학습 문제로 간주되지만, 비지도 학습 문제가 아닌 다른 화자의 레이블이 지정된 다량의 음성 및 텍스트 데이터를 활용함 

- 그리하여 이 논문에서는, TTSASR 작업의 이중 특성으로부터 영감을 받아 TTSASR 모두에 대해 몇 가지 쌍을 이루는 음성 및 텍스트 데이터와 추가로 쌍을 이루지 않는 데이터를 활용하여 거의 감독되지 않는 새로운 방법을 제안함

 

 

Method

1. DAE (Denoising Auto-Encoder)

 

- 짝을 이루지 않는 대량의 음성 및 텍스트 데이터를 감안할 때 표현 추출 및 언어 모델링 기능을 구축하는 것이 음성과 텍스트 간의 변환을 위한 첫 번째 단계임
- 이를 위해 논문에서는 DAE를 활용하여 손상된 버전 자체에서 음성 및 텍스트 시퀀스를 재구성함
- 노이즈 제거 자동 인코더는 일반적인자가지도 학습 방법이며 비지도 학습에 널리 사용되는데, 음성 및 텍스트 데이터에 대한 노이즈 제거 자동 인코더의 손실 함수 $L^{dae}$ 는 다음과 같이 공식화됨

$L^{dae}=L_s(x|C(x);\theta_{enc}^S,\theta_{dec}^S)+L_T(y|C(y);\theta_{enc}^T,\theta_{dec}^T)$

- 여기에서, $S, T$는 각각 음성과 텍스트 도메인의 시퀀스 데이터이며, $\theta_{enc}^T,\theta_{dec}^T$는 음성 인코더, 음성 디코더, 텍스트 인코더 그리고 텍스트 디코더의 파라미터들임
- $C$는 0값을 갖는 벡터로 일부 요소를 무작위로 마스킹하거나 음성 및 텍스트 시퀀스의 특정 창에서 요소를 교체하는 손상된 연산을 나타냄

- $L_s, L_T$ 각각 음성 및 텍스트 대상 시퀀스의 손실을 나타냄

- 이를 정리하면, $L_s$ 는 음성의 Mean Squared Errors로, $L_T$는 text Classification으로 나타낼 수 있음

 

2. Dual Transformation (DT)

1) DT는 TTS 및 ASR 작업의 이중 특성을 활용하고 텍스트를 음성으로 (TTS) 및 음성을 텍스트로 (ASR) 변환하는 기능을 개발하는 핵심 구성 요소임
- ASR 모델을 사용하여 음성 시퀀스 $x$를 텍스트 시퀀스 $\hat{y}$로 변환 한 다음 변환 된 쌍 $(\hat{y},x)$에서 TTS 모델을 훈련시킴
- 마찬가지로 TTS 모델에 의해 생성 된 변환 된 쌍 $(\hat{x},y)$에 대해 ASR 모델을 훈련함
- 이중 변환은 번역을 위해 단일 언어 데이터를 활용하는 가장 효과적인 방법 중 하나인 backtranslation(역번역) 으로서, Neural Machine Translation
- DT는 번역을 위해 단일 언어 데이터를 활용하는 가장 효과적인 방법 중 하나인 Neural Machine Translation의 backtranslation(역-번역) 방법에서 제안되었음

 

2) 손실 함수 $L^{dt}$ 다음 두 부분으로 구성됨

$L^{dt}=L_S(x|\hat{y};\theta_{enc}^T,\theta_{dec}^S)+L_T(y|\hat{x};\theta_{enc}^S,\theta_{dec}^T)$

- 여기에서, $\hat{y}$=argmax$P(y|x;\theta_{enc}^s,\theta_{dec}^S)$ 및, $\hat{x}=f(y;\theta_{enc}^T,\theta_{dec}^S)$는 각각 음성 $x$ 및 텍스트 $y$에서 변환된 텍스트 및 음성 시퀀스임
- 모델 학습 중에는 TTS 모델이 변환된 최신 텍스트 시퀀스를 활용하는 DT가 즉시 실행되며, 훈련을 위해 ASR 모델에 의해 또는 그 반대로 TTS 및 ASR의 정확도가 점진적으로 향상될 수 있도록 보장함

 

3. Bidirectional Sequence Modeling

1) Seq2seq 학습은 일반적으로 오류 전파로 어려움을 겪음

- 예를 들어, 추론 중에 요소가 실수로 예측되면 오류가 전파되며, 이로 인해 생성된 시퀀스의 오른쪽 부분 (끝 부분)이 왼쪽 부분보다(앞 부분) 정확도가 떨어짐
- 음성 및 텍스트 시퀀스는 일반적으로 신경 기계 번역과 같은 다른 NLP 작업의 시퀀스보다 길며 오류 전파로 인해 더 많은 문제를 겪을 수 있음 
- 예를 들어, 실험에서 DT중에 생성된 음성 시퀀스의 오른쪽 부분은 일반적으로 반복되는 단어나 누락된 단어가 있는 왼쪽 부분보다 품질이 낮음
- 결과적으로 훈련을 위해 변환된 데이터에 의존하는 DT이 영향을 받고 텍스트의 오른쪽 부분과 음성 시퀀스가 잘 훈련될 수 없음
- 따라서 TTS 및 ASR 모델은 모두 시퀀스의 오른쪽 부분, 특히 label이 있는 데이터가 부족하여 리소스가 낮거나 없는 환경에서 낮은 품질의 결과가 도출되는 경향이 있음
2) 위의 문제를 해결하기 위해 양방향 시퀀스 모델링을 활용하여 왼쪽에서 오른쪽 및 오른쪽에서 왼쪽 방향으로 음성 및 텍스트 시퀀스를 생성하는 것을 제안함
- 이러한 방식으로 기존의 DT 프로세스에서 항상 품질이 낮았던 시퀀스의 오른쪽 부분을 좋은 품질을 유지한 채로 오른쪽에서 왼쪽 방향으로 생성 가능함
- 결과적으로, 훈련을 위해 변환된 데이터에 의존하는 이중 작업은 시퀀스의 오른쪽 부분에서 개선된 품질의 혜택을 받을 것이며, 시퀀스의 왼쪽과 오른쪽 부분 사이의 생성 품질에서 더 균형을 이룰 것임
- 원래 왼쪽에서 오른쪽으로 생성된 것보다 더 높은 변환 정확도를 제공함

- 동시에 양방향 시퀀스 모델링은 양방향으로 데이터를 활용하는 데이터 증대 효과로도 작용할 수 있으며, 이는 특히 거의 비지도 학습 설정에서 쌍을 이룬 데이터가 거의 없을 때 유용하게 사용될 수 있음
- 양방향 DAE는 다음과 같이 구성할 수 있음

- 왼쪽에서 오른쪽 및 오른쪽에서 왼쪽 방향으로 손상된 음성 및 텍스트 시퀀스를 재구성하는 경우 $C(\cdot)$은 masking 연산임
- 시퀀스를 두 방향으로 모델링할 때 모델 매개 변수를 공유함
- DAE 및 DT를 기반으로 한 양방향 시퀀스 모델링은 왼쪽에서 오른쪽 및 오른쪽에서 왼쪽 세대 간에 모델을 공유함
- 즉, 시퀀스를 양방향으로 생성하는 하나의 모델을 학습할 수 있으며, 모델 매개 변수를 줄이는 것도 가능함
- 모델에게 훈련과 추론의 시작 요소로 제로 벡터를 사용하는 기존의 디코더와는 달리, 제안하는 방법은 두 개의 학습 가능한 내장 벡터를 훈련과 추론 방향을 나타내는 두 개의 시작 요소로, 하나는 왼쪽에서 오른쪽으로, 다른 하나는 오른쪽에서 왼쪽으로 사용함
- 따라서 총 4 개의 시작 임베딩을 학습함
- 2 개는 음성 생성 용이고 다른 2 개는 텍스트 생성 용임


- TTS 및 ASR의 음성 및 텍스트 시퀀스는 일반적으로 monotonic attention에 의해 alignment되므로, 예를 들어 디코더의 음성 시퀀스의 왼쪽 부분은 일반적으로 TTS의 인코더에서 텍스트 시퀀스의 왼쪽 부분에 집중될 수 있음
- 왼쪽에서 오른쪽 생성과 일치하기 위해 오른쪽에서 왼쪽 방향으로 대상 시퀀스를 생성할 때 오른쪽에서 왼쪽 방향으로 소스 시퀀스를 인코더에 공급함
- 따라서 소스 시퀀스를 역순으로 대상 시퀀스와 일치시킴

 

4. Proposed model details

1) 시퀀스 모델링에서 기존 RNN / CNN 보다 장점이 있기 때문에 Transformer로 선택하였음

 

2) 그림 a
- 녹색 및 노란색 화살표는 음성 및 텍스트에 대한 DAE를 나타냄
- 빨간색 화살표는 텍스트에서 음성으로 (TTS)
- 파란색 화살표는 음성에서 텍스트로 (ASR)의 DT를 나타냄
- DAE와 DT 모두 양방향 시퀀스 모델링을 포함함

 

3) 그림 b
- Transformer를 기반으로 하는 음성 및 텍스트 인코더 및 디코더
- Transformer는 주로 교차 위치 정보를 추출하기 위한 MHA와 각 위치에서 non-linear 변환을 보장하기 위한 FFN로 구성된 self-attention 메커니즘을 사용하고, 각각에 residual 연결 및 layer norm이 이루어짐
- 디코더는 인코더의 마지막 레이어에서 hidden representation을 추출하기 위해 추가 MHA를 사용함
- 인코더와 디코더는 모두 input d_model이 256이고 FFN은 1024의 크기이며, 4 layer로 쌓았음
- TTS와 ASR은 인코더와 디코더에 대해 동일한 모델 구조를 공유하지만 모델 매개 변수가 다름 (공개 안되어있음)

 

4) 그림 c
- 음성 및 텍스트에 대한 입력 및 출력 모듈이며, 음성 입력 모듈 (그림 c의 왼쪽 하단)은 hidden size가 256 인 Pre-Net으로 구성되며 출력 차원은 Transformer의 hidden size인 256과 같음
- 음성 출력 모듈 (그림 c의 왼쪽 상단)은 두 가지 구성 요소로 구성됨
- 하나는 출력 차원이 1 인 stop linear layer와 현재 디코딩 단계가 중지되어야 하는지 여부를 예측하는 sigmoid임
- 다른 하나는 각 단계에서 80 차원 벡터로 mel-spectrogram을 생성하기 위해 추가 Post-Net이 있는 mel linear layer임
- Post-Net은 생성된 mel-spectrogram의 품질을 개선하는 것을 목표로 하는 256의 hidden size를 갖는 5-layer 1-D Convolution 네트워크로 구성됨
- Griffin-Lim 알고리즘을 사용하여 mel-spectrogram을 audio로 변환함
- 텍스트 입력 모듈 (그림 c의 오른쪽 하단)은 phoneme 임베딩으로, phoneme ID를 임베딩으로 변환함
- 출력 모듈의 텍스트 linear layer (그림 c의 오른쪽 상단)와 phoneme 임베딩의 매개 변수를 공유함
- 텍스트 시퀀스는 모델에 입력하기 전에 먼저 텍스트-음소 변환기를 사용하여 음소 시퀀스로 변환됨

 

[1] Ren, Yi, et al. "Almost unsupervised text to speech and automatic speech recognition." International Conference on Machine Learning. PMLR, 2019.

728x90
728x90

이번에 리뷰할 논문은 Facebook AI에서 발표한, Self-Training for End-to-End Speech Recognition [1] 이며, Pseudo labels을 활용한 self-training에 대한 내용임

 

Overview

1. Self-training with pseudo-labels

2. Pseudo-labelled data set을 사용한 학습이 기준 모델의 정확도를 크게 향상시킬 수 있음을 보임

- 작은 쌍의 labeled 데이터셋에서 강력한 베이스라인 (음향 모델) training

- Pseudo-label을 생성하기 위해 대규모 text corpus에서 훈련된 LM으로 안정적인 디코딩 수행

- 시퀀스 간 모델의 일반적인 error에 조정된 filtering mechanism 제안

- Seq2Seq 모델에서 자주 접하게 되는 실수를 해결 하기 위해, 제안하는 pseudo-label filtering에 대한 heuristicconfidence-based approach 평가

-> Looping and early stopping

- 또한, 학습 중 여러 모델을 결합하는 앙상블 접근 방식 제안

-> 레이블 다양성을 개선하고 모델이 잡음이 있는 pseudo-label에 대해 지나치게 확신하지 않도록 함

 

Background & Issue

1. ASR 시스템을 구축하기 위해 많은 양의 transcribed data 필요

- Labeled 데이터 양이 감소하면 end-to-end 모델의 성능 저하

- 많은 양의 오디오를 transcribing 하는 것은 expensive, time-consuming

- Unpaired audio and text를 활용하기 위해 semi-supervised learning이 제안됨

 

2. Self-training

- Semi-supervised learning 기법 중 하나인 self-training 방법 채용

- 훨씬 더 작은 labeled 데이터에서 학습된 모델로부터 생성된 잡음이 있는 label을 사용

 

Proposed model

1. Baseline model architecture [2]

- 앞서 리뷰한 TDS block 논문 아키텍처를 사용

 

2. Inference

- Beam search를 사용하여 가능성이 가장 높은 hypothesis 탐색

$\bar{Y}=$argmax$_Y$log$P_{AM}(Y|X)+\alpha$log$P_{LM}(Y)+\beta|Y|$ ...(1)

- $\alpha$는 LM의 weight임

- $\beta$는 seq2seq 모델에서 흔히 볼 수있는 조기 중지 문제를 피하기위한 토큰 insertion [3]

-> 디코딩 중에 발생하는 모델의 실수로 인해, 음성의 특정 frame을 건너 뛰어 일부 단어가 decoding이 안되는 문제

-> 이는 특히 외부 언어 모델을 사용할 때 많이 발생

 

- [2]의 모델을 활용하여 decoder 안정화 (random sampling, EOS threshold)

log$P_u$(EOS$|y_{<u}$)$<\gamma\cdot$max$_{c\neq EOS}$log$P_u(c|y_{<u})$

- 위의 식이 성립될 경우에 EOS 사용

- $\gamma$는 튜닝 가능한 hyperparameter임

 

3. Semi-supervised Self-training

 

1) Supervised learning setting

- 우리가 많이 사용하는 supervised learning setting은 입력 $X$와 그에 해당하는 label $Y$가 있으며, 이를 paired dataset이라 부름. 이는 아래와 같음

$\mathcal{D}={(X_1,Y_1),...,(X_n,Y_n)}$

- 아래의 식처럼, $D$에 대해 학습된 모델은 레이블이 있는 $Y$에 주어진 ground-truth의 가능성을 최대화 함

$\sum_{(X,Y)\in\mathcal{D}}$log$P(Y|X)$ ...(2)

 

2) Semi-supervised setting

- $mathcal{D}$ 외에 label이 없는 오디오 데이터 세트 $\mathcal{X}$ 및 페어링되지 않은 텍스트 데이터 세트 $mathcal{Y}$ 만 포함 됨

- 먼저, 식 (2)를 최대화하여 $mathcal{D}$에서 AM 모델을 훈련함
- 둘째, $mathcal{Y}$에서 LM 교육

- 셋째, 두 모델을 결합하여 식 (1)을 적용하고, label이 지정되지 않은 각 데이터에 대한 pseudo label을 생성하고, 아래와 같이 paired pseudo label을 이룬 데이터 세트를 얻음
$\mathcal{D}={(X_i,\bar{Y_i})|X_i\in\mathcal{X}}$

- 마지막으로 새 AM은 $mathcal{D}$와 $D$의 조합에 대해 아래와 같은 목표로 훈련 할 수 있음

$\sum_{(X,Y)\in\mathcal{D}}$log$P(Y|X)+\sum_{(X,Y)\in\mathcal{D}}$log$P(\bar{Y}|X)$

 

3) Proposed filtering

- Pseudo-labelled dataset $\bar{\mathcal{D}}$는 noisy $\bar{Y}$를 포함하고 있음

- Filtering은 $\bar{\mathcal{D}}$의 크기와 pseudo-label 사이에 balance를 이루기 위해 사용됨

- Seq2seq에 특화된 두 가지 heuristic-based filtering 기능 제안

 

-> Confidence-based filtering [4] 추가 결합 가능하며, 문장 수준에 적용

-> $c$번 이상 반복되는 n-gram을 포함하는 pseudo-label을 제거하여 루프를 필터링 함

-> EOS확률이 threshold 이상인 $\hat{Y}$을 유지함으로써, early stopping을 해결할 수 있음

-> 또한, 완전한 $\hat{Y}$을 찾지 않고 beam search이 종료되는 경우에 대해서도 필터링 함

 

4) Confidence-based filtering [4]

- Decoder가 디코딩 된 $\bar{\mathcal{Y}}$에 대해 얼마나 확신하는가?

- Sentence-level confidence $C_{sent}$는 아래의 식인 평균 단어 신뢰도로 계산됨

$C_{sent}\frac{1}{N}\sum_{i=1}^N c_{w_i}$

- Word confidence $c_{w_i}$Confusion Network [5]의 $i$번째 step에 있는 단어 $w_i$의 사후 확률임

- Word sequence posterior 값은 예상되는 WER을 최소화하는 Minimum Bayes Risk Decoding [6]에 의해 얻어짐

 

5) Confusion network [5]

- 디코딩 결과가 얼마나 정확한지 검증하는 기법으로 사용 됨

- Word graph 혹은 Finite-state Machine에서 state transition 스코어의 합이 1이 되도록 확률로 normalize한 모델

- 이외에도 알아두면 좋을 것들: Lattice-based word error minimization algorithm

-> Lattice alignment algorithm

-> Intra-word clustering

-> Inter-word clustering

-> Pruning

-> The consensus hypothesis

-> Score scaling

- 올해 안에 확인해보기

 

6) Minimum Bayes decoding [6]

- ASR에 사용되는 MAP rule은 다음과 같음

$W^*=$argmax$_{w}P(W|\mathcal{O})$

- W word-sequence 이고, Oobservation sequence이며

- 이를 통해 WER과 관련된 Minimum Bayes Risk 추정치 제공 (Levenshtein edit distance를 기준으로 WER 사용하기 때문)

$W^*=$argmin$_w\sum_{w'}P(W'|\mathcal{O}L(W,W'))$

- 여기에서 $L(W,W')$는 word sequence $W$와 $W'$사이의 Levenshtein edit distance임

- 또한, $P(W'|\mathcal{O})$는 모델에 의해 $W'$에 할당된 posterior 확률임

 

다시 3)으로 돌아와서, - 각 pseudo-label에 대해 seq2seq에서 length-normalized log likelihood를 confidence score로 계산한 것은 아래의 식과 같음

 

ConfidenceScore$(\bar{Y_i})=\frac{log{P_{AM}(\bar{Y_i}|X_i)}}{|\bar{Y_i}|}$

- 여기에서 $|\bar{Y_i}|$는 각 발화의 토큰 수임

 

7) Ensembles in self-training 

7-1) 문제점

- Self-training에서 여러 모델을 활용하는 방법은 추론 중 모델들의 score 결합

- 더 높은 품질의 single pseudo-labelled 세트를 생성할 수 있음

- 하지만 $M$이 증가하면 디코딩 프로세스가 heavyweight

 

7-2) Proposed sample ensemble

- Given $M$ bootstrapped AM, 각 모델에 대한 pseudo-labelled dataset $\bar{D_m}$을 병렬로 생성

이후 pseudo-label의 모 $M$ setuniform 가중치와 combine

훈련 중 아래의 식을 최적화

$\sum_{(X,Y\in\mathcal{D})}$log$P(Y|X)+\frac{1}{M}\sum_{m=1}^M\sum{X,Y\in{D_m}}$log$P(\bar{Y}|X)$

 

- Implementation으로, 먼저 labelled $\mathcal{D}$를 이용하여 randomly initialized weights로 모 $M$ 학습

- 이후, 각각의 모델에 맞춰 tuninghyper-parameter로 $\bar{D_m}$생성

- 학습 동안, 모델 $M$중 하나에서 매 epoch마다 target으로 pseudo-label을 균일하게 샘플링함

 

Experiments

1. Data (LibriSpeech)

- Paired dataset: Train-clean 100

- Unpaired dataset (clean): Train-clean-360

- Unparied dataset (noisy): Train-other-500

- Realistic for self training

-> LibriSpeech는 총 14,476권의 공개 도서에서 파생되어 생성된 데이터셋임

-> LM을 위한 훈련 데이터에서 AM 훈련 셋과 관련된 모든 책 제거 (997개)

- NLTK toolkit for text normalization

--> 문장 분할 적용, 소문자로 모두 변경, ` 를 제외한 구두점 제거, 하이픈 공백으로 대체

 

2. Model

- 각각 10, 14 및 16 채널과 $k$ = 21이 있는 3 개 그룹의 9 개의 TDS 블록
- Soft-window 사전 교육 (attention 수렴을 위해), teacher-forcing, 20%의 dropout, 1%의 random sampling, 10%의 Label smoothing, 정규화를위한 1%의 word piece sampling
- SentencePiece [7]을 사용하여 "train-clean-100"의 transcripts에서 5,000 개의 word piece을 대상 토큰으로 계산

 

3. Training

- Pseudo-labels 학습시 8GPUs 사용

- Learning rate가 0.05 인 200 Epoch 동안 momentum이 없는 SGD 사용

- GPU 1개를 사용할 때 Epoch 40마다 0.5 씩 decay, GPU 8개에 Epoch 80 개씩 decay 먹임
- wav2letter ++ 프레임 워크 사용 [8]

 

4. LM

- ConvLM [9]과 동일한 model architecture 및 학습 방법 사용하여 word piece 학습

- 모든 beam search hyper-parameterpseudo-label 생성 전 dev set에서 조정

 

Results

1. Label measure

- Ground truth와 비교하여 필터링 된 pseudo-label의 WER로 정의함 (논문 자체에서 이렇게 했다는 말임)

2. Heuristic filtering

- No EOS + n-gram필터를 $c=2, n=4$에 적용

- 이후 필터링 된 데이터 세트 위에 confidence-based filtering 추가

- Confidence score에 대한 threshold 조정 시 pseudo-label 품질 개선됨 (그림 참조)

 

3. Model ensembles

- 여러 모델을 결합하면 특히 노이즈가 많은 설정에서 성능 향상

- 6개 모델과 heuristic filtering을 통해 13.7%의 상대적 개선률 획득

- 두 가지 필터링 기술이 ensemble과 효과적으로 결합 됨을 보임

- Sample ensemble이 학습 시간에 동일한 utterance에 대해 서로 다른 transcript를 사용하기 때문에 모델이 noise가 포함된 pseudo-label에 지나치게 확신하는 것을 방지함

 

4. Comparison with Literature

- 원본 책(label)과 비교를 하였는데 이때 쓰인 measure는 WRR (WER Recovery Rate) 이며 아래와 같음

$\frac{baseline WER - semi - supervised WER}{baseline WER - oracle WER}$

- WRR를 통해 pseudo-label과 연결할 수 있는 baselineoracle 사이의 간격을 보임

5. Comparison with other semi-supervised learning

- Seq2seq model에서 동일한 음성으로 실험 조건 세팅

기존 연구 (semi-supervised)

--> Cycle TTE [10]: inputoutput사이에 cycle-consistency loss 도입

--> ASR+TTS [11]: TTS 모듈을 활용하여 unpaired text에서 합성 데이터 생성

- 제안한 Self-training 방법이 기존 연구 보다 약 65.1% 우수한 WER 생성

Why?

- TDS 기반 encoder

- 실제 설정에서 쉽게 얻을 수 있는 훨씬 더 큰 unpaired text corpus 활용

 

 

Conclusion

- 대규모 Unlabelled dataset을 이용한 self-trainingend-to-end 시스템의 상당한 개선을 가져옴

- 기존의 Seq2seq 모델 및 앙상블에서 발생하는 문제점에 맞게 조정된 필터링 메커니즘의 효과

- Self-training에도 효과적임을 보임

 

- TDS block 및 이 논문 모두 Decoding, External LM 등에 대한 사전 지식이 있어야 충분히 이해할 수 있는 레벨이었음

- 소량의 Self-training을 통해 data augmentation 효과 및 unseen data의 distribution등의 개선을 기대할 수 있을 것 같고, real scenario에 사용해봄직 함

 

[1] Kahn, Jacob, Ann Lee, and Awni Hannun. "Self-training for end-to-end speech recognition." ICASSP 2020-2020 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP). IEEE, 2020.

[2] Kahn, Jacob, Ann Lee, and Awni Hannun. "Self-training for end-to-end speech recognition." ICASSP 2020-2020 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP). IEEE, 2020.

[3] Chorowski, Jan, and Navdeep Jaitly. "Towards Better Decoding and Language Model Integration in Sequence to Sequence Models." Proc. Interspeech 2017 (2017): 523-527.

[4] Veselý, Karel, Mirko Hannemann, and Lukáš Burget. "Semi-supervised training of deep neural networks." 2013 IEEE Workshop on Automatic Speech Recognition and Understanding. IEEE, 2013.

[5] Mangu, Lidia, Eric Brill, and Andreas Stolcke. "Finding consensus in speech recognition: word error minimization and other applications of confusion networks." Computer Speech & Language 14.4 (2000): 373-400.

[6] Xu, Haihua, et al. "An improved consensus-like method for Minimum Bayes Risk decoding and lattice combination." 2010 IEEE International Conference on Acoustics, Speech and Signal Processing. IEEE, 2010.

[7] Kudo, Taku, and John Richardson. "SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing." Proceedings of the 2018 Conference on Empirical Methods in Natural Language Processing: System Demonstrations. 2018.

[8] Vineel Pratap, Awni Hannun, Qiantong Xu, Jeff Cai, Jacob Kahn, Gabriel Synnaeve, et al., "Wav2letter++: A fast opensource speech recognition system", International Conference on Acoustics Speech and Signal Processing (ICASSP), 2019.

[9] Dauphin, Yann N., et al. "Language modeling with gated convolutional networks." International conference on machine learning. PMLR, 2017.

[10] Takaaki Hori, Ramon Astudillo, Tomoki Hayashi, Yu Zhang, Shinji Watanabe and Jonathan Le Roux, "Cycle-consistency training for end-to-end speech recognition", International Conference on Acoustics Speech and Signal Processing (ICASSP), 2019.

[11] Murali Karthick Baskar, Shinji Watanabe, Ramon Astudillo, Takaaki Hori, Luk áš Burget and Jan Černockỳ, "Semi-supervised sequence-to-sequence ASR using unpaired speech and text", Interspeech, 2019.

728x90
728x90

이번에 리뷰할 논문은 Sequence-to-sequence speech recognition with time-depth separable convolutions [1] 이며, receptive field를 크게 유지하면서 모델의 매개변수 수를 극적으로 줄이는 시간 깊이 분리형 CNN block을 제안한 논문임

 

Overview

1. TDS (Time-depth separable)

- Fully convolutional sequence-to-sequence encoder architecture
- RNN baseline에 비해 WER 우수, 계산의 병렬 특성으로 인해 효율적임을 주장
- Receptive field를 크게 유지하면서 모델의 매개 변수 수를 극적으로 줄이는 시간 깊이 분리형 CNN block 제안

 

2. 또한, 느리고 순차적인 기술 폐기
- Neural content attention
- Location based attention [2]
- Scheduled sampling [3]

3. CNN 기반의 언어 모델
- CNN 기반의 언어 모델을 효과적으로 통합할 수 있는 Beam search 추론 절차 제공
- Beam size가 매우 크더라도 정확도가 저하되지 않음

 

Proposed model

1. Background

1) 주어진 음성 입력 $X=[x_1,...,x_t]$, $Y=[y_1,...,y_u]$가 있을 때, Seq2seq 모델의 인코더는 $X$를 hidden representation으로 인코딩하며, 디코더는 인코더로부터 받은 hidden represetation과 디코더의 입력을 각각의 출력 토큰으로 디코딩하여 문장으로 생성함. 이를 아래에 자세히 설명함

 

2) 인코더는 아래의 식으로 볼 수 있음

$(K, V)$ = encode$(X)$

- 여기에서 $K=[k_1,...,k_t]$ 는 key이며, $V=[v_1,...,v_t]$는 value임

 

3) 디코더는 아래처럼 주어질 수 있는데,

$Q_u = g(y_{u-1},Q_{u-1})$

$S_u = $attend$(Q_u,K,V)$

$P(y_u|X,y_<u)=h(S_u,Q_u)$

- 여기에서 $g(\cdot)$은 이전 token과 query vector $Q_{u-1}$을 인코딩하여 다음 query vector를 처리하는 RNN임

- Attention mechanism인 attend$(\cdot)$은 summary vector인 $S_u$를 처리함. 여기에서 summary vector는 일방적인 context vector로도 알려짐

- $h(\cdot)$은 출력 token들의 전체 distribution을 계산함. 즉 attention score를 뜻함

 

2. Time-depth separable convolutions

1) 채널을 통한 mixing에서 시간 경과에 따른 집계를 부분적으로 분리

- 2D Convolution-based

- 매개 변수 수를 무시할 정도의 증가량으로, 모델의 receptive field를 늘릴 수 있음

 

 

2) 모델 구조 (그림 내의 b)

TDS convolution model architecture

- $t * w * c$의 입력을 받아 2D CNN으로 시작

-> $T$: time step의 수

-> $w$: 입력 width (frequency)

-> $c$: 입력과 출력의 채널 수

- 커널 사이즈는 $k * 1$

- 매개변수의 total 수: $kc^2$

- Residual, ReLU, Layer norm 적용

 

3) 모델 구조 (그림 내의 c)

- 입력: $T * 1 * wc$, 즉 (b)의 출력과 동일

- 2-layer of 1x1 CNN (즉, linear layer) with ReLU 추가

- 입력과 위의 결과를 residual로 연산

- Layer norm 적용

 

4) 3개의 sub-sampling layers

- Stride 2로 사용

- 전체 8 sub-sampling factor 사용

-> 이 중 1개는 첫 번째 layer, 나머지는 각각의 TDS block 사이에 사용

-> 시간 축에 대해서만 stride 2로 적용

 

5) Increasing the number of output channels

- Feature를 적시에 압축하기 때문에, 각 sub-sample에서 output channel 수를 늘림

- 이 때 단순화를 위해 residual connection은 사용되지 않고, ReLU와 Layer norm만 적용

 

Efficient Decoder 제안

1. 기존 방법

- Sequential Dependency in the decoder: 다음 출력을 계산하려면 decoder는 이전 예측이 필요

- 기존 방법 중 이에 대한 예시: scheduled sampling, input feeding [4], location-based attention

 

2. Inner-product key-value attention 제안

- Hidden 차원 $d$의 역 제곱근으로 inner-product 확장

$S=V\cdot$softmax$(\frac{1}{\sqrt{d}}K^TQ)$

- 이를 통해 수렴을 개선하고, 모델이 alignment를 학습하는데 도움이 된다고 함

- 하지만 일반화에서는 개선된 모습이 보이지 않았다고 함

 

3. Scheduled sampling의 한계

- 훈련 조건을 테스트 조건에 더 가깝게 만들어 노출 편향을 제한하지만, 다음 시간 단계에서 이전 예측을 사용하기 때문에 decoder에 순차 종속성이 도입된다는 단점이 있음

- 논문에서는 병렬로 계산하기 위해 위의 기술을 폐기하고, 대안으로 random sampling [5] 적용을 제안함

- 본 논문에서는 이전 예측이 무작위로 샘플링 된 토큰으로 대체되는 무작위 샘플링을 사용

- 입력 토큰을 샘플링 할 확률 $P_{rs}$로 결정

- 샘플링시, 균일한 분포에서 새 토큰 선택

- Random number $c_j$를 균일한 분포 $[0,1]$로부터 샘플링한 토큰 $U$를 얻음

- $R=[r_1,...,r_U]$로 설정, 이때 $r_j=\mathcal{I}(c_j>P_{rs})$이고, $P_{rs}$는 sampling 확률

- 이후 $U$토큰의 벡터 $Z$를 샘플링 함

- EOS를 포함하지 않는 출력 토큰에 대해 균일한 배포를 사용

- 이후 $\hat{Y}=R\cdot Z+(1-R)\cdot Y$ 

 

4. Soft window pre-training: Deep CNN-encoder를 학습하기 위한 soft attention 제안

- 모델이 원하는 위치에서 너무 멀리 떨어져 있는 attention 값에 페널티를 적용하여 입력을 따라 균일한 간격으로 출력을 정렬함

- $W$를 $T*U$ matrix with $W_{ij}=(1-\frac{T}{U}j)^2$라고 할 때,

- $W$는 출력이 입력을 따라 균일한 간격으로 있다고 가정하고, $i$번째 입력과 $j$번째 출력 사이의 제곱 거리를 인코딩함

- 따라서 스케일링 계수는 $\frac{T}{U}$가 됨

- 아래와 같이 $W$를 적용함

$S=V\cdot$softmax$(\frac{1}{\sqrt{d}}K^TQ-\frac{1}{2\sigma^2}W)$

- $\sigma$는 $W$의 효과를 약화시키는 hyperparameter임

- $W$의 적용은 정규화 된 attention vector (즉, softmax 이후)에 가우시안 모양의 마스크를 곱하는 것과 같음

 

- 처음 몇 epoch에 대해서만 window pre-training 진행

- 해당 작업으로 alignment와 수렴하는 것이 충분하다고 주장

- Encodersub-sampling 양이 변경될 때만 $\sigma$를 변경함

- 개인 적인 생각으론, 가우시안 필터 모양의 마스크를 곱하여 어텐션을 가이드하는 아이디어, 즉 휴리스틱한 내용은 도입해보고 잘 되었기 때문에 넣은 것인지 않을까 싶음

 

5. Regularization

- Dropout: 인코더 내에서 Non-linearity 이후 layer norm 이전에 적용

- Label smoothing: Prediction에 대한 과도한 신뢰성을 줄이기 위해 사용

- Word piece sampling

-> Word piece model 사용

-> 단어 수준에서 샘플링

-> 가 단어에 대해 확률 $1-P_{wp}$를 사용하여 가장 가능성이 높은 Word piece를 취하거나, $P_{wp}$가 가능성이 가장 높은 상위 10개에 대해 균일하게 샘플링하여 사용

 

6. Beam search decoding

- Stabilizing Beam Search

-> Seq2Seq Beam Search는 종종 beam size가 증가함에 따라 성능 저하 및 불안정 한 문제가 있음 [6]

-> 하지만 모델은 가능한 hypothesize를 효과적으로 검색하기 위해 큰 beam size를 사용할 수 있어야 함

-> Beam size를 크게 사용하기 위해 성능 저하 및 불안정 문제를 해결하는 아래의 2가지 방법론 제안

 

- Hard Attention Limit

-> Beam search가 이전 attention peak에서 $t_{max}$ 프레임 이상을 차지하는 $\hat{y}$값에 대해 허용하지 않음

-> $t_{max}$는 주어진 데이터 셋에 대해 한 번만 조정함

 

- End-of-sentence Threshold

-> 짧은 transcriptions에서 검색에 bias를 주기 위해, score가 최고 후보 score의 값보다 클 경우에만 EOS를 고려함

log$P_u(EOS|y_{<u})>\gamma\cdot max_c$log$P_u(c|y_{<u})$

-> Hard attention 한계와 마찬가지로, 매개 변수 $\gamma$는 주어진 데이터 세트에 대해 한 번만 조정함

 

7. Efficiency

- Heuristics method on Beam search

-> Beam threshold [7]를 설정하여 현재까지의 최고의 $\hat{y}$에서 고정된 범위 미만인 beam의 $\hat{y}$을 제거함

-> 또한, beam의 현재 $\hat{y}$ 세트에 새로운 후보 토큰을 제안 할 때, threshold 적용

-> 아래의 식

log$P_u(EOS|y_{<u})>\gamma\cdot max_c$log$P_u(c|y_{<u})$

-> 이 아래의 식을 만족해야 함

log$P_u(y|y_{<u})> max_c$log$P_u(c|y_{<u})-\eta$

-> Beam의 모든 후보에 대해 업데이트 된 probability 집합을 일괄 계산하므로, 각 단계에서 한 번의 forward만 필요

 

 

Experiments

1. Data

- LibriSpeech 960h

 

2. Encoder

- Two 10-channel, three 14-channel 그리고 six 18-channel TDS blocks (11 blocks)

- Using 1D convolutions to sub-sample over time

-> One as the first layer

-> One in between each group of TDS blocks

- Kernel sizes: all 21 x 1

- Final linear layer produces the 1024-dimensional encoder output

 

3. Decoder

- One-layer GRU with 512 hidden units

 

4. Initialization

- uniform distribution $\mathcal{U}(-\sqrt\frac{4}{f_{in}},\sqrt\frac{4}{f_{in}})$으로 초기화 되었으며, $f_{in}$은 각 유닛에 대한 fan-in임

 

5. Speech preprocessing

- 80-dimensional mel-scale filter banks computed every 10ms with a 25ms window

 

6. Token preprocessing

- 10k word pieces computed from the Sentence Piece toolkit [8]

 

7. Optimizer

- Synchronous SGD with a learning rate of 0.05, decayed by a factor of 0.5 every 40 epochs

- Clip the gradient norm to 15

 

8. Pre-train

- 해당 모델은 soft window와 $\sigma=4$로 3에폭 동안 pre-train 됨

 

9. Hyperparameters

- Dropout as 20%, label smoothing as 5%, random sampling as 1%, word piece sampling as 1%

 

10. Two word piece LMs on the 800M-word text-only dataset

- 두 개의 word piece 언어 모델을 사용하였음

- 첫 번째는 4-gram trained with KenLM [9]

- 두 번째는 convolutional LM (ConvLM) [10]

 

11. Beam setting

- Beam size of 80

- $t_{max}=30$

- EOS penalty $\gamma=1.5, \eta=10$

- LM 가중치 및 토큰 삽입 조건은 dev set LM 조합과 교차 검증으로 진행

- Wav2letter++ [11] 를 사용하여 training evaluation 평가

 

Results

 

1. TDS 모델은 외부 LM을 사용시 더 많은 이점을 얻음

- Better loss on the correct transcription

- More effective beam search

 

 

2. Model variants

 

 

- Varying the number of channels in TDS blocks

-> TDS Block의 채널 개수 변경

-> 기존: 10, 14, 18, params=36.5

--> (10, 12, 14), params=24.4

--> (10, 10, 10), params=14.9

 

- Fix params, Number of TDS blocks

-> N=9, k=27, c=(14, 16, 20), 5.18%

-> N=12, k=19, c=(10, 16, 16), 5.10%

 

- $P_{wp}$와 $P_{rs}$가 낮을수록 성능이 좋았음

 

- Soft window pre-training

--> Soft window 기법은 명확히 학습 초기에 모델 수렴에 도움이 되었음

 

- Receptive fields

--> 큰 사이즈의 receptive field가 없으면, encoder의 키 outputdecoderquery를 명확하게 할 수 없음을 주장

 

- Number of beam size

--> Beam size80까지 이득을 볼 수 있음

 

Conclusion

1. Fully convolutional encoder

- 제안하는 Fully convolutional encodersimple decoder가 강력한 RNN baseline의 도달함과 동시에 더 우수하고 효율적인 결과를 보임

 

2. TDS block

- CNN-based encode의 성공 핵심은 모델이 큰 사이즈의 receptive field를 유지할 수 있는 TDS에 의해 가능함

 

3. + ConvLM

- Convolutional LM을 안정적이고 확장 가능한 beam search 절차와 통합 하는 방법을 보임

 

 

[1] Hannun, Awni, et al. "Sequence-to-Sequence Speech Recognition with Time-Depth Separable Convolutions." Proc. Interspeech 2019 (2019): 3785-3789.

[2] Chorowski, Jan, et al. "Attention-based models for speech recognition." Proceedings of the 28th International Conference on Neural Information Processing Systems-Volume 1. 2015.

[3] Bengio, Samy, et al. "Scheduled sampling for sequence prediction with recurrent Neural networks." Proceedings of the 28th International Conference on Neural Information Processing Systems-Volume 1. 2015.

[4] Luong, Minh-Thang, Hieu Pham, and Christopher D. Manning. "Effective Approaches to Attention-based Neural Machine Translation." Proceedings of the 2015 Conference on Empirical Methods in Natural Language Processing. 2015.

[5] Wang, Xinyi, et al. "SwitchOut: an Efficient Data Augmentation Algorithm for Neural Machine Translation." Proceedings of the 2018 Conference on Empirical Methods in Natural Language Processing. 2018.

[6] Chorowski, Jan, and Navdeep Jaitly. "Towards Better Decoding and Language Model Integration in Sequence to Sequence Models." Proc. Interspeech 2017 (2017): 523-527.

[7] Collobert, Ronan, Christian Puhrsch, and Gabriel Synnaeve. "Wav2letter: an end-to-end convnet-based speech recognition system." arXiv preprint arXiv:1609.03193 (2016).

[8] Kudo, Taku, and John Richardson. "SentencePiece: A simple and language independent subword tokenizer and detokenizer for Neural Text Processing." Proceedings of the 2018 Conference on Empirical Methods in Natural Language Processing: System Demonstrations. 2018.

[9] Heafield, Kenneth. "KenLM: Faster and smaller language model queries." Proceedings of the sixth workshop on statistical machine translation. 2011.

[10] Dauphin, Yann N., et al. "Language modeling with gated convolutional networks." International conference on machine learning. PMLR, 2017.

[11] Pratap, Vineel, et al. "Wav2letter++: A fast open-source speech recognition system." ICASSP 2019-2019 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP). IEEE, 2019.

728x90
728x90

우분투에서 Anaconda를 설치하는 것은 생각보다 간단한데, initialization 할 때 귀찮은 문제가 종종 생기곤 한다.

 

우선 본인 환경에 맞는 anaconda를 설치한다.

 

https://docs.anaconda.com/anaconda/install/hashes/lin-3-64/

 

Anaconda with Python 3 on 64-bit Linux — Anaconda documentation

 

docs.anaconda.com

 

이 사이트에서 받을 수 있고, 나 같은 경우는 Anaconda3-2021.05-Linux-x86_64.sh 를 사용한다. (2021, 06, 25 기준)

 

다운받아서 우분투로 옮기고,

 

sh ./Anaconda3-2021.05-Linux-x86_64.sh 

 

그 다음 yes

 

enter, 등등..

 

설치가 완료된 뒤, conda init 을 해줘야하는데, 이 때 command not find가 뜬다.

 

이때, 

 

vi ~/.bashrc

export PATH="/your_workspace/anaconda3/bin:$PATH"

(예시: export PATH="/workspace/kaen2891/anaconda3/bin:$PATH")

source ~/.bashrc

 

conda init

 

으로 해결할 수 있다.

 

 

728x90
728x90

우분투 환경에서, python을 사용하여 mp4 파일을 wav로 변환 하는 것에 대해 소개한다.

 

즉, 영상 파일을 음성으로 변경하는 것이다.

 

우선 ffmpeg이 설치되어 있어야 한다.

 

apt-get install ffmpeg 을 하면 되고, sudo 권한이 필요하다.

 

이후 

 

import subprocess


command = "ffmpeg -i {} -ab 160k -ac 2 -ar 44100 -vn {}".format(item, os.path.join(this_path, save_file_id))
    
subprocess.call(command, shell=True)

 

로 진행하면 되며, 이때 item은 mp4 파일, this_path, save_file_id 저장할 wav 파일이다.

 

728x90
728x90

우분투에서 python으로 외부 library를 설치해서 사용해야 될 경우가 많다.

 

특히 open source, github에서 보면 requirements.txt 라는 파일이 종종 보이는데,

 

이는 source code 원작자가 다른 이들이 본인의 것을 사용하기 위해 필요한 version을 명시한 것이다.

 

보통 pip3 을 이용하여 외부 library를 설치하는데, 본인이 설치한 python3 library 확인은 pip3 freeze 를 치면 된다.

 

python external library

 

위의 보이는 것들은 내가 사용하고 있는 library들이다. tensorflow, torch 등이 설치된 것을 볼 수 있다.

 

github에서 보이는 것처럼 내가 쓰고 있는 환경을 다른 서버의 계정, 혹은 남에게 공유하고 싶다면?

 

pip3 freeze > requirements.txt 를 입력하면 된다.

 

 

위의 requirements.txt를 이제 공유하기만 하면 된다.

 

이후 requirements.txt 내의 library들을 설치하고 싶으면,

 

pip3 install -r requirements.txt

 

를 입력하면 된다.

 

728x90
728x90

이번에는 RNN을 MNIST로 돌려보는 것을 코딩해본다.

 

Experimental setups

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.autograd import Variable
import os
import matplotlib.pyplot as plt
import numpy as np
torch.__version__

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
torch.manual_seed(2891)
num_gpu = 1
if torch.cuda.device_count() > 1:
    num_gpu = torch.cuda.device_count()
print("Let's use", num_gpu, "GPUs!")
print('our device', device)

'''
Let's use 1 GPUs!
our device cuda
'''

 

RNN 모델 설계

class RNN(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, num_classes):
        super(RNN, self).__init__()
        
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.lstm = nn.LSTM(input_size, self.hidden_size, self.num_layers, batch_first=True)
        self.gru = nn.GRU(input_size, self.hidden_size, self.num_layers, batch_first=True)
        self.fc = nn.Linear(self.hidden_size, num_classes)
        
        
    def forward(self, x, rnn):
        
        if rnn == 'lstm':
            rnn_layer = self.lstm
            h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) 
            c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device)
            out, _ = self.lstm(x, (h0, c0))
        else:
            rnn_layer = self.gru
            h = torch.zeros(self.num_layers, x.size(0), self.hidden_size).to(device) 
            out, _ = self.gru(x, h)
        
        out = self.fc(out[:, -1, :])
        return out

model call시 원하는 rnn 계열 (lstm, gru) 선택 가능하도록 구현함

 

Parameter & Model shape & Hyper-parameter check 

sequence_length = 28
input_size = 28
hidden_size = 128
num_layers = 2
num_classes = 10
batch_size = 100
num_epochs = 10
learning_rate = 0.01

model = RNN(input_size, hidden_size, num_layers, num_classes).to(device)
#model shape
for p in model.parameters():
    print(p.size())
'''
torch.Size([512, 28])
torch.Size([512, 128])
torch.Size([512])
torch.Size([512])
torch.Size([512, 128])
torch.Size([512, 128])
torch.Size([512])
torch.Size([512])
torch.Size([384, 28])
torch.Size([384, 128])
torch.Size([384])
torch.Size([384])
torch.Size([384, 128])
torch.Size([384, 128])
torch.Size([384])
torch.Size([384])
torch.Size([10, 128])
torch.Size([10])
'''
def count_parameters(model):
    return sum(p.numel() for p in model.parameters() if p.requires_grad)

model_hp = count_parameters(model)
print('model"s hyper parameters', model_hp)
# model"s hyper parameters 374026

 

Dataset load, train, test loader 선언

train_loader = torch.utils.data.DataLoader(datasets.MNIST('data', train=True, download=True, transform=transforms.ToTensor()),batch_size=batch_size, shuffle=True)
print(len(train_loader)) # 600
test_loader = torch.utils.data.DataLoader(datasets.MNIST('data', train=False, transform=transforms.ToTensor()),batch_size=1000)
print(len(test_loader)) # 10
'''
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to data/MNIST/raw/train-images-idx3-ubyte.gz
9913344/? [04:53<00:00, 33768.69it/s]

Extracting data/MNIST/raw/train-images-idx3-ubyte.gz to data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to data/MNIST/raw/train-labels-idx1-ubyte.gz
29696/? [00:00<00:00, 433940.88it/s]

Extracting data/MNIST/raw/train-labels-idx1-ubyte.gz to data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to data/MNIST/raw/t10k-images-idx3-ubyte.gz
1649664/? [00:51<00:00, 32232.92it/s]

Extracting data/MNIST/raw/t10k-images-idx3-ubyte.gz to data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to data/MNIST/raw/t10k-labels-idx1-ubyte.gz
5120/? [00:00<00:00, 108088.65it/s]

Extracting data/MNIST/raw/t10k-labels-idx1-ubyte.gz to data/MNIST/raw

Processing...
Done!
600
10
/usr/local/lib/python3.7/dist-packages/torchvision/datasets/mnist.py:502: UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the tensor. You may want to copy the array to protect its data or make it writeable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at  /pytorch/torch/csrc/utils/tensor_numpy.cpp:143.)
  return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)
'''

 

Loss, optimizer 선언

이전에는 F.nll_loss로 하였는데, 이번에는 CrossEntropy loss를 선언하여 진행함

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

 

Training 진행

model.train()
total_loss = 0
total_acc = 0
train_loss = []
train_accuracy = []
i = 0
for epoch in range(num_epochs):
    for data, target in train_loader:
        data = data.reshape(-1, sequence_length, input_size).to(device)
        target = target.to(device)
         
        optimizer.zero_grad()
        output = model(data, 'lstm')
        loss = criterion(output, target)
       
        
        loss.backward()    # calc gradients
       
        total_loss += loss
       
        train_loss.append(total_loss/i)
        optimizer.step()   # update gradients
       
        prediction = output.data.max(1)[1]   # first column has actual prob.
        accuracy = prediction.eq(target.data).sum()/batch_size*100
       
        total_acc += accuracy
       
        train_accuracy.append(total_acc/i)
       
        if i % 10 == 0:
            print('Epoch: {}\t Train Step: {}\tLoss: {:.3f}\tAccuracy: {:.3f}'.format(epoch+1, i, loss, accuracy))
        i += 1
    print('Epoch: {} finished'.format(epoch+1))
'''
Epoch: 9 finished
Epoch: 10	 Train Step: 5400	Loss: 0.031	Accuracy: 99.000
Epoch: 10	 Train Step: 5410	Loss: 0.012	Accuracy: 100.000
Epoch: 10	 Train Step: 5420	Loss: 0.045	Accuracy: 99.000
Epoch: 10	 Train Step: 5430	Loss: 0.107	Accuracy: 98.000
Epoch: 10	 Train Step: 5440	Loss: 0.006	Accuracy: 100.000
Epoch: 10	 Train Step: 5450	Loss: 0.031	Accuracy: 99.000
Epoch: 10	 Train Step: 5460	Loss: 0.038	Accuracy: 98.000
Epoch: 10	 Train Step: 5470	Loss: 0.003	Accuracy: 100.000
Epoch: 10	 Train Step: 5480	Loss: 0.010	Accuracy: 100.000
Epoch: 10	 Train Step: 5490	Loss: 0.024	Accuracy: 100.000
Epoch: 10	 Train Step: 5500	Loss: 0.109	Accuracy: 97.000
Epoch: 10	 Train Step: 5510	Loss: 0.085	Accuracy: 96.000
Epoch: 10	 Train Step: 5520	Loss: 0.016	Accuracy: 100.000
Epoch: 10	 Train Step: 5530	Loss: 0.065	Accuracy: 99.000
Epoch: 10	 Train Step: 5540	Loss: 0.088	Accuracy: 98.000
Epoch: 10	 Train Step: 5550	Loss: 0.042	Accuracy: 99.000
Epoch: 10	 Train Step: 5560	Loss: 0.049	Accuracy: 98.000
Epoch: 10	 Train Step: 5570	Loss: 0.032	Accuracy: 99.000
Epoch: 10	 Train Step: 5580	Loss: 0.095	Accuracy: 97.000
Epoch: 10	 Train Step: 5590	Loss: 0.038	Accuracy: 98.000
Epoch: 10	 Train Step: 5600	Loss: 0.106	Accuracy: 98.000
Epoch: 10	 Train Step: 5610	Loss: 0.026	Accuracy: 99.000
Epoch: 10	 Train Step: 5620	Loss: 0.021	Accuracy: 100.000
Epoch: 10	 Train Step: 5630	Loss: 0.069	Accuracy: 98.000
Epoch: 10	 Train Step: 5640	Loss: 0.010	Accuracy: 100.000
Epoch: 10	 Train Step: 5650	Loss: 0.011	Accuracy: 100.000
Epoch: 10	 Train Step: 5660	Loss: 0.154	Accuracy: 97.000
Epoch: 10	 Train Step: 5670	Loss: 0.005	Accuracy: 100.000
Epoch: 10	 Train Step: 5680	Loss: 0.075	Accuracy: 97.000
Epoch: 10	 Train Step: 5690	Loss: 0.107	Accuracy: 97.000
Epoch: 10	 Train Step: 5700	Loss: 0.050	Accuracy: 98.000
Epoch: 10	 Train Step: 5710	Loss: 0.043	Accuracy: 98.000
Epoch: 10	 Train Step: 5720	Loss: 0.064	Accuracy: 99.000
Epoch: 10	 Train Step: 5730	Loss: 0.039	Accuracy: 98.000
Epoch: 10	 Train Step: 5740	Loss: 0.014	Accuracy: 100.000
Epoch: 10	 Train Step: 5750	Loss: 0.042	Accuracy: 99.000
Epoch: 10	 Train Step: 5760	Loss: 0.137	Accuracy: 96.000
Epoch: 10	 Train Step: 5770	Loss: 0.101	Accuracy: 97.000
Epoch: 10	 Train Step: 5780	Loss: 0.054	Accuracy: 97.000
Epoch: 10	 Train Step: 5790	Loss: 0.084	Accuracy: 97.000
Epoch: 10	 Train Step: 5800	Loss: 0.054	Accuracy: 98.000
Epoch: 10	 Train Step: 5810	Loss: 0.062	Accuracy: 97.000
Epoch: 10	 Train Step: 5820	Loss: 0.076	Accuracy: 98.000
Epoch: 10	 Train Step: 5830	Loss: 0.094	Accuracy: 97.000
Epoch: 10	 Train Step: 5840	Loss: 0.147	Accuracy: 96.000
Epoch: 10	 Train Step: 5850	Loss: 0.048	Accuracy: 99.000
Epoch: 10	 Train Step: 5860	Loss: 0.010	Accuracy: 100.000
Epoch: 10	 Train Step: 5870	Loss: 0.034	Accuracy: 98.000
Epoch: 10	 Train Step: 5880	Loss: 0.048	Accuracy: 99.000
Epoch: 10	 Train Step: 5890	Loss: 0.025	Accuracy: 99.000
Epoch: 10	 Train Step: 5900	Loss: 0.110	Accuracy: 97.000
Epoch: 10	 Train Step: 5910	Loss: 0.092	Accuracy: 98.000
Epoch: 10	 Train Step: 5920	Loss: 0.149	Accuracy: 96.000
Epoch: 10	 Train Step: 5930	Loss: 0.014	Accuracy: 100.000
Epoch: 10	 Train Step: 5940	Loss: 0.056	Accuracy: 98.000
Epoch: 10	 Train Step: 5950	Loss: 0.058	Accuracy: 97.000
Epoch: 10	 Train Step: 5960	Loss: 0.064	Accuracy: 98.000
Epoch: 10	 Train Step: 5970	Loss: 0.050	Accuracy: 98.000
Epoch: 10	 Train Step: 5980	Loss: 0.040	Accuracy: 99.000
Epoch: 10	 Train Step: 5990	Loss: 0.015	Accuracy: 100.000
Epoch: 10 finished
'''

RNN은 lstm으로 진행하였음

 

 

Plotting 결과

plt.figure()
plt.plot(np.arange(len(train_loss)), train_loss)
plt.show()
#plt.savefig('./train_loss_result.png')

plt.figure()
plt.plot(np.arange(len(train_accuracy)), train_accuracy)
plt.show()
#plt.savefig('./train_accuracy_result.png')

 

step에 따른 training loss 변화도
step에 따른 training accuracy 변화도

 

Evaluation 결과

with torch.no_grad():
    model.eval()
    correct = 0
   
    for data, target in test_loader:
        
        data = data.reshape(-1, sequence_length, input_size).to(device)
        target = target.to(device)        
        output = model(data, 'lstm')

        prediction = output.data.max(1)[1]
        correct += prediction.eq(target.data).sum()

print('\nTest set: Accuracy: {:.2f}%'.format(100. * correct / len(test_loader.dataset)))
# Test set: Accuracy: 97.63%

 

사실 RNN은 MNIST data를 돌리기에 최적의 모델이 아님

왜냐하면 RNN의 개념이 sequential 한 data에 적합하기 때문임

 

그럼에도 불구하고 결과값은 MLP의 성능을 넘어섰음

728x90
728x90

이번에는 이전 post와 같은 MNIST dataset을 활용하여, CNN으로 성능 뽑는것을 진행해본다.

 

CNN은 Fully-connected layer와 달리 flatten을 해줄 필요가 없어서 parameter가 비교적 적게 들고, 연산이 빠른 장점이 있으며, receptive field를 통해 local feature를 뽑는 것에 강인한 특징이 있음

 

Library importing 및 device 설정

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.autograd import Variable
import os
import matplotlib.pyplot as plt
import numpy as np
torch.__version__

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
torch.manual_seed(2891)
num_gpu = 1
if torch.cuda.device_count() > 1:
    num_gpu = torch.cuda.device_count()
print("Let's use", num_gpu, "GPUs!")

print('our device', device)
'''
Let's use 1 GPUs!
our device cuda
'''

2-layer CNN 네트워크 설계 (add here 부분에 batchnormalization, 더 깊게 쌓는 것들을 연습해보세요)

class CNN(nn.Module):
    def __init__(self, num_class, drop_prob):
        super(CNN, self).__init__()
        # input is 28x28
        # padding=2 for same padding
        self.conv1 = nn.Conv2d(1, 32, 5, padding=2) #input_channel, output_channel, filter_size, padding_size, (kernel=omit)
        # feature map size is 14*14 by pooling
        # padding=2 for same padding
        self.conv2 = nn.Conv2d(32, 64, 5, padding=2)
        # feature map size is 7*7 by pooling
        '''
        add here.. make more deep...

        batchnormalization ++
        '''
        self.dropout = nn.Dropout(p=drop_prob)

        self.fc1 = nn.Linear(64*7*7, 1024)
        self.reduce_layer = nn.Linear(1024, num_class)
        self.log_softmax = nn.LogSoftmax(dim=1)
        
    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), 2) # -> (B, 14, 14, 32)
        x = F.max_pool2d(F.relu(self.conv2(x)), 2)
        '''
        add here.. make more deep...
        and use dropout
        '''
        x = x.view(-1, 64*7*7)   # reshape Variable for using Linear (because linear only permit 1D. So we call this task as "flatten")
        x = F.relu(self.fc1(x))
        
        output = self.reduce_layer(x)
        return self.log_softmax(output)

 

Model loading 및 parameter, shape 체크

model = CNN(10, 0.3)
model.to(device)
'''
CNN(
  (conv1): Conv2d(1, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
  (conv2): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
  (dropout): Dropout(p=0.3, inplace=False)
  (fc1): Linear(in_features=3136, out_features=1024, bias=True)
  (reduce_layer): Linear(in_features=1024, out_features=10, bias=True)
  (log_softmax): LogSoftmax(dim=1)
)
'''
#model shape
for p in model.parameters():
    print(p.size())
'''
torch.Size([32, 1, 5, 5])
torch.Size([32])
torch.Size([64, 32, 5, 5])
torch.Size([64])
torch.Size([1024, 3136])
torch.Size([1024])
torch.Size([10, 1024])
torch.Size([10])
'''
def count_parameters(model):
    return sum(p.numel() for p in model.parameters() if p.requires_grad)

model_hp = count_parameters(model)
print('model"s hyper parameters', model_hp)
# model"s hyper parameters 3274634

Data setup 및 train, test loader 설정

batch_size = 64
train_loader = torch.utils.data.DataLoader(datasets.MNIST('data', train=True, download=True, transform=transforms.ToTensor()),batch_size=batch_size, shuffle=True)
print(len(train_loader)) # 938, 64 * 938 = 60032
test_loader = torch.utils.data.DataLoader(datasets.MNIST('data', train=False, transform=transforms.ToTensor()),batch_size=1000)
print(len(test_loader)) # 10, (10 * 1000 = 10000)
'''
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to data/MNIST/raw/train-images-idx3-ubyte.gz
9913344/? [04:51<00:00, 34050.71it/s]

Extracting data/MNIST/raw/train-images-idx3-ubyte.gz to data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to data/MNIST/raw/train-labels-idx1-ubyte.gz
29696/? [00:01<00:00, 26930.77it/s]

Extracting data/MNIST/raw/train-labels-idx1-ubyte.gz to data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to data/MNIST/raw/t10k-images-idx3-ubyte.gz
Failed to download (trying next):
HTTP Error 503: Service Unavailable

Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz
Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to data/MNIST/raw/t10k-images-idx3-ubyte.gz
1649664/? [00:00<00:00, 3989386.71it/s]

Extracting data/MNIST/raw/t10k-images-idx3-ubyte.gz to data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to data/MNIST/raw/t10k-labels-idx1-ubyte.gz
Failed to download (trying next):
HTTP Error 503: Service Unavailable

Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz
Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-labels-idx1-ubyte.gz to data/MNIST/raw/t10k-labels-idx1-ubyte.gz
5120/? [00:00<00:00, 139107.35it/s]

Extracting data/MNIST/raw/t10k-labels-idx1-ubyte.gz to data/MNIST/raw

Processing...
Done!
938
10
/usr/local/lib/python3.7/dist-packages/torchvision/datasets/mnist.py:502: UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the tensor. You may want to copy the array to protect its data or make it writeable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at  /pytorch/torch/csrc/utils/tensor_numpy.cpp:143.)
  return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)
'''

 

Adam optimizer, learning rate 1e-4로 설정

optimizer = optim.Adam(model.parameters(), lr=1e-4)

 

Model training, epoch은 10으로 설정

model.train()
epochs = 10 ### change
total_loss = 0
total_acc = 0
train_loss = []
train_accuracy = []
i = 0
for epoch in range(epochs):
    for data, target in train_loader:
        data, target = Variable(data), Variable(target)
        data = data.to(device)        
       
        target = target.to(device)
         
        optimizer.zero_grad()
        output = model(data)
       
        loss = F.nll_loss(output, target)
        loss.backward()    # calc gradients
       
        total_loss += loss
       
        train_loss.append(total_loss/i)
        optimizer.step()   # update gradients
       
        prediction = output.data.max(1)[1]   # first column has actual prob.
        accuracy = prediction.eq(target.data).sum()/batch_size*100
       
        total_acc += accuracy
       
        train_accuracy.append(total_acc/i)
       
        if i % 10 == 0:
            print('Epoch: {}\t Train Step: {}\tLoss: {:.3f}\tAccuracy: {:.3f}'.format(epoch+1, i, loss, accuracy))
        i += 1
    print('Epoch: {} finished'.format(epoch+1))
'''
Epoch: 10	 Train Step: 8450	Loss: 0.015	Accuracy: 100.000
Epoch: 10	 Train Step: 8460	Loss: 0.015	Accuracy: 100.000
Epoch: 10	 Train Step: 8470	Loss: 0.052	Accuracy: 98.438
Epoch: 10	 Train Step: 8480	Loss: 0.005	Accuracy: 100.000
Epoch: 10	 Train Step: 8490	Loss: 0.012	Accuracy: 100.000
Epoch: 10	 Train Step: 8500	Loss: 0.032	Accuracy: 98.438
Epoch: 10	 Train Step: 8510	Loss: 0.014	Accuracy: 100.000
Epoch: 10	 Train Step: 8520	Loss: 0.037	Accuracy: 98.438
Epoch: 10	 Train Step: 8530	Loss: 0.006	Accuracy: 100.000
Epoch: 10	 Train Step: 8540	Loss: 0.006	Accuracy: 100.000
Epoch: 10	 Train Step: 8550	Loss: 0.060	Accuracy: 98.438
Epoch: 10	 Train Step: 8560	Loss: 0.004	Accuracy: 100.000
Epoch: 10	 Train Step: 8570	Loss: 0.011	Accuracy: 100.000
Epoch: 10	 Train Step: 8580	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 8590	Loss: 0.075	Accuracy: 96.875
Epoch: 10	 Train Step: 8600	Loss: 0.006	Accuracy: 100.000
Epoch: 10	 Train Step: 8610	Loss: 0.035	Accuracy: 98.438
Epoch: 10	 Train Step: 8620	Loss: 0.005	Accuracy: 100.000
Epoch: 10	 Train Step: 8630	Loss: 0.059	Accuracy: 98.438
Epoch: 10	 Train Step: 8640	Loss: 0.026	Accuracy: 98.438
Epoch: 10	 Train Step: 8650	Loss: 0.003	Accuracy: 100.000
Epoch: 10	 Train Step: 8660	Loss: 0.017	Accuracy: 100.000
Epoch: 10	 Train Step: 8670	Loss: 0.001	Accuracy: 100.000
Epoch: 10	 Train Step: 8680	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 8690	Loss: 0.001	Accuracy: 100.000
Epoch: 10	 Train Step: 8700	Loss: 0.005	Accuracy: 100.000
Epoch: 10	 Train Step: 8710	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 8720	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 8730	Loss: 0.003	Accuracy: 100.000
Epoch: 10	 Train Step: 8740	Loss: 0.049	Accuracy: 98.438
Epoch: 10	 Train Step: 8750	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 8760	Loss: 0.028	Accuracy: 98.438
Epoch: 10	 Train Step: 8770	Loss: 0.031	Accuracy: 98.438
Epoch: 10	 Train Step: 8780	Loss: 0.008	Accuracy: 100.000
Epoch: 10	 Train Step: 8790	Loss: 0.059	Accuracy: 98.438
Epoch: 10	 Train Step: 8800	Loss: 0.011	Accuracy: 100.000
Epoch: 10	 Train Step: 8810	Loss: 0.025	Accuracy: 98.438
Epoch: 10	 Train Step: 8820	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 8830	Loss: 0.034	Accuracy: 96.875
Epoch: 10	 Train Step: 8840	Loss: 0.003	Accuracy: 100.000
Epoch: 10	 Train Step: 8850	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 8860	Loss: 0.009	Accuracy: 100.000
Epoch: 10	 Train Step: 8870	Loss: 0.020	Accuracy: 98.438
Epoch: 10	 Train Step: 8880	Loss: 0.011	Accuracy: 100.000
Epoch: 10	 Train Step: 8890	Loss: 0.003	Accuracy: 100.000
Epoch: 10	 Train Step: 8900	Loss: 0.001	Accuracy: 100.000
Epoch: 10	 Train Step: 8910	Loss: 0.013	Accuracy: 98.438
Epoch: 10	 Train Step: 8920	Loss: 0.043	Accuracy: 98.438
Epoch: 10	 Train Step: 8930	Loss: 0.001	Accuracy: 100.000
Epoch: 10	 Train Step: 8940	Loss: 0.003	Accuracy: 100.000
Epoch: 10	 Train Step: 8950	Loss: 0.001	Accuracy: 100.000
Epoch: 10	 Train Step: 8960	Loss: 0.018	Accuracy: 98.438
Epoch: 10	 Train Step: 8970	Loss: 0.006	Accuracy: 100.000
Epoch: 10	 Train Step: 8980	Loss: 0.033	Accuracy: 98.438
Epoch: 10	 Train Step: 8990	Loss: 0.022	Accuracy: 100.000
Epoch: 10	 Train Step: 9000	Loss: 0.008	Accuracy: 100.000
Epoch: 10	 Train Step: 9010	Loss: 0.011	Accuracy: 100.000
Epoch: 10	 Train Step: 9020	Loss: 0.000	Accuracy: 100.000
Epoch: 10	 Train Step: 9030	Loss: 0.013	Accuracy: 100.000
Epoch: 10	 Train Step: 9040	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 9050	Loss: 0.001	Accuracy: 100.000
Epoch: 10	 Train Step: 9060	Loss: 0.030	Accuracy: 98.438
Epoch: 10	 Train Step: 9070	Loss: 0.013	Accuracy: 100.000
Epoch: 10	 Train Step: 9080	Loss: 0.009	Accuracy: 100.000
Epoch: 10	 Train Step: 9090	Loss: 0.018	Accuracy: 98.438
Epoch: 10	 Train Step: 9100	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 9110	Loss: 0.007	Accuracy: 100.000
Epoch: 10	 Train Step: 9120	Loss: 0.001	Accuracy: 100.000
Epoch: 10	 Train Step: 9130	Loss: 0.008	Accuracy: 100.000
Epoch: 10	 Train Step: 9140	Loss: 0.001	Accuracy: 100.000
Epoch: 10	 Train Step: 9150	Loss: 0.042	Accuracy: 98.438
Epoch: 10	 Train Step: 9160	Loss: 0.004	Accuracy: 100.000
Epoch: 10	 Train Step: 9170	Loss: 0.001	Accuracy: 100.000
Epoch: 10	 Train Step: 9180	Loss: 0.055	Accuracy: 98.438
Epoch: 10	 Train Step: 9190	Loss: 0.016	Accuracy: 98.438
Epoch: 10	 Train Step: 9200	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 9210	Loss: 0.007	Accuracy: 100.000
Epoch: 10	 Train Step: 9220	Loss: 0.000	Accuracy: 100.000
Epoch: 10	 Train Step: 9230	Loss: 0.007	Accuracy: 100.000
Epoch: 10	 Train Step: 9240	Loss: 0.004	Accuracy: 100.000
Epoch: 10	 Train Step: 9250	Loss: 0.101	Accuracy: 96.875
Epoch: 10	 Train Step: 9260	Loss: 0.017	Accuracy: 100.000
Epoch: 10	 Train Step: 9270	Loss: 0.007	Accuracy: 100.000
Epoch: 10	 Train Step: 9280	Loss: 0.005	Accuracy: 100.000
Epoch: 10	 Train Step: 9290	Loss: 0.002	Accuracy: 100.000
Epoch: 10	 Train Step: 9300	Loss: 0.006	Accuracy: 100.000
Epoch: 10	 Train Step: 9310	Loss: 0.012	Accuracy: 100.000
Epoch: 10	 Train Step: 9320	Loss: 0.009	Accuracy: 100.000
Epoch: 10	 Train Step: 9330	Loss: 0.003	Accuracy: 100.000
Epoch: 10	 Train Step: 9340	Loss: 0.004	Accuracy: 100.000
Epoch: 10	 Train Step: 9350	Loss: 0.003	Accuracy: 100.000
Epoch: 10	 Train Step: 9360	Loss: 0.030	Accuracy: 98.438
Epoch: 10	 Train Step: 9370	Loss: 0.008	Accuracy: 100.000
Epoch: 10 finished
'''

Training accuracy에서 MLP 보다 높은 것을 알 수 있음

 

Plotting 결과

plt.figure()
plt.plot(np.arange(len(train_loss)), train_loss)
plt.show()
#plt.savefig('./train_loss_result.png')

plt.figure()
plt.plot(np.arange(len(train_accuracy)), train_accuracy)
plt.show()
#plt.savefig('./train_accuracy_result.png')

step에 따른 training loss 변화도
step에 따른 training accuracy 변화도

 

Evaluation 결과

with torch.no_grad():
    model.eval()
    correct = 0
   
    for data, target in test_loader:
        data, target = Variable(data), Variable(target)
        data = data.to(device)
        target = target.to(device)
        output = model(data)
        prediction = output.data.max(1)[1]
        correct += prediction.eq(target.data).sum()

print('\nTest set: Accuracy: {:.2f}%'.format(100. * correct / len(test_loader.dataset)))
# Test set: Accuracy: 99.11%

마찬가지로 MLP보다 CNN의 성능이 더 높음을 알 수 있음

 

728x90
728x90

이번 시간에는 여러 개의 Fully-connected layer를 쌓는 것을 코딩해본다.

 

먼저 아래의 코드를 통해 library 를 importing 함

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
from torch.autograd import Variable
import os
import matplotlib.pyplot as plt
import numpy as np

 

또한 아래의 코드를 통해 현재의 pytorch 버전에 대해 확인함

torch.__version__

 

이후 연산할 장치에 대해 선언해야 함

아래와 같이 device를 gpu로 설정함

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
torch.manual_seed(2891)
num_gpu = 1
if torch.cuda.device_count() > 1:
    num_gpu = torch.cuda.device_count()
print("Let's use", num_gpu, "GPUs!") # 1
print('device', device) # cuda

이후 간단한 MLP (Multi-Layer Perceptron) 모델을 구현함

 

입력은 MNIST dataset을 사용함

 

MNIST dataset의 각각의 요소는 (28, 28) 의 shape을 갖고 있기 때문에,

MLP를 통과하기 위해서는 각 요소를 flatten 시켜야 함

 

즉 reshape 을 사용하여 (28, 28) --> (1, 784)로 변경해야 함

 

class MnistMLP(nn.Module):
    def __init__(self, num_class, drop_prob):
        super(MnistMLP, self).__init__()
        # input is 28x28
        # need for flatten ==> 784
        self.dropout = nn.Dropout(p=drop_prob)
        self.linear1 = nn.Linear(784, 512)
        self.linear2 = nn.Linear(512, 256)
        self.linear3 = nn.Linear(256, 10)

        self.reduce_layer = nn.Linear(10, num_class)
        self.logsoftmax = nn.LogSoftmax(dim=1)
       
    def forward(self, x):
       
        x = x.float()
        mlp1 = F.relu(self.linear1(x.view(-1, 784)))
        mlp1 = self.dropout(mlp1)
        mlp2 = F.relu(self.linear2(mlp1))
        mlp2 = self.dropout(mlp2)
        mlp3 = F.relu(self.linear3(mlp2))
        mlp3 = self.dropout(mlp3)
  
        output = self.reduce_layer(mlp3)

    
        return self.logsoftmax(output)

 

이후 아래의 코드처럼 모델을 선언하고 gpu에 올림

model = MnistMLP(10, 0.3)
model.to(device)

'''
MnistMLP(
  (dropout): Dropout(p=0.3, inplace=False)
  (linear1): Linear(in_features=784, out_features=512, bias=True)
  (linear2): Linear(in_features=512, out_features=256, bias=True)
  (linear3): Linear(in_features=256, out_features=10, bias=True)
  (reduce_layer): Linear(in_features=10, out_features=10, bias=True)
  (logsoftmax): LogSoftmax(dim=1)
)
'''

MNIST의 class 개수는 10개 이므로, 첫 번째 인자에 10을 넣었고, dropout은 30%확률로 진행

 

작성한 모델의 매 layer 마다의 shape은 아래를 통해서 확인할 수 있고,

#model shape
for p in model.parameters():
    print(p.size())
'''
torch.Size([512, 784])
torch.Size([512])
torch.Size([256, 512])
torch.Size([256])
torch.Size([10, 256])
torch.Size([10])
torch.Size([10, 10])
torch.Size([10])
'''

 

총 hyperparameter는 아래를 통해 확인 가능함

def count_parameters(model):
    return sum(p.numel() for p in model.parameters() if p.requires_grad)

model_hp = count_parameters(model)
print('model"s hyper parameters', model_hp)
'''
model"s hyper parameters 535928
'''

 

이제 모델 선언은 끝났고, data를 loading 해야 함

아래의 코드를 통해 MNIST dataset을 다운받고, train 및 test로 분할함

batch_size = 128
train_loader = torch.utils.data.DataLoader(datasets.MNIST('data', train=True, download=True, transform=transforms.ToTensor()),batch_size=batch_size, shuffle=True)
print(len(train_loader)) # 118, 512 * 118 = 60000
test_loader = torch.utils.data.DataLoader(datasets.MNIST('data', train=False, transform=transforms.ToTensor()),batch_size=1000)
print(len(test_loader)) # 10, 10 * 1000 = 10000
'''
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to data/MNIST/raw/train-images-idx3-ubyte.gz
9913344/? [04:54<00:00, 33670.03it/s]

Extracting data/MNIST/raw/train-images-idx3-ubyte.gz to data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to data/MNIST/raw/train-labels-idx1-ubyte.gz
29696/? [00:01<00:00, 26891.25it/s]

Extracting data/MNIST/raw/train-labels-idx1-ubyte.gz to data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to data/MNIST/raw/t10k-images-idx3-ubyte.gz
Failed to download (trying next):
HTTP Error 503: Service Unavailable

Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz
Downloading https://ossci-datasets.s3.amazonaws.com/mnist/t10k-images-idx3-ubyte.gz to data/MNIST/raw/t10k-images-idx3-ubyte.gz
1649664/? [00:00<00:00, 3911534.90it/s]

Extracting data/MNIST/raw/t10k-images-idx3-ubyte.gz to data/MNIST/raw

Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz
Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to data/MNIST/raw/t10k-labels-idx1-ubyte.gz
5120/? [00:00<00:00, 159181.34it/s]

Extracting data/MNIST/raw/t10k-labels-idx1-ubyte.gz to data/MNIST/raw

Processing...
Done!
469
10
/usr/local/lib/python3.7/dist-packages/torchvision/datasets/mnist.py:502: UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the tensor. You may want to copy the array to protect its data or make it writeable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at  /pytorch/torch/csrc/utils/tensor_numpy.cpp:143.)
  return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)
'''

 

Optimizer 선언은 아래와 같이 진행하며, 가장 많이 사용되는 Adam을 learning rate 1e-4로 사용

optimizer = optim.Adam(model.parameters(), lr=1e-4)

 

Training을 진행함 (epoch은 10까지만 진행)

model.train()
epochs = 10 ### change
total_loss = 0
total_acc = 0
train_loss = []
train_accuracy = []
i = 0
for epoch in range(epochs):
    for data, target in train_loader:
        data, target = Variable(data), Variable(target)
        data = data.to(device)        
       
        target = target.to(device)
         
        optimizer.zero_grad()
        output = model(data)
       
        loss = F.nll_loss(output, target)
        loss.backward()    # calc gradients
       
        total_loss += loss
       
        train_loss.append(total_loss/i)
        optimizer.step()   # update gradients
       
        prediction = output.data.max(1)[1]   # first column has actual prob.
        accuracy = prediction.eq(target.data).sum()/batch_size*100
       
        total_acc += accuracy
       
        train_accuracy.append(total_acc/i)
       
        if i % 10 == 0:
            print('Epoch: {}\t Train Step: {}\tLoss: {:.3f}\tAccuracy: {:.3f}'.format(epoch+1, i, loss, accuracy))
        i += 1
    print('Epoch: {} finished'.format(epoch+1))
'''
Epoch: 9	 Train Step: 4200	Loss: 0.652	Accuracy: 78.906
Epoch: 9	 Train Step: 4210	Loss: 0.422	Accuracy: 85.156
Epoch: 9	 Train Step: 4220	Loss: 0.496	Accuracy: 61.719
Epoch: 9 finished
Epoch: 10	 Train Step: 4230	Loss: 0.432	Accuracy: 84.375
Epoch: 10	 Train Step: 4240	Loss: 0.435	Accuracy: 89.062
Epoch: 10	 Train Step: 4250	Loss: 0.370	Accuracy: 86.719
Epoch: 10	 Train Step: 4260	Loss: 0.468	Accuracy: 83.594
Epoch: 10	 Train Step: 4270	Loss: 0.479	Accuracy: 85.156
Epoch: 10	 Train Step: 4280	Loss: 0.422	Accuracy: 85.156
Epoch: 10	 Train Step: 4290	Loss: 0.538	Accuracy: 78.906
Epoch: 10	 Train Step: 4300	Loss: 0.493	Accuracy: 87.500
Epoch: 10	 Train Step: 4310	Loss: 0.531	Accuracy: 82.031
Epoch: 10	 Train Step: 4320	Loss: 0.524	Accuracy: 82.031
Epoch: 10	 Train Step: 4330	Loss: 0.520	Accuracy: 83.594
Epoch: 10	 Train Step: 4340	Loss: 0.557	Accuracy: 82.812
Epoch: 10	 Train Step: 4350	Loss: 0.597	Accuracy: 80.469
Epoch: 10	 Train Step: 4360	Loss: 0.272	Accuracy: 90.625
Epoch: 10	 Train Step: 4370	Loss: 0.402	Accuracy: 85.938
Epoch: 10	 Train Step: 4380	Loss: 0.552	Accuracy: 78.906
Epoch: 10	 Train Step: 4390	Loss: 0.450	Accuracy: 85.156
Epoch: 10	 Train Step: 4400	Loss: 0.505	Accuracy: 85.156
Epoch: 10	 Train Step: 4410	Loss: 0.498	Accuracy: 79.688
Epoch: 10	 Train Step: 4420	Loss: 0.550	Accuracy: 77.344
Epoch: 10	 Train Step: 4430	Loss: 0.515	Accuracy: 84.375
Epoch: 10	 Train Step: 4440	Loss: 0.556	Accuracy: 78.125
Epoch: 10	 Train Step: 4450	Loss: 0.363	Accuracy: 88.281
Epoch: 10	 Train Step: 4460	Loss: 0.376	Accuracy: 88.281
Epoch: 10	 Train Step: 4470	Loss: 0.409	Accuracy: 86.719
Epoch: 10	 Train Step: 4480	Loss: 0.494	Accuracy: 84.375
Epoch: 10	 Train Step: 4490	Loss: 0.550	Accuracy: 82.031
Epoch: 10	 Train Step: 4500	Loss: 0.349	Accuracy: 90.625
Epoch: 10	 Train Step: 4510	Loss: 0.465	Accuracy: 82.812
Epoch: 10	 Train Step: 4520	Loss: 0.577	Accuracy: 78.906
Epoch: 10	 Train Step: 4530	Loss: 0.412	Accuracy: 85.938
Epoch: 10	 Train Step: 4540	Loss: 0.557	Accuracy: 81.250
Epoch: 10	 Train Step: 4550	Loss: 0.481	Accuracy: 83.594
Epoch: 10	 Train Step: 4560	Loss: 0.373	Accuracy: 86.719
Epoch: 10	 Train Step: 4570	Loss: 0.445	Accuracy: 84.375
Epoch: 10	 Train Step: 4580	Loss: 0.543	Accuracy: 77.344
Epoch: 10	 Train Step: 4590	Loss: 0.358	Accuracy: 88.281
Epoch: 10	 Train Step: 4600	Loss: 0.408	Accuracy: 87.500
Epoch: 10	 Train Step: 4610	Loss: 0.523	Accuracy: 82.812
Epoch: 10	 Train Step: 4620	Loss: 0.418	Accuracy: 86.719
Epoch: 10	 Train Step: 4630	Loss: 0.423	Accuracy: 85.938
Epoch: 10	 Train Step: 4640	Loss: 0.512	Accuracy: 79.688
Epoch: 10	 Train Step: 4650	Loss: 0.625	Accuracy: 77.344
Epoch: 10	 Train Step: 4660	Loss: 0.379	Accuracy: 86.719
Epoch: 10	 Train Step: 4670	Loss: 0.440	Accuracy: 82.812
Epoch: 10	 Train Step: 4680	Loss: 0.499	Accuracy: 81.250
Epoch: 10 finished
'''

Training에 대한 loss를 시각화 하기 위해 matplotlib 사용

plt.figure()
plt.plot(np.arange(len(train_loss)), train_loss)
plt.show()
#plt.savefig('./train_loss_result.png')

plt.figure()
plt.plot(np.arange(len(train_accuracy)), train_accuracy)
plt.show()
#plt.savefig('./train_accuracy_result.png')

training step에 따른 loss 변화도
training step에 따른 accuracy 변화도

모델의 실제 성능 평가를 하기 위해 training에 쓰이지 않은 test data로 아래와 같이 평가 진행

with torch.no_grad():
    model.eval()
    correct = 0
   
    for data, target in test_loader:
        data, target = Variable(data), Variable(target)
        data = data.to(device)
        target = target.to(device)
        output = model(data)
        prediction = output.data.max(1)[1]
        correct += prediction.eq(target.data).sum()

print('\nTest set: Accuracy: {:.2f}%'.format(100. * correct / len(test_loader.dataset)))
#Test set: Accuracy: 96.04%

간단한 MLP 3-layer 만으로도 96%의 성능을 얻었음

728x90

+ Recent posts