리눅스 커널을 vi로 분석하기 위한 태크닉 기술


설정파일


vimrc


2019-01-08 version

vimrc




1. ctags + cscope 설치하기

apt-get install ctags -y
apt-get install cscope -y


TIP: 리눅스 커널의 경우 아키텍쳐를 설정하여 tag를 생성하게 할 수 있음.

스크립트 있는지 확인: "ls -al ./scripts/tags.sh"


2. vim + 플러그인 설치 및 설정하기


http://www.vim.org/scripts/index.php 에서 제공하는 Plugin을 다룬다.


vim 플러그인은 대부분 vundle이라는 plugin manager에 의해서 관리 된다.

이것으로 인해서 plugin 추가 설치 삭제 등이 매우 간편해 졌다.


vim 환경설정 파일만 있어도 필요한 플러그인을 자동으로 검색하여 설치해주기 때문에

작업 컴퓨터의 재구성이 매우 편해졌다.


vim과 git 설치


sudo apt-get install vim -y

sudo apt-get install git -y


디렉터리 생성

mkdir ~/.vim

mkdir ~/.vim/bundle


Plugin Manager Download (vundle)

git clone https://github.com/VundleVim/Vundle.vim.git ~/.vim/bundle/Vundle.vim

# 영문 메뉴얼 사이트가서 매번 최신 link를 확인해 보는 것이 좋음 (2020.1.16일 업데이트 주소)


영문 메뉴얼 사이트: Click


Vundle 사용법 한글 블로그: Click


vi ~/.vimrc 내용 추가



set rtp+=~/.vim/bundle/Vundle.vim

call vundle#begin()


Plugin 'gmarik/Vundle.vim'

Plugin 'The-NERD-Tree' #계층 별로 파일을 보고 접근할 수 있다.

Plugin 'Source-Explorer-srcexpl.vim' 

Plugin 'SrcExpl' #커서가 지시하는 변수들의 정보를 보여줌

Plugin 'taglist.vim' #ctags를 사용하여 소스코드 파일에서 함수, 전역 변수 리스트를 확인할 수 있는 강력한 사이드바를 제공

Plugin 'AutoComplPop' #자동완성 플러긴

Plugin 'snipMate' #for, while과 같은 예약어를 입력할 경우 snip code를 자동으로 제공해 준다. ~/.vim/snippets 에 제공 기준이 있음.

call vundle#end()


 -- 자동완성과 관련된 코드 --
"========== AutoCompletePop ==========
function! InsertTabWrapper()
    let col=col('.')-1
    if !col||getline('.')[col-1]!~'\k'
        return "\<TAB>"
    else
        if pumvisible()
            return "\<C-N>"
        else
            return "\<C-N>\<C-P>"
        end 
    endif
endfunction

inoremap <TAB> <c-r>=InsertTabWrapper()<cr>
hi Pmenu ctermbg=blue
hi PmenuSel ctermbg=yellow ctermbg=black
hi PmenuSbar ctermbg=blue




vim에서 명령 모드 ":" 에서 아래 명령어를 수행

:PluginInstall

#BundleInstall에서 PluginInstall로 명령어가 변경됨.


하단에 Done이 출력 되면 설정한 모든 Plugin이 설치된 것이다.







□ ctags를 이용한 방법

 

ctags의 정의: ctags는 프로그래밍 소스코드에서 태그(전역변수 선언, 함수 정의, 매크로 선언)들의 데이터베이스(tags 파일)를 생성하는 유닉스 명령이다.

 

ctags에서 인식하는 파일 종류

Assembler, ASP, Awk, C, C++, BETA, Cobol, Eiffel, Fortran, Java, Lisp, Lua, Make, Pascal, Perl

PHP, PL/SQL, Python, REXX, Ruby, Scheme, Shell scripts( Bourne/Korn/Z ), S-Lang, Tcl

Vera, Verilog, Vim, VACC/Bison

 

vim에 tags 파일을 등록하는 방법

--단일 지정

:set tags=./tags

--복수 지정

:set tags=./tags,(콤마) 

//매번 해주어도 되고, vimrc에 등록을 해도 된다.

 

 

tj명령은 tag jump의 약자이다. 이 명령어를 실행하면 태크 데이터베이스

파일(tags)에서 start_kernel 태크를 찾아 리스트로 보여주게 된다.

 

:tj start_kernel


창을 분할 해서 오픈 한다.

 

:sts [태크]


스택에 넣었다가 빼면서 이동 한다.


컨트롤 + ] , 컨트롤 + t

 

[ctags 명령 요약]

:ta [태그] or Ctrl+] or :ts[태그] or :tj [태그] //[tag]가 정의된 위치를 나열하고 선택한 위치로 점프, 현재 위치는 스택에 push된다.

:po or Ctrl+t // 스택 top에 저장된 위치를 pop하고 그 위치로 점프

:sts [태그] or :stj [태그] // [태그]가 정의된 위치를 나열하고 선택한 위치로 창을 수평 분할해 새로 생성된 창에 표시

:tn // tj or ts로 점프 했을때 그 선택적으로 점프할 수 있는 목록이 많을 경우 다음 태그로 이동 한다.

:tp // tj or ts로 점프 했을때 그 선택적으로 점프할 수 있는 목록이 많을 경우 이전 태그로 이동 한다.

:tr // tj or ts로 점프 했을때 그 선택적으로 점프할 수 있는 목록이 많을 경우 처음 태그로 이동 한다.

:tl // tj or ts로 점프 했을때 그 선택적으로 점프할 수 있는 목록이 많을 경우 끝 태그로 이동 한다.

 

:pts [태그] // sts랑 매우 유사하지만 커서가 현재 창에 있다.

:ptj [태그] // 미리보기 윈도우에 태그가 정의된 형식을 보여줌. ( 그닥 차이를 못느끼겠다.)

:ptn // ptj나 pts로 점프했을 때 다음 태그로 점프

:ptp // ptj나 pts로 점프했을 때 이전 태그로 점프

:ptr // ptj나 pts로 점프햇을 때 처음 태그로 점프

:ptl // ptj나 pts로 점프했을 때 마지막 태그로 점프

 

 

vim 내장 스크립트 작성

 

홈 디렉터리의 .vimrc 파일을 열어 다음과 같은 행을 추가한다.

 "ctags macro setting
 if version >= 500 // vim 버전이 5.0 이상일 때만 적용하게 만들 었다.
 func! Sts()
       let st = expand("<cword>") // let을 이용해서 st라는 변수를 생성 한다.
          exe "sts ".st // exe를 이용해서 뒤에나온 명령어를 출력 한다. .st를 출력한다.
 endfunc
 nmap ,st :call Sts()<cr> // ,st와 Sts()함수를 매핑 하였다. 
 
 func! Tj()
       let tj = expand("<cword>")
          exe "tj ".tj
 endfunc
 nmap ,tj :call Tj()<cr>
 endif

 


□ CSCOPE를 사용하는 것 

 

ctags로 찾을 수 있는 C, C++ 태그 종류

classes

macro definitions (and # undef names)

enumerators

function definitions

enumeration names

class, struct, or union members

namespaces

function prototypes and declarations [off]

structure names

typedefs

union names

vriable definitions

extern and forward variable declarations [off]

 

위와 같은 종류로는 결국 지역변수나 전역변수가 사용된 곳이나 함수가 사용된 곳을 찾기 힘들다.

 

ctags가 단지 vim이 사용하는 태그 데이터베이스만 만드는 프로그램임에 비해 cscope는 원래부터 C소스를 분석하기 위해 만들어졌다. 그래서 cscope는 vim 없이 자체적으로 동작 가능하며, C 소스를 분석할 때 유용하게 사용할 수 있다.

 

cscope로 분석 가능한 소스 파일에는

Assembly, C, C++, Lex, Yacc등이 있다.

 

이 cscope 또한 심볼 데이터베이스 파일을 만들어야 한다.

 

이것을 매번 입력하기 힘드니 스크립트 파일을 만든다.

mkcscope.sh 파일을 작성 하자.

 

#!/bin/sh
rm -rf cscope.files cscope.files

find . \( -name '*.c' -o -name '*.cpp' -o -name '*.cc' -o -name '*.h' -o -name '*.s' -o -name '*.S' \) -print > cscope.files

cscope -i cscope.files

 

chmod 755 mkcscope.sh

mv mkcscope.sh /usr/local/bin

 

스크립트 파일을 언제든지 실행 할수 있게 해준다.

 

이제 mkcscope.sh를 실행하면 database를 생성하게 된다.

그 다음 Ctrl+d를 이용해서 빠져 나간다.

 

이제 앞으로 cscope를 사용할 것이라고 vim에게 알려주어야 한다.

=============================================

set csprg=/usr/bin/cscope

set csto=0

set cst

set nocsverb


if filereadable("./cscope.out")

cs add cscope.out

else

cs add /usr/src/linux/cscope.out

endif

set csverb

==============================================



 

-> 사용방법

 

-> cscope 를 실행 하기 위해서는 :cs find {질의종류} {심벌} 을 입력

ex) :cs find s start_kernel

cscope 의 질의 종류

0 or s - > Find this C symbol

1 or g - > Find this definition

2 or d - > Find functions called by this function

3 or c - > Find functions calling this function

4 or t - > Find assignments to

6 or e - > Find this egrep pattern

7 or f - > Find this File

 

 

vim에 스크립트를 등록하자.

 65 func! Css()
 66       let css = expand("<cword>")
 67          new
 68             exe "cs find s ".css
 69                if getline(1) == ""
 70                      exe "q!"
 71                         endif
 72                         endfunc
 73                         nmap ,css :call Css()<cr>
 74
 75                         func! Csc()
 76       let csc = expand("<cword>")
 77          new
 78             exe "cs find c ".csc
 79                if getline(1) == ""
 80                      exe "q!"
 81                         endif
 82                         endfunc
 83                         nmap ,csc :call Csc()<cr>
 84
 85                         func! Csd()
 86       let csd = expand("<cword>")
 87          new
 88             exe "cs find d ".csd
 89                if getline(1) == ""
 90                      exe "q!"
 91                         endif
 92                         endfunc
 93                         nmap ,csd :call Csd()<cr>
 94
 95                         func! Csg()
 96       let csg = expand("<cword>")
 97          new
 98             exe "cs find g ".csg
 99                if getline(1) == ""
100                      exe "q!"
101                         endif
102                         endfunc
103                         nmap ,csg :call Csg()<cr>

 

이렇게 ctags와 cscope를 2개 동시에 사용하면 된다.

일단은 그냥 ctags만 쓰다가 ctags가 찾지 못할 때만 cscope를 쓰자. 왜냐하면 cscope가 더 느리기 때문이다.

즉, 함수나 변수가 사용된 곳을 찾을 때와 같은 경우에만 cscope를 사용하자.

□ vim과 조합하는 기타 기능.

 

http://www.vim.rog/scripts 사이트에서 taglist.vim 스크립트를 받아와 ~/.vim/plugin 디렉토리에 설치한다.


그 다음 명령모드에서 :Tlist를 해보면 스크린샷과 같은 편리한 기능이 나오는것을 볼 수 있다.





vim의 유용한 단축키들


자동완성 기능

Ctrl+p //위로 검색해서 자동완성

Ctrl+n //아래로 검색해서 자동완성

 

해더파일 바로 읽어오기

Ctrl + wf

 

빠른 괄호 탐색 기능

{ }의 부분에서 % 기호를 누른다.

 



git difftool 사용법


git mergetool로 병합을 수행할 시 conflict문제가 발생하면 아래와 같이 해결한다.

git difftool 설정

git config --global diff.tool vimdiff
git config --global difftool.prompt false
git config --global alias.d difftool

vimdiff 사용법

리눅스에서 두 파일을 비교하는 명령어인 vimdiff의 간단한 사용법을 말씀 드리겠습니다.
기본적으로 vimdiff는 vim에서 화면을 분할하고, 두 파일을 열었을 상태와 같다고 보시면 됩니다.
추가적으로 좋은 점은 서로 다른 부분을 표시해주는 부분이죠.
두 파일을 비교하고, 병합하는데 사용할 수 있습니다.

우선 분할된 창에서 다른 창으로 이동하는 명령은 Ctrl + w + w입니다.

차이점이 있는 부분으로 이동하는 명령은 ] + c  [ + c 입니다.
] + c는 현재 위치에서 아래쪽으로 탐색하며,
[ + c는 현재 위치에서 위쪽으로 탐색을 진행합니다.

수정을 원하는 부분을 찾았으면 복사를 해야겠지요.
d + o는 현재 위치에 반대쪽 창의 내용을 복사해 옵니다.
d + p는 현재 위치의 내용을 반대쪽 창에 복사합니다.

vimdiff는 동일한 부분은 생략하여 보여줍니다.
이를 펼치기 위해서는 z + o 또는 z + space를 누르면 됩니다.
반대로 접기 위해서는 z + c를 누르면 됩니다.

마지막으로, 한쪽 창의 내용을 편집하다보면 차이점을 나타내는 표시가 없어질 경우가 있습니다.
이때 :diffupdate를 누르시면 다시 비교하여, 차이점을 표시해 줍니다.

참고 자료

https://www.rosipov.com/blog/use-vimdiff-as-git-mergetool/


Transitioning to TensorFlow 1.0


TensorFlow 1.0 부터는 모든 backwards compatible을 지원하지 않는다.
깔끔한 1.N lifesycle을 위해서 이러한 작업을 수행 한다.

upgrade

$ sudo pip3 install --upgrade TF_BINARY_URL # Python 3.N

https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.0.0-cp35-cp35m-linux_x86_64.whl

Collecting tensorflow-gpu==1.0.0 from https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.0.0-cp35-cp35m-linux_x86_64.whl
  Downloading https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow_gpu-1.0.0-cp35-cp35m-linux_x86_64.whl (95.0MB)
    100% |████████████████████████████████| 95.0MB 25kB/s
Requirement already up-to-date: six>=1.10.0 in ./.local/lib/python3.5/site-packages (from tensorflow-gpu==1.0.0)
Requirement already up-to-date: numpy>=1.11.0 in ./.local/lib/python3.5/site-packages (from tensorflow-gpu==1.0.0)
Requirement already up-to-date: wheel>=0.26 in ./.local/lib/python3.5/site-packages (from tensorflow-gpu==1.0.0)
Collecting protobuf>=3.1.0 (from tensorflow-gpu==1.0.0)
  Downloading protobuf-3.2.0-cp35-cp35m-manylinux1_x86_64.whl (5.6MB)
    100% |████████████████████████████████| 5.6MB 392kB/s
Collecting setuptools (from protobuf>=3.1.0->tensorflow-gpu==1.0.0)
  Downloading setuptools-34.3.0-py2.py3-none-any.whl (389kB)
    100% |████████████████████████████████| 399kB 2.4MB/s
Collecting appdirs>=1.4.0 (from setuptools->protobuf>=3.1.0->tensorflow-gpu==1.0.0)
  Downloading appdirs-1.4.2-py2.py3-none-any.whl
Collecting packaging>=16.8 (from setuptools->protobuf>=3.1.0->tensorflow-gpu==1.0.0)
  Downloading packaging-16.8-py2.py3-none-any.whl
Requirement already up-to-date: pyparsing in ./.local/lib/python3.5/site-packages (from packaging>=16.8->setuptools->protobuf>=3.1.0->tensorflow-gpu==1.0.0)
Installing collected packages: appdirs, packaging, setuptools, protobuf, tensorflow-gpu
  Found existing installation: setuptools 32.3.1
    Uninstalling setuptools-32.3.1:
      Successfully uninstalled setuptools-32.3.1
  Found existing installation: protobuf 3.1.0.post1
    Uninstalling protobuf-3.1.0.post1:
      Successfully uninstalled protobuf-3.1.0.post1
  Found existing installation: tensorflow-gpu 0.12.1
    Uninstalling tensorflow-gpu-0.12.1:
      Successfully uninstalled tensorflow-gpu-0.12.1
Successfully installed appdirs-1.4.2 packaging-16.8 protobuf-3.2.0 setuptools-34.3.0 tensorflow-gpu-1.0.0

버전 확인

jemin@jemin-desktop:~$ python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import tensorflow as tf
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcublas.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcudnn.so.5 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcufft.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:135] successfully opened CUDA library libcurand.so.8.0 locally
>>> tf.__version__
'1.0.0'

Code-Upgrade

아래와 같이 Google에서 제공하는 python코드를 이용해서 업그레이드 할 수 있다.

다운로드: link

To convert a single 0,n TensorFlow source file to 1.0, enter a command of the following format:

python tf_upgrade.py --infile InputFile --outfile OutputFile

출력 결과로 report.txt도 나오게 된다. 이것은 상세한 결과와 추가적으로 수작업 해야할 부분을 알려 준다.

디렉터리에 있는 모든것을 업데이트 하기위해서는 아래의 명령어를 사용 한다.

python tf_upgrade.py --intree InputDir --outtree OutputDir

실행하면 아래와 같이 정상적으로 잘 동작하는 것을 알 수 있다.

jemin@jemin-desktop:~/ESLAB_ML/jemin$ python ~/tensorflow_source/tensorflow/tensorflow/tools/compatibility/tf_upgrade.py --intree ./TensorFlowLecture --outtree ./TensorFlowLecture_1.0
TensorFlow 1.0 Upgrade Script
-----------------------------
Converted 33 files

Detected 0 errors that require attention
--------------------------------------------------------------------------------

Make sure to read the detailed log 'report.txt'


Faster R CNN Training


실제 해당 과정을 통해서 학습을 수행해 본다.

Prepare dataset and Pre-trained model

VOC-2007 데이터를 다운 받는다.

if [ ! -d data ]; then mkdir data; fi; cd data
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCdevkit_08-Jun-2007.tar
tar xvf VOCtrainval_06-Nov-2007.tar
tar xvf VOCtest_06-Nov-2007.tar
tar xvf VOCdevkit_08-Jun-2007.tar
rm -rf *.tar; cd ../

test_format error

error: AttributeError: 'module' object has no attribute 'text_format'
해결을 위해서 train.py에 import google.protobuf.text_format을 추가 한다.

