2016년 9월 13일 화요일

ResNet

딥 네트웍의 층이 깊어지면 추상화 능력이 높아져 표현 능력이 커지고, 비선형성이 높아지므로 더 복잡한 문제를 수용할 수 있다.  그러나 깊은 넷을 학습하는 것은 gradient vanishing/expoding문제로 인해 더 어렵게 된다.



깊은 층을 가지는 네트웍을 학습하기 위해 ReLU, Dropout, Normalized initialization, Intermediate layer normalization, Batch normalization 등의 다양한 기술이 개발되어 왔다. 이러한 기술들을 통해 딥넷의 층의 수를 높이면 일정 수의 깊이까지는 인식률이 증가한다
상기한 그림을 보면 최근 10년의 연구결과는 DNN 깊이의 증가에 따라 오차률이 점차 개선됨을 보여 준다


그러나 CIFAR-10 문제의 학습 오차에서 보듯이 기존 넷(plain net)의 경우 깊이를 단순히 증가만 시키니 학습 오차가 오히려 더 증가하였다. 그림에서 20개의 레이어를 가진 넷보다 56개의 레이어를 가진 넷의 오차가 더 크게 나타난다.  


깊이의 한계가 깨진 것은 ILSVRC'2015에서이다. DNN 깊이 증가의 혁신이 일어나는데 ResNet이 그 주인공이다. 직전의  22개의 층을 가진 GoogLe넷에 비해 획기적으로 증가된 152개의 층을 가지고 있으며 2015년 영상 분류, 물체 감지, 객체 분할 등의 벤치마크 분야에서 가장 높은 성능을 보여주었다.





ResNet 이해의 핵심은 identity 매핑이다. 위 그림에서 좌측은 2014년의 VGG넷이고 우측은 VGG넷을 일부 변경한 더 깊은 넷이다. VGG넷은 2014년에 기존 분류기 중에서 최고의 성능을 낸 것으로 알려져 있다.
두 넷을 비교할 때 파란색의 추가 블럭(extra layers)들을 주목하자. 만일 이 블럭들이 입력에 대해 입력과 동일한 출력을 줄 수 있다면 VGG넷에 아무 영향을 주는일 없이 추가 할 수 있다. 즉, 입출력이 같다면 추가하여도 빼버려도 무관할 것이다. 입출력이 동일하므로 이 블럭들은 identity 매핑을 하는 유닛이고 얼마든지 층들을 쌓아서 깊은 층을 가진 넷을 구성할 수 있다.

또 다른 면에서 생각해 보면, 유닛이 추가되기 전의 VGG넷이 최적이라고 가정하자. 이때 추가된 유닛이 최적으로 학습 되었다면, 전체 VGG넷은 유닛 추가 전의 최적 성능을 내어야 하고, 추가 유닛은 identity 매핑을 하여야 한다.  


그런데 개별 유닛을 살펴보면 아래 그림과 같다. 두 세개의 학습 층과 ReLU 활성부를 가지고 있다. 즉,여러개의 비선형 층들이 쌓여 있으며 이러한 복합층들로는 입출력이 같은 identity 매핑을 만들기가 어렵다.


이 유닛을 identity 매핑으로 만들기 위해 유닛의 구조를 약간 바꾼다.


skip 메카니즘이라고 부르며 층을 건너 뛰어 입력을 바로 출력부로 연결한다. 이렇게 유닛을 구성하게 되면 입력은 그대로 출력으로 나가게 되므로 identity 매핑이 만들어지고 중간에 거치는 층들은 웨이트 값들이 0이나 0근처의 값을 가져도 될 것이다. 즉, 어떤 맵핑을 만들기 보다는 잔차(Residual)나 변동(perturbation)을 검출하기 적절한 내부 유닛으로 바뀌게 된다. 

Residual block

Resnet은 연산량과 파라메터의 수를 줄이기 위해 bottleneck 블럭을 사용하는데 아래 그림과 같다.


좌측의 원형 residual block을 수정한 것이 우측의 bottleneck block이다. bottleneck 블럭은 가운데에만 파라메터가 몰려있어 이름이 이렇게 붙여졌다. 이 블럭은 더 많은 맵 수를 유지하면서도 내부 파라메터의 수는 더 작다. 파라메터 수를 계산해 보면, 좌측은

$3\times3\times64\times64+3\times3\times64\times64=73,728$

개가 되고, 우측은 

$1\times1\times256\times64+3\times3\times64\times64+1\times1\times256\times64=69,632$

개이다. 즉, 특징 맵의 수는 더 많이 유지하면서도 파라메터 수는 비슷하거나 더 작다. 여기서 1x1 convnet연산이 맵의 수를 바꾸기 위해 사용되었다.



ResNet(Residual Net)은 Residual block을 여러개 반복적으로 쌓아 많은 수의 층을 가진 넷으로 구성한다. 층의 수가 많으므로 비선형성이 높아 Alexnet이나 VGG에서 사용하는 FCL(fully connected layer)을 가지지 않는다. 1x1 conv층은 FCL과 같고 이러한 FCL이 block마다 있으므로 따로 FCL이 필요하지 않기도 하다.
FCL 대신에 ResNet에서는 Average pooling을 사용하는데 AP은 맵별로 값의 평균을 구하고 이 평균값들의 벡터를 특징값으로 사용한다. 예를 들면, ResNet의 말단에서 <mini-batch, 512,4,4>의 맵이 AP되면 <mini-batch,512,1,1>이 된다.
보통 기존 넷 내부의 파라메터들은 FCL에 몰려 있는데 이 부분이 없으므로 층의 깊이에 비해 파라메터의 수가 많지 않다. 따라서 런타임에서는 ResNet의 실행 속도는 VGG등과 비슷하거나 오히려 빠르다. 





(Ref.) 
[1] Kaiming He. et. al., Deep residual learning for image recognition, 2015.
[2] Kaiming He. et. al., Identity mapping in deep residual networks, eccv'2016.
[3] Kaiming He. et. al., ResNet presentation



















2016년 9월 11일 일요일

Batch Normalization

Batch Normalization은 딥러닝 네트웍의 학습에서 gradient vanishing과 exploding을 회피하기 위한 방법 중의 하나이다.

딥러닝 알고리즘은 층이 깊어질수록 표현 능력과 추상화 레벨이 높아지는 것으로 알려져 있다. 그러나 층이 깊어질 때 출력단의 Loss값의 gradient가 내부로 도달하지 않고 소멸해버리는 현상으로 학습에 한계가 있었다. 이러한 문제점을 해결하고 깊은 층을 가지는 넷을 설계하기 위해, ReLU 활성함수, Dropout, 학습 샘플 초기화 전략, Learning rate 조절 등의 여러가지 방법이 개발되어 왔다.

딥러닝 구조의 내재적 불안정성은 Internal Covariance Shift 현상에 의한 것으로 BN 논문의 저자는 주장한다. 이것은 넷 각 층의 입력 값의 분포(variance)가 일관성없이 계속해서 달라지는 현상을 말한다.
레이어 입력값 분포의 변화가 발생하면 입력을 받아들이는 레이어는 새로운 분포에 계속해서 적응해야 한다. 레이어의 입력 값은 이전의 모든 레이어 파라메터에 의해 영향을 받고, 네트웍 파라메터의 작은 변화는 네트웍이 깊어질 때 증폭되고 학습의 복잡성은 증가한다.

이에 대한 해결책으로 각 층의 입력값의 평균을 구해 제거하고 분산으로 값들을 나누어 표준편차를 1로 만드는 것을 생각할 수 있다.
그러나 이 방법은 역행렬의 요구 등으로 계산량이 많은 점과 $f=Wx+b$의 연산에서 오프셋 $b$의 영향이 소거되는 등의 문제로 적용이 어렵다.

또한 층의 입력 값을 정규화를 통해 평균 0, 분산 1로 고정시키는 것은 Activation 함수의 가장 중요한 역할인 비선형성을 없애 버릴 수 있다. 즉, 넷은 비선형성을 가지고 있어야 복잡한 함수를 표현할 수 있는데 이 능력이 사라질 수 있다.  예를 들면, sigmoid 활성함수의 입력 값이 평균 0, 분산 1이라면 입력 값의 범위는 -1~+1이 되고, 이 범위의 sigmoid 함수 값은 0.5를 중심으로 0.2~0.7사이의 거의 직선인 선형 영역이다.
이 점을 보완하기 위해 정규화된 값에 scale 팩터($\gamma$)와 shift 팩터($\beta$)을 도입하고 정규화된 값에 곱하고 더해준다. 두 인자는 오차 역전파 과정에서 학습해 준다. 이를 통해 활성함수로 들어가는 값의 범위를 바꾸어줌에 의해 비선형성을 부여할 수 있다.


