일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 큐
- 캐치카페신촌점 #캐치카페 #카페대관 #대학생 #진학사 #취준생
- DFS
- 정렬
- 계수정렬
- BFS
- 퀵정렬
- Machine Learning
- 다이나믹 프로그래밍
- 스택
- 재귀함수
- 이진 탐색
- 알고리즘
- 머신러닝
- GRU
- 그리디
- AI
- rnn
- 선택정렬
- 선형대수
- LSTM
- 딥러닝
- pytorch
- RESNET
- 삽입정렬
- 인공지능
- 최단 경로
- Today
- Total
hyeonzzz's Tech Blog
[Andrew Ng] 딥러닝 1단계 : 4. 얕은 신경망 네트워크 -(2) 본문
7. 왜 비선형 활성화 함수를 써야할까요?
신경망이 흥미로운 함수를 계산하려면 비선형 활성화 함수가 필요하다.
4개 식에서 g를 없애고 z^[1]로 대체하면 g(z) = z이다. 이건 선형 활성화 함수라고 부른다. 여기선 입력값을 출력값으로 내보내기 때문에 항등 함수라고 부르는게 더 맞다. a^[2]도 z^[2]로 만들어 준다. 모델은 ŷ을 입력 특성 x에 대한 선형 함수로 계산하게 된다. 첫 두 식을 보면 a^[1] = z^[1] = W^[1]x + b^[1]이 된다. a^[2] = z^[2] = W^[2]a^[1] + b^[2]가 된다. a^[1]을 두번째 식에 대입하면 a^[2] = z^[2] = W^[2]( W^[1]x + b^[1] ) + b^[2]가 되고 간소화하면 W'x + b'이 된다. 선형 활성화 함수 또는 항등 활성화 함수를 쓴다면 신경망은 입력의 선형식만을 출력하게 된다. 심층 신경망이어도 선형 활성화 함수만 계산하기 때문에 은닉층이 없는 것과 다름없다. 두 선형 함수의 조합은 하나의 선형 함수가 되기 때문에 선형 은닉층은 쓸모가 없다!!
선형 활성화 함수인 g(z) = z를 쓸 데가 하나 있는데 회귀 문제에 대한 머신러닝을 할 때이다. 예를 들어 y가 실수일 때, 집값을 예측할때 같은 경우이다. y가 0이나 1이 아닌, 0부터 집값이 비싸지는대로 올라간다. 출력값 ŷ 이 - ∞부터 ∞까지의 실수값이 된다. 하지만 이때 은닉 유닛은 선형 활성화 함수가 아닌 ReLU, tanh, leaky ReLU나 다른 비선형 함수를 써야한다. 선형 활성화 함수를 쓸 수 있는 곳은 대부분 출력층이다.
집값은 항상 양수이기 때문에 출력값 ŷ이 양수가 되도록 ReLU 함수를 쓸 수 있다.
8. 활성화 함수의 미분
신경망의 역방향 전파를 구현하려면 활성화 함수의 도함수를 구해야 한다. 우리가 고른 활성화 함수와 그 함수의 기울기를 어떻게 구하는지 살펴보자.
sigmoid 함수는 주어진 값 z에 대해 특정한 기울기를 가진다. 기울기는 선을 그었을 때 삼각형의 높이를 너비로 나눈 값이다. g(z)가 sigmoid 함수일때 기울기는 d/dz g(z)가 된다. 이 값은 g(z)(1 - g(z))와 같다.
1) z가 큰 값인 10일 때 g(z)는 1에 가까워진다. d/dz g(z)는 1(1 - 1) = 0과 가까워진다. z가 커지면 기울기가 0에 가까워지기 때문에 맞는 공식이다.
2) z가 작은 값인 -10일 때 g(z)는 0에 가까워진다. d/dz g(z)는 0(1-0) = 0과 가까워진다. z가 작아지면 기울기가 0에 가까워지기 때문에 맞는 공식이다.
3) z가 0일 때 g(z)는 1/2이다. d/dz g(z)는 1/2(1-1/2)인 1/4가 된다. z가 0일때의 기울기의 값과 일치하기 때문에 맞는 공식이다.
d/dz g(z) 대신 g'(z)로 쓸 수 있다. g'(z)는 z에 대한 g의 도함수를 의미한다.
신경망에서 a는 g(z)와 같고 d/dz g(z)는 a(1-a)로 간소화할 수 있다. 가끔 구현에서 g'(z)가 a(1-a)라고 되어있는 걸 볼 수 있을 것이다. 공식의 장점은 이미 a를 계산했다면 g'의 값을 빠르게 계산할 수 있다는 것이다.
tanh 함수에서 g'(z) = d/dz g(z) = 1 - (tanh(z))^2 이다.
1) z = 10이면 tanh(z)는 1에 가까워지고 g'(z)는 1 - 1인 0에 가까워진다.
2) z = -10이면 tanh(z)는 -1에 가까워지고 g'(z)는 1 - 1인 0에 가까워진다.
3) z = 0이면 tanh(z)는 0이고 g'(z)는 1이 된다.
a가 g(z)인 tanh(z)일 때 도함수인 g'(z)는 1-a^2이 된다.
1) ReLU
ReLU에서 g(z)는 max(0,z)가 된다. g'(z)는
0 ( if z<0)
1 ( if z>=0)
g'은 활성화 함수 g(z)의 서브 경사이기 때문에 경사 하강법이 잘 작동한다. z=0일때는 엄밀하게는 정의되지 않았지만 0, 1 둘중 하나라고 해도 괜찮다. z가 정확히 0이 될 확률은 정말 작기 때문에 0일때 도함수를 뭐라고 하든지 상관없다.
2) Leaky ReLU
Leaky ReLU에서 g(z)는 max(0.01z,z)가 된다. g'(z)는
0.01 ( if z<0)
1 ( if z>=0)
9. 신경망 네트워크와 경사 하강법
현재는 w^[1], b^[1], w^[2], b^[2]의 변수를 가진다.
한 개의 은닉 유닛을 가진 n^[2] = 1인 경우)
n_x는 n^[0]를 입력 특성으로 가지고 n^[1]은 은닉 유닛으로 가지며 n^[2]를 출력 유닛으로 가진다. 우리가 사용한 샘플에서 n^[2] = 1 이었다. 행렬 w^[1]은 ( n^[1], n^[0]) 차원을 가지고 벡터 b^[1]은 ( n^[1],1) 차원을 가진다. (행 벡터) w^[2]은 (n^[2], n^[1]) 차원을, b^[2]은 (n^[2],1) 차원을 가진다.
이진 분류를 하고 있다고 가정하면)
각 변수들에 대한 비용은 손실함수의 평균이 된다. 이진 분류를 하는 경우에 손실 함수는 로지스틱 회귀에서 사용한 것과 같다.
변수들을 훈련시키기 위해 경사하강법을 사용하면)
0이 아닌 값으로 변수를 초기화하는 것이 중요하다. 변수를 어떤 값으로 초기화한 후 경사 하강법이 반복될 때마다 예측값을 계산한다 = ŷ^[i]를 계산한다. dw^[1] = w^[1]에 대한 비용 함수의 도함수, db^[1] = b^[1]에 대한 비용 함수의 도함수, dw^[2], db^[2] 를 계산한다. 결과적으로 w^[1] = w^[1] - α dw^[1] , b^[1] = b^[1] - α db^[1] 으로 바꾸고 w^[2], b^[2]에 대해서도 동일하게 적용한다. 이것이 경사하강법의 한 반복이다. 변수들이 수렴할 때까지 이것을 반복한다.
왼쪽 4개식은 정방향 전파에 대한 식들이다.
오른쪽 6개식은 역방향 전파에 대한 식들이다.
행렬 Y는 (1,m) 행렬, m가지의 모든 샘플을 가로로 나열한 것이 된다.
처음 3개의 식은 로지스틱 회귀에서의 경사 하강법과 매우 비슷하다. keepdims가 하는 역할은 파이썬이 잘못된 1차원 배열을 출력하지 않게 하는 것이다. keepdims = True로 설정하면 db^[2]에 대한 파이썬 출력값은 (n^[2],1) 벡터가 된다.
dz^[1] = w^[2]T dz^[2] * g^[1]' (z^[1]) 이고 g^[1]' 은 은닉층에서 사용했던 활성화 함수의 도함수이다. 출력층에서는 sigmoid함수를 이용해 이진 분류를 한다. w^[2]T dz^[2]는 (n^[1],m) 행렬이 되고 g^[1]' (z^[1])도 (n^[1],m) 행렬이 된다. 따라서 둘의 곱은 요소별 곱셈이 되어야 한다. dw^[1], db^[1]을 이어서 계산한다. 마지막식에서 keepdims = True로 설정하면 db^[1]은 (n^[1],1) 벡터가 된다. reshape함수를 사용해서 np.sum의 출력값을 다시 재배열해 db에 맞는 차원으로 만들 수 있다.
10. 역전파에 대한 이해 (Optional)
지난 시간 로지스틱 회귀 식들
정방향 전파에서 z를 계산하고 a를 계산한 뒤 손실값을 계산했다. 역방향 패스에서는 도함수를 계산했다. da 계산후 dz, dw, db 계산하였다. 손실값 L의 정의는 -y log(a) -(1-y)log(1-a) = -y/a + (1-y)/(1-a)이다. dz = a-y = da * g'(z)이다. 여기서 g는 sigmoid 함수이다. a는 z에 대한 sigmoid 함수이고 z에 대한 L의 편미분은 연쇄법칙에 따라 a에 대한 L의 편미분에 da/dz를 곱한 것이기 떄문이다. da/dz = d/dz * g(z) = g'(z)와 같다. 따라서 보라색 박스 두개가 같은 식이 된다. dw = dz * x이고 db = dz이다.
hidden layer가 2개인 신경망에서의 역전파
da^[2], dz^[2], dw^[2], db^[2]를 계산한 뒤 da^[1], dz^[1]을 계산한다. 입력값 x에 대한 도함수는 계산할 필요가 없다. 지도학습에서 입력값 x는 고정된 값이기 때문이다. dw계산에서 w는 열 벡터이므로 a^[1]을 전치해주어야 한다. da^[1]과 dz^[1]은 한 단계로 계산할 수 있다.
이 신경망에서 행렬 w^[2]는 (n^[2], n^[1]) 차원을 가진다. z^[2]와 dz^[2]는 (n^[2], 1) 차원을 가진다. 이진 분류에 한에서 이것은 (1, 1) 차원이 된다. z^[1]와 dz^[1]는 (n^[1], 1) 차원을 가지는데 foo라는 변수와 dfoo는 항상 같은 차원인 것을 알 수 있다. w와 dw, b와 db, z와 dz도 동일하게 같은 차원을 가진다.
요소별 곱셈을 계산하면 차원일 일치하는 것을 확인할 수 있다.
이후 dw^[1]과 db^[1]을 계산한다. x는 a^[0]의 역할을 한다.
벡터화한 훈련 샘플에서 정방향 전파 식
벡터화하면 Z^[1] = w^[1]X + b^[1]이 되고 A^[1] = g^[1](Z^[1])이 된다.
역방향 전파 식
두번째 식에서 비용 함수 J가 1부터 m까지의 손실 함수의 합을 m으로 나눈 것이기 때문에 1/m을 곱한다.
네번째 식에서 dZ^[1]은 (n^[1], m) 차원의 벡터가 된다. 옆의 식 두개도 같은 차원이고 요소별 곱셈을 해준다.
11. 랜덤 초기화
변수를 0으로 초기화하고 경사 하강법을 적용할 경우 올바르게 동작하지 않는 이유
입력 특성이 2개이기 때문에 n^[0] = 2이다. 2개의 hidden unit를 가진다. n^[1] = 2이고 이 hidden unit의 행렬 w^[1]은 (2,2)행렬이 된다. 행렬 w와 b를 모두 0으로 초기화한다. 여기서 문제는 어떤 샘플의 경우에도 a_1^[1]과 a_2^[1]가 같은 값을 가진다는 것이다. 두 개의 활성이 같은 것이 된다. 두 은닉 유닛 모두 정확히 같은 함수를 계산하기 때문이다. 역전파를 계산할 때 dz_1^[1]과 dz_2^[1]도 같은 결과를 가지게 된다. 두 은닉 유닛이 같은 값으로 초기화되기 때문에 가중치의 결과값이 항상 같다. w^[2]는 [0 0]가 될 것이다. a_1^[1]과 a_2^[1]의 hidden unit은 symmetric하다. 완전히 같은 함수를 계산한다. 수학적 귀납법을 이용하면 각 훈련의 반복마다 두 hidden unit은 항상 같은 함수를 계산한다.
dw의 각 열이 같은 값이라고 할때 가중치를 계산하면 w^[1] = w^[1] - αdw가 된다. 각 반복 이후의 w^[1]은 첫번째 열과 두번째 열이 같아지게 된다.
수학적 귀납법에 의해 w의 값을 모두 0으로 초기화할 경우 두 은닉 유닛이 같은 함수를 계산하는 것으로 시작하기 때문에 두 은닉 유닛이 출력 유닛에 항상 같은 영향을 주게 되고 첫번째 반복 이후에 같은 상태가 계속해서 반복된다.
세개의 입력 특성이 있고 매우 많은 은닉 유닛이 있는 경우에도 비슷한 논리가 적용된다. 모든 값을 0으로 초기화한다면 모든 은닉 유닛은 대칭이 되고 경사 하강법을 얼마나 적용시키는지 상관없이 모든 유닛은 항상 같은 함수를 계산하게 된다. 다른 함수를 계산하기 위해 각각 다른 유닛이 필요하다.
해결방법은 변수를 임의로 초기화하는 것이다.
w^[1]을 np.random.randn으로 설정한다. 이 함수는 가우시안 랜덤 변수를 생성한다. (2,2)행렬로 설정한다. 일반적으로 이 값에 0.01과 같은 굉장히 작은 수를 곱해준다. 따라서 굉장히 작은 임의의 수를 초기값으로 만들어낼 수 있다. b^[1]의 경우 대칭의 문제를 가지지 않는다. 따라서 b^[1]을 0으로 초기화하는 것은 괜찮다. w가 이미 임의의 값으로 초기화되었기 때문에 다른 은닉 유닛에서 계산은 다른 결과를 만들어내고 더 이상 대칭 회피 문제가 존재하지 않는다. 비슷한 방법으로 w^[2]도 임의의 값으로 초기화한다. b^[2]도 0으로 초기화한다.
왜 0.01을 사용할까? 가중치의 초기값은 매우 작은 값으로 설정하는 것이 좋다. 만약 tanh나 sigmoid 활성 함수를 사용하거나 출력층에서 sigmoid 형태를 사용한다고 했을 때 가중치가 너무 큰 값을 가지는 경우 활성값을 계산하면 z^[1] = w^[1]x + b^[1]이고 활성함수 a^[1] = g^[1](z^[1])이다. w가 큰 값을 가지는 경우 z도 커지고 몇몇 값이 굉장히 크거나 작은 값이 된다. tanh 함수에서 z가 굉장히 크거나 작은 값인 경우 함수의 기울기가 매우 작기 때문에 경사 하강법 또한 매우 느리게 작용되어 학습 속도가 매우 느려진다. 따라서 초기 변수들이 너무 큰 값을 가지지 않도록 해야 한다.
한개의 은닉층을 가진 상대적으로 얕은 신경망에서는 0.01을 곱하는 것이 괜찮지만 깊은 신경망의 경우 다른 값을 선택하는 것도 방법이다.
로지스틱 회귀 모델과 가중치 초기화
- 로지스틱 회귀는 입력 특성과 가중치의 선형 조합을 기반으로 하기 때문에 가중치가 0에서 시작하더라도 경사 하강법(Gradient Descent) 같은 최적화 알고리즘을 통해 적절한 값으로 업데이트될 수 있다.
- 로지스틱 회귀에서 가중치를 0으로 초기화하는 것은 일반적인 접근 방법 중 하나➡️모델이 처음에는 모든 입력에 대해 중립적인 예측을 하게 하고, 그 후에 데이터로부터 학습을 통해 가중치를 조정하기 위함이다.
로지스틱 회귀에서 가중치를 0으로 초기화하는 것은 심층 신경망의 break symmetry와 관련 없으며, 학습 과정에서 적절한 결정 경계(decision boundary)를 찾을 수 있도록 한다.
반면 은닉층이 여러 개 있는 심층 신경망과 같은 복잡한 모델에서는 무작위 초기화를 통해 대칭성 문제를 해결해야 한다.
'Deep Learning > Basics' 카테고리의 다른 글
[Andrew Ng] 딥러닝 2단계 : 2. 신경망 네트워크의 정규화 (2) | 2024.01.25 |
---|---|
[Andrew Ng] 딥러닝 1단계 : 5. 심층 신경망 네트워크 (1) | 2024.01.24 |
[Andrew Ng] 딥러닝 1단계 : 4. 얕은 신경망 네트워크 -(1) (0) | 2024.01.17 |
[Andrew Ng] 딥러닝 2단계 : 1. 머신러닝 어플리케이션 설정하기 (0) | 2023.10.10 |
[Andrew Ng] 딥러닝 1단계 : 3. 파이썬과 벡터화 (0) | 2023.09.19 |