TypeError: slice indices must be integers

(caffe_py2_virtualenv) jemin@jemin-desktop:~/caffe/second/py-faster-rcnn$ TypeError: slice indices must be integers or None or have an __index__ method
TypeError:: 명령을 찾을 수 없습니다

해결을 위해서는 numpy 1.12버전을 down-grade 한다.

pip uninstall numpy
pip install 'numpy==1.11.0'

모델 학습 방법

Training + Testing = 9963

Testing = 4952

학습하는 방법

일단 free training model을 들고 온다.
$ ./data/scripts/fetch_imagenet_models.sh

학습 방법은 총 2가지이다.

  • alternating optimization algorithm
  • approximate joint training

여기선 후자를 선택한다.

# ./experiments/scripts/faster_rcnn_end2end.sh [GPU_ID] [NET] [DATASET]
# Directly run this command might have an error "AssertionError: Selective search data not found at:". For the solution, please refer to Part 4.

$ ./experiments/scripts/faster_rcnn_end2end.sh 0 ZF pascal_voc

테스팅 방법

caffe zoo model

기본제공되는 caffe zoo 모델의 경우 ./data/faster_rcnn_models/ZF_faster_rcnn_final.caffemodel에 있다.
이것을 이용해서 테스팅을 수행해 본다.

./tools/test_net.py --gpu 0 --def models/pascal_voc/ZF/faster_rcnn_end2end/test.prototxt --net ./data/faster_rcnn_models/ZF_faster_rcnn_final.caffemodel --imdb voc_2007_test --cfg experiments/cfgs/faster_rcnn_end2end.yml

위와 같이 caffe zoo 모델은 mAP 0.4518로 그다지 정확도가 높지 않은 것을 알 수 있다.

새로 학습 모델

end2end
0.6116 mAP이다.

testing 데이터를 이용해서 과적합 시켜서 학습

  • testing data
  • end2end
  • 80000

정확도는 mAP = 0.8805

**직접 테스팅 실행 **

  • 정확도: mean AP = 0.8805
./tools/test_net.py --gpu 0 --def models/pascal_voc/ZF/faster_rcnn_end2end/test.prototxt --net ./output/faster_rcnn_end2end/voc_2007_test/zf_faster_rcnn_iter_80000.caffemodel --imdb voc_2007_test --cfg experiments/cfgs/faster_rcnn_end2end.yml


Faster-R-CNN Install on Ubuntu 16.04(GTX1080 CUDA 8.0,cuDNN 5.1)


pycaffe로 구현된 py-faster R-CNN을 uBuntu 16.04에 설치하는 방법을 다룬다.
그래픽카드는 GTX 1080이며 CUDA 8.0과 cuDNN 5.1을 사용한다.

Caffe 의존성 라이브러리 설치

핵심은 BVLC에서 최신 caffe는 설치할 필요가 없다.
왜냐하면, Faster-R-CNN 소스코드에 이미 구버전 caffe가 포함되어 있기 때문이다.
해당 버전은 2015년에 Microsoft에서 기존 Caffe를 수정해서 만든것이다.
버클리 대학에서 지공하는 공식 Caffe에는 Faster R-CNN에만 있는 RoI pooling와 같은 여러 기능들을 지원하지 않아서 실행이 안된다.

따라서 http://caffe.berkeleyvision.org/에서 prerequisites를 보고 그것들만 설치해 준다.

1. CUDA, cuDNN 설치하기

GTX 1080이기 때문에 CUDA 8과 cuDNN 5.1을 설치한다.
이전 post 참조

2. CUDA 환경변수 설정하기

TensorFlow와 다르게 설정 해줘야 한다.

vi ~/.bashrc

export PATH=/usr/local/cuda/bin:$PATH
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH

3. python virtual environment 설정

tensorflow와의 충돌을 막기위해서 virtualenv를 사용한다.

#install
$ sudo apt-get install python-pip python-dev python-virtualenv 
$ virtualenv --system-site-packages targetDirectory 

# activate shell
$ source ~/tensorflow/bin/activate # If using bash, ksh, sh, or 

활성화 하면 shell 앞에 (caffe_py2_virtualenv) jemin@jemin-desktop:와 같이 나옵니다.
이제부터 pip로 설치하면 모두 해당 virtual environment directory에 설치가 됩니다.
이때 sudo를 붙이면 중복성이 발생하니 pip로만 설치를 합니다.

4. 필요 라이브러리 설치

uBuntu 16.04를 기준으로 한다.

의존성 가이드 공식사이트: http://caffe.berkeleyvision.org/install_apt.html

sudo apt-get install opencl-headers build-essential \
  protobuf-compiler libprotoc-dev libboost-all-dev libleveldb-dev \
  hdf5-tools libhdf5-serial-dev \
  libopencv-core-dev libopencv-highgui-dev \
  libsnappy-dev libsnappy1 libatlas-base-dev cmake libstdc++6-4.8-dbg \
  libgoogle-glog0 libgoogle-glog-dev libgflags-dev liblmdb-dev

5. openCV 설치하기

openCV를 직접 받아서 compile해서 설치해야 최신 CUDA를 잘 지원한다.
그래서 github에서 직접 받아서 cmake를 통해서 설치한다.

의존성 라이브러리들

sudo apt-get install build-essential cmake git pkg-config libjpeg8-dev \
libjasper-dev libpng12-dev libgtk2.0-dev \
libavcodec-dev libavformat-dev libswscale-dev libv4l-dev gfortran
sudo apt-get install libtiff5-dev 

앞으로도 caffe에서도 사용하는 ATLAS (among many other BLAS implementation)을 설치한다.
sudo apt-get install libatlas-base-dev
이것 역시 openCV에서도 사용한다.

openCV 설치

git clone https://github.com/opencv/opencv.git
cd opencv
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE \
	-D CMAKE_INSTALL_PREFIX=/usr/local \
	-D INSTALL_C_EXAMPLES=ON \
	-D INSTALL_PYTHON_EXAMPLES=ON \
	-D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \
	-D BUILD_EXAMPLES=ON ..
  
make -j8
sudo make -j8 install
sudo ldconfig

설치확인

py-faster-rcnn 설치

공식사이트

1. github 다운

내부에 fast-rcnn git이 또 존재하므로 반드시 --recursive option을 줘서 두 개의 git repository에서 모두 다운 받아야 한다.

# Make sure to clone with --recursive
git clone --recursive https://github.com/rbgirshick/py-faster-rcnn.git

2. 의존성 파일 설치

  • cython 필요

    • sudo apt-get install cython
  • python package 설치, virtual env 활성화 상태에서

    • pip install easydict
    • pip install scikit-learn
    • pip protobuf
  • requirements.txt에 있는 python module 설치

    • cd py-faster-rcnn/caffe-faster-rcnn/python
    • for req in $(cat requirements.txt); do pip install $req | cut -d ">" -f1; done

3. 핵심 caffe 버전 통합

BVLC Caffe 2017최신 버전과 현재 내부에 있는 2015년 버전 MS 수정 caffe를 merge해야 한다.

원래 Microsoft Caffe

(caffe_py2_virtualenv) jemin@jemin-desktop:~/caffe/second/py-faster-rcnn/caffe-f                                                                                                                                                             ast-rcnn$ git log
commit 0dcd397b29507b8314e252e850518c5695efbb83
Author: Ross Girshick <ross.girshick@gmail.com>
Date:   Sun Aug 9 13:41:39 2015 -0700

    Fast and Faster R-CNN change set
     - smooth l1 loss
     - roi pooling
     - expose phase in pycaffe
     - dropout scaling at test time (needed for MSRA-trained ZF network)

차이점은
vi src/caffe/proto/caffe.proto를 열어서 보면 아래와 같이 Faster R CNN용 옵션들이 모두 있다는 것이다.
optional ROIPoolingParameter roi_pooling_param = 8266711;

최신 버전의 caffe를 설치해서 사용할 경우 이러한 Microsoft에서 변경한 내용들이 없기 때문에 추후에 demo.py를 실행 할 때

Message type "caffe.LayerParameter" has no field named "roi_pooling_param". 에러를 발생 시킨다. 따라서 반드시 2015년에 수정된 Microsoft caffe를 기반으로 merge를 수행 해야 한다.

(caffe_py2_virtualenv) jemin@jemin-desktop:~/caffe/second/py-faster-rcnn/caffe-f                                                                                                                                                             ast-rcnn$ git remote add caffe https://github.com/BVLC/caffe.git
(caffe_py2_virtualenv) jemin@jemin-desktop:~/caffe/second/py-faster-rcnn/caffe-f                                                                                                                                                             ast-rcnn$ git remote -v
caffe   https://github.com/BVLC/caffe.git (fetch)
caffe   https://github.com/BVLC/caffe.git (push)
origin  https://github.com/rbgirshick/caffe-fast-rcnn.git (fetch)
origin  https://github.com/rbgirshick/caffe-fast-rcnn.git (push)
(caffe_py2_virtualenv) jemin@jemin-desktop:~/caffe/second/py-faster-rcnn/caffe-f                                                                                                                                                             ast-rcnn$ git fetch caffe
remote: Counting objects: 13599, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 13599 (delta 3344), reused 3341 (delta 3341), pack-reused 10251
오브젝트를 받는 중: 100% (13599/13599), 13.71 MiB | 55.00 KiB/s, 완료.
델타를 알아내는 중: 100% (9619/9619), 로컬 오브젝트 582개 마침.
https://github.com/BVLC/caffe URL에서
 * [새로운 브랜치]   device-abstraction -> caffe/device-abstraction
 * [새로운 브랜치]   gh-pages   -> caffe/gh-pages
 * [새로운 브랜치]   master     -> caffe/master
 * [새로운 브랜치]   opencl     -> caffe/opencl
 * [새로운 브랜치]   parallel   -> caffe/parallel
 * [새로운 브랜치]   tutorial   -> caffe/tutorial
 * [새로운 브랜치]   williford-patch-1 -> caffe/williford-patch-1
 * [새로운 브랜치]   windows    -> caffe/windows
 * [새로운 태그]     acm-mm-oss -> acm-mm-oss
 * [새로운 태그]     bsd        -> bsd
 * [새로운 태그]     rc         -> rc
 * [새로운 태그]     rc2        -> rc2
 * [새로운 태그]     rc3        -> rc3
 * [새로운 태그]     rc5        -> rc5
 * [새로운 태그]     rcnn-release -> rcnn-release
 * [새로운 태그]     v0.1       -> v0.1
 * [새로운 태그]     v0.9       -> v0.9
 * [새로운 태그]     v0.99      -> v0.99
 * [새로운 태그]     v0.999     -> v0.999
 * [새로운 태그]     v0.9999    -> v0.9999
 * [새로운 태그]     rc4        -> rc4
(caffe_py2_virtualenv) jemin@jemin-desktop:~/caffe/second/py-faster-rcnn/caffe-fast-rcnn$ git branch
* (HEAD 0dcd397 위치에서 분리됨)
  master

git merge -X theirs caffe/master

-X theirs의 의미는 caffe/master를 기준으로 merge 한다는 의미이다.

추가로 아래의 파일에서 해당 코드를 주석처리 하거나 제거한다.

vi ./include/caffe/layers/python_layer.hpp
Remove self_.attr("phase") = static_cast<int>(this->phase_); from include/caffe/layers/python_layer.hpp after merging.

요약하면 아래와 같으며, 해당 issue는 원래 저자 github에 있다.
issue 316

# Maybe you can try to merge caffe master branch into caffe-fast-rcnn.
cd caffe-fast-rcnn  
git remote add caffe https://github.com/BVLC/caffe.git  
git fetch caffe  
git merge -X theirs caffe/master  
#Remove self_.attr("phase") = static_cast<int>(this->phase_); 
#from include/caffe/layers/python_layer.hpp after merging.

4. py-caffe 빌드와 설치

Makefile.config 설정
py-faster-rcnn/caffe-fast-rcnn에서 caffe를 빌드할 때 사용한다.

cp Makefile.config.example Makefile.config를 한다.
각자 환경에 맞춰서 주석처리된 부분을 풀고 환경변수를 설정 해야 한다.

# cuDNN acceleration switch (uncomment to build with cuDNN).
USE_CUDNN := 1
# Uncomment if you're using OpenCV 3
OPENCV_VERSION := 3
# CUDA directory contains bin/ and lib/ directories that we need.
CUDA_DIR := /usr/local/cuda
# CUDA architecture setting: going with all of them.
# For CUDA < 6.0, comment the *_50 through *_61 lines for compatibility.
# For CUDA < 8.0, comment the *_60 and *_61 lines for compatibility.
CUDA_ARCH := -gencode arch=compute_20,code=sm_20 \
		-gencode arch=compute_20,code=sm_21 \
		-gencode arch=compute_30,code=sm_30 \
		-gencode arch=compute_35,code=sm_35 \
		-gencode arch=compute_50,code=sm_50 \
		-gencode arch=compute_52,code=sm_52 \
		-gencode arch=compute_60,code=sm_60 \
		-gencode arch=compute_61,code=sm_61 \
		-gencode arch=compute_61,code=compute_61
# BLAS choice:
# atlas for ATLAS (default)
# mkl for MKL
# open for OpenBlas
BLAS := atlas
# NOTE: this is required only if you will compile the python interface.
# We need to be able to find Python.h and numpy/arrayobject.h.
PYTHON_INCLUDE := $(VIRTUAL_ENV)/include/python2.7 \
		$(VIRTUAL_ENV)/lib/python2.7/site-packages/numpy/core/include
# We need to be able to find libpythonX.X.so or .dylib.
PYTHON_LIB := /usr/lib
# Uncomment to support layers written in Python (will link against Python libs)
WITH_PYTHON_LAYER := 1

# Whatever else you find you need goes here.
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial/
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib /usr/lib/x86_64-linux-gnu/hdf5/serial
# Uncomment to use `pkg-config` to specify OpenCV library paths.
# (Usually not necessary -- OpenCV libraries are normally installed in one of the above $LIBRARY_DIRS.)
USE_PKG_CONFIG := 1
# N.B. both build and distribute dirs are cleared on `make clean`
BUILD_DIR := build
DISTRIBUTE_DIR := distribute
# The ID of the GPU that 'make runtest' will use to run unit tests.
TEST_GPUID := 0
# enable pretty build (comment to see full commands)
Q ?= @

caffe-fast-rcnn에서 빌드하기

mkdir build
cd build
cmake ..
make -j8 all
make -j8 pycaffe
make -j8 install
make -j8 runtest

cython module들 빌드

py-faster-rcnn/lib에서 make -j8

caffe 환경변수 설정

vi ~/.bashrc
export CAFFE_ROOT=/home/jemin/caffe/second/py-faster-rcnn/caffe-fast-rcnn
export PYTHONPATH=/home/jemin/caffe/second/py-faster-rcnn/caffe-fast-rcnn/python:$PYTHONPATH

5. 설치 확인

(caffe_py2_virtualenv) jemin@jemin-desktop:~/caffe/second/py-faster-rcnn/caffe-fast-rcnn$ python
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import caffe
>>> caffe.__version__
'1.0.0-rc5'

6. 미리 빌드된 모델 다운받기

caffe zoo에서 VOC2007로 미리 트레이닝된 zf net과 vgg16을 다운 받는다.

cd py-faster-rcnn
./data/scripts/fetch_faster_rcnn_models.sh

Simple demo.py 실행

이제 데모를 실행한다.

putty로 실행하더라도 X11 forwarding이 설정 되었다면 image가 정상적으로 표시된다.

./tools/demo.py --net zf

Demo for data/demo/000456.jpg
Detection took 0.038s for 300 object proposals
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo for data/demo/000542.jpg
Detection took 0.031s for 135 object proposals
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo for data/demo/001150.jpg
Detection took 0.033s for 231 object proposals
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo for data/demo/001763.jpg
Detection took 0.033s for 200 object proposals
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Demo for data/demo/004545.jpg
Detection took 0.037s for 300 object proposals

참고사이트

https://github.com/rbgirshick/py-faster-rcnn
http://lastone9182.github.io/2016/09/16/aws-caffe.html#index-table


'AI > Caffe' 카테고리의 다른 글

openPose 설치 및 구동 (ubuntu 16.04 + 1080)  (2) 2018.04.12
Faster R CNN Training  (0) 2017.02.27

Introduction to OpenCL


What is openCL (personal definition)

Low-level language for high-performance heterogeneous data-parallel computation

  • low-level: manual memory management and parallelization. You choose the global dimensions and allocate data
  • Language: a framework with C-like computation kernels. Not really a language
  • High-performance: if your algorithm is a good fit for the hardware E.g., data-parallel
  • Heterogeneous: Code is protable, but perfomrance is not. Different vendors/versions require different optimizations
  • Data-parallel: hardware and software only support data-parallel. Task parallel support is limited on GPUs today.

Why Limited Synchronization?

  • Scales well in hardware
    • Only work-items within a work-group need to communicate
    • GPUs run 32-128 work-gropus(Thread) in parallel

Global Synchronization

  • OpenCL only supoorts global synchronization at the end of a kernel execution

Utility Functions

  • information about each work-item
    • get_global_id(dim)
      • current work-item's ID in a particular dimension

int id = get_global_id(0);
data[id] = sin(data[id]);

- get_work_dim()
	- number of global dimensions in use
- get_global_size(dim)
	- number of global work-items in a particular dimension
- get_local_size(), get_local_id(), get_num_groups(), get_group_id()
	- information about the local dimensions

What do we need to change to use the GPU?

All we have to do is change the CL_DEVICE_TYPE when we get the device to get a_GPU type deivce. The rest of the code will then use the GPU.

Howeverm if we have a complicated kernel while it will run on both the cpu and the gpu you won't get optimal performance.

To get optimal performance, we should modify kernel code along with the number of available cores in the machine.