$BN(x_i)=\gamma(\frac{x_i-\mu_B}{\sqrt{\sigma^2_B+\epsilon}})+\beta$

BN의 적용 방식은 현재 입력되는 학습 샘플의 mini-batch에 대해 특징 맵 별로 정규화를 수행한다. 이 값에 scale과 shift팩터를 곱하고 더해 적용하게 된다. 따라서, 맵 별 파라메터는 2개이다.
예를 들면, 어떤 중간층에서 BN유닛의 입력이 (mini-batch,128, 32, 32)였다면 (mini-batchx32x32)의 데이터에 대해 mean($\mu_B$)과 vari($\sigma_B$)를 구해 정규화를 수행한 후 scale, shift팩터를 위 식처럼 적용한다. 인자 수는  맵이 128개이므로 256개이다.


(Ref.)
[1] Batch Normalization: Accelerating deep network training by reducing internal covariance shift, ICML2015.
[2] Batch Normalization의 설명 및 구현
[3] Understanding the backward pass through BN Layer


2016년 8월 6일 토요일

선형 분류기

정의

하나의 층(layer) 만을 가진 분류기이다. 층의 수를 셀 때 입력층은 제외하므로 입력층 하나와 출력층 하나만을 가진 신경망이며 딥 신경망의 가장 기본적인 형태이다. 선형분류기의 학습에 필요한 수식과 용어들을 살펴보자.  

score 함수: 입력 데이터를 부류별 득점(스코어) 값으로 바꾸는 함수
loss 함수: 스코어 값과 참 값(ground true)이 얼마나 일치하는지를 수치화한 함수

선형분류기의 연산은 다음 수식을 통해 수행된다.

$f(x_i, W, b) =  W x_i + b$
여기서 $f$는 score 함수이고 $x$는 입력, $(W, b)$는 분류기의 파라메터 값이다. Loss 함수는 스코어 함수를 이용하여 구성된다. 



Loss 함수

SVM loss와 cross entropy(softmax) loss 두가지에 대해 살펴본다. Loss는 손실이니 손실이 작아지도록 분류기를 설계해야 한다. 

(1) SVM Loss


Multiclass SVM

기계학습에서 소개되는 기존의 전통적 SVM(support vector machine) 마진을 최대화하는 이진 분류기(binary classifier) 얻는 것이었다. 
여기서는 다 부류를 분류하는 경우에 어떻게 SVM으로 비용(penalty)을 정의하는지에 대해 살펴본다. 

어떤 입력이 들어가 선형분류기를 통과해서 클래스당 스코어 값을 얻었다고 하자. 이 때 SVM Loss는 부류별 출력 값 중 입력이 속해야 하는 정 부류(correct class) 스코어가  부 부류(incorrect class) 스코어보다 어떤 마진이상  값을 가지도록 하는 Loss이다.
스코어 값 차이가 마진보다 크면 SVM 로스는 0, 그렇지 않으면 차이 값에 의한 Loss가 나타난다.

$L_i = \sum_{j\neq y_i} \max(0, s_j - s_{y_i} + \Delta)$,  where $s_j = f(x_i, W)_j$.

여기서 $s_j$는 입력 $x_i$가 선형분류기 $f$를 통과해서 얻어진 부류 $j$에 대한 score 값을 나타낸다. $s_{y_i}$는 정 부류에 대한 스코어 값이다.


