안녕하세요. 날씨가 많이 춥네요. 겨울이에요 완전 ㅠㅠ
몸 건강 조심하세요!
이번에는 이미지 영상 인식 처리 딥러닝 강의 cs231n 6장입니다.
가면 갈수록 어려워지네요 ㅠㅠ 회사일도 바빠서 이걸 따로 시간 빼내면서 정리하는 것도 일이네요. 하지만 딥러닝과 머신러닝 인공지능쪽이 핫한 요즘 지체할 수 없죠! 조금씩이라도 힘내서 공부해봅니다.
6장 정리 들어가봅니다
앞에는 과제니까 넘어가구요
우리는 앞서 이런 모양의 computational graph를 배웠습니다. 말 그대로 f = Wx + regularization 인거를 배웠죠.
F = Wx 는 기본적인 식입니다. 그리고 뉴럴 네트워크에서는 이제 hidden layer가 쌓이게 되죠. 그래서 f = wx의 기본적인 식에서 층이 생기게 됩니다. F = w2max(0, w1x) 이런식으로 층을 쌓는 것이죠.
이제 우리는 CNN에 배웠습니다. CNN은 큰 input에서 점차 세부적으로 들어가면서 보는 것입니다. 지난 시간까지 CNN에서 사용되는 필터, activation map과 optimization 등을 배웠습니다.
그리고 SGD도 배웠구요. 이제 우리는 Training Neural Networks에 대해서 더 자세히 배워볼 것입니다.
뉴럴네트워크는 이번장하고 다음장인 7장까지 해서 2번에 걸쳐서 자세히 배우게 됩니다.
이번장에서는 활성화 함수(activation functions)들에 대해서 배우고 그리고 data preprocessing(데이터 전처리)에 대해서 배울것입니다. 이후에 weight를 효율적으로 초기화 하는 weight initialization 배우고 정~말 많이 사용하는 배치 정규화(Batch Normalization, BN) 등 이런것들을 배울것입니다.
자 시작하죠!
먼저 활성화 함수(Activation Functions)입니다.
이 Activation Function은 f = Wx에 대해서 앞에서 input값이 들어오면 이 값을 다음 노드로 보낼 때 값을 어떻게 보낼지를 정해줍니다. 보통 활성화 함수는 non-linear한 함수를 사용합니다.(input은 linear한 값이 들어오지만 이걸 통과하면 non-linear한 값이 나오게 되죠)
왜냐하면 linear한 값을 사용하게 되면 예를 들어 3개면 y(x) =h(h(h(x))) 처럼 되어서 마치 y = c^3이 되서 마치 1개의 layer처럼 됩니다. 내 의도는 3개의 layer가 쌓여야 하는데 이게 마치 1개로 되는 것이죠. 그래서 non-linear한 값을 사용합니다.
활성화 함수(activation function)의 역할은 말 그대로 ‘활성화’시켜주는 것입니다. 어떤 값이 들어오면 이 값들을 어떻게 활성화 시킬 것인지를 정하는 것입니다. 이 값이 이제 다음 layer로 전달되는 것이죠. 그래서 활성화 함수의 종류에 따라 그 값의 형태도 다양합니다.
그리고 활성화 함수는 이렇게 있습니다~ 이것들을 하나하나 알아보죠
먼저 우리가 자주 본 sigmoid 함수 입니다. 과거에는 많이 사용했습니다. 그리고 단순한 ‘단일, 이진’ 분류 등에서도 아직도 많이 쓰긴 하죠. 하지만 최종 출력에서만 사용합니다. 중간의 hidden layer에서는 사용하지 않죠. 그 이유는 3가지가 있습니다.
먼저 가장 ‘큰’ 문제입니다. 바로 기울기 소실 문제인 gradient vanishing 문제가 있습니다.
이게 왜 발생될까요?
여기 시그모이드 그래프를 봅시다. 그럼 -10, 0, 10일 때 어떻게 될까요? -10일 때 기울기가 거의 0이 됩니다. 10일 떄도 마찬가지구요. 0일때는 그나마 0에 매우 가깝지는 않는데 (참고로 0일 때 가장 gradient가 제일 쎈데 => 0일 때 0.5니까 (1-0.5)(0.5) 즉 이게 1/4가 나오니까 이것도 문제입니다. 그러다보니까 계속 backpropagation을 하게 되면 0과 가까운 값이 계속 곱해지잖아요? 그래서 기울기가 0에 매우매우매우 가까워진 수가 되어버려서 기울기가 소실되어 버립니다.
2번째 문제는 zero-centered가 되어 있지 않는 문제입니다.
시그모이드 그래프를 보면 0을 중심으로 되어 있지 않죠. 0을 중심으로 될라면 y축도 0 밑으로 내려와야겠죠? 근데 이게 무슨 문제가 되냐??
결론적으로 말하면 zero-centered가 되지 않으면 매우 민감해집니다. 즉, 조그만한 변화에도 갑자기 훅훅 변화가 되기 때문에 안좋죠.
그리고 자세히 보면 input이 뉴런 즉 x가 언제나 양수일 때 어떻게 될까요? X는 언제나 양수가 됩니다. 왜냐하면 들어오는 x는 앞단의 sigmoid 계산을 통해서(exp) 들어왔기 때문에 언제나 양수가 되죠. 이 상태에서 W의 gradient값은 어떻게 될까요? 저 f(시그모이드 wixi + b)식을 미분해보죠.미분을 하면 df/dwi = xi가 됩니다. 이걸 편미분을 해보면 dL/dwi = dL/df * df/dwi
dL/df*xi가 됩니다. 근데 xi는 sigmoid처리가 되서 넘어오기 때문에 무조건 양수가 됩니다. 결국 dL/dwi는 dL/df의 부호에 따라서 부호가 결정이 되죠. 왜냐? Xi가 향상 양수니까요. 그래서 dL/df가 음수면 음수, 양수면 양수가 됩니다. 즉 W의 gradient는 모두 양수이거나 모두 음수이게 됩니다!
그래서 이 그래프를 보시면 모두 양수 혹은 모두 음수가 되기 때문에 지그재그 형태로 넘어가게 됩니다. 이상적인 방법은 대각선으로 가는 것인데 이게 그렇게 되지 않고 지그재그로 가니까 매우 비효율적이라는 것이죠. 이게 문제입니다.
또 3번째 문제는 exp 연산의 값이 매우 비싼 연산입니다. 어려운 연산이라 이거죠.
그래서 sigmoid는 잘 쓰지 않습니다.
그래서 이거 대신에 하이퍼볼릭 탄젠트(tanh)가 나오게 되는데요. Sigmoid를 조금 바꾼것입니다. Zero centered가 되었죠. 그러나 아직까지도 기울기 소실문제와 exp연산이 있습니다.
그 다음 볼 것이 ReLU(Rectified Linear Unit)입니다. 이거는 지금 가장 대중적으로 많이 사용하는 activation function입니다. ReLU는 0이하인 애들은 전부 0으로 그리고 그 이상인 값들은 그 값대로 내보내줍니다. 그래래서 f(x) = max(0,x)의 식을 가지고 있죠. 매우 단순하지만 잘 동작하는 활성화함수입니다.
. 하지만 이것도 문제가 있습니다. 일단 0 이하 값들은 전부 버리게 되죠. 그리고 zero centered가 되어 있지 않습니다.
그래서 여기서 처럼 -10, 0 이면 0이 되게 되는데요 만약 이렇게 된다면 dead ReLU에 빠지게 됩니다.
왜냐하면 전부 0이 되어 버리기 때문이죠.
그래서 몇몇 사람들은 이 파란색 글씨처럼 0.01의 bias값을 주고자 했습니다. 조금이라도 움직임을 줘서 해보자는 것인데.. 반반이라고 합니다.
그래서 그것에 대한 보완점으로 Leaky ReLU가 나옵니다. 이 Leaky ReLU도 많이 사용됩니다. 0 이하의 값을 0.01x값을 줘서 작은 값이라도 주게 하는 것이죠.
그리고 이걸 조금 변형한게 parametric Rectifier인데(PReLU) 이거는 알파 값을 줘서 이것도 일종의 학습을 통해 찾아가는 뭐 그런것입니다.
그리고 ReLU의 변형으로 나온 것이 ELU도 있습니다. 이것도 ReLU의 모든 장점을 가지고 있고 zero mean과 가까운 결과가 나오게 됩니다. 하지만 exp계산을 해야하는게 단점이라고 합니다.
또 뭐 Maxout이라고 있는데 이거는 잘 사용안한다고 하네요. Max( )값을 통해 2개의 파라미터를 줘서 보고 더 좋은 것을 선택하는 것인데요. 이게 연산량이 2배가 더 늘어나니까 잘 사용은 안한다고 합니다.
그래서 일반적으로 딥러닝에서는 ReLU와 Leaky ReLU를 많이 사용한다고 합니다. 필요에 따라서 ELU 등을 찾아보는 것이 좋겠네요. Tanh는 RNN과 LSTM에서 자주 사용합니다. CNN에선 사용하지 않아요.
그리고 sigmoid는 절대 사용하지 않습니다.
자 여기까지가 활성화함수(activation function)에 대한 내용이었습니다.
이제 데이터 전처리를 보죠.
데이터 전처리(data preprocessing)은 머신러닝을 해보신 분들은 매우 익숙하실 겁니다. 그리고 딥러닝에서도 필수죠. 사실 딥러닝이나 머신러닝이나 데이터 전처리가 80%이니까요..
데이터 전처리는 zero-centered, normalized를 많이 사용합니다. Zero-centered는 앞서 본 것에서 중요성을 아시겠죠? 그리고 normalized는 특정 범위 안에 이 값들을 모아놓는 것입니다. 뭐 예를 들어서 어떤 값은 1인데 어떤값은 3000 이러면 값의 폭이 너무 커서 그래프가 이쁘지 않잖아요? 이런것들을 위해서 표준편차를 나눠줍니다. 하지만 이미지에서는 사용하지 않아요.
왜냐하면 이미지는 0~255라는 이미 값이 정해져있죠? 그렇기 때문에 굳이 normalized를 하지 않는다고 합니다. 대신 zero-centered를 하죠.
그 외에도 분산에 따라 차원을 감소시켜주는 PCA, 또 다른 whitened data 등이 있는데 이것들은 이미지에서 잘 사용하지는 않습니다.
그래서 이미지에선 zero-centered를 주로 하구요 방법은 채널별로 하냐, 전체를 하냐로 나뉘어 지는데 케바케입니다.
전처리에 대한 내용이 끝났습니다. 다음은 weight initialization입니다. 최근에 정말 핫한 영역이죠. weight값이 어떻게 초기화 되냐에 따라서 모델 학습이 잘 되냐 안되냐가 정해지니까요.
만약 W가 0이면 어떻게 될까요? Gradient vanishing이 발생하겠죠?? 그래서 첫번째 아이디어가 바로 랜덤의 작은 값들을 넣는 것입니다.
그래서 0.01 * np.random.randn(D,H)를 통해 랜덤으로 값을 넣어줍니다. 그리고 생각보다 잘 됩니다.
. 하지만 네트워크가 깊어질수록 이게 문제가 되죠.
여기처럼 네트워크를 10개의 레이어에 500개 노드를 둡니다. 그리고 활성호 함수는 tanh입니다.
아래 그림을 보니 레이어가 깊어질수록 값들이 전부 날라갑니다. 이건 왜 그러냐면요 tanh 그림을 보면 기울기가 0인지점이 날라가죠? 그래서 기울기가 0이 안되는 지점 (가운데 지점)만 살아남는 것입니다.
그림이 이쁘지 않지만................(ㅈㅅ합니다)
아무튼 저렇게 가운데만 살아남은 모습입니다.
이렇게요.
결국 엑티베이션들이 0이 되버립니다.
그렇다면 값을 크게 하면 어떻게 될까요? W값이 너무 크기 때문에 오벼슈팅이 일어나게 됩니다. 그래서 -1과 1에 포화되어집니다.
이런 모양이 나오게 됩니다.. 그림이 좀 삐뚤어졌지만 가운데 지점이 아닌 사이드 부분에 값이 치우치게 됩니다. 그래서 좋은 weight값을 주기 위해서 Xavier initalization을 사용하게 됩니다.
이거는 노드의 개수(fan_in)을 normalized하자는 것입니다. 큰거는 큰걸로 나눠주고 작은거는 작은값으로 나눠주는 것이죠. 즉, input의 개수가 많아지면 나눠주기 때문에 값이 작아지고 input의 개수가 적으면 weight값이 커지는 이렇게 합리적으로 weight를 초기화 합니다.
그래서 하이퍼볼릭 탄젠트에서는 잘 적용이 되는데 한 가지 문제는 ReLU에 적용이 잘 안된다는 것입니다.
그래서 2015년에 카이밍 he가 2를 나눠주는 방식을 적용했더니 잘 동작하더라 라고 발표를 하게 됩니다. 그래서 relu에서는 2를 나눠주어 진행합니다.
성능이 잘 나오네요
이 weight initialization 분야는 지금도 매우 활발하게 연구가 진행되고 있는 분야입니다.
근데 우리가 굳이 weight initalization을 안해도 되는 방법이 있는데요. 그게 바로 Batch Normalization입니다.
Batch normalization(BN)은 기본적으로 Gradient Vanishing이 나오지 않도록 하는 아이디어입니다. 앞서서 우리는 이 문제를 activation function의 변화로 해결하려고 했습니다. 근데 BN은 이것이 아니라 training하는 과정 자체를 전체적으로 안정화시켜 주는 것입니다.
이거는 internal covariance shift를 방지하는 건데요. 이게 뭐냐면 network각 층이나 activation 마다 input의 distribution이 달라지는 것입니다. 이걸 막기 위해서 각 층의 input distribution을
평균0, 표준편차1인 분포로 만들어버리는 것입니다.
보통 우리는 input을 한 번에 처리하지 않고 batch 별로 처리합니다. 그래서 이 그림에서 처럼 N x D의 input이 들어오죠. 이 batch가 들어오면 이걸 nomalize한다는 것입니다.
이거는 일반적으로 activation전에 잘 분포되도록 한 다음에 activation을 진행할 수 있도록 해줍니다. 그래서 FC -> BN -> activation 으로 들어가게 되죠.
근데 여기서도 이렇게 BN을 하면 unit gaussian이 되는데 이게 적합하냐? 안하냐? 를 고민해야 합니다. 이런 판단히 필요하죠.
근데 BN에서는 이 판단 조차도 학습에 의해 가능하다라라고 말합니다. 처음에 normalize를 하고 두 번째에서 정규화 된 것을 조정할 수 있도록 기회를 주는데 감마랑 이런 값들이 있는데 감마는 노멀라이즈 스케일링 값 등입니다. 그래서 y(k)에다가 위의 x식과 감마 등의 식을 대입하면 상쇄가 되기 때문에 BN을 undo할지 do할지 판단합니다. B는 쉬프트하는 값입니다. 이 감마와 B도 학습을 통해서 값을 찾게 되는 것이죠. 즉 학습을 통해서 BN을 어느정도로 할 것이냐를 결정합니다.
그래서 실제 값은 이렇게 과정을 거칩니다. mean값을 구하고 variance값을 구한 다음(보통 분산은 얼마나 퍼져있나? 라는 지표죠) normalize를 합니다. 그리고 scale은 어느 정도 퍼지게 해주는지 정하는 것이고 shift는 이동성입니다. 앞서 설명드린대로 이 scale과 shift는 학습을 통해서 값을 찾습니다
보통 BN을 하면 Dropout을 안써도 된다고 합니다. 그 이유가 무엇일까요? Dropout은 랜덤하게 값을 꺼줍니다. BN도 마찬가지이죠. 배치마다 값이 조금씩 다르게 들어가고 값이 계속 바뀌게 되니까 노이즈가 적어지게 된다고 합니다. 즉, 계속 바뀌면서 이럴떄 해보고 저럴떄 해보니까 그런건가봐요… 잘은 모르게네요. 근데 아무튼 BN을 쓰면 dropout을 안써도 됩니다. 실제로 BN이 더 잘나올 때가 많습니다
자 이제 learning process에 대해서 배워보죠.
먼저 처음은 전처리입니다. 아까 말씀 드렸듯이 보통 이미지 인식에서는 zero-centered를 합니다. Normalized는 잘 하지 않습니다. 왜냐하면 이미 값이 0~255값을 가지고 있으니까요
그런 다음 이제 아키텍처를 선택합니다. Hidden layer를 어떻게 구성할 것인지 등을 선택하는 것이죠. 물론 선택해서 진행했다고 한들 바로 잘 나오지는 않을꺼지만 보통 이렇게 대충 사이즈를 잡아놓고 진행합니다.
그리고 이렇게 레이어를 구상했으면 loss값이 잘 나오는지 확인합니다.
여기서 하는 방식은 앞서 3강에서 소개드렸던 sanity check입니다. softmax에서는 loss가 –log(x)였죠? 근데 규제값을 0으로 줘버리면 –log(1/c)가 나옵니다. 그 값이 2.3인거죠
그리고 규제값을 살짝 올렸을 때 loss가 증가된 것을 볼 수 있습니다. 이렇게 우리의 layer가 동작하는지 확인하는 것이 sanity check입니다.
그 다음 훈련을 시켜보는데요. 바로 모든 데이터를 넣지 않고 작은 데이터 셋을 먼저 넣습니다.
데이터 수가 작기 때문에 거의 100% overfitting이 나옵니다. 그래서 train accuracy가 100%가 나오죠! 이게 overfitting이 제대로 되고 있으면 모델이 동작한다는 것을 의미합니다.
자 이제 regularization값과 learning rate값을 찾아봅니다. 적절한 값들을 넣어줘서 차근히 찾아보는데요.
Learning rate가 1e-6일 때 loss가 바뀌는 것을 볼 수 있습니다. 대신 lr값이 너무 작기 떄문에 cost값이 매우 조금씩 떨어집니다.
하지만 train값은 서서히 증가되는 것을 볼 수 있죠.
아무리 작아도 점차 훈련은 되고 있기 때문에 accuracy가 증가되는 것입니다.
이제 learning rate값을 1e6값으로 올려보죠.
그러면 cost값이 nan이 됩니다. 이건 값이 너무 커서 튕겨져 나가버린거죠!
그래서 3e-3으로 수정합니다. 그래도 inf로 튕겨져 나가네요.
하지만 우리는 여기서 1e-3 ~ 1e-5값이 적당하다~ 라는 것을 추측할 수 있습니다.
이런식으로 적절한 lr값을 찾아가는 것이죠!
이제 하이퍼파라미터를 찾아봅니다.
처음은 값을 넓은 범위에서 좁은 범위로 줄여나가는 방법을 사용합니다.
For example을 보죠.
여기서 10**uniform(-5, 5)값을 취해줍니다. 로그값을 취해주면 값이 더 안정적이 되기 때문이라고 하네요. 이것도 일종의 normalization 이라고 생각이 듭니다.
어쨌든 이 범위에서 하니까 nice한 영역이 보입니다. 바로 val_acc가 48%가 나오는 지점인데요. lr값이 e-04인 지점입니다. 그리고 reg는 e-01이네요. 그럼 이제 값의 범위를 좁혀보죠!
Reg는 -4에서 0, lr는 -3에서 -4로 수정했습니다. 그러니까 best지점이 이제 53%지점으로 변경되었죠? 이렇게 좁혀갑니다.
하지만 53% 지점이 ‘잘’나온 것이 아닙니다. 왜냐하면 -3부터 -4까지다 보니까 범위에 들어가지 않는 값이 있을 수도 있습니다. 처음에 nice한 지점이 lr이 e-04, reg가 e-01이어서 값을 저렇게 수정했지만 이게 값을 ‘모두’ 충족시키지 않을 수도 있습니다. 그래서 값을 조금 줄여줘서 하는게 좋습니다. 예를 들어 -3이 아니라 -2.5 정도나 이렇게요!
자 근데 이렇게 찾는 방법은 그리스 서치(grid search)와 random serach 2가지가 있습니다. 아마 머신 러닝을 해보신 분들은 그리드 서치가 익숙하실 탠데요. 여기서는 랜덤 서치가 더 좋습니다.
그 이유는 이 사진만 봐도 아시겠죠? 그리드 서치는 찾지 못할 수도 있습니다. 일정한 간격이기 때문이죠. 하지만 랜덤은 말 그대로 랜덤으로 떨어지기에 더 좋은 값의 영역에 접근할 확률이 좋다고 합니다. 그래서 보통 random search를 사용합니다.
이런 하이퍼파라미터를 찾는 과정은 DJ가 클럽에서 노래를 킬 때 저 스피커? 기계?를 조절하는 것과 비슷하다고 합니다. 저 기계를 조절함으로써 좋은 사운드가 나오게 하죠? 하이퍼 파라미터도 이렇게 조절하면서 좋은 값을 찾아내는 것입니다.
이러한 하이퍼파라미터는 네트워크 아키텍처, learning rate, dccay, regularization 등에 값이 있습니다.
실제로 강사는 이렇게 엄청나게 많은 방법으로 최적의 값을 찾는다고 하네요.
그리고 loss curve를 모니터링 하면 이런 모양을 볼 수 있습니다. 노란색은 learning rate가 매우 높을 때고 파란색은 learning rate가 낮을 때, 초록색은 learning rate가 ‘조금’ 높을 때 발생될 수 있다고 합니다. 우리가 원하는 learning rate는 빨간색과 같은 것이죠!
그리고 가끔 이런 모양의 loss를 볼 수도 있는데요. 이거는 계속 처음에 적절한 값을 찾지 못해서 훈련이 되지 않다가 갑자기 어느 지점에 다달아서 값을 찾아 확~ 학습이 되어버린 것입니다.
앞에선 initialization이 좋지 않았던 것이죠.
그리고 우리는 이 빨간색 선과 초록색 선의 gap이 없어야 할 것입니다. 이렇게 gap이 커버리면 거의 100이면 95는 overfitting입니다. 과적합이 걸린 것이죠. 오버피팅이 걸리면 실제 데이터 셋에서 잘 동작이 되지 않습니다. 꼭 유의 하셔야 합니다.
그래서 이번 강의는 이렇게 마쳤습니다.
다음 7장에서 뉴럴 네트워크 2번째 시간을 정리해봅니다.
수고하셨습니다.
'deep learning(딥러닝)' 카테고리의 다른 글
cs231n 2017년 강의 9강 CNN Architectures 정리 (4) | 2018.11.28 |
---|---|
cs231n 2017 강의 7강 training neural networks part2 정리 (2) | 2018.11.26 |
cs231n 2017 5강 convolutional neural networkds(컨볼루션 네트워크)정리 (4) | 2018.11.11 |
cs231n 2017 4강 정리 backpropagation and neural networks (0) | 2018.11.06 |
cs231n 2017 3강 정리 loss functions and optimization (6) | 2018.10.31 |