OpenCL programming model

  • Setup
    • Get the devices (and platform)

    어떤 장치를 사용할지를 선택한다.

    • Create a context (for sharing between devices)

    data 연산을 위해서 어디에서 처리할 지를 선택 하는 것이다.

    • Create command queues (for submitting work)

    선택한 장치에 어떻게 작업을 할당 할지를 선택 한다.
    work을 submit하는 작업을 수행 한다.

  • Compilation
    • Create a program
    • Build the program (compile)
    • Create kernels

    생성된 커널을 command queue에 할당하는 방식을 취한다.

  • Create memory objects
  • Enqueue writes to copy data to the GPU

    데이터를 CPU로부터 복사해서 GPU로 전달하는 작업을 수행 한다.

  • Set the kernel arguments
  • Enqueue kernel executions

    kernel을 command queue로 전달해서 작업을 처리한다.

  • Enqueue reads to copy data back from the GPU
  • Wait for your commands to finish

왜 근데 기다려야 하는가?
이유는 OpenCL은 asynchronous이기 때문이다.
When we enqueue a command we have no idea when it will finish (it's just in the queue.)
By explicitly waiting we make sure it is finished before continuiting.


Tensor Board


Serializing the data

summary data는 Tensor Flow실행 중에 생성된 데이터를 담고 있다.

아래는 일반적인 Tensor Board의 lifecycle을 담고 있다.

  1. TensorFlow Graph를 생성 한다. 그것은 어떻게 summary 데이터를 수집할지에 대한 정보를 담고 있다.

예를 들어서 scalar_summary를 이용해서 loss function의 진행상황을 기록할 수 있다.
추가로 gradient weight를 하고 싶다면histogram_summary를 사용 한다.

  1. summary들을 초기화 해주어야 한다.
    그것을 일일이 하나하나 하는것은 tedious한 방법이니tf.summary.merge_all을 실행 시키면single operation으로 모든 summary data를 초기화 하게 된다.

  2. merged summary op를 실행 한다.
    그리고 probuf 데이터는 결국 tf.train.SummaryWriter에 의해서 object로 기록된다.

사용방법 포인트

  • tf.global_variables_initializer().run() 전에merged = tf.summary.merge_all()을 해도 된다.tf.summary.FileWriter도 실행 해도 된다.

0.012 패치에 따른 API deplicated

init = tf.initialize_all_variables()

  • tf.global_variables_initializer().run()

tf.histogram_summary

  • tf.summary.histogram
  • tf.summary.scalar

merged = tf.merge_all_summaries()

  • merged = tf.summary.merge_all()

writer = tf.train.SummaryWriter("./logs/xor_logs", sess.graph_def)

  • train_writer = tf.summary.FileWriter(FLAGS.log_dir + '/train', sess.graph)

summary = sess.run(merged, feed_dict={X:x_data, Y:y_data})
좋은 코드 패턴 google

def feed_dict(train):
"""Make a TensorFlow feed_dict: maps data onto Tensor placeholders."""
if train or FLAGS.fake_data:
  xs, ys = mnist.train.next_batch(100, fake_data=FLAGS.fake_data)
  k = FLAGS.dropout
else:
  xs, ys = mnist.test.images, mnist.test.labels
  k = 1.0
return {x: xs, y_: ys, keep_prob: k}

summary, _ = sess.run([merged, train_step],
                      feed_dict=feed_dict(True),
                      options=run_options,
                      run_metadata=run_metadata)

Troubleshooting

kenrel panic

tensorboard를 쓰기위해서 잘못된 naming을 사용하면 발생

InvalidArguementError

Jupyter Notebook의 오류인것 같다.

관련사이트: tensorflow/tensorflow#225

그냥 python3 name.py 로 실행하거나 kernel을 껏다가 다시키면 1번은 동작한다. 똑같은 코드라도 어딘 되고 안되는게 tensorboard가 아무래도 불안정 한것 같다.

5 steps of using tensorboard

From TF graph, decide which node you want to annotate

  • with tf.name_scope("test") as scope:
  • tf.histogram_summary("weights", W), tf.scalar_summary(“accuracy", accuracy)

모두다 병합해서 하나로 보여준다.
Merge all summaries

  • merged = tf.merge_all_summaries()

Create writer

  • writer = tf.train.SummaryWriter("/tmp/mnist_logs", sess.graph_def)

실행 시킨 결과를 보여준다.
Run summary merge and add_summary

  • summary = sess.run(merged, …); writer.add_summary(summary);

Launch Tensorboard

  • tensorboard --logdir=/tmp/mnist_logs

Name variables

X = tf.placeholder(tf.float32, name='X-input')
Y = tf.placeholder(tf.float32, name='Y-input')

W1 = tf.Variable(tf.random_uniform([2, 2], -1.0, 1.0), name='Weight1')
W2 = tf.Variable(tf.random_uniform([2, 1], -1.0, 1.0), name='Weight2')

b1 = tf.Variable(tf.zeros([2]), name="Bias1")
b2 = tf.Variable(tf.zeros([1]), name="Bias2")

Add scope for between graph hierarchy

# Our hypothesis
with tf.name_scope("layer2") as scope:
    L2 = tf.sigmoid(tf.matmul(X, W1) + b1)

with tf.name_scope("layer3") as scope:
    hypothesis = tf.sigmoid(tf.matmul(L2, W2) + b2)

# Cost function
with tf.name_scope("cost") as scope:
    cost = -tf.reduce_mean(Y*tf.log(hypothesis) + (1-Y)*tf.log(1-hypothesis))
    cost_summ = tf.scalar_summary("cost", cost)

# Minimize
with tf.name_scope("train") as scope:
    a = tf.Variable(0.1) # Learning rate, alpha
    optimizer = tf.train.GradientDescentOptimizer(a)
    train = optimizer.minimize(cost)

Add histogram

# Add histogram
w1_hist = tf.histogram_summary("weights1", W1)
w2_hist = tf.histogram_summary("weights2", W2)

b1_hist = tf.histogram_summary("biases1", b1)
b2_hist = tf.histogram_summary("biases2", b2)

y_hist = tf.histogram_summary("y", Y)

Add scalar variables

# Cost function
with tf.name_scope("cost") as scope:
    cost = -tf.reduce_mean(Y*tf.log(hypothesis) + (1-Y)*tf.log(1-hypothesis))
    cost_summ = tf.scalar_summary("cost", cost)

merge summaries and create writer after creating session

# Launch the graph,
with tf.Session() as sess:
    # tensorboard --logdir=./logs/xor_logs
    merged = tf.merge_all_summaries()
    writer = tf.train.SummaryWriter("./logs/xor_logs", sess.graph_def)

매번 기록하면 너무 log데이터가 많으니 아래처럼 기술해 준다.

    # Fit the line.
    for step in xrange(20000):
        sess.run(train, feed_dict={X:x_data, Y:y_data})
        if step % 200 == 0:
            summary = sess.run(merged, feed_dict={X:x_data, Y:y_data})
            writer.add_summary(summary, step)
            print step, sess.run(cost, feed_dict={X:x_data, Y:y_data}), sess.run(W1), sess.run(W2)

실행 예제

아래의 실행 예제는 이전에 작성한 NN with XOR를 가지고 만든것이다.

전체코드

import tensorflow as tf
import numpy as np

xy = np.loadtxt('XORtrain.txt', unpack=True)


x_data = np.transpose(xy[0:-1])
y_data = np.reshape(xy[-1], (4, 1))

X = tf.placeholder(tf.float32, name='X-input')
Y = tf.placeholder(tf.float32, name='Y-input')

W1 = tf.Variable(tf.random_uniform([2, 2], -1.0, 1.0), name='Weight1')
W2 = tf.Variable(tf.random_uniform([2, 1], -1.0, 1.0), name='Weight2')

b1 = tf.Variable(tf.zeros([2]), name="Bias1")
b2 = tf.Variable(tf.zeros([1]), name="Bias2")


# Our hypothesis
with tf.name_scope("layer2") as scope:
    L2 = tf.sigmoid(tf.matmul(X, W1) + b1)

with tf.name_scope("layer3") as scope:
    hypothesis = tf.sigmoid(tf.matmul(L2, W2) + b2)

# Cost function
with tf.name_scope("cost") as scope:
    cost = -tf.reduce_mean(Y*tf.log(hypothesis) + (1-Y)*tf.log(1-hypothesis))
    cost_summ = tf.scalar_summary("cost", cost)

# Minimize
with tf.name_scope("train") as scope:
    a = tf.Variable(0.1) # Learning rate, alpha
    optimizer = tf.train.GradientDescentOptimizer(a)
    train = optimizer.minimize(cost)

# Add histogram
w1_hist = tf.histogram_summary("weights1", W1)
w2_hist = tf.histogram_summary("weights2", W2)

b1_hist = tf.histogram_summary("biases1", b1)
b2_hist = tf.histogram_summary("biases2", b2)

y_hist = tf.histogram_summary("y", Y)


# Before starting, initialize the variables. We will `run` this first.
init = tf.initialize_all_variables()


# Launch the graph,
with tf.Session() as sess:
    # tensorboard --logdir=./logs/xor_logs
    merged = tf.merge_all_summaries()
    writer = tf.train.SummaryWriter("./logs/xor_logs", sess.graph_def)

    sess.run(init)
    # Fit the line.
    for step in xrange(20000):
        sess.run(train, feed_dict={X:x_data, Y:y_data})
        if step % 200 == 0:
            summary = sess.run(merged, feed_dict={X:x_data, Y:y_data})
            writer.add_summary(summary, step)
            print step, sess.run(cost, feed_dict={X:x_data, Y:y_data}), sess.run(W1), sess.run(W2)

    # Test model
    correct_prediction = tf.equal(tf.floor(hypothesis+0.5), Y)
    # Calculate accuracy
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    print sess.run([hypothesis, tf.floor(hypothesis+0.5), correct_prediction, accuracy], feed_dict={X:x_data, Y:y_data})
    print "Accuracy:", accuracy.eval({X:x_data, Y:y_data})

실행방법

  1. chrome 브라우저를 사용한다.
  2. 전체 경로를 설정해야한다.

아래와 같이 log file이 저장된 full path를 입력해주어야 한다.

tensorboard --logdir=/root/PycharmProjects/TensorFlowTest/logs/xor_logs/

정상적으로 실행이 됬다면 아래와 같은 메시지가 나온다.

Starting TensorBoard on port 6006
(You can navigate to http://localhost:6006)

그리고 웹브라우저 크롬을 이용해서 접속하면 아래와 같은 화면을 볼 수 있다.

위에 보면 메뉴바에
EVENTSIMAGESGRAPHHISTOGRAMS이렇게 4개의 메뉴가 있는것을 알 수 있다.
각각 우리가 설정한대로 데이터를 보여주게된다.

cost 값이 interation에 따라서 감소하는 것을 시각화 해서 알 수 있다.

생성한 Neural networks를 graph로 확인 할 수 있다.

참고자료


Week 05: 2. Backpropagation Algorithm


본 장에서는 각각의 레어이어의 Wegiht을 학습하기위한 backpropagation알고리즘에 대해서 다룬다.

Gradient computation with forward propagation

각각의 Layer의 wegiht 초기 값을 결정하기 위해서 아래와 같이 forward propagation을 수행하게 된다.

아래와 같이 각각의 레이어에 맞는 $a^{(j)}$ 값들이 결정 된다.

Gradient computation: Backpropagation algorithm

Bakpropagatio 알고리즘의 목적은 각각의 $\theta$값들이 Cost function $J$에 미치는 영향을 효율적으로 계산하는 것이다. 즉Gradient를 계산 하는 것이다.

Gradient를 구하게 되면, Gradient descent알고리즘으로 아래와 같이 cost $J$를 최소화 하는 $\Theta$를 찾을 수 있다.

$$ min_{\theta}J(\theta) $$

Gradient는 아래와 같이 편미분을 수행 해야 한다.

$$\dfrac{\partial}{\partial \Theta_{i,j}^{(l)}}J(\Theta)$$

이것을 빨리 계산하기 위해서 Backpropagation알고리즘을 이용한다.

각각의 레어이어의 노드 j에서의 에러는 아래와 같이 정의된다.

$\delta_{j}^{(l)}$ = error of node $j$ in layer $l$.

마지막 레이어 에서의 error 값은 델타는 아래와 같이 계산 된다.
$$ \delta^{(L)} = a^{(L) - y} $$
L은 총 레이어의 수를 의미하고 $a^{L}$은 마지막 레이어에서의 activiation unit의 output이다.

각 레이어의 local error를 나타내는 식은 아래와 같이 $\delta$로 표현 된다.

$$\delta^{(l)} = ((\Theta^{(l)})^T \delta^{(l+1)})\ .*\ g'(z^{(l)})$$

이후 뉴런 계층도 아래와 같이 계산된다.
$$\delta^{(3)} = ((\Theta^{(3)})^T \delta^{(4)})\ .*\ g'(z^{(3)})$$

$$\delta^{(2)} = ((\Theta^{(2)})^T \delta^{(3)})\ .*\ g'(z^{(2)})$$

$\delta^{(L)}$를 이용해서 나머지 $\delta$들의 값들은 위와 같이 계산된다.
여기서 $\delta^{(1)}$이 없는 이유는 input 값을 변경하지 않기 위함이다.
input은 error로 생각하지 않는다.

식 유도하기

우선, network 구조는 위의 네트웍을 따른다.

이제 아래와 같이 $\theta^{(3)}$이 Cost function에 미치는 영향(gradient)을 계산해보자.

Sigmoid derivative
$$g(x) = \dfrac{1}{1 + e^{-x}}$$
$$\dfrac{d}{dx}g(x) = g(x)(1 - g(x))$$

Chain rule에 의해서 Cost function은 다음과 같이 편미분 된다.
Cost function을 미분을 간단하기 위해서 cross entropy가 아닌 square error로 생각하자. 그리고 non-multiclass classification (k=1)로 생각한다. 그럼 아래의 cross entropy가 간단해 진다.
실제로도 거의 유사하게 동작하기 위해서 만들어진 cost function이다.

$$cost(t) =y^{(t)} \ \log (h_\Theta (x^{(t)})) + (1 - y^{(t)})\ \log (1 - h_\Theta(x^{(t)}))$$

$$Cost = \frac{1}{2}(\hat{y}-y)^2$$

$$ \frac { \partial Cost }{\partial \theta^{ (3) }} = \frac { \partial Cost } {\partial a^{(4)} } \cdot \frac { \partial a^{(4)} }{\partial z^{ (4) }} \cdot \frac { \partial z^{(4)}} {\partial \theta ^{ (3) }} $$

$$ = (\hat{y}-y) \times g(z^{(4)})(1-g(z^{(4)}))\times a^{ (3) }$$

$$ = (\hat{y}-y) \times \hat{y}(1-\hat{y})\times a^{ (3) }$$

결국 $g(z^{(4)})=a^{(4)}$는 예측 값이므로 $\hat{y}$로 치환한 것이다.
그리고 특정 부분을 $\delta^{L}$로 치환 하면 아래와 같다.
여기서 $L$은 마지막 Layer를 의미한다.

$$\delta ^{ (L) }= (\hat{y}-y) \times \hat{y}(1-\hat{y})$$

$$=\delta^{(L)}\times a^{ (3) }$$

두 번째는 $\theta^{(2)}$이 Cost function에 미치는 영향을 계산해보자.

$$\frac { \partial Cost }{\partial \theta^{ (2) }} = \frac { \partial Cost } {\partial a^{(4)} } \cdot \frac { \partial a^{(4)} }{\partial z^{ (4) }} \cdot \frac { \partial z^{(4)}} {\partial a^{(3)}} \cdot \frac { \partial a^{(3)}} {\partial z^{(3)}} \cdot \frac { \partial z^{(3)}} {\partial \theta^{(2)}} $$

$$=(\hat{y}-y) \times \hat { y } (1-\hat { y } )\times \theta ^{ (3) }\times \frac { \partial a^{(3)}} {\partial z^{(3)}} \times \frac { \partial z^{(3)}} {\partial \theta^{(2)}}$$

나머지 뒷 부분도 모두 미분하면 아래와 같이 유도 된다.

$$=(\hat{y}-y) \times \hat { y } (1-\hat { y } )\times \theta ^{ (3) }\times g(z^{(3)})(1-g(z^{(3)}))\times a^{(2)} $$

여기서도 위와 마찬가지로 $\delta^{(3)}$을 정의해서 치환 하면 아래와 같다.

$$\delta^{(3)} = (\hat{y}-y) \times \hat{y}(1-\hat {y} )\times \theta^{(3)}\times g(z^{(3)})(1-g(z^{(3)}))$$

$$ \frac { \partial Cost } {\partial \theta ^{ (2) }} = \delta^{(3)}\times a^{ (2) }$$

그리고 $\delta^{(3)}$을 계산하기 위해서 앞에서 계산된 $\delta^{(L)}$을 활용할 수 있다.

$$\delta^{(L)} = (\hat{y}-y) \times \hat { y } (1-\hat { y } )$$

$$\delta^{(3)} = \delta ^{(L)} \times \theta^{(3)}\times g(z^{(3)})(1-g(z^{(3)}))$$

결국 생각해보면 각각의 $\delta$만 계산할 수 있다면, 해당 $\theta$즉 wegiht가 Cost function에 미치는 영향(Gradient)를 계산할 수 있다.
왜냐하면, $a^{(3)}$, $a^{(2)}$같은 값들은 forward propagation을 통해서 쉽게 구할 수 있기 때문이다.
그리고 각 layer에서의 gradient는 앞에서 계산한 delta를 활용하여 계산량을 줄일 수 있다.

$\delta_j^{(l)}$의 의미는 $a_j^{(l)}$에 대한 에러이다.
좀 더 formal하게 표현 하면 delta values are actually the derivative of the cost function:

$$\delta_j^{(l)} = \dfrac{\partial}{\partial z_j^{(l)}} cost(t)$$

결국 아래와 같이 Andrew Ng교수님이 말한 식이 유도 된 것이다.

$$\delta^{(l)} = ((\Theta^{(l)})^T \delta^{(l+1)})\ .*\ g'(z^{(l)})$$

$$ \frac { \partial Cost } {\partial \theta^{(l)}}=a^{(l)}\delta^{(l+1)}$$

결국 아래의 Andrew Ng 교수님 수업에서 말한 식이 도출 되었다.

Analyzing the mathematics

위 예제는 결국 [3-5-5-5]의 구조를 가진다. bais는 생각하지 않는다.
$\theta^{3}$는 [4 X 5]의 matrix 이다. bias를 포함하면 4 X 6 이지만 그렇게 생각하지 않는다.
$(\theta^{(3)})^{T}$라고 하면 결국 transpose 이기 때문에 [5 X 4] matrix가 된다.

이전에 계산한 $\delta^{4}$는 4x1 vector라고 하자.
[5 X 4] matrix with [4 X 1] vector를 계산하면 결국 [5 X 1] vector가 된다.
[5 X 1] matrix의 dimensionality는 $a^3$ vector와 같게 된다. 따라서 pairwise multiplication이 성공 한다.

결국, $\delta^{3}$은 $a^3.*(1-a^3)$이랑 연산을해서 구해 질 수 있다.
$\delta^2$도 마찬가지로 구할 수 있다.

Why do we do this?

모든 $\delta$를 계산 했다면 그것을 가지고
Cost function에 대한 각각의 $\theta$에 따른 Partial Derivative를 구할 수 있다.
이러한 Partial Derivative를 통해서 $\theta$값들이 Cost Function에 미치는 영향을 알 수 있다.
그리고 이 영향을 이용해서 gradient descent를 수행해서 최적화를 달성 할 수 있다.

Backpropagation의 장점은 이런한 각각의 $\theta$값을 $\delta$를 이용해서 효율적으로 구할 수 있다는 것이다.
하지만 이 방법을 이용하면 쉽게 구할 수 있다.

결국 아래와 같이 regularization을 람다 0으로 설정해서 무시한다면 간단한 식이 완성 된다.
$$ \dfrac{\partial}{\partial \Theta_{i,j}^{(l)}}J(\Theta) = a_j^l \delta_i^{(l+1)}$$

그리고 이러한 partial derivative 값들을 이용해서 cost function을 최소화 하는 $\theta$값들을 찾게 된다.
즉 각각의 $\theta$가 y에 미치는 영향을 계산하여 각각의 $\theta$를 업데이트 할 수 있는 것이다.

좀 더 자세한 Python기반 코드는 링크에 있다.

알고리즘 상세 설명

Training set이 아래와 같이 있다고 가정해 보자.
$\lbrace (x^{(1)}, y^{(1)}) \cdots (x^{(m)}, y^{(m)})\rbrace$

최종적인 델타값은 모든 트레닝에 대해서 각각의 델타값을 누적한다음 평균값을 구해야 한다.
따라서 누적을 위한 델타 값을 아래와 같이 0으로 설정한다.
$\Delta^{(l)}_{i,j}$

이제 루프를 전 트레이닝 셋에 대해서 돌면서 수행 한다.

For t = 1 to m 까지

$a^{(1)}$은 $x^{(t)}$로 초기화 된다.
forward propagation을 통해서 각각의 layer에 있는 $a^l$들을 계산한다. l=1,2,..,L 까지 존재한다.
그다음 output label과 함께 $\delta^L$을 계산하고 그것을 이용해서 순차적으로 $\delta^L=a^L-y^t$를 계산하게 된다.
이렇게 함으로써 초기 delta 값들이 구해진다.
그다음 back propagation을 통해서 L-1 layer 를 구하고 차큰 차큰 내려 간다.
그리고 각 layer에서의 델타들을 아래와 같이 누적 시킨다.

여기서,

  • $l$ = layer
  • $j$ = node in that layer
  • $i$ = the error of affected node in the target layer

위의 것을 vectorize하면 아래와 같다.

Finally
Loop를 모두 실행 하면 아래와 같이 누적한 값으로 평균 값을 구한다.
해당 평균 에러는 모든 트레이닝 데이터에 대한 값이 된다.

최종 Cost function J에 대한 partial derivative는 아래와 같이 구해진다.

결국 이를 통해서 각각의 $\theta$즉 parameter에 대한 partial derivative를 계산 할 수 있게 된다.
출력값에 미치는 영향을 계산 할 수 있으므로 이를 조정 할 수 있게 된다.

강의 슬라이드 페이지는 아래와 같다.

사실, Back-propagation의 좀 더 자세한 내용은 많인 강의에서 다루지 않는다.
이것도 나름 상세한 강의에 속하는 것 같다.
대략적인 컨셉과 수식적 표현은 알겠는데 아직 까지 남에게 설명할 정도는 안되는 것 같다.


'MOOC > Machine Learning (python)' 카테고리의 다른 글

Week 10: Online Learning  (0) 2017.07.20
Week 05: 1. Neural Network Cost Function  (0) 2017.01.28
Programming Exercise 4: Neural Networks Learning  (0) 2017.01.02
Autonomous Driving Example  (0) 2016.10.12
Putting it together  (0) 2016.10.12

Python 파라메터 앞에 *와 **의 의미 (*args, **kwargs)


다른사람들이 작성한 python 코드를 보다보면
*args, **kwargs 를 심심치 않게 본다.
그냥 막연하게 "어떤 파라미터를 몇개를 받을지 모르는 경우 사용한다" 라고 알고 있었지만
자세히 설명한 예 가 있어서 소개한다.

*args

  • 파라미터를 몇개를 받을지 모르는 경우 사용한다. args 는 튜플 형태로 전달된다.
def print_param(*args):
    print args
    for p in args:
        print p
 
print_param('a', 'b', 'c', 'd')
#('a', 'b', 'c', 'd')
#a
#b
#c
#d

**kwargs

  • 파라미터 명을 같이 보낼 수 있다. kwargs는 딕셔너리 형태로 전달된다.
def print_param2(**kwargs):
    print kwargs
    print kwargs.keys()
    print kwargs.values()
 
    for name, value in kwargs.items():
        print "%s : %s" % (name, value)
 
print_param2(first = 'a', second = 'b', third = 'c', fourth = 'd')
 
#{'second': 'b', 'fourth': 'd', 'third': 'c', 'first': 'a'}
#['second', 'fourth', 'third', 'first']
#['b', 'd', 'c', 'a']
#second : b
#fourth : d
#third : c
#first : a

그러면 두개를 같이 쓰는 경우는??

def print_param3(*args, **kwargs):
    print args
    print kwargs
 
print_param3('a', 'b')
#('a', 'b')
#{}
 
print_param3(third = 'c', fourth = 'd')
#()
#{'fourth': 'd', 'third': 'c'}
 
print_param3('a', 'b', third = 'c', fourth = 'd')
#('a', 'b')
#{'fourth': 'd', 'third': 'c'}

응용 해 보자

def print_param4(a, b, c):
    print a, b, c
 
p = ['a', 'b', 'c']
print_param4(*p)
#a b c
 
p2 = {'c' : '1', 'a' : '2', 'b' : '3'}
print_param4(**p2)
#2 3 1

출처

http://jhproject.tistory.com/109


GIT tip 정리


충돌 회피

git push 충돌 회피

# git pull시 현재 commit하지 않은 것 때문에 충돌이 발생하면 아래와 같이 stash를 이용해서 임시저장 할 수 있다.
git stash
git stash list
git pull
git stash pop

submodule

가장 처음 실행 했을 때

git submodule update --init --recursive

지속적인 업데이트

git submodule update --recursive

상태 확인

git submodule status

변경 사항 있을 때 강제로 원래대로 돌리기

git submodule update -f --init --recursive

Git stash

branch를 변경할 때 임시로 파일을 저장하는 수단.

# 임시 저장
git stash
# 임시저장 리스트 확인
git stash list
# 임시저장 적용하고 바로 stage 상태로 만듬
git stash apply --index
# 임시저장 제거, hash를 지정하지 않으면 가장 최근 것을 제거함.
git stash drop
# 적용하면서 바로 제거함
git stash pop

파일 삭제

git rm

working directory의 실제 파일을 삭제하는 것이다.
그리고 commit을 해야 한다.

git rm --cached

Staging Area (git index)에서만 제거하고 Working directory에 있는 파일은 지우지 않고 남겨둘 수 있다.
다시 말해서 하드 디스크에 있는 파일은 그대로 두고 Git만 추적하지 않게 한다.

이것은 .gitignore파일에 추가하는것을 빼먹었거나 대용량 로그 파일이나 컴파일된 파일 .a파일 같은 것을 실수로 추가 했을 때 쓴다.

$ git rm --cached readme.txt

#여러게 삭제
$ git rm log/\*.log

rm.txt 파일 생성해서 하기
*명령으로는 이름 매칭이 안될 수도 있다.

  • git status > rm.txt형식으로 list를 만들고 파일명을 다듬은 다음
  • cat rm.txt | xargs git rm --cached으로 해당 txt에 있는것을 staging area에서 제거 한다.

git log

  • checkout 하고 log가 안보이면 git log --all
  • git reflog

특정 파일 변화 로그 찾기

  • git log -p -- ./vta/tutorials/resnet.py
    파일 이름 바뀐것 까지 참조하면서 모두 보이기
  • git log --follow -p --

HEAD detached at

checkoutsha1 hash코드로 하게 되면 자동으로 HEAD가 설정 되지 않는다.
branch 이름으로 할 경우 이런 문제가 발생하지 않지만 그냥 할 경우 발생하게 된다.

commit message를 잃어 버릴 수도 있기 때문에 HEAD 설정을 다시 해주는 것이 좋다.

  • merge를 이용한 방법
    git commit -m "....."
    git branch my-temporary-work
    git checkout master
    git merge my-temporary-work

git diff

기본 설정 포멧

git diff [--options] <commit> <commit> [--] [<path>...]

지금 커밋과 뒤로 두 단계 커밋의 main.c에 대한 비교 커멘드는 아래 3개 모두 동일한 기능을 한다.

$ git diff HEAD^^ HEAD main.c
$ git diff HEAD^^..HEAD -- main.c
$ git diff HEAD~2 HEAD -- main.c

remote하고의 비교

git fetch origin #pull과 다르게 local repo.와 merge하지 않음. 이력만 받아옴.
git diff master origin/master

특정 파일만 보고 싶은 경우

git ls-files | grep .java | xargs git diff

간단히 파일 변화만 보기 --state

$ git diff --stat 2ed6ec *.R

 2018_03_09_NB_SVM_RF_MLP.R       | 314 +++++++++++++++++++++++++++++++
 Class Imbalance.R                |  90 +++++++++
 FeatureSelectionWithRFE.R        |  59 ++++++
 FileWriter.R                     |  93 ++++++++++
 evaluationModel.R                |  38 ++++
 graph.R                          | 188 +++++++++++++++++++
 jsonESLABCollector.R             | 116 ++++++------
 jsonToDataFrame.R                | 385 +++++++++++++++++++++++++++++++++++++++
 jsonToSingleDataFrame.R          | 208 +++++++++++++++++++++
 phone_status_anlysis.R           |  41 ++++-
 post_matchig_with_arrival_time.R | 277 ++++++++++++++++++++++++++++
 refinedAutoLabels.R              | 158 ++++++++++++++++
 12 files changed, 1905 insertions(+), 62 deletions(-)

git 무식하게 완전 초기화

rm -rf .git

git init
git add .
git commit - m "initial commit"

git remote add origin <github-uri>
git push -u --force origin --all

단 위 방법은 submodule이 있을 경우 문제가 발생한다.
그 때는 rebase를 이용해서 정공법으로 해결해야 한다.

Branch 관련

Branch 삭제

#local delete
git branch -d <branch_name>

#remote delete
git push <remote_name> :<branch_name>

Branch 이름 변경

# Local에 있는 branch 이름 변경하기
git branch -m oldbranch newbranch

# Remote에 존재하는 oldbranch 삭제하기
git push origin :oldbranch

# newbranch push 하기
git push origin newbranch

파일 복원

파일 변경 사항 알아내기

특정 파일 변동 사항 검색

git log -- UNLOCKED_Analysis.R

해당 로그 확인

$ git show --stat f27a8d
commit f27a8d01f6fa828d4e38919823fb1ddb462136b6
Author: Jemin Lee <leejaymin@cnu.ac.kr>
Date:   Tue Nov 8 23:50:22 2016 +0900

    change file name

 README.md                                  | 17 +++++++++++++++++
 jsonToDataFrame.R                          |  9 +++++++++
 phone_status_anlysis.R                     |  1 +
 UNLOCKED_Analysis.R => refinedAutoLabels.R |  4 +++-
 4 files changed, 30 insertions(+), 1 deletion(-)

위와 같이 UNLOCKED_Analysis.R파일이 refinedAutoLabels.R로 변경된 것을 알 수 있다.
갑자기 파일이 사라져서 log를 통해서 확인해본 예제이다.

개별파일 원복

git checkout -- <파일> : 워킹트리의 수정된 파일을 index에 있는 것으로 원복
git checkout HEAD -- <파일명> : 워킹트리의 수정된 파일을 HEAD에 있는 것으로 원복(이 경우 --는 생략가능)
git checkout FETCH_HEAD -- <파일명> : 워킹트리의 수정된 파일의 내용을 FETCH_HEAD에 있는 것으로 원복? merge?(이 경우 --는 생략가능)

index 추가 취소

git reset -- <파일명> : 해당 파일을 index에 추가한 것을 취소(unstage). 워킹트리의 변경내용은 보존됨. (--mixed 가 default)
git reset HEAD <파일명> : 위와 동일

특정 commit message에서 복원
$ git checkout ec76bc~1 allData.RData

commit 취소

  • git reset HEAD^ : 최종 커밋을 취소. 워킹트리는 보존됨. (커밋은 했으나 push하지 않은 경우 유용)
  • git reset HEAD~2 : 마지막 2개의 커밋을 취소. 워킹트리는 보존됨.

hard, soft, mixed 차이점

  • git reset --hard HEAD~2
    • 마지막 2개의 커밋을 취소. stage와 워킹트리 모두 원상 복구. 즉 모든 상태가 복구됨.
  • --soft:
    • stage에 올라간 상태로 변경이력이 복구됨
  • --mixed;
    • 워킹트리에만 변경사항이 남아있음. 커밋은 완전 초기화

revert 방식
reset 계열은 결국 커밋을 조작 하기 때문에 혼자 사용하는 branch에서 사용하는것이 적당하다.
여럿이 사용하는 branch라면 revert를 이용해서 이력을 rollback한 내용들도 commit으로 남기는 것이 좋다.

  • git revert HEAD : HEAD에서 변경한 내역을 취소하는 새로운 커밋 발행(undo commit). (커밋을 이미 push 해버린 경우 유용)
    • 취소 커밋 범위 설정 가: git revert [hash1]..[hashN]

워킹트리 전체 원복

git reset --hard HEAD : 워킹트리 전체를 마지막 커밋 상태로 되돌림. 마지막 커밋이후의 워킹트리와 index의 수정사항 모두 사라짐.
(변경을 커밋하지 않았다면 유용)
git checkout HEAD . : ??? 워킹트리의 모든 수정된 파일의 내용을 HEAD로 원복.
git checkout -f : 변경된 파일들을 HEAD로 모두 원복(아직 커밋하지 않은 워킹트리와 index 의 수정사항 모두 사라짐. 신규추가 파일 제외)

* 참조 : reset 옵션

--soft : index 보존, 워킹트리 보존. 즉 모두 보존.
--mixed : index 취소, 워킹트리만 보존 (기본 옵션)
--hard : index 취소, 워킹트리 취소. 즉 모두 취소.

* untracked 파일 제거

git clean -f
git clean -f -d : 디렉토리까지 제거

Git tracked file 용량 파악 하기

git count-objects -vH

100MB 이상 파일 push 하기

100MB이상의 파일을 push 할 경우 아래와 같은 error 메시지를 나타낸다.

remote: error: GH001: Large files detected. You may want to try Git Large File Storage - https://git-lfs.github.com.
remote: error: Trace: a021e64e835a3163bc978f98da55335e
remote: error: See http://git.io/iEPt8g for more information.
remote: error: File huge_files.zip is 151.37 MB; this exceeds GitHubs file size limit of 100.00 MB

large file system (lfs)를 설치하고 이를 이용해서 commit & push를 한다.

brew install git-lfs
git lfs install # you only need to run this once per user account
git lfs track "*.psd" # Git LFS selects the file types you would like.
git add .gitattributes # make sure .gitattributes is tracked.

git add file.psd
git commit -m "Add design file"
git push origin master

트랙킹 파일 리스트 확인: git lfs ls-files

Reference site

민감 파일 이력에서 자동 찾아 제거 (sensitive data remove in entire history)

.gitignore설정을 하지 않아 password와 같은 정보가 들어 있는 config 파일이 commit push 되었을 때 변경이력에서 이러한 부분을 제거하는 방법을 다룬다.

그냥 untacked시키는 방법은 git rm --cached를 사용하면 되나 저장소 history안에 해당 파일 변경 내역이 그대로 남기 때문에 문제는 계속된다.

해결방법으로는
git filter-branchBFG Repo-Cleaner를 이용한 방법 있다.

BFG Repo-Cleaner를 이용한 방법을 다룬다.

java -jar bfg-1.13.0.jar --delete-files <지울 파일 이름>
java -jar bfg-1.13.0.jar --replace-text <지울 파일 이름>
# 원격 저장소에 강제로 반영
git push origin --force --all

Git commit 메시지들 정리하기

Squash all commits (Pull Request 이후에 처리)

git checkout <branch-name>
git rebase -i master # interactive mode
# vim 화면에서 pick이 선택이고 s가 squash 한다는 의미가 된다.
# 그 다음 새로운 commit log를 작성하게 된다.


git push origin branch-name --force

PR이 다수 반영된 upstream 내용을 origin과 local에 반영하기

아래는 여러 방법들 중 하나의 것이다.

git checkout master
git fetch upstream
git rebase upstream/master
git push -f origin master

기존 local branch 삭제

git branch -d <branch name>

참고자료
공식 홈피: https://help.github.com/en/articles/removing-sensitive-data-from-a-repository
BFG: https://rtyley.github.io/bfg-repo-cleaner/

Gitlab, Merge-request fetch 방법

vi ~/.gitconfig
# 추가
[alias]
    mr = !sh -c 'git fetch $1 merge-requests/$2/head:mr-$1-$2 && git checkout mr-$1-$2' -

# fetch and checkout.
# specify mr number in the last
git mr origin 5

또는
git fetch origin merge-requests/58/head:relay_mr

참고자료

참고자료

2.2 Git의 기초 - 수정하고 저장소에 저장하기

Python 2 와 Python 3의 차이점


코드를 유지보수 하다보면 Python2로 작성된 것을 Python3으로 Migration 할 때가 많다.
이 때 생각보다 두 버전간의 backward compatibility를 지원하지 않는 부분이 많다는 것을 알게 된다.
이러한 부분을 다룬다.

xrange vs range

python3는 더이상 xrange를 지원하지 않는다.
무조건 range를 쓴다. 그리고 내부적으로 그형태가 약간 다르므로
xrange를 무조건 range로 대체 할 수도 없다.

python2에서 xrange는 정해진 숫자 만큼 object를 생성한다. 이는 list를 생성하는 range와는 다른 방식이고
looping을 할 때 약간 더 memory efficint 때문에 빠르다. 그래서 python2를 보면 대다수가 xrange를 사용 한다.

python 2    |  python 3
#------------------------
xrange(10)  |  range(10)
range(10)   |  list(range(10))

# example
# python2
[10] + xrange(9)

# python3
[10] + list(range(9))

만약 python3 코드를 python2에서 수행한다면 아래와 같이 입력해주면 된다.

import sys
if sys.version_info < (3,):
    range = xrange

print

python2는 print "string"
python3는 무조건 함수 호출이다. print ("string")

나눗셈

python2는 정수 / 정수 = 졍수 (5/2=2)
python2는 정수 / 정수 = 실수 (5/2=2.5)

생각보다 이런 사소한 문제 때문에 기능이 이상하게 동작 할때가 많다.
자동 타입할당이 편하지만 떄로는 디버깅할 때 상당히 난감하다.


자동으로 commit 위치 찾아서 Git으로 지운 파일 복원하기


버전관리 시스템을 쓰는 이유중 하나가 실수로 지워진 파일을 복원하거나
예전에 필요 없다고 지운 파일을 손쉽게 복원하기 위해서이다.

문제는 commit이 많이 누적 됬다면 해당 파일이 존재하는 위치를 찾는것은 꽤나 귀찮은 일이 된다.
이러한 부분 쉽게 검색으로 해결하는 방법을 다룬다.

특정 경로에 관련된 commit을 찾는 명령어
맨 처음부터 HEAD까지 전부 검색한다는 의미이다.
git rev-list -n 1 HEAD -- <file_path>

git rev-list -n 1 HEAD -- ./0.Basic

f75de024ee267c765d8abfea460ac5f5c506b015

해당 commit 바로 이전으로 checkout하는 방법 caret^을 넣으면 된다.
git checkout <deleting_commit>^ -- <file_path>

git checkout f75de0^ -- ./0.Basic

# 정상적으로 복원됨
jemin@jemin-desktop:~/ESLAB_ML/jemin/TensorFlowLecture$ git status
현재 브랜치 master
브랜치가 'origin/master'에 맞게 업데이트된 상태입니다.
커밋할 변경 사항:
  (스테이지 해제하려면 "git reset HEAD <파일>..."을 사용하십시오)

        새 파일:       0.Basic/Basic_usageOfConstant.py
        새 파일:       0.Basic/Basic_usageOfPlaceholder.py
        새 파일:       0.Basic/Basic_usageOfVariables.py
        새 파일:       0.Basic/TensorFlow Basic of concept.ipynb
        새 파일:       0.Basic/__init__.py
        새 파일:       0.Basic/basic.py
        새 파일:       0.Basic/hellowTensorFlow.py

특정 파일 1개만 하고 싶을 경우
git checkout $(git rev-list -n 1 HEAD -- "$file")^ -- "$file"


Loading [Contrib]/a11y/accessibility-menu.js

Week 05: Neural Network Cost Function


1. Cost Function

Training Set은 아래와 같다고 하자.
$$ (X^1,y^1),(x^2,y^2),(x^3,y^3)...(x^n,y^m) $$

$L$은 network에 존재하는 Layer의 수이다.
아래와 같은 network 모형에서는 $L$은 4이다.
$s_{l}$은 layer $l$에서의 unit의 숫자이다. 단 여기서 bias unit은 카운트 하지 않는다.

결국, 아래와 같은 값을 가지게 된다.

  • $l$ = 4
  • $s_1$ = 3
  • $s_2$ = 5
  • $s_3$ = 5
  • $s_4$ = 4

2. Types of classification problems with NNs

Binary Classification

당연히 output은 0,1 이다.
k = 1 이다.

Multi-class classification

k개의 distinct classifications가 존재 한다.
$y$는 k-dimensional vector of real numbers이다.
모습은 아래와 같다.

Cost function for neural networks

일반적인 (regularized) logistic regression cost function은 아래와 같다.

위 식에 약간의 중첩 summation을 추가한 것이다.
이것은 다중 아웃풋 노드를 처리하기 위함이다.
$h_{\theta}(x)$는 k dimensional vector이고 $h_{\theta}(x)_{i}$는 vector에서 i로 참조 되어 진다.

Cost function만 따로 띠어내면 아래와 같다.
결국, k=4라고 할 때 각각의 Logistic regression classifier를 합하게 된다.
트레이닝 데이터 1에서 m 까지에서 가능한 output vector를 모두 합친것을 의미한다.

삼중 summation 되어서 복잡해 보이지만, 그냥 단순히 모든 $\theta$를 합친다는 의미이다.
즉 l layer에서의 j 번째 unit에서 i 번째 input이나 activation과 매칭되는 모든 것들의 합을 구해서 람다 만큼 증폭을 시켜서 overfitting을 줄여주는 것이다.

최종적으로 두개의 식을 합치면 regularized neural network cost function을 아래와 같이 구할 수 있다.


'MOOC > Machine Learning (python)' 카테고리의 다른 글

Week 10: Online Learning  (0) 2017.07.20
Week 05: 2. Backpropagation Algorithm  (1) 2017.02.05
Programming Exercise 4: Neural Networks Learning  (0) 2017.01.02
Autonomous Driving Example  (0) 2016.10.12
Putting it together  (0) 2016.10.12


as + p.p (~한 대로)의 의미로 사용된다.



이 때의 as는 접속사이다.


문법적으로는 접속사 다음에 be동사 가 생략된 형태이다.



~ 한 대로 뜻의 예문


In almost every instance, the books as originally written is the best


The money is as gone.

Is the price as marked? (표시된 가격대로 인가?)

It didn't go as planned.

The operation is processing as scheduled.

Everyone counted the boy as lost (모두들 그 소년이 행방불명된 것으로 간주했다.)

We regarded the money as gone.

I just took it as read. (읽혀진 대로)



~ 처럼 (논문에서 많이 쓰임)

As before

As above 

As below

As shown in 


회화적 표현 end up with



end up 끝나다.

End up with ~을 얻고 끝나다.



end up: to reach a particular place or achieve a situation after other activities.

(어떤 행동의 결과로 특벼한 장소나 처지에 다다르게 되다)

-> She will end up penniless if she carries on spending like that.


예문

I thought my date was with Yuna, but I ended up with her sister.

나는 데이트 상대가 연아인지 알았는데, 연아의 언니와 데이트를 하게 되었다.


If lose my job, we'll end up in the poorhouse.

직업을 잃게 되면, 우리는 결국 구빈원에서 살아야 할거야.



내가 제안하는 것은 end up with를 

"결국 ~을 가지게 되다"

(직역으로 하면 "~와 함께 끝나다")

로 해석하는 것이다.


- An increasing number of these people are ending up with no children at all.

( 점점 더 많은 이러한 사람들이 결국 전혀 아이를 가지지 않게 되고 있다.)

( 의역: 점점 더 많은 이러한 사람들이 전혀 아이를 가지지 않게 되고 있다.)


- I can't believe I ended up with detention this month

( 이번 달에 결국 방과 후 학교에 남게 되는 것을 가지게 되다니 믿을 수 없군!)

( 의역: 이번 달에 방과 후 학교에 남아야 한다니 믿을 수 없군!)


- How did I get lucky enough to end up with you?

( 내가 결국 당신을 가지게 된 행운이 어떻게 주어졌을까요?

( 의역: 내가 당신과 맫어진 행운이 어떻게 주어졌을까요?




wind up: to find yourself in an unexpected and usually unpleasant situation, especially as a result of what you do

(특별히 당신이 한 행동의 결과로 예상치 못한, 일반적으로 유쾌하지 않은, 상황에 처하게 되다)


Do you think that only good guys wind up with people like us?

좋은 사람들만 우리와 같은 사람들하고 엮이게 된다고 생각해?

회화에서 많이 쓰이는 "it turns out"에 대해서 알아 본다.



주로 어떤것이 사실로 밝혀질 때 사용한다.

문어적 표현은 아니므로 논문작성 때는 사용하지 않는다. 주로 회화를 할 때 사용 한다.



It turns out fresh vegetables and fresh fruits can be cheaper.


We use the phrase "it turns out" to express something that is not expected.

Notice the following:


1) It turns out the movie is free. We don't have to pay.

2) I thought I have school tomorrow but it turns out it is a national holiday.



'영어 > 영문법' 카테고리의 다른 글

as + p.p (~한 대로, ~한 대로인)  (0) 2017.01.18
end up with ~  (0) 2017.01.14
Difference between Occur and Incur  (0) 2016.12.23
not only but also 와 as well as 사용법 및 차이점  (2) 2016.06.19
조동사 정리  (0) 2016.04.07

Early Stopping 및 Index Shuffling


그런데 실제로 Deep Learning을 학습할 때에는 우리가 정한 횟수만큼의 iteration을 무조건 반복하는 것이 아니라, 적당히 학습이 완료되었다고 생각되면 학습을 중단하는 Early Stopping을 해야한다. 이것을 하지 않고 무조건 정해진 iteration을 하게되면, 모델이 주어진 데이터에만 과도하게 학습하여, 보지않은 데이터에 대한 일반화 성능이 떨어지는 overfitting이 일어나게 된다. 따라서 Early Stopping을 통해 이러한 일이 일어나기 전에 학습을 중단해야 한다.

또한 위의 MNIST 데이터는 이미 구현된 함수를 통해 미리 순서가 뒤섞이고, one-hot coding이 된 데이터를 필요한 개수만큼 가져올 수 있었다. 그러나 실제로 자신의 데이터를 학습시키기 위해서는 이러한 과정도 파이썬의 numpy를 이용해 구현해 주어야한다.

그래서 이번 예제에서는 아주 간단하면서 유명한 Iris 데이터를 이용해 위의 구현을 실습해보도록 한다.

Iris data : 50개*3종의 iris 꽃에서 4종류의 feature를 추출한 데이터

https://en.wikipedia.org/wiki/Iris_flower_data_set

%matplotlib inline
import tensorflow as tf
from tensorflow.contrib.learn.python.learn.datasets.base import load_iris
import numpy as np
tf.reset_default_graph()

def MLP_iris():
    # load the iris data.
    iris = load_iris()

    np.random.seed(0)
    random_index = np.random.permutation(150)

    iris_data = iris.data[random_index]
    iris_target = iris.target[random_index]
    iris_target_onehot = np.zeros((150, 3))
    iris_target_onehot[np.arange(150), iris_target] = 1

    accuracy_list = []
    
    # build computation graph
    x = tf.placeholder("float", shape=[None, 4], name = 'x')
    y_target = tf.placeholder("float", shape=[None, 3], name = 'y_target')

    W1 = tf.Variable(tf.zeros([4, 128]), name = 'W1')
    b1 = tf.Variable(tf.zeros([128]), name = 'b1')
    h1 = tf.sigmoid(tf.matmul(x, W1) + b1, name = 'h1')

    W2 = tf.Variable(tf.zeros([128, 3]), name = 'W2')
    b2 = tf.Variable(tf.zeros([3]), name = 'b2')
    y = tf.nn.softmax(tf.matmul(h1, W2) + b2, name = 'y')

    cross_entropy = -tf.reduce_sum(y_target*tf.log(y), name = 'cross_entropy')

    train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_target, 1))

    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) 

    sess = tf.Session(config=tf.ConfigProto(gpu_options=tf.GPUOptions(allow_growth=True)))
    sess.run(tf.initialize_all_variables())

    for i in range(500):
        sess.run(train_step, feed_dict={x: iris_data[0:100], y_target: iris_target_onehot[0:100]})

        train_accuracy = sess.run(accuracy, feed_dict={x: iris_data[0:100], y_target: iris_target_onehot[0:100]})
        validation_accuracy = sess.run(accuracy, feed_dict={x: iris_data[100:], y_target: iris_target_onehot[100:]})
        print ("step %d, training accuracy: %.3f / validation accuracy: %.3f" %(i, train_accuracy, validation_accuracy))

        accuracy_list.append(validation_accuracy)
        
        if i >= 50:
            if validation_accuracy - np.mean(accuracy_list[int(round(len(accuracy_list)/2)):]) <= 0.01 :
                break
            
    sess.close()