(예제
만일 3개의 부류(즉, 출력 클래스)를 가지고 있고, 어떤 입력 데이터에 대해 스코어 $s=[13, -7, 11]$ 나왔다고 하자, 첫번째 클래스가 true 클래스라고 가정하고, 마진 값은 10이라 가정한다. 위 수식에 넣어서 계산하면,

$L_i=max(0,-7-13+10)+max(0,11-13+10)$.

수식의 두 항중에서 첫번째 항은 0이다. 13> -7이고 10이상의 차이가 난다. 두번째 항은 13>11이지만 2밖에 차이가 안나고, 8 값이 나온다. 즉, 정 부류의 스코어 13은 부 부류의 스코어 11과의 마진이 10이 될 만큼 충분하지 않아 loss 8이 생기고, 전체 로스도 8이

Regularization


분류기가 같은 Loss 값을 주었다고 해도 이 Loss를 결정하는 파라메터 $(W, b)$는 유일하지 않을 수 있다. 이 문제를 해결하고 분류기의 일반화 능력을 높이기 위해  Loss 값에 Regularization이라 불리는 두번째 항을 추가한다
$R(W)$는 weigts 행렬의 각 요소 값들의 절대치 합(L1 penalty), 또는 제곱 합(L2 penalty)으로 요소값이 커지는 것을 억제한다.

$L =  \underbrace{ \frac{1}{N} \sum_i L_i }_\text{data loss} + \underbrace{ \lambda R(W) }_\text{regularization loss} \\\\$


Regularization항은 일반화 능력을 높이고 $w$값의 확산을 유도한다.

(예제)
입력이 $x=[1,1,1,1]$이다. 선택 가능한 가중치에 $w_1=[1,0,0,0]$과 $w_2=[0.25,0.25,0.25,0.25]$가 있다면 둘 중 어떤 것을 선택할지에 대해 살펴본다. 두 가중치에 대한 선형 분류기 연산은

$w_1^Tx = w_2^Tx = 1$

로 둘 다 1이다. 따라서 위의 식 $L$에 대입해 보면  가중치 벡터는 같은 값의 data Loss(첫번째 항의 값)을 준다. 그러나 두 번째 항을 살펴보면, $w_1$ L2 penalty 1이고, $w_2$는 0.25이다. 따라서 더 작은 $w_2$ 선호된다

$w_2$는 $w_1$보다 크기가  작고 값이  퍼져(diffuse)있다. 이것은 입력 $x$의 4개 값 중의 특정 부분에 집중하는 보다는 모든 입력요소가 골고루 기여하게 하고, 이것은 일반화 능력의 상승과 과적합(overfitting) 감소로 나타난다


(2) Cross-entropy Loss


Softmax classifier


SVM 로스 외에 보편적인 Loss 중의 하나인 cross entropy 로스를 사용하는 softmax 분류기를 살펴 본다. data loss항은 다음과 같다. 

$L_i = -\log\left(\frac{e^{f_{y_i}}}{ \sum_j e^{f_j} }\right) $


cross-entropy는 정보 이론(information theory)에서 왔는데 참 분포 $p$ 추정 분포 $q$ 사이의 cross-entropy[2] 

$H(p,q) = - \sum_x p(x) \log q(x)$

처럼 정의된다. 두 확률 분포의 겹칩의 정도를 표현하는 식이다. 
따라서 softmax 비교하여 $q = e^{f_{y_i}} / \sum_j e^{f_j}$이고, $p=[0,…,1,…0]$라면(, one-hot 벡터처럼 정확한 부류 하나만 1이고 나머지는 0인 경우) 식은 같다.
두 식의 모양은 동일하며 softmax 분류기는 cross-entropy loss 분류기로 불린다. 



수치적 안정성

지수 값을 가진 $exp$ 함수는 값이 아주 크고, 값의 나누기는 수치적 불안정성을 야기한다. 
이를 해결하기 위해 

$C=-\max_j{f_j}$

되도록 선정된 $C$값을 분자/분모에 곱하여 해결한다($exp$ 지수 값이 0근처로 shift 된다). 

$\frac{e^{f_{y_i}}}{\sum_j e^{f_j}}$ $= \frac{Ce^{f_{y_i}}}{C\sum_j e^{f_j}}$$= \frac{e^{f_{y_i} + \log C}}{\sum_j e^{f_j + \log C}}$



softmax 확률값

확률값이 confidence 의미하는 것은 아니다. 만일 regularization $\lambda$ 증가시키면 $w$ 값이 퍼지고 이에 따라 클래스의 스코어 값이 퍼지도록 변화된다. 따라서 스코어의 ordering 중요하지 절대 값은 변화 가능하다.



References

[1] cs231n linear classification
[2] 오일석, 패턴인식, 부록, 교보문고













2016년 7월 12일 화요일

Policy Gradients

직관적 이해

제어할 대상 시스템(환경, $env$), 시스템에 가하는 $action$, 이 $action$을 만들어 내는 제어기(DNN, CNN, or RNN)가 있다고 하자. 
요점은 $env$에 가해지는 최적 $action$ 샘플링 하나를 얻는 것이라기 보다, 랜덤 샘플링(가능한 여러 $action$ 중의 하나)을 제공하는 확률 분포(DNN 출력이 만드는)를 개선하는 것이다. 
$env$ 상태(state, 이미지 등) 입력에 대해 제어기(DNN)가 준 랜덤 $action$을 시스템($env$)에 가했을 때 받은 보상값($reward$)을 loss에 반영하여 DNN 학습을 반복하면, 이 샘플링을 발생 시켰던 분포(DNN 출력)가 $reward$를 크게하는 방향으로 개선된다.  



수식

신경망 $\pi$의 출력은 확률분포이며 기대값의 가중치로 사용된다. 아래 식 우측 [~] 부분은 loss의 grad이다.  




수렴성

Policy gradient는 여러 RL(강화 학습) 학습 방법 중에서 Alphago가 사용하였다. 확률분포가 $reward$를 크게하는 방향으로 수렴함을 확인해 보자.

용어들은 $^{각주1}$을 참고한다.


RL에서 학습이란 파라메터 값을 잘 바꾸어 분포를 조정함에 의해 $action$ 샘플링이 주는 보상함수를 높이는 것이 목표이다.
보상함수 $f(x)$ 기대치를 높이는 것이 목표이므로

$\nabla_\theta{E_x[f(x)]}$

처럼 기대치 $E$의 $\theta$에 대한 구배를 계산한다. 즉, 구배를 계산하여 갱신하면 $\theta$ 값을 바꿀 수 있다. $\theta$를 통해 $p$가 바뀌게 되고 여기서 샘플링되는 $action$이 바뀌게 된다. 위 식은 약간의 계산 절차를 통해

$E_x{[f(x){\nabla_\theta}\log{p(x)}]}$

가 되고, 이 값은 샘플링된 모든 $x$에 대해, 보상함수 $f(x)$와 ${\nabla_\theta}\log{p(x)}$의 곱에 대한 평균이다.




[from Karphaty's blog]

간단한 2차원 Gaussian $p(x)$로 위 수식에 따른 샘플들과 그 보상값이 분포를 어떻게 바꾸는지 확인해 보자.
$\log{p(x)}$에 대한 분포 파라메터(여기서는 평균값 $m$, 따라서 $p(x;\ m)$이다)에 대해 도함수를 계산하면

${\nabla_\theta}\log{p(x)}$ = $c_1(x-m)$

이다. 즉, 평균점 $m$에서 샘플 점 $x$를 향하는 벡터가 된다. 첫번째 그림에서 파란색 점은 샘플점들을 나타내고 화살표는 그 방향을 보여준다.

두번째 그림에서 샘플들 위치에서 얻어진 보상함수 값을 표현한다. 특정 샘플은 +1의 보상치(녹색)를 가지고 나머지는 -1 보상치(주황색)를 가진다.
보상치와 벡터들을 곱하고 평균을 내면 분포 파라메터(여기서는 mean 위치 $m$)가 움직여야 하는 방향이 계산되고, 왼쪽 아래 방향이 나오게 된다.

계산된 방향에 따라 분포(평균 위치)를 조정하면 세번째 그림이 되고, 이제 새로운 분포에서 샘플링된 점들은 보상치가 +1이 될 가능성이 더욱 높아지게 된다.



실제 적용 예OpenAI의 pong게임을 이용한 것으로 초기에는 컴퓨터가 주로 이기나, 학습이 진행될수록 agent가 이기는 확률이 높아진다.




(각주 1)

$\bullet$ $p(x;\theta)$: 입력 $x$와 결합된 파라메터 $\theta$의 조합으로 값 $p$가 결정된다는 의미이고 $p$는 확률 분포(비슷한 내용으로 여기 참고)이다.  즉, $p$는 agent action을 만들어 내는 policy를 나타낸다. agent가 선택하는 action은 확률분포 $p$에서 샘플링을 통해서 생성된다.

예를 들어 $p$가 어떤 입력에 대해 action분포를 만들어 내는 CNN으로 구성된 policy network이라면, 이미지 $I$가 입력 되었을 때 action에 대한 분포인 $p(a|I;\theta)$가 되고, $\theta$는 넷 내부 weights 등 파라메터가 된다.

$p(x)$는 $p(a)$이고, 분포 $p(a)$를 바꾸려면 이미지 입력에 의해 만들어지는 $p(a)$에 관여하는 파라메터 $\theta$를 바꾸어야 한다.


$\bullet$ $f(x)$: 함수 $f$ 인자인 $x$는 $p$상에서 sampling되며 선택된 샘플(action)이 만들어 내는 보상 함수(scalar값을 가짐)이다. 선택된 action으로 끝까지 게임을 진행했을 때 win, fail에 대한 보상치이다.





References
[1] Mastering the game of Go with deep neural networks and tree search, Nature, 2016.
[2] http://karpathy.github.io/2016/05/31/rl/
[3] 한정수, 정책기울기 값 강화학습을 이용한 적응적 QoS라우팅 기법연구, 컴퓨터정보학회, 2011.

[4] What's right way of implementing policy gradient?





2016년 5월 31일 화요일

github 사용법

글올리기, 간편 안내
funmv

git init # 내 컴퓨터의 파일이 있는 특정 폴더로 가서 실행
git add pg_pong.ipynb # 로드할 파일 지정
git commit -m "policy gradients example"
git remote add origin https://github.com/funmv/RL.git # 먼저 git에 repository(폴더)를 만들어 놓아야 함

git push -u origin master # 여기서 id, pw를 필요로 함

그 외 명령: git clean -f 

2016년 5월 20일 금요일

(python) decoration, thread & yield

작성 중...

1. decoration pattern, @ 사용.
호출부에서 read_batches(50) 시,

read_batches = mpgen(read_batches(50))

처럼 원 함수의 기능 확장.


2. python에서는 GIL문제로 thread 대신에 multiprocessing 사용.
mpgen을 통해 주 프로세스와는 별도의 데이터 생성 프로세스가 시작
Queue는 thread에서 데이터 공유에 사용(아래, 최대 3개까지의 item 저장 가능)


3. yield
함수의 형태를 가지는 iterator (generator, 생성기라고 부름)를 만들어 줌.
iterator란?
c = iter(range(5))
c.next(), c.next(),... # 0,1,2,...

함수의 인자를 비휘발성으로 만듬
함수 재호출 시, yield 다음이 수행
return은 결과값 반환, yield는 iterator 반환


4. functools.wraps:
디버깅 시 func.__doc__ 또는 func.__name__ 등의 속성을 요청 시
원 함수 read_batches의 속성이 안나오고 decoration된 mpgen함수의 속성이 나오는 것을 방지.
함수 속성을 인자인 원 함수 f로 되돌리는 역할.
데코레이터에서 closure문제 해결을 위해 사용.



def mpgen(f):
    def main(q, args, kwargs):
        try:
            for item in f(*args, **kwargs):
                q.put(item)
        finally:
            q.close()

    @functools.wraps(f) 
    def wrapped(*args, **kwargs): #*args(리스트 받고), **kwargs(map 받음)
        q = multiprocessing.Queue(3)
        proc = multiprocessing.Process(target=main, args=(q, args, kwargs))
        proc.start()
        try:
            while True:
                item = q.get()
                yield item
        finally:
            proc.terminate()
            proc.join()

    return wrapped
     

@mpgen # mpgen의 인자함수로 read_batches을 사용함을 지정
def read_batches(batch_size):
    def gen_vecs():
        for im, c, p in gen.generate_ims(batch_size):
            yield im, code_to_vec(p, c)

    while True:
        yield unzip(gen_vecs()) # yield는 휘발성이 없는 함수(iterator 만듬)


2016년 5월 16일 월요일

(python) debugger

import ipdb 에서 빠져나올 때는 cntl+z
import pdb
pdb.set_trace()

명령법


(python) video read and write

opencv의 cv와 cv2의 차이
cv2 내에 cv있음. cv2가 최신.
import cv2.cv as cv

python 에서 버전 확인
import cv2
cv2.__version__

video 읽기
installed\opencv\3rdparty\ffmpeg\opencv_ffmpeg_64.dll 필요
이것을 작업 폴더에 복사해서 이름을 opencv_ffmpeg249_64.dll로 바꿈


테스트
import cv2
cap = cv2.VideoCapture('tmp1.mp4')
cap.grab() # true로 나와야 함


(Ref)
1. cv & cv2
2. about video working
3. opencv version 

2016년 4월 30일 토요일

(python) tips

import sys
sys.path
sys.path.append('c:\\python\\pathtest')
sys.path.remove('c:\\python\\pathtest')

set PYTHONPATH=c:\python
>>map(lambda apath: apath.find('pathtest'), sys.path)
[-1, -1, -1, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]

import numpy as np
dir(), dir(np)

import pdb
pdb.set_trace()
n(step next), s(step in), run
print var

(package 작성 예)
path 연결
import sys
sys.path.append('c:\\python')
(또는 set PYTHONPATH=c:\....)

python 실행 후 path 확인하기 위해
import sys
map(lambda ap: ap.find('pathtest'), sys.path)

사용하기 위해
from pathtest.keras.imgproc import misc as mymisc

가능한 명령확인 위해
dir(mymisc)


[출처]
1. python modules
2. Jump to python - 패키지
3. python debugger- pdb


Keyboard shortcuts

[Mac]

cmd, w                     (현재 윈도 또는 탭 닫기)
cmd, t                      (현재 윈도의 새로운 탭 열기, 또는 아무 것도 없으면 새로운 파일 메니저)
cmd, [ 또는 ]            (브라우저 경로 되돌리기)
cntl, -> or <-           (여러 창을 우회하기)
cmd, cntl, F              (Full Window)
cmd, opt, <- or ->   (탭을 우회하기)

cmd, space              (새 spotlight 오픈, 파일 찾을 때)
alt, space                 (영문 한글 토글)

with iSnap
opt, -> or <- or ...



[Chrome]

cmd, n                     새로운 크롬 시작
cmd, t                      새로운 탭 시작
cmd, w                     탭 종료
cmd, shift, n            시크릿 모드 시작

cmd, L                     주소창 가기
cmd, alt, ->             탭 이동
cmd, alt, i                개발자 도구 열기

cntl, Enter               주소에 .com 추가하여 열기

Alt, <-, ->               이전 페이지로 가기, 다시 오기





[WIndows]

windows + left, right, up, down
windows + Tab

windows + cntl + D, create
windows + cntl + F4, close
windows + cntl + left/right

cntl + c/v/a



[출처]
[1] 크롬단축키,  chrome 단축키
[2] 윈도 단축키

2016년 3월 30일 수요일

(가상환경) Anaconda commands

conda -V
conda info --envs
conda update conda
conda create -n yourenvname python=2.7 anaconda
source activate yourenvname #windows에서는 source 생략
deactivate
conda remove -n yourenvname --all

conda info -e
conda install -n yourenvname [package]

windows에서 새로운 가상환경을 생성 때는 가상환경 생성 후, 그 환경 내에서도 mingw, libpython 설치 필요.

For ubuntu,
source bin/activate ~/anaconda2/
conda info --envs
...
source bin/activate /home/user/anaconda2/envs/keras1.0.1

theano/keras 실행 시는
THEANO_FLAGS=floatX=float32,device=gpu python

bash shell prompt 축약
PS1='\u:\W\$ '


(Ref.)
1. http://uoa-eresearch.github.io/eresearch-cookbook/recipe/2014/11/20/conda/
2. http://antilibrary.org/m/post/766
3. http://askubuntu.com/questions/145618/how-can-i-shorten-my-command-line-bash-prompt

2016년 3월 16일 수요일

(Windows) keras 설치

Backend를 Theano로 사용하므로 아래 설명은 theano설치도 포함한다.

먼저, cuda(v7.5), vs2013, git설치
git은 설치 중 옵션에서 "Run Git from the WIndows command prompt" 선택

TDM GCC x64 설치
Anaconda x64 설치

cmd 창을 관리자 모드로 연다(방법은 아래).
(or open Anaconda prompt)
conda update conda
conda update --all
conda install mingw libpython

Install latest version of Theano
git clone git://github.com/Theano/Theano.git
(or pip install git+git://github.com/Theano/Theano.git)
cd Theano
python setup.py develop

Install keras
git clone https://github.com/fchollet/keras
(pip install keras)
cd keras
python setup.py develop

Test
cd examples
ipython mnist_mlp.py


제어판->시스템->고급시스템설정->환경변수->사용자변수에 가서
PATH 변수에 cuda의 nvcc가 있는 bin폴더 추가
THEANO_FLAGS 변수 만들고 다음 사항 추가
"floatX=float32,device=gpu,nvcc.fastmath=True"


cmd 창을 관리자 모드로 여는법
시작->프로그램 및 파일검색
cmd 입력
리스트에 나타난 cmd를 클릭해서 “관리자모드로 시작”.


설치를 확인하는 법
cmd창에서 
where cl
where gcc
where nvcc
where g++


cuDNN을 같이 설치하면 학습 속도가 더욱 빨라진다. 
nvidia에서 cuDNN 4.0을 다운 받아 압축을 풀면 bin, include, lib의 3개의 폴더가 있다. 
내부의 파일들을   
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.5
아래의 해당 위치에 옮겨주면 된다.



출처:
1. Setup a Deep Learning Environment on Windows (Theano & Keras with GPU Enabled)
2. How to install Keras and Theano in Anaconda Python 2.7 in Windows
3. FunMV
4. Installing Keras, Theano and Dependencies on Windows 10












2016년 3월 2일 수요일

tflearn 설치

Mac의 anaconda 가상환경 아래에 tflearn을 설치한다. 

을 참고해서 먼저 tensorflow를 설치후, "pip install tflearn"으로 설치 하였으나, 

titanic 예제를 실행해 보니 포함되지 않은 lib가 많아 

git에 들어가서 소스를 다운 받은 후에 

python setup.py install

명령으로 설치하였다. 




2016년 3월 1일 화요일

keras test

# 레이어 중간 값을 확인할 수 있는 방법
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Convolution2D
from keras.layers.normalization import BatchNormalization
from keras import backend as K
from keras.layers import Input
from keras.datasets import mnist, cifar10

(X_train, y_train), (X_test, y_test) = cifar10.load_data()
X_train = X_train.reshape(X_train.shape[0], 3, 32, 32).astype('float32')
X_train = (X_train - np.mean(X_train))/np.std(X_train)

inputs = Input(shape=(3,32,32))
bn1 = BatchNormalization(axis=1)(inputs)
act1 = Activation('relu')(bn1)
conv1 = Convolution2D(32, 3, 3, border_mode='same')(act1)
func1 = K.function([inputs], [conv1]) #conv1대신 act1 등 입력가능
val1 = func1([X_train[0:1]])[0]  # [0]을 붙인 것은 val1이 list로 나오기 때문



# test용 입력을 만드는 방법
inp = np.random.randn(2,3,32,32)
rez = model.predict(inp[0:1])
rez.shape


# layers의 shape 출력
model.summay()




(Ref.)
[1] Keras FAQ.

2016년 2월 19일 금요일

가상환경 아래 패키지 설치 경로

Mac에서 Anaconda 설치 후에 가상 환경을 생성하고 여러 패키지들을 설치할 경우의 경로:

예를 들어 가상환경 tflearn 만들면 아래 경로가 생김.
home_directory/anaconda/envs/tflearn


만일 가상환경인 tflearn으로 들어와서 tensorflow 패키지를 설치한다면 아래 경로
home_directory/anaconda/envs/tflearn/lib/python2.7/site-packages/tensorflow
로 설치된다.


특정 폴더 아래에서 파일을 찾을 때는 그 위치로 가서 아래 명령 입력.
find . -name "tflearn" or "tflea*" 




2016년 2월 1일 월요일

(우분투 리눅스에서 파이썬) keras 코드 분석 예

파이썬에서 실행되는 DNN 툴 중에 keras 라는 것이 있습니다. keras 코드를 통해 python 명령 실행과 패키지 설치 폴더 구조와의 관계에 대해 분석해 봅시다.

keras 샘플 코드 중에 cifar10_cnn.py 라는 파일이 있는데 서로 다른 물체 10가지를 convolution net으로 분류해 내는 예제를 보여주는 코드입니다.
이 코드를 보면 헤드부에 아래와 같은 명령이 있습니다.

...
from keras.datasets import cifar10
...
# the data, shuffled and split between train and test sets
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
...


이 명령을 Ubuntu 리눅스의 경우에 대해 살펴 봅시다.

keras에서 cifar10을 학습하려면 먼저 cifar10의 database 파일을 다운받아야 합니다. 이를 위해 상기한 바와 같이 db 다운에 필요한 lib를 import 합니다.


그런데, 처음 keras를 설치할 때,

keras의 설치 위치는 미리 설정된 어떤 디폴트 설치 위치 아래에서의 keras이고 그 아래에 필요한 lib들이 설치 됩니다. 설정된 이 위치는
/usr/local/lib/python2.7/dist-packages입니다.

여기서 dist-는 배포(distribution) 패키지의 의미로 이 폴더 아래에 들어가 보면
python과 관련하여 그동안 설치한 다양한 패키지(numpy, pandas, Theano, sklearn, ...) 들의 폴더가 있습니다.
따라서 keras의 설치 위치도 여기이며
/usr/local/lib/python2.7/dist-packages/keras 처럼 됩니다.

이 위치를 찾아 keras 폴더에 들어가면 다시 datasets라는 폴더가 있고(즉, 위 코드에서 from keras.datasets 임) 다시 그 밑에 cifar10.py 파일(import cifar10 임)이 있습니다.


다음은 cifar10.py 코드입니다
==========================
from __future__ import absolute_import
from .cifar import load_batch
from .data_utils import get_file
import numpy as np
import os


def load_data():
    dirname = "cifar-10-batches-py"
    origin = "http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz"
    path = get_file(dirname, origin=origin, untar=True)

    nb_train_samples = 50000

    X_train = np.zeros((nb_train_samples, 3, 32, 32), dtype="uint8")
    y_train = np.zeros((nb_train_samples,), dtype="uint8")

    for i in range(1, 6):
        fpath = os.path.join(path, 'data_batch_' + str(i))
        data, labels = load_batch(fpath)
        X_train[(i-1)*10000:i*10000, :, :, :] = data
        y_train[(i-1)*10000:i*10000] = labels

    fpath = os.path.join(path, 'test_batch')
    X_test, y_test = load_batch(fpath)

    y_train = np.reshape(y_train, (len(y_train), 1))
    y_test = np.reshape(y_test, (len(y_test), 1))

    return (X_train, y_train), (X_test, y_test)
============================


위 코드의 앞 부분을 살펴보면 web상의 origin 주소에 있는 db 파일에 접근해서 data file을 다운하는 부분이 있습니다. python을 실행하고 한라인씩 입력하여 수행해 보면

파인썬 명령 쉘에서

>>dirname = "cifar-10-batches-py"
>>origin = "http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz"

를 입력 후, 다음으로 get_file 함수를 실행해야 하는데, 이 파일은 python의 기본 함수가 아닙니다.
함수를 찾아 보면 keras/datasets에 있는 data_utils.py코드 내에 있습니다. 따라서 이 함수를 사용하기 위해

>>from keras.datasets import data_utils

하면 됩니다.  data_utils를 import하였으므로

>>path = data_utils.get_file(dirname, origin=origin, untar=True)

처럼 입력하고, path를 출력해 보면

>>path
'/home/vis/.keras/datasets/cifar-10-batches-py'

입니다. 즉, 내 계정인 vis 아래에 .keras 폴더 아래에 다운받을 db파일이 저장 된다는 것을 알 수 있습니다.
따라서 cifar10_cnn.py파일의 앞 부분의 다운로드 부분을 실행해 본 후에 path가 가리키는 위치에 가보면


vis@vis-VirtualBox:~/.keras/datasets$ ls -la
합계 198956
drwxrwxr-x 3 vis vis      4096  2월  1 11:37 .
drwxrwxr-x 3 vis vis      4096  1월 27 11:43 ..
drwxr-xr-x 2 vis vis      4096  6월  5  2009 cifar-10-batches-py
-rw-rw-r-- 1 vis vis 170498071  2월  1 11:37 cifar-10-batches-py.tar.gz


와 같이 database파일이 다운되어 있는 것을 볼 수 있습니다.









2016년 1월 31일 일요일

Angular 2

0_Angular 2 소개


5 스타트




  1. app/app.component.ts
——————————————————
// 모든 앱은 적어도 하나의 root 컴퍼넌트를 가져야 한다.
// 이름이 보통 AppComponent 불리고, 클라이언트의 사용자 경험을
// 담당한다. 화면 일부를 제어하는 역할을 한다
// Component Angular 가장 기본적인 블럭 요소이다

import { Component } from '@angular/core';

// Component 데코레이션 함수이며 인자로 메타데이터 {..} 가짐
// —> 함수를 컴퍼넌트 클래스에 적용 
// 메타데이터는 angular 컴퍼넌트를 어떻게 만들고 사용 할지를 알려 준다.
@Component({    
  selector: 'my-app',
  template: '<h1>My First Angular 2 App</h1>'
})
// (1) selector: html에서 my-app 만나면 위치에서 AppComponent 
//      객체를 만들고 화면 출력함
// (2) template: html 컴퍼넌트의 데이터를 바인딩하거나 
//      다른 컴퍼넌트를 연결함

export class AppComponent { }
// 다른 곳에서 컴퍼넌트를 import 있도록 속성과 로직을 내보냄 





         2. app/app.module.ts
——————————————————
// 우리가 만든 앱과 기본 앵귤러 앱과의 연관성을 보여 준다
// Angular 앱은 앵귤러 모듈들과 상호 인접하게 연관된 기능들로 분해 가능하다.
// 앱은 적어도 하나의 모듈이 있어야 하며, 이것은 root 모듈이며
// AppModule 불린다
// AppComponent import해서 declarations, bootstrap 적용한다
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent }  from './app.component';

@NgModule({
  imports:      [ BrowserModule ],  
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
// 브라우저 내에서 앱을 실행시키기 위해 필요하다. 비슷한 것들은
// FormsModule, RouteModule, HttpModule 등이 있다.

export class AppModule { }






         3. app/main.ts
——————————————————
모듈을 로드한다고 앵귤러에게 알려야 .
브라우저에서 앱을 시작할 있거나 모바일에서 시작할 수도 있다.
이런 선택의 설정이 가능하다


import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);
// 여기에서는 브라우저에서 bootstrap했지만
// 다른 bootstrapper 함께 다중 환경에서 AppModule 시작할수도 있다
// 예를 들면, mobile device에서는 Apache Cordova NativeScript 
// 로드할 수도 있다








         4. index.html
——————————————————
html 내에서 여러가지 다양한 패키지들을 사용해도 runtime에서 손실이 없다
패키지들은 요구될 로딩되기 떄문이다

앵귤러의 실행 순서를 보면 다음과 같다.

main.ts bootstrapModule 함수를 호출 —>
AppModule 메타 데이터를 읽음 —>
AppComponent 시작 컴퍼넌트임을 인지 —>
my-app selector 발견 —>
index.html내에 my-app태그 위치를 찾음


<!DOCTYPE html>
<html>
  <head>
    <title>Angular 2 QuickStart</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">

    <!-- 1. Load libraries -->
     <!-- Polyfill(s) for older browsers -->
    <script src="https://npmcdn.com/core-js/client/shim.min.js"></script>
    // core-js: ES2015(ES6)

    <script src="https://npmcdn.com/zone.js@0.6.12?main=browser"></script>
    <script src="https://npmcdn.com/reflect-metadata@0.1.3"></script>
    <script src="https://npmcdn.com/systemjs@0.19.27/dist/system.src.js"></script>

    <!-- 2. Configure SystemJS -->
    <script src="systemjs.config.js"></script>
    <script>
      System.import('app').catch(function(err){ console.error(err); });
    </script>
  </head>


  <!-- 3. Display the application -->
  <body>
    <my-app>Loading...</my-app>
// my-app태그는 AppComponent selector 설정되어 있었다
// 태그 사이에서 어플리케이션 뷰를 rendering한다.

  </body>
</html>




,

앱을 실행시키는 명령은 
npm start 
인데

ts js 번역하는 , server 실행하는 일을 한다.


실행 중에도 내용 변화가 있으면 실시간 반영됨(watch mode)


lib 업데이트는 package.json 주로 바꾸고,
index.html에서 css, lib 추가한다








2016년 1월 29일 금요일

Django 프레임웍

1. Frameworks


(1) html(template) 내에서 form을 통해 입력 event 발생(설정이 필요한 변수도 함께 생성)
(2) javascript로 된 event 처리 함수가 호출(form 변수들은 태그(#~) 대입 형태로 접근)
(3) event 함수 내에서 특정 url 호출
(4) urls.py에 있는 url과 views 함수 사이의 매핑에 따라 연결된 views 함수 호출
(5) views 함수에서 html(template)과 dict를 결합시켜 render할 객체 생성
 -views 함수에서 html에서 필요한 url이나 필요 변수를 dict로 만들고 이를 html로 보내서 사용함
 -만일 page를 전환 한다면(1.html에서 2.html로), view함수에서 dict를 만든 후, 이를 html과 결합할 때 1.html 대신에 2.html과 결합시켜 render 객체 생성.
(6) render 객체(HttpResponse)를 client로 리턴



2. Control flow




(1) html 내의 form은 file을 선택해 주는 file event, 웹 화면상의 객체를 선택해 주는 event 등이 다양하게 발생한다. 또 따로 설정이 필요한 변수들도 발생시킬 수 있다.
(2) event가 발생 시는 처리함수인 javascript함수를 호출하고, 호출된 함수에서는 html의 form이나 특정 id에 #(태그)로 접근하여 선택하고 설정해 준다.
(3) 그리고 폼을 django의 view 함수로 넘긴다. view 함수에서는 넘어온 form으로부터 필요한 image 소스나 data에 접근하여 필요한 가공(가공함수 호출)을 해 준 후에 이 결과를 다시 html로 넘겨준다. 이 때 dict 형태로 데이터를 넘겨준다.
(4) html은 넘어온 dict로 부터 정보를 받아 html을 완성하고 render를 실행하여 HttpResponse객체를 생성한다.


-모든 image(문서)들은 업로드 후에 url이 있는(저장 경로 있음) 위치에 저장. 또는 처음부터 url를 가지고(저장 경로를 가지는) 있다.
-데이터 가공, 처리(함수 실행에 의한)는 이 url를 통해 선택된 이미지를 입력으로 한다.




2016년 1월 23일 토요일

Django 요약

예제로 배우는 python 프로그래밍 (Django 기초: http://pythonstudy.xyz/Python/Django)

Django 소개
-----------
Django는 웹어플프레임웍(web app framework)의 하나이다. 파이썬으로 개발되었고 오픈소스이다.

가상 환경 구축
----------------
Django 설치
-----------
>pip install django
>pip install django=1.8 #특정버전 지정

Django 프로젝트 생성과 실행
---------------
>django-admin startproject myweb #새 프로젝 만듬
>python manage.py runserver #서버 실행
서버실행 시 127.0.0.1:8000 또는 8080에 접속.

Django App
----------
프로젝 하에 위치하며, 하나의 프로젝은 여러개 App을 포함할 수 있다. 잘 모듈화된 App은 여러 프로젝에서 재 사용 가능.
>manage.py startapp home # home이라는 새 App생성

views.py는 html 웹을 호출하는 역할을 한다.
간단하게 화면에 글자를 출력해 보자.

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def index(request):
    return HttpResponse("Hello, World!")

01.settings.py: INSTALLED_APPS 리스트에 App 추가
02.urls.py: urlpatterns 리스트에 사용할 URL 패턴 추가. 또 ^는 시작, $는 끝이므로 빈 문자열, 즉, 루트를 가리킴.


Django 뷰
---------
보통 GUI는 MVC framework인데 여기서는 MTV이다. (Model,View, Controller) == (Model, Templates, View)
장고 뷰는 HTTP Request를 받아, HTTP Response를 리턴.
Request에는 (문서) Model 데이터가 들어 있으며, Response에서는 Template html을 생성하거나 호출.


Django 템플릿
-------------
View에서 이쪽으로 전달된 데이터를 받아, 동적인 웹페이지를 만든다.
App폴더 아래에 templates 폴더 만들고 그아래 html을 위치.
여러개의 App이 한 프로젝 아래에 있는 경우에는

"App폴더/templates/App명/템플릿파일"

로 한다. 복수의 App들이 동일 이름 템플릿을 가진 경우에 대비: 템플릿을 찾을 때, 자신 App아래 템플릿을 먼저 찾는 것이 아니라, 전체 App들 템플릿 폴더들을 처음부터 순서대로 찾는다.

from django.shortcuts import render

def index(request):
    msg = 'My Message'
    return render(request, 'index.html', {'message': msg})

render함수는 index.html을 호출하며, 세번째 파라메터는 dict형태로 넘겨줌.

(템플릿 언어)
.변수: {{ }}로 둘러싸이면 변수 값이 이 위치에 치환.
.템플릿 태그: {%...%}. if, for와 같은 python명령이 내부에 온다.
{% if count > 0 %}
    Data Count = {{ count }}
{% else %}
    No Data
{% endif %}

{% for item in dataList %}
  <li>{{ item.name }}</li>
{% endfor %}

{% csrf_token %} # 해킹 공격에 대응

.템플릿 필터: 변수값을 특정 포맷으로 변형.
날짜 포맷 지정
{{ createDate|date:"Y-m-d" }}

소문자로 변경
{{ lastName|lower }}

.템플릿에서 주석
싱글 라인: {#...#}
여러 라인: {% comment %} ... {% endcomment %}



Django 모델
-----------
필드 타입: CharField, TextField, FileField, ...
ImageField(FileField의 파생클래스로 이미지 파일인지 체크)

  필드 옵션      설명
.null (Field.null): Empty 값을 DB에 NULL로 저장. DB에 Null 허용.
                    예: models.IntegerField(null=True)
.blank (Field.blank): blank=False(Required 필드). blank=True(Optional 필드).
                   예: models.DateTimeField(blank=True)
.primary_key(Field.primary_key): 해당 필드가 Primary Key.
            예: models.CharField(max_length=10, primary_key=True)
.unique (Field.unique): 해당 필드가 테이블에서 Unique함 표시. 해당 컬럼에 대해 Unique Index를 생성.
             예: models.IntegerField(unique=True)
.default (Field.default): 필드 디폴트값을 지정.
            예: models.CharField(max_length=2, default="WA")
.db_column (Field.db_column): 컬럼명은 디폴트로 필드명을 사용하는데, 만약 다르게 쓸 경우 지정한다.



DB 설정과 Migration
-------------------
Model클래스 생성 후, 해당 모델 테이블(틀)을 DB에 생성 가능.
> manage.py makemigrations # migration을 준비하는 과정. 스키마 생성 또는 수정. App내에 migrations서브폴더 생성.
> manage.py migrate # migration을 DB에 적용하는 과정
migrate후에 생기는 파일 명: App명_ModelClass명

DB 관리 쉘
> manage.py dbshell #테이블, 컬럼정보, 테이블 내용 확인 가능
sqlite> .tables #테이블 리스트 출력
sqlite> PRAGMA table_info(리스트중하나) # 테이블 컬럼정보
sqlite> select * from 리스트중하나 # (이미 입력 저장된) 테이블 데이터



Django 모델 API
---------------
일단 모델 클래스가 정의되면 장고는 데이터추가, 갱신에 관련된 다양한 API를 제공

(INSERT)
from feedback.models import *  # feedback(App명)/models.py
from datetime import datetime

# Feedback 객체 생성
fb = Feedback(name = 'Kim', email = 'kim@test.com', comment='Hi', createDate=datetime.now())

# 새 객체 INSERT
fb.save()

(SELECT)
장고는 모델 클래스에 objects라는 관리 객체를 자동 추가해 줌. 이를 통해 여러 제어 가능.
"모델클래스명.objects"로 사용함.
all(): 테이블 데이터 전부 가져옴
for f in Feedback.objects.all():
    s += str(f.id) + ' : ' + f.name + '\n'

get(): 하나의 row만 가져옴. pk(primary key)를 사용.
row = Feedback.objects.get(pk=1)
print(row.name)

filter(): 특정조건에 맞는 row가져옴
rows = Feedback.objects.filter(name='Kim')

exclude(): 특정 조건을 제외한 나머지 row가져옴
rows = Feedback.objects.exclude(name='Kim')

count(): 데이터 갯수
n = Feedback.objects.count()

order_by(): 키를 따라 정렬. -는 내림차순.
rows = Feedback.objects.order_by('id', '-createData') #id를 기준으로 올림차순, createData를 기준으로 내림차순 정렬

distinct(): 중복 시 하나만 표시.
rows = Feedback.objects.distinct('name')

first(): 처음 row만 리턴.
rows = Feedback.objects.order_by('name').first() #정렬 후 첫 요소 리턴

last(): 마지막 row 리턴
rows = Feedback.objects.order_by('name').last()

체인연결 가능
row = Feedback.objects.filter(name='Kim').order_by('-id').first()


(UPDATE)
수정할 객체 얻고 변경 필드 수정. 다시 저장.
fb = Feedback.objects.get(pk=1)
fb.name = 'Park'
fb.save()

(DELETE)
대상 row얻은 후 delete호출
fb = Feedback.objects.get(pk=2)
fb.delete()



URL 매핑
--------
어떤 프로젝 아래에 App이 여러개일 때, proj 아래 urls.py 파일에 각 App의 urls.py를 매핑하면 편리.

myWeb/urls.py
urlpatterns = [
   ...
   url(r'^feedback/', include('feedback.urls')), #'feedback/': App별 기준 url위치.
   url(r'^home/', include('home.urls')),
]

# home/urls.py
from django.conf.urls import url
from home import views

urlpatterns = [
    url(r'^contact', views.contact), #url: /home/contact, 함수:home.views.contact
    url(r'^about', views.about),
]

# feedback/urls.py
from django.conf.urls import url
from feedback import views

urlpatterns = [
    url(r'^list', views.list), #url: /feedback/list, 함수:feedback.views.list
    url(r'^add', views.add),
    url(r'^update', views.update),
]


RegEx사용. r'정규표현식'형식이고, 앞에 r(raw) prepix붙임. ^로 시작.

(..): Capture 표현. 일부 문자열 추출.

url(r'^blogs/([0-9]{4})/([0-9]{2})/$$', views.blogs_month)  #4개/2개 추출
만약 입력 URL이 "/blogs/2015/12" 이면, 이 URL은 views.blogs_month(request, '2015', '12') 과 같이 함수를 호출

Named Group:  (?P<그룹이름>pattern). 캡춰한 것에 이름붙여 전달.
url(r'^blogs/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.blogs_month)
입력 URL이 "/blogs/2015/12" 이면, 이 URL은 views.blogs_month(request, year='2015', month='12') 과 같이 함수를 호출


템플릿 확장
-----------
아래 두 파일 경우, 일단 base.html이라는 파일을 생성하고, 이 내부에서 block위치를 찾는다. 그리고, 그 위치에 index.html에 있는
<h1>{{message}}</h1>
을 치환한다.


(base.html)
<!DOCTYPE html>
<html lang="en">
<head>
     ...
</head>
<body>
     ....
     {% block content %}   # 삭제 후 index.html에 있는
     {% endblock content %} # <h1>{{message}}</h1> 부분 대입

</body>
</html>


(index.html)
{% extends "base.html" %} #첫 라인에 base.html 추가

{% block content %}
    <h1>{{message}}</h1>
{% endblock content %}



Django 폼(form)
---------------
모델 클래스로부터 폼을 자동으로 생성하는 기능.

from django.forms import ModelForm
from .models import Feedback

class FeedbackForm(ModelForm):
    class Meta:
        model = Feedback
        fields = ['id', 'name','email','comment'] #모델 필드중 일부만 폼에서 사용.



이렇게 정의 후, 뷰에서 이 폼을 사용한다.

from django.shortcuts import render, redirect
from .models import *
from .forms import FeedbackForm

def create(request):
    if request.method=='POST': # 뭐가 전달되는지 모르지만 어떤 객체가 전달된 경우를 표현
        form = FeedbackForm(request.POST) #사용자가 입력한 것을 인자로 넘겨줘서 폼 생성.
        if form.is_valid():
            form.save()
        return redirect('/feedback/list') #urls.py의 urlpatterns을 통해 view함수 호출.
    else:
        form = FeedbackForm()

    return render(request, 'feedback.html', {'form': form}) #세번째 인자는 dict()

위 코드는
. 데이터를 입력받을 폼을 보여주는 부분
. 사용자가 데이터 입력하여 저장 버턴 클릭 시, 이를 DB에 저장하는 부분.
. view에서 html로 form을 전달하였다. 그래서, 아래 html에서 이를 랜드링.

{% extends "base.html" %}
{% block content %}
    <p>
        <a href="{% url 'list' %}">Goto Feedback List</a>
    </p>

    <div>
        <form method="POST"> # 뷰에서 form을 넘겨주었었다.
            {% csrf_token %}
            {{ form.as_p }} #p태그(paragraph), 즉 새 문단으로 form 연다.
            <button type="submit">저장</button>
        </form>
   </div>
{% endblock content %}



Static 파일
-----------
장고홈(settings.py 내 BASE_DIR) 아래에 static 폴더를 만들어 js, css, image 등 웹에서 사용하는 파일 저장:
STATIC_URL = '/static/' #웹에서 주소로 살펴볼 때
STATICFILES_DIRS=[os.path.join(BASE_DIR, 'static'),]

.html에서 static 파일 사용 시는 템플릿 상단에
{% load staticfiles%}
를 명시하고, 실제 static file을 가리키기 위해서는 link태그로 지정.
{% static 'bootstrap/css/bootstrap.min.css' %}

.배포(deploy) 시에는 각 App의 static 폴더 아래 파일을 그대로 복사하므로 이름 충돌을 피하기 위해 다음 처럼 한다:
 -App명/static/App명 #각 App하의 static 폴더명 지정 시.
 -settings.py에 다음 지정.
  STATIC_ROOT = '/var/www/myweb_static' #배포용 web 경로하의 static 폴더.

  STATICFILES_FINDERS = (
     'django.contrib.staticfiles.finders.FileSystemFinder',
     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
  )


.collectstatic
배포 시 흩어져 있는 static 파일 들을 모아 특정 폴더로 옮기는데, 이 때,
'manage.py collectstatic' 실행.


샘플 Feedback App
-----------
Site Deployment (Nginx)
-----------
Site Deployment (Apache)
-----------
Django 디버깅


[참고]
1. Django 기초.











2016년 1월 22일 금요일

django

$\underline{DJango\ short\ Tutorial}$

django-admin startproject tutorial #프로젝트를 만듬(이름이 tutorial)
tree
cd tutorial
./manage.py startapp community #프로젝트 앱을 만듬(app명은 comunity)
                                                       
하나의 project내에 여러개의 앱이 있는 구조이다 

./manage.py migrate # db 생성
./manage.py createsupperuser # db 관리할 계정 생성

./manage.py runserver #서버 들어가서 접속해 본다
#접속 주소 밑에 …/admin 치고 들어가서 계정정보를 넣으면 관리자 계정으로 여러 정보를 보는 것이 가능



tutorial(project)아래의 settings.py 가서 방금 생성한
app community 등록해 주어야 한다.

INSTALLED_APPS = [
    'django.contrib.staticfiles',
    'community',
]



(1) 저장할 데이터의 형태(필드) 생성


app community models.py 가서 db 저장될 데이터의 형태에 대한 정의를 주어야 한다
데이터 필드를 가진 클래스를 models에서 상속받아 작성해 준다.

class Article(models.Model):
     name = models.CharField(max_length=50)
     title = models.CharField(max_length=50)
     contents = models.TextField()
     email = models.EmailField()
     cdate = models.DateTimeField(auto_now_add=True)

새로 생성한 app comunity 관련된 db 생성해 주어야 한다
./manage.py make migrations community


community model 생성한 데이터를 반영하기 위해 db 변화가 있는지 체크해서 반영해 준다
./manage.py migrate




(2) 접속 경로 지정과 경로를 통해 호출할 함수 작성


게시판 작성이 목표이므로 사용자가 접근해서 글을 작성할수 있는 페이지가 있어야 한다. 이를 위해 
project urls.py파일에서 write라는 이름으로 접근할 있는 경로를 지정해 준다.
from community.views import *

urlpatterns = [
    …
    url(r'^write/', write, name='write'),
]

url에서 "write"이름의 경로이면 views에서 "write" 함수를 작성한다.  

이제 views.py파일에서 write 함수를 만들어 보자. url명에서 인자가 있다면 request를 통해 넘어간다. 

def write(request):
     return render(request, 'write.html')

views에 있는 write 함수는 화면에 표시할 것을 정의한다. 
여기서는 html template를 이용해서 표시를 수행한다.
따라서 community 아래에 html 파일들을 저장할 templates 폴더를 하나 생성한다(이름을 정확하게 “templates”로 적어야 한다)


views.py의 역할은 urls.py에서 받은 parameters에 맞게 출력할 data를 생성한다. 또, 템플릿을 로드하고 data와 함께 템플릿을 render한다. 




(3) 화면에 표시할 폼과 템플릿을 작성


templates 폴더 아래에 write.html 파일을 하나 만든다.
sublime에서 text 타입을 html로 설정하고 첫줄에 <html.. 라고만 치면 필요한 형식이 자동으로 생성된다.
<body>
hello django!

라고 입력하고 runserver를 다시 실행하고, 
127.0.0.1:8000/write에 접속해 보면 
hello django! 
메시지가 나타난다.




전통적인 방식으로는 write.html에서 입력받는 폼을 복잡하게 구성해야 하나, django에서는 form를 이용하여 간단하게 구성해 줄 수 있다.
community 아래에  forms.py 파일을 만든다. 

from community.models import *
class Form(ModelForm):
     class Meta:
     model = Article
     fields = ['name', 'title', 'contents', 'email', ‘cdate']

db에서 만들었던 필드명을 나열하여 form을 제작한다. 





구성한 폼클래스를 이용하여 폼 객체를 생성해야 하는데, 이것은 views에서 해준다.  또 생성한 form 객체를 html에 전달해 주어야 한다.  

from community.forms import *
def write(request):
     form = Form()
     return render(request, 'write.html', {'form':form})

forms.py의 클래스를 import하고 이를 이용해 객체 form을 생성하고 이를 html에 전달하기 위해 render내에 {…}형식을 사용해 주었다.




(4) 구성된 폼과 템플릿을 화면에 표시


write.html에서 form을 사용하기 위해 p태그를 사용하여 아래와 같이 지정한다.  또 submit 버턴도 추가한다.
<body>
<form action="" method="post">
     {{ form.as_p}}
<button type="submit" class="btn btn-primary">저장</button> 
</form>


이렇게 저장해 놓고 다시 실행해보면 폼 형태를 가진 입력창들이 웹에 표시되게 된다. 
추가로 다양한 외부 공격에 대비하기 위해 {% csrf_token %}와 같은 토컨을 추가한다.
이제 입력 창들에 값들을 입력하면 form이 값들을 받아서 db에 저장하면 되는 것이다.  





form 버턴을 누르면 request를 통해서 POST(또는 GET)가 발생하게 되고 이를 체크해서 필요한 처리를 해준다.  
메세지를 처리해 주기 위해 views.py로 가서 수정해 준다.

def write(request):
     if request.method == 'POST':
          form = Form(request.POST)
          if form.is_valid():
               form.save()
     else:
          form = Form()

     return render(request, 'write.html', {'form':form}) 



여기까지 앱에서 하나의 페이지를 작성하고 데이터를 처리하는 것을 살펴 보았다.  
——————————




이제 작성한 데이터의 리스트를 볼 수 있는 list라는 url을 만들어보자.
위와 똑같이 한다.

project 아래 urls 아래에 다음을 추가한다:
url(r'^list', list, name='list'),



views에 list함수를 만든다.



실행과 테스트

Mac을 기준으로 하면, 먼저 django가 설치된 (아나콘다 등의) 가상 환경에 들어간다.  장고의 프로젝트 폴더로 가서
./manage.py runserver

로 실행할 수 있다. 실행된 곳에 접속하기 위해 브라우저 창에
http://127.0.0.1:8000/admin
http://127.0.0.1:8000/photo/1

등의 프로젝트에 설정된 주소를 입력하여 접속할 수 있다.










2016년 1월 21일 목요일

bootstrap

0_bootstrap case



w3school youtube 한글 강의 자료를 요약하였다
start from scratch, 처음부터 차근차근 시작한다는 의미



Container
bootstrap jquery css 기반하므로 관련 파일들을 html 포함해야 한다.
헤드에 css 파일 추가, 하단에 jquery  bootstrap.js 순서지켜서 추가한다.
<div>..</div> 둘러싸고 속성으로 class=“container” 삽입한다.
<div class=“container”>…</div> 된다.


Jumbotron
Jumbotron 강조를 위한 영역 설정(그레이박스 커진 글씨체로 나타남) 사용.
<div> 속성에 class=“jumbotron” 추가 


Button
버턴을 추가할 (다른 형식도 비슷함) 속성 표시에 같은 단어가 번을 반복해서 나타남.  
class = “btn btn-default”처럼 btn btn-…형태임. 따라서,
<button type=“button” class=“btn btn-default”>  Text </button> 또는
<a href=“#” class=“btn btn-info btn-lg>Search</a> 등으로 링크 연결 버턴에 사용한다.  
btn-default, btn-info, btn-warning,..등의 다양한 버턴이 있고 차이로 용도 표시.
btn-xs, btn-sm, btn-md, btn-lg 등으로 버턴 크기를 설정



Glyphicon, 상형문자
속성 표기에는 위와 비슷하게 같은 단어가 두번 표시됨.
class=“glyphicon glyphicon-print” 프린트모양 상형문자 추가
보통 <span>태그를 사용하여 속성으로 추가하면 된다.
위의 Search 단어 앞에다 추가하면
<a href=“#” class=“btn btn-info btn-lg”>
<span class=“glyphicon glyphicon-search”></span> Search</a>

*span 태그는 자체로는 아무일도 하지 않으나, 문장 단위에서 css 스타일 지정에 사용 



Multicolumn
(row) (column) 있으며, 각각의 설정이 필요하다
설정은 class=“row” 속성으로 <div>태그로 둘러쌈.
내의 칸은 class=“col-xs-3” 등으로 사용. 전체 칸은 항상 12개이므로 개별 칸을 합쳤을 12 되어야
폭은 xs, sm, md, lg 등으로 적용 기기에 따라 나누어
<div class=“row></div> 먼저 줄을 둘러 싼다. 안에 칸에 대한 것을 넣음. 예를 들면, <div class=“col-sm-4>문자 문자 ..</div> 4 짜리 설정이므로 이런 것이 3개가 들어가면 12 된다.



Menu
html 자체가 가지는 기본 메뉴는 다음과 같다
<ul>
   <li> <a href=“#”>Home </a></li>
   <li> <a href=“#”>Menu 1</a></li>
   <li> <a href=“#”>Menu 2</a></li>
</ul>

여기에 클래스를 추가한다. <ul class=“nav nav-tabs“>이다속성에 nav 들어 갔다. nav-tabs외에 nav-pills(알약 디자인처럼 나열 표시하는 형식) 가지 타입이 있다
<li>탭에 class=“active” 주면 화면 표시 때에 메뉴가 선택 .
메뉴 밑에 메뉴도 가능한데, 부메뉴 추가할 메뉴를 고르고 아래에 <li class=“dropdown”> 사용한다.  
<span class=“caret”> 사용하는데 부메뉴 존재를 나타내는 펼침 표기인 삼각형 표시이다.


Navigation bar
페이지의 상단에 고정되어 있는 방향 바이다.
 <nav class=“navbar navbar-default”> </nav> 둘러싼다.
nav html5 태그 중의 하나이다

navbar-default 대신에 navbar-inverse 사용하면 배경 값이 역으로 되어 색다른 디자인이 .
navbar-fixed-top(bottom) 추가하면 화면 부분이 아래위로 스크롤되어도 navbar 스크롤 안되고 상단에(하단에) 고정되는 효과를 가지게 있다.


navbar-right 메뉴를 오른쪽 단에 고정.
<ul class=“nav navbar-nav navbar-right>…</ul>처럼 사용 가능


class=“nav navbar-header” class=“nav navbar-nav”속성을 사용한다.
접을수 있는 방향 바를 만들기 위해서는 navbar-header 부분 수정
<div class=“nav navbar-header>
    <button type=“button” class=“navbar-toggle” data-toggle=“collapse” data-target=“#myNavBar”>
    <span class=“icon-bar”></span>
    <span class=“icon-bar”></span>
    <span class=“icon-bar”></span>
    </button>

toggle 토글된다는 의미, collapse 접을 있음을 의미한다
# 붙은 것은 id표시고, 하단에  id myNavBar 부분과 연동.
icon-bar 표시가 3개가 있고, 화면이 좁을 때는 메뉴대신에 3개가 표시됨.





참고 만한 사이트
Bootstrap 네비게이션바, http://m.blog.naver.com/naripuru/220232331848
밑바닥부터 홈페이지 만들기, http://unikys.tistory.com/333