MLP_iris()

핵심 코드는 아래와 같다.
1,2 번 째의 validation accuracy 값은 제거하고 너무 큰 값이기 때문이
그 이후부터의 값을 누적 시켜서 평균을 계산하게 된다.
그 다음 해당 값이 현재의 validation accuracy와의 차이를 구해서 그 차이가 0.01보다 큰지 작은지를 반단해서
break 여부를 결정하게 된다.

if i >= 50:
	if validation_accuracy - np.mean(accuracy_list[int(round(len(accuracy_list)/2)):]) <= 0.01 :
	    break

실행 결과를 보면 어느정도 동작하다가 멈추는 것을알 수 있다.

step 166, training accuracy: 0.970 / validation accuracy: 0.960
step 167, training accuracy: 0.970 / validation accuracy: 0.960
step 168, training accuracy: 0.970 / validation accuracy: 0.960
step 169, training accuracy: 0.970 / validation accuracy: 0.960
step 170, training accuracy: 0.970 / validation accuracy: 0.960
step 171, training accuracy: 0.970 / validation accuracy: 0.960


Programming Exercise 4: Neural Networks Learning


This exercise is to implement the backpropagation algorithm for neural netwroks.
The application is hand-written digit recognition.

  • ex4data1.mat: training set of ahnd-written digits
  • ex4weights.mat: neural network parameters for exercise 4
  • computeNuericalGradient.m: numerically compute gradients.

구현해야 할 함수들

  • sigmoidGradient.m: compute the gradient of the sigmoid function.
  • randInitializeWeights.m: randomly initialize weights.
  • nnCostFunction.m: Neural network cost function.

Neural Networks

이전 과제에서는 matlab으로 feedforard propagation을 구현 했었다.
이번엔 python을 이용해서 최적의 parameter들을 찾는 backpropagation을 구현해 보도록 한다.

1.1 Visualizing the data

데이터를 읽어서 2-dimensional plot으로 표시하는 작업을 수행 한다.
5000개의 training example들로 구성 되어 있다.
각각의 손글씨 이미지들은 20 pixel by 20 pixel grayscale image로 구성되어 있다.
각각의 pixel들은 floating point number로 구성 되어 있다.
이것을 unrolled하게 된다면 400-dimensional vector로 구성 된다.
각각은 단일 row vector가 된다. 트레이닝이 5000이므로 최종적인 input X는 5000 by 400이 된다.

y는 1~9 숫자값을 가지고 있다. matlab에서는 0을 반드시 가지고 있으므로 10으로 그것을 labeled 한다.

Python 구현
필요 라이브러리 Load

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import scipy.io #Used to load the OCTAVE *.mat files
import scipy.misc #Used to show matrix as an image
import matplotlib.cm as cm #Used to display images in a specific colormap
import random #To pick random images to display
import scipy.optimize #fmin_cg to train neural network
import itertools
from scipy.special import expit #Vectorized sigmoid function
datafile = 'data/ex4data1.mat'

mat = scipy.io.loadmat( datafile )

X, y = mat['X'], mat['y']

#Insert a column of 1's to X as usual
X = np.insert(X,0,1,axis=1)

print "'y' shape: %s. Unique elements in y: %s"%(y.shape,np.unique(y))
print "'X' shape: %s. X[0] shape: %s"%(X.shape,X[0].shape)
#X is 5000 images. Each image is a row. Each image has 400 pixels unrolled (20x20)
#y is a classification for each image. 1-10, where "10" is the handwritten "0"

출력 결과

'y' shape: (5000, 1). Unique elements in y: [ 1  2  3  4  5  6  7  8  9 10]
'X' shape: (5000, 401). X[0] shape: (401,)

이미지 출력함수

def getDatumImg(row):
    """
    Function that is handed a single np array with shape 1x400,
    crates an image object from it, and returns it
    """
    width, height = 20, 20
    square = row[1:].reshape(width,height)
    return square.T
    
def displayData(indices_to_display = None):
    """
    Function that picks 100 random rows from X, creates a 20x20 image from each,
    then stitches them together into a 10x10 grid of images, and shows it.
    """
    width, height = 20, 20
    nrows, ncols = 10, 10
    if not indices_to_display:
        indices_to_display = random.sample(range(X.shape[0]), 100)
        
    big_picture = np.zeros((height*nrows,width*ncols))
    
    irow, icol = 0, 0
    for idx in indices_to_display:
        if icol == ncols:
            irow += 1
            icol  = 0
        iimg = getDatumImg(X[idx])
        big_picture[irow*height:irow*height+iimg.shape[0],icol*width:icol*width+iimg.shape[1]] = iimg
        icol += 1
    fig = plt.figure(figsize=(6,6))
    img = scipy.misc.toimage( big_picture )
    plt.imshow(img,cmap = cm.Greys_r)
displayData()

최종적으로 10x10으로 축소해서 100장을 출력 한다.

1.2 Model representation

NN의 구성은

  • 3 layers. an input layer (20x20)+1, a hidden layer, and an output layer.
  • a set of network parameters ($\theta^{(1)}$,$\theta^{(2)}$)이고 이미 완벽히 학습된 parameters는ex4weights.mat에 저장되어 있다.
  • $\theta^{(1)}$은 25 dimension을 $\theta^{(2)}$는 10 dimension을 가진다.

  • theta1 has size 25 x 401
  • theta2 has size 10 x 26
  • X has size 5000 x 401
  • Y has size 5000 x 1

모델 표현에 필요한 코드는 다음과 같다.

#You have been provided with a set of network parameters (Θ(1),Θ(2)) 
#already trained by us. These are stored in ex4weights.mat
datafile = 'data/ex4weights.mat'
mat = scipy.io.loadmat( datafile )
Theta1, Theta2 = mat['Theta1'], mat['Theta2']
# The matrices Theta1 and Theta2 will now be in your workspace
# Theta1 has size 25 x 401
# Theta2 has size 10 x 26

# These are some global variables I'm suing to ensure the sizes
# of various matrices are correct
#these are NOT including bias nits
input_layer_size = 400
hidden_layer_size = 25
output_layer_size = 10 
n_training_samples = X.shape[0]

#Some utility functions. There are lot of flattening and
#reshaping of theta matrices, the input X matrix, etc...
#Nicely shaped matrices make the linear algebra easier when developing,
#but the minimization routine (fmin_cg) requires that all inputs

def flattenParams(thetas_list):
    """
    Hand this function a list of theta matrices, and it will flatten it
    into one long (n,1) shaped numpy array
    """
    flattened_list = [ mytheta.flatten() for mytheta in thetas_list ]
    combined = list(itertools.chain.from_iterable(flattened_list))
    assert len(combined) == (input_layer_size+1)*hidden_layer_size + \
                            (hidden_layer_size+1)*output_layer_size
    return np.array(combined).reshape((len(combined),1))

def reshapeParams(flattened_array):
    theta1 = flattened_array[:(input_layer_size+1)*hidden_layer_size] \
            .reshape((hidden_layer_size,input_layer_size+1))
    theta2 = flattened_array[(input_layer_size+1)*hidden_layer_size:] \
            .reshape((output_layer_size,hidden_layer_size+1))
    
    return [ theta1, theta2 ]

def flattenX(myX):
    return np.array(myX.flatten()).reshape((n_training_samples*(input_layer_size+1),1))

def reshapeX(flattenedX):
    return np.array(flattenedX).reshape((n_training_samples,input_layer_size+1))
  • flattenParams 들어온 matrix로 구성된 list를 단일 [n,1] matrix로 변환 한다.
  • reshapeParams: 들어온 flattened_array를 다시 theta1theta2로 변경 한다.
  • flattenX 들어온 X를 [n,1]로 변경 한다.
  • reshapeX flatten을 다시 X로 reshape한다.

1.3 Feedforward and cost function

Now you will implement the cost function and gradient for the neural network.
First, complete the code in nnCostFunction.m to return the cost.

nnCostFunction은 아래 4개의 인자를 입력으로 받는다.

  • mythetas_flattened
  • myX_flattened
  • myy
  • mylambda=0.

원래 참값을 아래와 같이 표현을 변경해주는 코드가 필요하다.

def computeCost(mythetas_flattened,myX_flattened,myy,mylambda=0.):
    """
    This function takes in:
        1) a flattened vector of theta parameters (each theta would go from one
           NN layer to the next), the thetas include the bias unit.
        2) the flattened training set matrix X, which contains the bias unit first column
        3) the label vector y, which has one column
    It loops over training points (recommended by the professor, as the linear
    algebra version is "quite complicated") and:
        1) constructs a new "y" vector, with 10 rows and 1 column, 
            with one non-zero entry corresponding to that iteration
        2) computes the cost given that y- vector and that training point
        3) accumulates all of the costs
        4) computes a regularization term (after the loop over training points)
    """
    
    # First unroll the parameters
    mythetas = reshapeParams(mythetas_flattened)
    
    # Now unroll X
    myX = reshapeX(myX_flattened)
    
    #This is what will accumulate the total cost
    total_cost = 0.
    
    m = n_training_samples

    # Loop over the training points (rows in myX, already contain bias unit)
    for irow in xrange(m):
        myrow = myX[irow]
                
        # First compute the hypothesis (this is a (10,1) vector
        # of the hypothesis for each possible y-value)
        # propagateForward returns (zs, activations) for each layer
        # so propagateforward[-1][1] means "activation for -1st (last) layer"
        myhs = propagateForward(myrow,mythetas)[-1][1]

        # Construct a 10x1 "y" vector with all zeros and only one "1" entry
        # note here if the hand-written digit is "0", then that corresponds
        # to a y- vector with 1 in the 10th spot (different from what the
        # homework suggests)
        tmpy  = np.zeros((10,1))
        tmpy[myy[irow]-1] = 1
        
        # Compute the cost for this point and y-vector
        mycost = -tmpy.T.dot(np.log(myhs))-(1-tmpy.T).dot(np.log(1-myhs))
     
        # Accumulate the total cost
        total_cost += mycost
  
    # Normalize the total_cost, cast as float
    total_cost = float(total_cost) / m
    
    # Compute the regularization term
    total_reg = 0.
    for mytheta in mythetas:
        total_reg += np.sum(mytheta*mytheta) #element-wise multiplication
    total_reg *= float(mylambda)/(2*m)
        
    return total_cost + total_reg
       

def propagateForward(row,Thetas):
    """
    Function that given a list of Thetas (NOT flattened), propagates the
    row of features forwards, assuming the features ALREADY
    include the bias unit in the input layer, and the 
    Thetas also include the bias unit

    The output is a vector with element [0] for the hidden layer,
    and element [1] for the output layer
        -- Each element is a tuple of (zs, as)
        -- where "zs" and "as" have shape (# of units in that layer, 1)
    
    ***The 'activations' are the same as "h", but this works for many layers
    (hence a vector of thetas, not just one theta)
    Also, "h" is vectorized to do all rows at once...
    this function takes in one row at a time***
    """
   
    features = row
    zs_as_per_layer = []
    for i in xrange(len(Thetas)):  
        Theta = Thetas[i]
        #Theta is (25,401), features are (401, 1)
        #so "z" comes out to be (25, 1)
        #this is one "z" value for each unit in the hidden layer
        #not counting the bias unit
        z = Theta.dot(features).reshape((Theta.shape[0],1))
        a = expit(z)
        zs_as_per_layer.append( (z, a) )
        if i == len(Thetas)-1:
            return np.array(zs_as_per_layer)
        a = np.insert(a,0,1) #Add the bias unit
        features = a

실행 코드

#Once you are done, using the loaded set of parameters Theta1 and Theta2,
#you should see that the cost is about 0.287629
myThetas = [ Theta1, Theta2 ]

#Note I flatten the thetas vector before handing it to the computeCost routine,
#as per the input format of the computeCost function.
#It does the unrolling/reshaping itself
#I also flatten the X vector, similarly
print computeCost(flattenParams(myThetas),flattenX(X),y)

실행 결과

0.287629165161

함수 실행

  • flattenParams(myThetas) -> (10285,1) # (25*401) + (10*26) 이다.
  • flattenX(X) -> (2005000, 1) #5000*401 이다.
  • propagateForward는 인자로 1개의 입력 값을 받아서 thetas [theta1, theta2]가 저장된 것을 가지고 연산을 시작 한다. 최종적으로 z W*X가 저장된 것과 a activation(z)된 결과를 저장된한 두 개를 각layer별로 저장한 tuple을 반환하게 된다.

1.4 Regularized cost function

overfitting 문제를 막기 위해서 Regularized cost function을 Design 한다.

#Once you are done, using the loaded set of parameters Theta1 and Theta2,
#and lambda = 1, you should see that the cost is about 0.383770
myThetas = [ Theta1, Theta2 ]
print computeCost(flattenParams(myThetas),flattenX(X),y,mylambda=1.)

2. Backpropagation

오류 역전파를 구현 한다.
computeCost를 통해서 grad값을 받을 수 있다.
계산한 graident를 가지고 cost function $J(\theta)$를 advanced optimizer fmincg를 이용해서 최적화 할 수 있다.

우선 각각의 parameter들에 대한 cost-function에 대한 gradient를 backpropagation algorithm으로 계산해 본다.

2.1 Sigmoid Gradient

sigmoid의 gradient를 알기 위해서는 derivative를 수행 한다.
$g'(z) = g(z)(1 - g(z))$
여기서 $g(z)$는 아래와 같다.
$g(z) = \frac{1}{1+e^{-z}}$ 이다.

def sigmoidGradient(z):
    dummy = expit(z)
    return dummy*(1-dummy)

위 구현이 맞는지 확인해 보는 방법은 z값을 아주 큰 양수나 음수를 넣었을 때 0에 근접한 값이 나오면 된다.
그리고 z=0이라면 gradient는 0.25가 되어야 한다.

실행결과는 아래와 같다.

print(sigmoidGradient(5))
print(sigmoidGradient(0))
print(sigmoidGradient(-5))
0.00664805667079
0.25
0.00664805667079

이러한 특성 때문에 추후에 Vanishing gradient 문제가 발생한다.

원인은 다음과 같다.

  • Weight matrix W가 큰 값으로 초기화 되었다면
  • $Z = W^{T}X$의 결과는 당연히 큰 값이다.
  • sigmoid(Z)는 당연히 0아니면 1이다.
  • sigmoid(z)의 도함수는 $ g(z)(1 - g(z))$ 이므로 결국
  • z가 0,1이 빈번하면 계속 0이된다. 대부분의 경우에 말이다.
  • 그리고 이렇게 앞부분에서 0이 발생하면 backwrad pass는 모두 chain rull로 연결 되어 있으므로 전부다 zero가 된다.
  • local gradient의 maximum은 0.25이다. 그것도 z가 0.5일 때 말이다. 즉 1번 sigmoid를 지날 때마다 그것의 magnitude는 항상 one quarter 만큼 까지 작아지며 그 이상 작아지는 경우도 많다.
  • 결국 초기값 설정이 중요하다.

2.2 Random Initialization

초기 weight값을 저장한 $\theta$를 랜덤하게 초기화 시켜야 한다.
모두 같은 값이면 항상 같은 error를 가지므로 값이 같이 변해서 의미가 없어 진다.

uniformly 하게 range [-x,x]범위로 초기화 하는 것이다.
작은 값으로 초기화 하는것이 sigmoid의 derivative 특성상 유리하다. 큰 값으로 해버리면 0이되고 chain rule을 이용한
backpropagation 알고리즘 특성상 학습이 되지 않는다.

초기화 공식은 아래와 같다.
$$ \varepsilon { init }=\frac { \sqrt {6} }{ \sqrt {L{in}+L_{out}} } $$
where $L_{in}=s_l$ and $L_{out}=s_{l+1}$ 이다.

def genRandThetas():
    epsilon_init = 0.12
    theta1_shape = (hidden_layer_size, input_layer_size+1)
    theta2_shape = (output_layer_size, hidden_layer_size+1)
    rand_thetas = [ np.random.rand( *theta1_shape ) * 2 * epsilon_init - epsilon_init, \
                    np.random.rand( *theta2_shape ) * 2 * epsilon_init - epsilon_init]
    return rand_thetas

2.3 Backpropagation

def backPropagate(mythetas_flattened,myX_flattened,myy,mylambda=0.):
    
    # First unroll the parameters
    mythetas = reshapeParams(mythetas_flattened)
    
    # Now unroll X
    myX = reshapeX(myX_flattened)

    #Note: the Delta matrices should include the bias unit
    #The Delta matrices have the same shape as the theta matrices
    Delta1 = np.zeros((hidden_layer_size,input_layer_size+1))
    Delta2 = np.zeros((output_layer_size,hidden_layer_size+1))

    # Loop over the training points (rows in myX, already contain bias unit)
    m = n_training_samples
    for irow in xrange(m):
        myrow = myX[irow]
        a1 = myrow.reshape((input_layer_size+1,1))
        # propagateForward returns (zs, activations) for each layer excluding the input layer
        temp = propagateForward(myrow,mythetas)
        z2 = temp[0][0]
        a2 = temp[0][1]
        z3 = temp[1][0]
        a3 = temp[1][1]
        tmpy = np.zeros((10,1))
        tmpy[myy[irow]-1] = 1
        delta3 = a3 - tmpy 
        delta2 = mythetas[1].T[1:,:].dot(delta3)*sigmoidGradient(z2) #remove 0th element
        a2 = np.insert(a2,0,1,axis=0)
        Delta1 += delta2.dot(a1.T) #(25,1)x(1,401) = (25,401) (correct)
        Delta2 += delta3.dot(a2.T) #(10,1)x(1,25) = (10,25) (should be 10,26)
        
    D1 = Delta1/float(m)
    D2 = Delta2/float(m)
    
    #Regularization:
    D1[:,1:] = D1[:,1:] + (float(mylambda)/m)*mythetas[0][:,1:]
    D2[:,1:] = D2[:,1:] + (float(mylambda)/m)*mythetas[1][:,1:]
    
    return flattenParams([D1, D2]).flatten()

$\delta$를 구하기 위해서 Backpropagation을 수행하면 다음과 같다.

#Actually compute D matrices for the Thetas provided
flattenedD1D2 = backPropagate(flattenParams(myThetas),flattenX(X),y,mylambda=0.)
D1, D2 = reshapeParams(flattenedD1D2)

아래의 $\delta$는 구하려고하는 2개의 $\theta$값의 matrix 구조와 정확히 일치한다.
이유는 해당 $\delta$가 gradient를 의미하고 이것을 이용해서 $\theta$값을 조정하기 때문이다.

  • D1.shape은 (25,401)이다. $\theta_{1}$ 25 x 401
  • D2.shape은 (10,26)이다. $\theta_{2}$ 10 x 26

입력받는 인자는 4개이다.

  • mythetas_flattened <- flattenParams(myThetas), 구하고자하는 2개의 $\theta$를 담고있다.
  • myX_flattened <- flattenX(X), 입력된 이미지값 20x20+1(bias)
  • myy <- y, 참값
  • mylambda=0. <- 정규화의 수치

델타 값을 구하는 공식은 아래와 같다.
$$ \delta^{(l)} = ((\Theta^{(l)})^T \delta^{(l+1)})\ .*\ g'(z^{(l)}) $$
해당 공식과 같이 각각의 델타값을 계산한 것이다.

2.4 Gradient cheecking

def checkGradient(mythetas,myDs,myX,myy,mylambda=0.):
    myeps = 0.0001
    flattened = flattenParams(mythetas)
    print(flattened.shape)
    
    flattenedDs = flattenParams(myDs)
    myX_flattened = flattenX(myX)
    n_elems = len(flattened) 
    #Pick ten random elements, compute numerical gradient, compare to respective D's
    for i in xrange(10):
        import time
        #Actually compute D matrices for the Thetas provided
        start_time=time.time() #taking current time as starting time
        x = int(np.random.rand()*n_elems)
        epsvec = np.zeros((n_elems,1))
        epsvec[x] = myeps
        cost_high = computeCost(flattened + epsvec,myX_flattened,myy,mylambda)
        cost_low  = computeCost(flattened - epsvec,myX_flattened,myy,mylambda)
        mygrad = (cost_high - cost_low) / float(2*myeps)
        elapsed_time=time.time()-start_time #again taking current time - starting time 
        print (elapsed_time)
        print "Element: %d. Numerical Gradient = %f. BackProp Gradient = %f."%(x,mygrad,flattenedDs[x])

실행

checkGradient(myThetas,[D1, D2],X,y)
(10285, 1)
0.372140884399
Element: 8125. Numerical Gradient = 0.000022. BackProp Gradient = 0.000022.
0.366824150085
Element: 6642. Numerical Gradient = -0.000070. BackProp Gradient = -0.000070.
0.368250131607
Element: 7657. Numerical Gradient = -0.000001. BackProp Gradient = -0.000001.
0.362774133682
Element: 5270. Numerical Gradient = -0.000031. BackProp Gradient = -0.000031.
0.356532096863
Element: 5933. Numerical Gradient = 0.000057. BackProp Gradient = 0.000057.
0.350827932358
Element: 5394. Numerical Gradient = 0.000001. BackProp Gradient = 0.000001.
0.391266107559
Element: 2606. Numerical Gradient = -0.000006. BackProp Gradient = -0.000006.
0.363577127457
Element: 6160. Numerical Gradient = 0.000075. BackProp Gradient = 0.000075.
0.379949092865
Element: 8722. Numerical Gradient = 0.000001. BackProp Gradient = 0.000001.
0.373861789703
Element: 931. Numerical Gradient = 0.000100. BackProp Gradient = 0.000100.

backpropagation을 이용할 경우 단 0.37의 시간으로 모든 gradient를 계산 할 수 있다.
하지만 numerical 방식으로는 한번에 1개의 theta값만 계산 가능하므로 계산적 오버해드가 크다고 할 수 있다.

2.5 Learning parameters using fmincg

fmin_cg함수를 이용해서 학습을 수행 한다.

  • Minimize a function using a nonlinear conjugate gradient algorithm.

간략히 설명하면 아래와 같다.

  • 장점
    • No need to manually pick $\alpha$.
      • inter-loop를 돌면서 최적의 learning rate을 스스로 매번 다르게 결정한다.
    • Often faster than gradient descent.
  • 단점
    • More complex.
#Here I will use scipy.optimize.fmin_cg

def trainNN(mylambda=0.):
    """
    Function that generates random initial theta matrices, optimizes them,
    and returns a list of two re-shaped theta matrices
    """

    randomThetas_unrolled = flattenParams(genRandThetas())
    result = scipy.optimize.fmin_cg(computeCost, x0=randomThetas_unrolled, fprime=backPropagate, \
                               args=(flattenX(X),y,mylambda),maxiter=50,disp=True,full_output=True)
    return reshapeParams(result[0])

fmin_cg의 인자는 아래와 같다.
scipy.optimize.fmin_cg(fx0fprime=Noneargs=()gtol=1e-05norm=inf,epsilon=1.4901161193847656e-08maxiter=Nonefull_output=0disp=1retall=0,callback=None)

  • f(x, *args): Objective function to be minimized. Here x must be a 1-D array of the variables that are to be changed in the search for a minimum, and args are the other (fixed) parameters of f.
  • fprime: callable, fprime(x, *args), optional
    A function that returns the gradient of f at x. Here x and args are as described above for f. The returned value must be a 1-D array. Defaults to None, in which case the gradient is approximated numerically (see epsilon, below).

학습 수행 결과

#Training the NN takes about ~70-80 seconds on my machine
learned_Thetas = trainNN()

실행 결과

Warning: Maximum number of iterations has been exceeded.
         Current function value: 0.279615
         Iterations: 50
         Function evaluations: 112
         Gradient evaluations: 112

정확도 검증

def predictNN(row,Thetas):
    """
    Function that takes a row of features, propagates them through the
    NN, and returns the predicted integer that was hand written
    """
    classes = range(1,10) + [10]
    output = propagateForward(row,Thetas)
    #-1 means last layer, 1 means "a" instead of "z"
    return classes[np.argmax(output[-1][1])] 

def computeAccuracy(myX,myThetas,myy):
    """
    Function that loops over all of the rows in X (all of the handwritten images)
    and predicts what digit is written given the thetas. Check if it's correct, and
    compute an efficiency.
    """
    n_correct, n_total = 0, myX.shape[0]
    for irow in xrange(n_total):
        if int(predictNN(myX[irow],myThetas)) == int(myy[irow]): 
            n_correct += 1
    print "Training set accuracy: %0.1f%%"%(100*(float(n_correct)/n_total))

정확도 결과

computeAccuracy(X,learned_Thetas,y)
Training set accuracy: 96.2%


'MOOC > Machine Learning (python)' 카테고리의 다른 글

Week 05: 2. Backpropagation Algorithm  (1) 2017.02.05
Week 05: 1. Neural Network Cost Function  (0) 2017.01.28
Autonomous Driving Example  (0) 2016.10.12
Putting it together  (0) 2016.10.12
Random Initialization  (0) 2016.09.19

Convolutional Neural Network (CNN) 구현


Introduction

고양이 실험에서 시작 되었다.
고양이에게 어떤 그림을 보여줬더니, 동시에 뉴런이 모두 시작되지 않았다.
각각의 부분에 대해서 다르게 동작 하였다.

이러한 개념을 이용해서 필터를 생성하여 각각의 부분을 추출하는 방식을 이용 한다.

CNN을 Image가 아닌 input data에 대해서 적용 할 때는 CNN이 왜 잘 동작하는지에 대한 직관적인 이해가 필요하다.
만약 적용하려는 데이터가 여전히 이것을 만족한다면 구지 Image가 아니어도 CNN은 우수한 성능을 보장한다.

convnet 적용하기 위한 데이터 특징

CNN의 핵심은 Weight Sharing이라고 한다. 왜냐하면 보통 Stride=1을 주기 때문이 다수의 필터들이 한칸씩만 옆으로 이동하면서 적용 되기 때문에 많은 weight들이 서로 공유하고 있는 형태가 된다. 따라서 사진 처럼 인접한 픽셀들이 서로 관련성이 매우 높아야 한다.

즉, convnet은 지역적으로 weight값들이 공유 된다는 가정하게 수행 되게 된다.
만약 이미지가 아니라면 최소한 근처 데이터 끼리 상관 관계가 높아야 한다.
예를 들면, Audio데이터 같은 time series라고 하면 이전의 사건이 이후의 사건과 관계가 높으므로 convnet을 적용하기 좋다.

만약 data.frame데이터의 각 컬럼이 서로 연관성이 없고 scaling이 심지어 서로 다르다면 convnet을 적용할 의미는 없다.

Implementation

TensorFlow를 이용해서 간단한 CNN을 구현해 보자.
이전에 MLP에서 사용한 MNIST set을 그대로 사용한다.

구현하고자 하는 모델을 표현하면 아래와 같다.

conv를 적용하기 위해선 아래의 함수를 이용한다.

tf.nn.conv2d(X, w, strides=[1, 1, 1, 1], padding='SAME')

위와 같을 때 SAME의 의미는 원래 Image와 같은 크기의 Activiation Map을 만들 겠다는 의미이다.

파라메터는 순서대로 아래와 같다.

  • input: [batch, in_height, in_width, in_channels] 형식. 28x28x1 형식의 손글씨 이미지.
  • filter: [filter_height, filter_width, in_channels, out_channels] 형식. 3, 3, 1, 32의 w.
  • strides: 크기 4인 1차원 리스트. [0], [3]은 반드시 1. 일반적으로 [1], [2]는 같은 값 사용.
  • padding: 'SAME' 또는 'VALID'. 패딩을 추가하는 공식의 차이. SAME은 출력 크기를 입력과 같게 유지.

28x28x1의 이미지 이다.
필터는 32 filters로 (3x3x1)이다. 필터의 사이즈는 조절이 가능하다.

필터를 만든다는 것은 weight을 생성 한다는 것이다.
초기가값은 정규분포에 따르는 랜덤 값을 주게되고
학습이 되어야 하는 필터이므로 Variable로 선언한다.

w=tf.Variable(tf.random_normal([3,3,1,32], stddev=0.01))

이제 각각의 필터들을 이동하면서 적용을 해주어야 하는데 이게 귀찮기 때문에 TensorFlow에서는 이것을 지원 한다.

tf.nn.cov2d(X,W)함수로 이것을 지원 한다.
X는 이미지가 되고 w는 필터가 된다.
strides=[1,1,1,1], padding='SAME으로 합치게 된다.
strides = [1, stride, stride, 1]

아래와 같이 결국 activation map은 32개 층을 이루며 size는 same 이기 때문에 28x28의 크기를 가지게 된다.

그리고 Convolution과 Relu를 같이 주고 싶다면 아래 코드로 간단하게 적용이 가능하다.

l1a = tf.nn.relu(tf.nn.conv2d(X, w, strides=[1, 1, 1, 1], padding='SAME'))

풀링도 아래와 같이 간단히 구현이 가능하다.
c1은 컨볼루셔널 결과를 받는 것이다.

결과는 2by2로 2,2를 하기 때문에 반 줄어든
14,14,32가 된다.
SAME 이라도 stride 2라서 14기 때문이다.

print l1a를 하면 shape을 얻을 수 있다. 오류를 막기 위해서 직접 출력해 보는 것도 좋은 방법이다.

Tensor reshape

tf.reshape(tensor, shape, name=None)

위 함수를 이용해서 주어진 tensor를 다른 모양으로 변경해서 반환 하게 된다.
-1을 쓰게 되면 평평한 1-D 모양을 생성 한다.
최종적인 the number of elements는 결국 같아야 한다.

동작 예제는 아래와 같다.

# tensor 't' is [1, 2, 3, 4, 5, 6, 7, 8, 9]
# tensor 't' has shape [9]
reshape(t, [3, 3]) ==> [[1, 2, 3],
                        [4, 5, 6],
                        [7, 8, 9]]

# tensor 't' is [[[1, 1], [2, 2]],
#                [[3, 3], [4, 4]]]
# tensor 't' has shape [2, 2, 2]
reshape(t, [2, 4]) ==> [[1, 1, 2, 2],
                        [3, 3, 4, 4]]

# tensor 't' is [[[1, 1, 1],
#                 [2, 2, 2]],
#                [[3, 3, 3],
#                 [4, 4, 4]],
#                [[5, 5, 5],
#                 [6, 6, 6]]]
# tensor 't' has shape [3, 2, 3]
# pass '[-1]' to flatten 't'
reshape(t, [-1]) ==> [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6]

# -1 can also be used to infer the shape

# -1 is inferred to be 9:
reshape(t, [2, -1]) ==> [[1, 1, 1, 2, 2, 2, 3, 3, 3],
                         [4, 4, 4, 5, 5, 5, 6, 6, 6]]
# -1 is inferred to be 2:
reshape(t, [-1, 9]) ==> [[1, 1, 1, 2, 2, 2, 3, 3, 3],
                         [4, 4, 4, 5, 5, 5, 6, 6, 6]]
# -1 is inferred to be 3:
reshape(t, [ 2, -1, 3]) ==> [[[1, 1, 1],
                              [2, 2, 2],
                              [3, 3, 3]],
                             [[4, 4, 4],
                              [5, 5, 5],
                              [6, 6, 6]]]

# tensor 't' is [7]
# shape `[]` reshapes to a scalar
reshape(t, []) ==> 7

코드

import tensorflow as tf
import numpy as np
import input_data
import time

batch_size = 128
test_size = 256

def init_weights(shape):
    return tf.Variable(tf.random_normal(shape, stddev=0.01))

# Filter weight vectors: w, w2, w3, w4, w_0
def model(X, w, w2, w3, w4, w_o, p_keep_conv, p_keep_hidden):
    l1a = tf.nn.relu(tf.nn.conv2d(X, w,                       # l1a shape=(?, 28, 28, 32)
                        strides=[1, 1, 1, 1], padding='SAME'))
    l1 = tf.nn.max_pool(l1a, ksize=[1, 2, 2, 1],              # l1 shape=(?, 14, 14, 32)
                        strides=[1, 2, 2, 1], padding='SAME')
    l1 = tf.nn.dropout(l1, p_keep_conv)

    l2a = tf.nn.relu(tf.nn.conv2d(l1, w2,                     # l2a shape=(?, 14, 14, 64)
                        strides=[1, 1, 1, 1], padding='SAME'))
    l2 = tf.nn.max_pool(l2a, ksize=[1, 2, 2, 1],              # l2 shape=(?, 7, 7, 64)
                        strides=[1, 2, 2, 1], padding='SAME')
    l2 = tf.nn.dropout(l2, p_keep_conv)

    l3a = tf.nn.relu(tf.nn.conv2d(l2, w3,                     # l3a shape=(?, 7, 7, 128)
                        strides=[1, 1, 1, 1], padding='SAME'))
    l3 = tf.nn.max_pool(l3a, ksize=[1, 2, 2, 1],              # l3 shape=(?, 4, 4, 128)
                        strides=[1, 2, 2, 1], padding='SAME')
    l3 = tf.reshape(l3, [-1, w4.get_shape().as_list()[0]])    # reshape to (?, 2048)
    l3 = tf.nn.dropout(l3, p_keep_conv)

    l4 = tf.nn.relu(tf.matmul(l3, w4))
    l4 = tf.nn.dropout(l4, p_keep_hidden)

    pyx = tf.matmul(l4, w_o)
    return pyx

# Read data
mnist = input_data.read_data_sets("MNIST_DATA/", one_hot=True)
trX, trY, teX, teY = mnist.train.images, mnist.train.labels, mnist.test.images, mnist.test.labels

# trx.reshape( n-inputs, image size, image size, depth )
 # this variable is input in model()
trX = trX.reshape(-1, 28, 28, 1)  # 28x28x1 input img
teX = teX.reshape(-1, 28, 28, 1)  # 28x28x1 input img

X = tf.placeholder("float", [None, 28, 28, 1])
Y = tf.placeholder("float", [None, 10])

w = init_weights([3, 3, 1, 32])       # 3x3x1 conv, 32 outputs
w2 = init_weights([3, 3, 32, 64])     # 3x3x32 conv, 64 outputs
w3 = init_weights([3, 3, 64, 128])    # 3x3x32 conv, 128 outputs
w4 = init_weights([128 * 4 * 4, 625]) # FC 128 * 4 * 4 inputs, 625 outputs
w_o = init_weights([625, 10])         # FC 625 inputs, 10 outputs (labels)

p_keep_conv = tf.placeholder("float")
p_keep_hidden = tf.placeholder("float")
py_x = model(X, w, w2, w3, w4, w_o, p_keep_conv, p_keep_hidden)

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(py_x, Y))
train_op = tf.train.RMSPropOptimizer(0.001, 0.9).minimize(cost)
predict_op = tf.argmax(py_x, 1)

# Launch the graph in a session
with tf.Session() as sess:
    # you need to initialize all variables
    start_time = time.time()
    tf.initialize_all_variables().run()

    for i in range(100):
        training_batch = zip(range(0, len(trX), batch_size),
                             range(batch_size, len(trX)+1, batch_size))
        for start, end in training_batch:
            sess.run(train_op, feed_dict={X: trX[start:end], Y: trY[start:end],
                                          p_keep_conv: 0.8, p_keep_hidden: 0.5})

        test_indices = np.arange(len(teX)) # Get A Test Batch
        np.random.shuffle(test_indices)
        test_indices = test_indices[0:test_size]

        print(i, np.mean(np.argmax(teY[test_indices], axis=1) ==
                         sess.run(predict_op, feed_dict={X: teX[test_indices],
                                                         Y: teY[test_indices],
                                                         p_keep_conv: 1.0,
                                                         p_keep_hidden: 1.0})))

    print("time elapsed: {:.2f}s".format(time.time() - start_time))

출력

/root/tensorflow/bin/python /root/DataScience/TensorFlowLecture/5.CNN/CNNforMNIST.py
Extracting MNIST_DATA/train-images-idx3-ubyte.gz
/usr/lib/python2.7/gzip.py:268: VisibleDeprecationWarning: converting an array with ndim > 0 to an index will result in an error in the future
  chunk = self.extrabuf[offset: offset + size]
/root/DataScience/TensorFlowLecture/5.CNN/input_data.py:47: VisibleDeprecationWarning: converting an array with ndim > 0 to an index will result in an error in the future
  data = data.reshape(num_images, rows, cols, 1)
Extracting MNIST_DATA/train-labels-idx1-ubyte.gz
Extracting MNIST_DATA/t10k-images-idx3-ubyte.gz
Extracting MNIST_DATA/t10k-labels-idx1-ubyte.gz
(0, 0.95703125)
(1, 0.96875)
(2, 0.98828125)
(3, 0.984375)
(4, 0.984375)
(5, 0.9765625)
(6, 0.99609375)
(7, 0.98046875)
(8, 1.0)
(9, 0.9921875)
(10, 0.99609375)
(11, 0.99609375)

원래 100번 Loop를 수행 해야하나 CPU로는 너무 느려서 그냥 중간에 포기했다.
대충 몇번만 Epoch해도 정확도가 1에 근접하는 놀라운 성능을 보여준다.

작성된 완전한 코드는 아래에 있습니다.
https://github.com/leejaymin/TensorFlowLecture/blob/master/5.CNN/CNNforMNIST.ipynb

참고 사이트

모두를위한 딥러닝
CNN을 Text Classification에 적용하기


'AI > TensorFlow, PyTorch, Keras, Scikit' 카테고리의 다른 글

Tensor Board  (0) 2017.02.08
Early Stopping 및 Index Shuffling  (0) 2017.01.03
Convolutional Neural Network (CNN) 이론  (1) 2016.12.31
AWS의 GPU를 이용한 TensorFlow  (1) 2016.12.31
rpy2 Windows 10에 설치 하기  (0) 2016.12.13

Convolutional Neural Network (CNN) 이론


Convolutional Neural Network (CNN)은 결국 CONVReLUPOOLDropu-out을 번갈아서 적용하는 것을 말한다.
마지막에는 Fully connected network으로 구성 된다.
Pooling은 sampling과 resizing을 의미한다.

Start with an image (width x hight x depth)으로 구성된다.
결국, 32 x 32 x 3 image 이다.
3이라고 하면 red, green, blue를 나타낸다.
gray scale일 경우 1의 depth를 나타낸다.

결국은 위와 같이 filter를 상징하는 weight를 찾는 것이 Convolutional Neural Network(CNN)의 목적이라고 할 수 있다.

필터를 이미지에 적용 (conv + ReLU)

필터를 이미지에 적용하고 Stride에 따라서 나오는 이미지의 크기가 달라지게 된다.

필터의 사이즈가 너무 작으면 Weight를 구하는것이 의미가 없어 진다.

아래의 공식대로 필터가 구해진다.
출력 크기 = 1 + (입력 크기 - 필터 크기) / stride 크기

핵심은 구하려고하는 값이 2.33과 같이 나머지가 존재해서는 안된다.
정수로 딱 떨어져야 이 방법이 적용 가능하다.


실전에서는 위와 같이 Filter를 적용할 때 마다 원본 image의 크기가 작아지는 문제가 발생 한다.
stride크기에 상관 없이 최소한 (필터 크기 -1)만큼 줄어들 수 밖에 없다.
따라서 padding을 처리하는 것이 중요 하다.

Max Pooling

Pooling의 다른 말은 Sampling 또는 Resizing이다.
Pooling을 거치면 크기가 작아지게 된다.
결국 이전에 filter를 통해서 생성 했던 activation map이 크기는 1/2로 작아지고 channel의 두께는 바뀌지 않게 되는 것이다.

MAX POOLING

Pooling 기법 중에서 가장 많이 사용하는 Max pooling이 있다.
여러 개의 값 중에서 가장 큰 값을 꺼내서 모아 놓은것을 말한다.

이전의 Convolutional Layer에서는 Filter를 곱해서 새로운 출력 결과를 만들어 낸다.
이와 다르게 polling에서는 단순하게 존재하는 값 중에서 하나를 선택하게 된다.
Max pooling은 여기서 가장 큰 값을 선택하는 것을 말한다.

참고문헌

http://pythonkim.tistory.com/52


AWS의 GPU를 이용한 TensorFlow


최근 실행해본 CNN 정도만해도 이제 CPU TensorFlow로는 학습이 느린감이 있다.

이전에 학생 크래딧 받기를 참조해서 아마존으로 부터 $100를 받아서 AWS EC2를 사용해 보자.
이전포스트

계정을 생성하고 EC2를 생성해보자.
아래와 같은 GPU Instance 모델들이 존재 한다.

필자는 아래의 모델중 g2.8xlarge를 선택 했다.

Instance를 생성 할 때 김성훈 교수님께서 이미 EC2를 공유해 주셨기 때문에 해당 Instance를 카피해서 생성한다.
AMI라고해서 Amazon Machine Instance를 검색해서 찾을 수 있다.
아래의 이름으로 검색하면 된다.

  • ami-9e39dcf3 (N. Virginia)
  • ami-38f60658 (oregon)

그리고 생성 하려고하면 아마 limit fail이 발생할 것이다.
고객센터가서 사용 목적을 적어서 이메일 보내면 30분내로 instance 갯수 허용이 늘어나고
생성할 수 있게된다.

아래와 같이 정상적으로 생성 할 수 있다.

인증키로 로그인 하기

putty로 접속을 하려면 key를 생성해야 합니다.
http://www.chiark.greenend.org.uk/~sgtatham/putty
PUtty key generator를 실행해야하므로 모든 관련 파일이 있는 putty.zip을 다운 받아야 합니다.

PUTTYGEN을 실행 합니다.
Conversions-> Import key를 선택합니다.
EC2를 생성할 때 사용 했던 key를 이용해서 접속 key를 생성해야 합니다.

키를 로드하고 save private key 버튼을 눌러서 저장합니다.

EC2 키의 확장자는 pem이고 PUTTYGEN에 의해서 생성한 키의 확장자는 ppk입니다.

Amazon EC2 관리자로가서 Public IP 주소를 확인 합니다.
Putty를 실행해서 IP 주소를 입력하고
오른쪽 창에서 SSH-> Auth로 이동합니다.
Browse버튼을 눌러서 생성한 Key를 선택합니다.
open버튼을 눌러서 접속 합니다.

각 EC2 Instance의 운영체제에 따라서 기본 사용자명이 다릅니다.

  • Amazon Linux: ec2-user
  • Red Hat Enterprise Linux: ec2-user
  • SuSE Linux: root
  • Ubuntu Linux: ubuntu

필자는 Ubuntu이므로 아이디는 ubuntu 이다.

아래와 같이 정상적으로 로그인 되는것을 알 수 있습니다.

MNIST set을 가지고 CNN모델을 트레이닝 하는것을
AWS GPU와 i7-cpu에서 트레이닝 했을 때를 녹화한 것이다.

동영상은 아래의 유투브에서 볼 수 있다.
Youtube: https://youtu.be/-kQ4fm2fqcM

대략 5배~7배 정도 차이인것 같다.
K520 GPU가 4대 있는 EC2인데 생각보다 차이는 크지 않다.

최종 결과는 아래와 같다.

EC2

MNIST로 CNN 모델을 트레이닝 하는데 총 22분 4.040초 걸렸다.

i7 CPU

결론적으로 4.8배 차이이다.


Ch08: Punctuation(2)


Hyphen

compound terms을 기술 할 때 사용 한다.
Latex에서는 -이다.

  • check-in
  • free-for-all

en-dash

em-dash 보다는 잛고
hyphen 보다는 약간긴 것이다.

latex에서는 --이다.

연결 대상 사이에 공백을 없앤다.

  • June-July 1967
  • 1:00 2:00 p.m
  • For ages 3-5
  • pp. 38-55
  • The 2010–2011 season was our best yet.
  • You will find this material in chapters 8–12.
  • The professor holds office hours every Wednesday, 11:00 a.m.–1:00 p.m.

중요한 것은 from between을 사용 할 때 en-dash를 섞어서 쓰지 않는 것이다.

  • Correct: She served as secretary of state from 1996 to 1999.
  • Incorrect: She served as secretary of state from 1996–1999.
  • Correct: The regime’s most oppressive treatment occurred between 1965 and 1970.
  • Incorrect: The regime’s most oppressive treatment occurred between 1965–1970.

em-dash

보통 문장안에 다른 설명을 끼워 넣을 때 사용한다.

  • Since 2007, the consensus of the economic establishment—bankers, policymakers, CEOs, stock analysts, pundits—has been catastrophically wrong.
  • However, in order to develop ecologically valid systems that work well in the real world, the data used for development should be collected in the wild — capturing people’s authentic behavior in their regular environments.
  • In this paper, we present the tool we used to collect the data — the ExtraSensory App, a mobile app designed to collect sensor data and engage participants to contribute detailed and frequent labels describing their behavioral context.

Latex에서는 ---로 표현 한다.

colon

어떤 list를 소개 할 때 사용 한다.

  • The bookstore specializes in three subjects: art, architecture, and graphic design.
  • I have three sisters: Daphne, Rose, and Suzanne.

하지만 해당 list가 선행 문장의 일부분이면 안된다.

  • (x) The bookstore specializes in: art, architecture, and graphic design.

두 개의 독립적인 절 (independent clauses)를 연결하며 첫 번째 문장을 두 번째 문장으로 설명할 때 사용 한다.
이러한 용법에서는 semicolon과 그 요법이 거의 같다고 할 수 있다.
연이은 문장은 capitalize하지 않는 것이 일반적이다. 고유명사가 아니라면 보통 하지 않는다.

  • Bob could not speak: he was drunk.
  • I have very little time to learn the language: my new job starts in five weeks.
  • A college degree is still worth something: a recent survey revealed that college graduates earned roughly 60% more than those with only a high school diploma.
  • All three of their children are involved in the arts: Richardis a sculptor, Diane is a pianist, and Julie is a theatre director.

만약 colon뒤에 두 개 이상의 문장이 따라오다면 capitalize를 한다.

  • He made three points: First, the company was losing over a million dollars each month. Second, the stock price was lower than it had ever been. Third, no banks were willing to loan the company any more money.

semicolon

동등한 두 개의 절을 연결 할 때 conjunction(for, and, nor, but, or, yet, so)의 사용 없이 연결 할 수 있게 한다.

  • (;사용) The upperclassmen are permitted off-campus lunch; the underclassmen must remain on campus.
  • (but 사용) The upperclassmen are permitted off-campus lunch, but the underclassmen must remain on campus.

사실 semicolon으로 연결된 두 문장은 마침표(period)로 분리 할 수 있다. 그럼에도 불구하고 ;을 사용하는 것은 두 개의 문장이 연관성이 있음을 강조하기 위해서 사용 한다.
하지만, 두 번째 문장이 첫 번째 문장을 설명하는 방식으로 연결된 구조라면 semicolon보다는 colon이 더 좋은 표현이다.

  • She saw three men: Jamie, who came from New Zealand; John, the milkman’s son; and George, a gaunt kind of man.

문장이 서로 연결되어 있고 표현이 전이되는 것이라면, 즉 transitional expression (e.g., accordingly, consequently, for example, nevertheless, so, thus)을 사용한다면 그 때semicolon을 사용 한다.

  • Heavy snow continues to fall at the airport; consequently, all flights have been grounded.
  • Hyperinflation makes it extremely difficult to keep track of prices; thus a quart of milk might cost $10 in the morning and $200 in the afternoon.

  • She stood at the edge, but then decided otherwise; she walked home.

참고자료

http://www.thepunctuationguide.com/hyphen.html


'논문 작성 > Writing for computer science' 카테고리의 다른 글

Chapter 8: Punctuation  (0) 2015.06.28
Chapter 7 Style Specifics  (0) 2015.03.05
Chapter 1-6  (0) 2015.02.17

Difference between Occur and Incur


Answer:
Occur: to happen, to take place unexpectedly.

The lunar eclipse occurred while I was traveling to Australia.
The corruption of the bank occurred during the 1980s.

Incur: To acquire or come into (something usually undesirable).

Peter incurred many additional expenses while he was studying abroad.
Any extra cost will be incurred by the client. (the client will have to pay)


'영어 > 영문법' 카테고리의 다른 글

end up with ~  (0) 2017.01.14
It turns out  (0) 2017.01.14
not only but also 와 as well as 사용법 및 차이점  (2) 2016.06.19
조동사 정리  (0) 2016.04.07
Leverage 명사 동사  (0) 2016.02.21

Latex 줄 번호 삽입


논문 peerreview를 위해서 줄 번호를 생성한 상태로 제출하면 편리하다.

사용 package는 lineno이다.

\usepackage[<options>]{lineno}

\usepackage[mathlines,switch]{lineno} % peer review, line number

번호 간격 설정

\modulolinenumbers[3] % line number

번호 시작

\linenumbers % line number

번호 중단

\nolinenumbers


'논문 작성 > LaTex' 카테고리의 다른 글

ShareLaTex 설치 및 사용법  (6) 2017.11.23
TextStudio 문법 검사 기능 사용  (0) 2016.06.29
TexLive 2016 설치법  (0) 2016.06.15
Latex 에 하이퍼링크 추가방법  (0) 2016.05.30
citation 번호 합치기  (0) 2016.04.22

CDF stat_ecdf


누적 밀도 함수를 R의 ggplot2 페키지를 이용해서 생성한다.

mydf = data.frame(
   a = rnorm(100, 0, 1),
   b = rnorm(100, 2, 1),
   c = rnorm(100, -2, 0.5)
)

mydf_m = melt(mydf)

p0 = ggplot(mydf_m, aes(x = value)) + 
   stat_ecdf(aes(group = variable, colour = variable)) 
print(p0)


'AI > R ggplot2' 카테고리의 다른 글

ggplot2: 그래픽 라이브러리  (0) 2016.03.20
R에서 EPS 이미지 생성  (0) 2015.06.16
ggplot2 package를 이용한 Graph 그리기  (0) 2015.02.16
R 그래프 페키지 종류  (0) 2014.11.05

rpy2 Windows 10에 설치 하기

정식으로 rpy2에서 Window를 지원하지 않아서 생각 보다는 까다로운 것 같다.

설치한 환경은 아래와 같다.

  • Window 10 1주년 버전
  • Anaconda 4.x
  • python 3.5.x
  • R.3.3.2

pip instal rpy2를 실행 할경우 여러 오류가 발생 한다.

환경 변수 미 설정에 따른 오류

해당 오류는 init.py에서 R_HOME 환경변수를 참조 하기 때문이다. 기타 R을 쓰기위한 환경 변수를 모두 설정 해줘야 한다.

모두 시스템 변수로 설정 했다.

  • R_HOME: C:\Program Files\R\R-3.3.2
  • R_USER: 사용자 계정을 적는다.
  • Path: 맨뒤에 C:\Program Files\R\R-3.3.2\bin추가한다.

*.sh 스크립트 실행 불가 오류

자동 다운로드가 안되서 직접 .whl을 받아서 설치 한다.
사이트: http://www.lfd.uci.edu/~gohlke/pythonlibs/#rpy2

Python3의 환경 이므로
rpy2‑2.8.4‑cp36‑cp36m‑win_amd64.whl을 다운 받았다.

"not a supported wheel on this platform". 오류

아래 명령어를 실행 하면 위와 같은 오류가 발생한다.
파일 명을 변경해줘야한다.
Python 3.5 부터 파일 이름가지고 구분 하는것 같다.

pip install rpy2‑2.8.4‑cp36‑cp36m‑win_amd64.whl

파일명을 rpy2-2.8.4-py3-none-win_amd64.whl로 변경 한다.
즉 py3-none이 cp36-cp36m을 대체한 것이다.

실행 테스트


Python에서 rpy2를 이용한 ROjbect 불러오기


rpy2 설치하기 (ubuntu)

R 구 버전 삭제
ubuntu 14.04는 기본적으로 3.0.1 버전을 설치한다.
rpy2는 guswo 3.2 버전 이상부터 동작하므로, 기본 보전인 2013년도 R을 설치하면 진행이 안된다.

우선 현재 구 버전 R이 설치되었다면 아래 방법으로 깨긋이 삭제 한다.

R을 실행해서 관련 package들이 어디에 설치 되어 있는지 확인 한다.

.libPaths() 

그리고 아래의 명령어로 삭제한다.

sudo apt-get remove r-base-core
sudo apt-get remove r-base
sudo apt-get autoremove

확인한 package 경로에 들어가서 남아있는 파일들이 없는지 확인 한다.

R 최신 버전 설치
Youtube 동영상: https://www.youtube.com/watch?v=Nxl7HDUyw0I
원본 방법: https://launchpad.net/~marutter/+archive/ubuntu/rrutter

필자는 동영상 처럼 Update방식으로 할 경우 충돌이나서 이전 버전을 완전히 지우고 새로 설치 하는 방법으로 진행 했다.

# Add PPA:
sudo add-apt-repository ppa:marutter/rrutter 

# Update ubuntu for upgrade:
sudo apt-get update

# install
sudo apt-get install r-base

rpy2 설치 하기
간단히 pip 명령어로 설치 할 수 있다.

pip install rpy2

아래와 같은 에러가 발생하면 R version이 구버전 이거나 중요 시스템 package들이 설치 안되서이다.
rpy2 error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

해결 방법은 아래의 package들을 모두 설치하는 것이다.

sudo apt-get install build-essential autoconf libtool pkg-config python-opengl python-imaging python-pyrex python-pyside.qtopengl idle-python2.7 qt4-dev-tools qt4-designer libqtgui4 libqtcore4 libqt4-xml libqt4-test libqt4-script libqt4-network libqt4-dbus python-qt4 python-qt4-gl libgle3 python-dev

통상 python-dev와 build-essential을 설치하지 않아서 발생 한다고 한다.
참고사이트: http://stackoverflow.com/questions/26053982/error-setup-script-exited-with-error-command-x86-64-linux-gnu-gcc-failed-wit

rpy2로 Rdata 불러오기

import rpy2.robjects as robjects
import pandas.rpy.common as com
import pandas as pd

# check the current working directory 
os.getcwd()

## load .RData and converts to pd.DataFrame
robj = robjects.r.load("seenPhoneStatus10FeaDfList.Rdata")

robjects.r('lapply(seenPhoneStatus10FeaDfList,dim)')

실행 결과

R object with classes: ('list',) mapped to:
<ListVector - Python:0x7f7b64129d40 / R:0x2e68950>
[IntVe..., IntVe..., IntVe..., ..., IntVe..., IntVe..., IntVe...]
  X: <class 'rpy2.robjects.vectors.IntVector'>
  R object with classes: ('integer',) mapped to:
<IntVector - Python:0x7f7b65bf67e8 / R:0x3f4ae18>
[    1038,       10]


가끔 저널에서 Latex template이 없는 경우가 있다.


MS Word를 사용해야 하는 경우 수식 조판을 위해서는 보통 MathType을 쓰라고 저널에서 지시하고 있다.


WIndow 10 기준 MS Word 2016에는 MathType 6.9b 최신 버전을 설치해야 메뉴바에 MathType이 정확히 보인다.

6.9를 설치하면 안보이니 주의해야 한다.


공식 홈페이지: http://www.dessci.com/en/products/mathtype/

단축키 정리: http://blossompassion.tistory.com/entry/MathType-%EB%8B%A8%EC%B6%95%ED%82%A4-%EC%A0%95%EB%A6%AC



Troubleshooting


MathType toolbar/tab이 여전히 MS Word 상단에 보이지 않을 때


아래의 과정을 수행해보자. 간혹 MS Word에서 안보이게 할 수도 있다고 한다.


Microsoft Word for Windows 2010 and later


1 Launch Microsoft Word.

2 From the File tab choose Options.

3 In the resulting window, from the left-side navigation menu choose Add-ins.

4 Using the drop-down menu located at the bottom of the window, choose Word Add-ins and click the button labeled, "Go".

5 In the resulting window, under Global Templates and add-ins, the following items should be present and have a checkmark next to each:

MathType Commands 6 for Word 20XX.dotm

MathPage.wll (if it's not there, it's OK)

WordCmds.dot

6 Click OK.


This will restore the MathType Tab to the Word Ribbon.

'논문 작성' 카테고리의 다른 글

How to write Abstract effectively  (0) 2015.01.06

Feature Selection with Caret (Auto)


자동 Feature Selection을 통해서 해당 Featrue가 Accurate Model을 생성하는데 필요한지 안한지를 결정할 수 있다.

기법들은 많이 있지만 인기있는 기술중 하나가Recursive Feature Elimination (RFE)방법 이다. 그리고 이 방법을 Caret R package에서 지원 한다.

Caret에서는 rfeInter와 rfe가 존재 한다.
하지만 재귀적 방법을 사용하는 rfe에 초점을 맞춘다.

rfe 함수의 필요 인자는 아래와 같다.

  • x, a matrix or data frame의 예측에 사용되는 feature들
  • y, 결과 백터값
  • sizes, subset의 크기를 결정하는 integer vector이다. 지정하지 않으면 ncol(x)로 설정 된다.
  • rfeControl, option을 포함 한다.

rfeControl 설정시 중요한것이 모델링에 사용할 function을 정하는 것이다.

control <- rfeControl(functions=nbFuncs, method="cv", number=10)

위경우 cross validation 방식으로 naive Baeys로 모델링 한다는 것이다.
그리고 cv는 10개로 쪼개서 수행 한다. 기본값이 10이다. 따로 설정안해도 number=10의 효과를 얻는다.

repeatedcv를 수행하기 위해서는 아래와 같다.

ctrl <- rfeControl(functions = lmFuncs,
                   method = "repeatedcv",
                   repeats = 5,
                   verbose = FALSE)

그 외에는 아래와 같다.

  • linear regression lmFuncs
  • random forests rfFuncs
  • naive Bayes nbFuncs

- bagged tress treebagFuncs

참고문헌

[1] Recursive Feature Elimination

[2] Feature Slection with the Caret R Package


'AI > Machine Learning with R' 카테고리의 다른 글

클래스 불균형을 다루는 방법 (Class Imbalance)  (1) 2017.07.20
Caret의 이해  (0) 2016.03.06
Cross Validation  (0) 2016.02.26
Ensemble method: Bagging (bootstrap aggregating)  (0) 2015.11.19
Bootstrapping  (0) 2015.11.19

R Notebook


Python의 Jupyter Notebook과 다르게 R의 경우 그동안 R Markdown만 있을뿐 Interative한 Document 타입이 없어서 불편 했었다.

하지만 이번 R Studio preview 업데이트로 막강한 Notebook기능이 업데이트 되었다.

Data Analysis시 좀 더 체계적인 문서와 관리가 가능해진 것 같다.

RStudio v1.0.44 Preview — Release Notes

  • Authoring tools for R Notebooks.
  • Integrated support for the sparklyr package (R interface to Spark).
  • Enhanced data import tools based on the readr, readxl and haven packages.
  • Performance profiling via integration with the profvis package.
  • Authoring tools for R Markdown websites and the bookdown package.
  • Many other miscellaneous enhancements and bug fixes.

동작 모습

아래와 같이 Notebook생성 기능이 새로 만들어 졌다.

그리고 아래와 같이 preview버튼으로 실행하고 옵션을 in panel로 하면 viewer 창에 결과가 보이고
interactive 하게 편집할 수 있도록 바뀐다.


+ Recent posts