Quiz / ML 신경망 / 전체 문항
GitHub

ML 신경망 전체 문항

순전파, 역전파, 활성화 함수, 옵티마이저. 문항과 선택지별 해설을 글 순서대로 나열했습니다.

36문항 · 글 6편
직접 풀어보기 →

퍼셉트론에서 다층 신경망까지, 신경망의 구조

원문 읽기 →
개념 확인구조

신경망이 로젠블랫의 계단 함수를 버린 결정적인 이유는 무엇인가?

  1. 출력이 0과 1뿐이라 확률로 해석할 수 없기 때문이다.

    확률 해석은 부수적인 이점이다. 확률이 필요 없는 문제에서도 계단 함수는 쓸 수 없다.

  2. 정답0에서 미분이 정의되지 않고 나머지 구간에서 도함수가 0이라 경사하강법을 쓸 수 없기 때문이다.

    기울기가 어디서나 0이면 가중치를 어느 방향으로 옮겨야 할지 알 수 없다. 퍼셉트론이 자기만의 학습 규칙을 따로 가져야 했던 이유이기도 하다.

  3. 계단 함수로는 선형 분리 가능한 문제도 유한 번에 풀 수 없기 때문이다.

    선형 분리 가능하면 퍼셉트론이 유한 번 안에 반드시 답을 찾는다는 수렴 정리가 있다. 그쪽은 보장되어 있다.

  4. 계단 함수는 입력 범위에 따라 출력이 포화되어 큰 값에서 정보가 사라지기 때문이다.

    포화 문제는 시그모이드 같은 매끄러운 함수에서 다루는 이야기다. 계단 함수의 근본 문제는 미분이다.

해설

퍼셉트론이 하는 일은 입력에 가중치를 곱해 더하고 그 결과를 함수 하나에 통과시키는 두 단계뿐이다. 원래 퍼셉트론에서 그 함수는 문턱을 넘으면 1, 아니면 0을 내놓는 계단 함수였다. 그런데 이 함수는 0에서 미분이 정의되지 않고 나머지 구간에서는 도함수가 0이라 경사하강법을 쓸 방법이 없다. 기울기가 어디서나 0이면 가중치를 어느 방향으로 얼마나 옮겨야 할지 알 수 없기 때문이다. 그래서 퍼셉트론은 틀린 샘플을 만날 때마다 가중치를 입력 방향으로 밀어주는 자기만의 규칙을 따로 가졌다. 계단 함수 대신 시그모이드를 끼우면 이 모델은 그대로 로지스틱 회귀가 되고, 미분이 가능해지면서 경사하강법이라는 일반적인 학습 절차가 열린다.

이 내용 다시 읽기 →
상황 적용구조
XOR을 두 직선으로 분해한다. 직선 A: x1 + x2 - 0.5 > 0 직선 B: -x1 - x2 + 1.5 > 0

이 두 조건으로 XOR을 만드는 방법은 무엇인가?

  1. 둘 중 하나만 참인 영역을 고른다. 두 직선이 서로 배타적인 반평면을 정의하기 때문이다.

    두 반평면은 겹치는 영역이 있어 배타적이지 않다. 그리고 둘 중 하나만 참인 영역은 XOR과 다른 집합이다.

  2. 두 부등식의 좌변을 그대로 더한 값을 1.5로 자른다.

    두 식을 그대로 더하면 상수 1만 남아 입력에 무관한 값이 된다. 정보가 사라진다.

  3. 직선 A를 통과한 결과를 다시 직선 B에 입력으로 넣는다.

    두 직선은 나란히 놓이는 은닉 뉴런 둘이지 직렬로 이어지는 두 층이 아니다. 같은 입력을 각자 받는다.

  4. 정답두 조건이 동시에 참인 영역을 고른다. 그 영역이 정확히 XOR이 1인 두 점이다.

    두 입력이 모두 1인 점은 앞 조건은 통과하지만 뒤에서 걸리고, 모두 0인 점은 반대다. 은닉 뉴런 둘이 각각 직선을 긋고 출력 뉴런이 그 둘을 곱으로 묶는 구조다.

해설

직선 하나로 못 가르는 문제도 직선 두 개를 조합하면 갈린다. 앞 조건은 OR에 해당하고 뒤 조건은 NAND에 해당하는데, 두 입력이 모두 1인 점은 앞은 통과하지만 뒤에서 걸리고 모두 0인 점은 반대다. 남는 것은 정확히 XOR이 1인 두 점뿐이다. 중간 층의 뉴런 두 개가 각각 직선을 긋고 출력 뉴런이 그 둘을 동시에 참인 조건으로 묶는 구조이고, 이 중간 층을 은닉층이라 부른다. 사람이 교차항을 설계해 넣어주던 일을 은닉층이 대신한 셈이다. 교차항을 직접 만드는 우회로도 있기는 하지만 그것은 어떤 조합이 필요한지 사람이 미리 알아야 한다는 뜻이고, 특성이 수백 개로 늘어나면 그 판단이 불가능해진다.

이 내용 다시 읽기 →
상황 적용계산
입력 3개, 은닉 4개, 출력 1개인 신경망이다. 층마다의 계산은 다음과 같다. z = W·a + b

학습해야 할 파라미터는 모두 몇 개인가?

  1. 정답21개다. 첫 층에 4×3 가중치와 4 편향, 둘째 층에 1×4 가중치와 1 편향이다.

    가중치 행렬의 크기는 언제나 현재 층 뉴런 수 곱하기 이전 층 뉴런 수다. 행렬의 각 행이 뉴런 하나의 가중치 벡터인 셈이다.

  2. 16개다. 가중치만 세면 12개와 4개이고 편향은 학습 대상에서 빠진다.

    편향도 경사하강법으로 함께 갱신되는 학습 대상이다. 문턱의 위치를 정하는 값이라 빠뜨릴 수 없다.

  3. 8개다. 층마다 뉴런 수만큼의 가중치와 편향 하나씩이면 된다.

    뉴런 하나가 이전 층의 모든 뉴런과 연결되므로 뉴런당 가중치가 이전 층 뉴런 수만큼 필요하다.

  4. 24개다. 입력층에도 가중치와 편향이 붙는다.

    입력층은 원본 특성을 그대로 받는 자리라 학습할 파라미터가 없다. 파라미터는 층 사이의 연결에 붙는다.

해설

층이 몇 개든 각 층이 하는 계산은 같다. 이전 층의 출력에 가중치 행렬을 곱하고 편향을 더한 뒤 활성화 함수를 통과시킨다. 층 하나가 곧 뉴런 여러 개이므로 가중치는 벡터가 아니라 행렬이 되고, 크기는 언제나 현재 층 뉴런 수 곱하기 이전 층 뉴런 수다. 현재 층의 뉴런 하나가 이전 층의 모든 뉴런과 연결되므로 뉴런당 가중치가 이전 층 뉴런 수만큼 필요하고 그런 뉴런이 현재 층 개수만큼 있기 때문이다. 행렬의 각 행이 뉴런 하나의 가중치 벡터인 셈이다. 편향은 현재 층 뉴런 수만큼이다. 형상 오류의 상당수가 이 순서를 뒤집어 만들면서 생긴다. 라이브러리에 따라 저장 순서가 반대인 경우도 있으므로 값을 꺼내 볼 때 확인해야 한다.

이 내용 다시 읽기 →
분석과 판단판단
범용 근사 정리는 은닉층 하나에 뉴런이 충분하면 임의의 연속 함수를 원하는 정밀도로 근사할 수 있다고 말한다. 그런데 XOR을 은닉 뉴런 2개로 풀어보면 시드를 30번 바꿔도 4번만 정확도 1.0에 닿고, 8개로 늘리면 28번 닿는다.

이 결과가 정리에 대해 말해주는 것은 무엇인가?

  1. 은닉 뉴런 2개로는 XOR을 표현할 수 없으므로 정리의 조건인 충분함을 만족하지 못한 것이다.

    은닉 뉴런 둘이면 두 직선을 그을 수 있어 XOR을 표현할 수 있다. 실제로 30번 중 4번은 찾아냈다.

  2. 정답정리가 그런 가중치의 존재만 말할 뿐 경사하강법이 그 값에 도달한다는 보장은 하지 않는다는 것이다.

    표현할 수 있다는 것과 최적화가 실제로 그 해를 찾아낸다는 것은 다른 문제다. 여유 있게 뉴런을 두면 도달 확률이 올라간다는 점도 이 구분에서 나온다.

  3. 정리가 시그모이드에 대한 것이라 다른 활성화 함수에서는 성립하지 않는다는 것이다.

    활성화 함수를 바꿔도 비슷한 결과들이 알려져 있다. 여기서 갈리는 것은 함수 종류가 아니라 최적화의 성공 여부다.

  4. 은닉 뉴런이 많을수록 근사 오차가 작아지므로 정리가 정밀도의 하한을 준다는 것이다.

    정리는 원하는 정밀도에 도달할 수 있다고 말할 뿐 뉴런 수와 오차의 관계를 주지 않는다. 여기서 달라진 것도 오차가 아니라 도달 확률이다.

해설

범용 근사 정리는 은닉층 하나에 뉴런이 충분하면 임의의 연속 함수를 원하는 정밀도로 근사할 수 있다고 말한다. 주의할 점은 이 정리가 그런 가중치의 존재만 말한다는 것이다. 어떻게 찾는지는 말하지 않고 경사하강법이 실제로 그 값에 도달한다는 보장도 없다. 은닉 뉴런 2개로도 XOR을 표현할 수 있지만 대부분의 초기값에서 실패하고, 8개로 늘리면 대부분 성공하는 실험이 그 구분을 보여준다. 여기에 더해 충분함의 크기가 현실적으로 감당 못 할 수준일 수도 있다. 특정 함수족에서는 얕은 한 층으로 표현하려면 뉴런이 지수적으로 필요한 반면 층을 나누면 훨씬 적게 든다는 결과들이 알려져 있고, 딥러닝이 넓은 쪽 대신 깊은 쪽을 택한 근거가 여기에 있다.

이 내용 다시 읽기 →
상황 적용진단
반달 데이터에 ReLU 신경망을 구성만 바꿔가며 학습했다. 은닉 (2,) 0.850 은닉 (8,) 0.845 은닉 (16, 8) 0.970

뉴런을 네 배로 늘렸는데 제자리이던 정확도가 층을 하나 더 얹자 오른 이유는 무엇인가?

  1. 층을 쌓으면 파라미터 수가 늘어 데이터를 더 많이 기억할 수 있기 때문이다.

    파라미터 수만 보면 뉴런을 옆으로 늘려도 늘어난다. 갈리는 것은 개수가 아니라 경계가 꺾일 수 있는 자리의 수다.

  2. 정답ReLU 경계는 직선 조각을 이어 붙인 모양인데 층을 쌓는 쪽이 조각 수를 훨씬 빠르게 늘리기 때문이다.

    은닉 뉴런 2개면 꺾이는 곳이 한 군데뿐이고 8개로 늘려도 세 군데에 그쳐 큰 줄기가 그대로다. 층을 얹으면 꺾이는 곳이 열 몇 군데로 늘어 경계가 반달 사이를 파고든다.

  3. 층이 둘이면 두 번째 층이 첫 번째 층의 오차를 보정하는 잔차 학습이 일어나기 때문이다.

    잔차를 이어받는 구조는 부스팅의 방식이다. 신경망의 층은 오차가 아니라 앞 층의 출력을 입력으로 받는다.

  4. 은닉 뉴런이 8개일 때 과적합이 시작되어 정확도가 떨어졌다가 층을 늘리며 회복된 것이다.

    0.850과 0.845는 사실상 같은 수준이라 하락으로 읽을 값이 아니다. 두 구성 모두 경계의 표현력이 부족한 상태다.

해설

ReLU를 쓰는 신경망의 결정 경계는 언제나 직선 조각을 이어 붙인 모양이다. 은닉 뉴런이 2개면 꺾이는 곳이 한 군데뿐이고 8개로 늘려도 세 군데로 느는 데 그쳐, 두 반달을 비스듬히 가로지르는 큰 줄기가 그대로 남는다. 정확도가 제자리인 이유다. 층을 하나 더 얹으면 꺾이는 곳이 열 몇 군데로 늘면서 경계가 반달 사이를 파고들고 정확도가 크게 오른다. 뉴런을 옆으로 늘리는 것보다 층을 쌓는 쪽이 조각 수를 훨씬 빠르게 불린다는 뜻이고, 얕은 한 층으로 표현하려면 뉴런이 지수적으로 필요하다는 이론적 결과가 세는 것도 이 조각 수다. 물론 조각이 많을수록 좋은 것은 아니다. 표현력이 커지면 훈련 데이터의 잡음까지 따라가는 위험도 함께 커진다.

이 내용 다시 읽기 →
분석과 판단구조
뉴런 하나의 계산에서 편향 항을 빼고 가중합만 남겼다. z = w₁x₁ + w₂x₂ + ... + wₙxₙ

이 상태에서 표현할 수 없게 되는 것은 무엇인가?

  1. 출력의 부호를 뒤집는 경계다. 편향이 없으면 가중치가 양수 방향으로만 학습된다.

    가중치는 음수도 자유롭게 가질 수 있다. 부호를 뒤집는 것은 편향 없이도 가능하다.

  2. 정답원점을 지나지 않는 경계다. 편향이 없으면 z = 0인 경계면이 항상 원점을 지나야 한다.

    편향은 문턱의 위치를 옮기는 값이다. 없으면 모든 입력이 0일 때 출력도 반드시 0이 되어 경계가 원점에 묶인다.

  3. 입력 사이의 상호작용을 반영하는 경계다. 편향이 두 입력을 잇는 역할을 하기 때문이다.

    상호작용은 은닉층이나 교차항이 담당한다. 편향은 입력과 곱해지지 않으므로 상호작용과 무관하다.

  4. 축에 기울어진 경계다. 편향이 없으면 경계가 좌표축에 평행해진다.

    기울기는 가중치들의 비가 정한다. 편향과 무관하게 어떤 방향으로도 기울 수 있다.

해설

편향은 문턱의 위치를 옮기는 값이다. 이것이 없으면 경계면의 식이 가중합만 0이 되는 자리로 정해져 항상 원점을 지나야 하고, 원점을 지나지 않는 경계는 아예 표현할 수 없다. 편향을 키우면 입력이 작아도 쉽게 켜지고 줄이면 웬만해서는 꺼진다. 선형 회귀의 절편이 하는 역할과 같다. 가중치 쪽은 다른 일을 한다. 각 입력이 결과에 얼마나 세게 작용하는지를 부호까지 포함해 정하는데, 양수면 그 입력이 커질 때 출력이 켜지는 쪽으로 밀리고 음수면 반대로 밀리며 절댓값이 크면 그 입력 하나가 판단을 좌우한다. 그래서 층 하나의 파라미터를 셀 때도 가중치 행렬과 편향 벡터를 함께 세어야 한다.

이 내용 다시 읽기 →

입력이 예측이 되기까지, 순전파의 행렬 연산

원문 읽기 →
개념 확인계산
입력 2개, 은닉 3개(ReLU), 출력 1개인 신경망이다. x = [1.0, 0.5] W1 = [[0.2, 0.4], [0.6, 0.1], [0.3, 0.7]], b1 = 0 W2 = [0.5, 0.3, 0.2], b2 = 0

은닉층을 통과한 값과 출력층으로 들어가는 값은 각각 얼마인가?

  1. a1 = [0.40, 0.65, 0.65], z2 = 1.70. 세 은닉값을 그대로 더한 값이다.

    출력층도 가중치를 곱해 더한다. 단순 합이 아니라 두 번째 층의 가중치와의 내적이다.

  2. a1 = [0.20, 0.60, 0.30], z2 = 0.340. 첫 열만 입력과 곱해진다.

    행렬의 각 행 전체가 입력 벡터와 내적된다. 한 열만 쓰이지 않는다.

  3. 정답a1 = [0.40, 0.65, 0.65], z2 = 0.525. 행렬의 각 행과 입력의 내적이 은닉값이 된다.

    첫 행은 0.2와 0.4에 각각 1.0과 0.5를 곱해 0.40이고, 나머지 두 행도 같은 방식으로 0.65가 나온다. 세 값이 모두 양수라 ReLU를 지나도 그대로다.

  4. a1 = [0, 0, 0], z2 = 0. 편향이 0이라 ReLU가 전부 잘라낸다.

    ReLU가 잘라내는 것은 음수다. 편향이 0이어도 가중합이 양수면 값이 그대로 통과한다.

해설

층 하나의 계산은 이전 층의 출력에 가중치 행렬을 곱하고 편향을 더한 뒤 활성화 함수를 원소마다 적용하는 두 단계다. 여기서 첫 행과 입력의 내적이 0.40이고 나머지 두 행도 0.65로 나오며, 세 값이 모두 양수라 ReLU를 지나도 그대로다. 두 번째 층은 완전히 같은 연산이 반복될 뿐이라 두 번째 가중치와 은닉값의 내적으로 0.525가 나오고, 시그모이드를 통과하면 0.6283이 된다. 정답이 1이라면 손실은 그 값에 로그를 씌워 부호를 뒤집은 0.4647이다. 층이 100개로 늘어도 달라지는 것은 반복 횟수와 행렬의 크기, 활성화 함수뿐이다. 값이 입력에서 출력 방향으로 흘러가는 이 계산을 순전파라 부르고, 추론할 때도 학습할 때도 첫 단계는 여기다.

이 내용 다시 읽기 →
상황 적용구조
def forward_layer(a_prev, W, b, activation):
    z = np.dot(W, a_prev) + b
    a = activation(z)
    return a, (z, a_prev, W)

반환값에 z와 a_prev를 함께 담아 두는 이유는 무엇인가?

  1. 정답학습할 때 기울기 계산에 순전파 도중의 중간값이 그대로 필요하기 때문이다.

    그때 다시 계산하면 순전파를 두 번 하는 셈이 된다. 추론만 할 것이라면 버려도 되는 값이다.

  2. 다음 층의 입력으로 z가 필요하기 때문이다.

    다음 층이 받는 것은 활성화를 통과한 값이다. z는 그 직전 단계의 중간값이다.

  3. 층마다 형상을 확인해 차원 오류를 잡기 위해서다.

    디버깅에 쓸 수는 있지만 반환값에 담아 둘 이유는 되지 못한다. 형상은 그때그때 찍어 보면 된다.

  4. 활성화 함수가 원소별 적용이라 원본 값을 남겨야 되돌릴 수 있기 때문이다.

    되돌릴 일은 없다. 앞으로 필요한 것은 역방향 계산에 쓸 재료이지 역함수가 아니다.

해설

순전파는 추론에도 쓰이고 학습의 첫 단계이기도 하다. 학습에서는 손실을 각 가중치로 미분한 값을 구해야 하는데, 그 계산에 순전파 도중에 나온 중간값이 그대로 필요하다. 그때 다시 계산하면 순전파를 두 번 하는 셈이 되므로 흘러가는 김에 담아 두는 것이다. 추론만 할 것이라면 이 캐시는 버려도 되고, 실제로 추론 전용 모드에서는 메모리를 아끼기 위해 저장하지 않는다. 학습 때 메모리 사용량이 추론보다 훨씬 큰 것도 층마다 이 중간값을 들고 있어야 하기 때문이다. 배치 크기를 키우면 이 값들도 함께 커지므로 메모리가 먼저 한계에 닿는 일이 흔하다.

이 내용 다시 읽기 →
상황 적용설계
집값을 예측하는 회귀 모델을 만들면서 출력층에 시그모이드를 붙이고 손실은 MSE로 두었다. 예측값이 전부 0.9 근처에 몰려 있다.

무엇이 잘못됐는가?

  1. MSE 대신 교차 엔트로피를 써야 시그모이드와 짝이 맞는다.

    손실을 바꿔도 출력이 0과 1 사이에 갇힌 문제는 그대로다. 교차 엔트로피는 확률을 다루는 손실이라 집값에 맞지도 않는다.

  2. 출력 뉴런이 하나뿐이라 값의 범위가 좁아진 것이므로 뉴런을 늘려야 한다.

    회귀에서 출력 뉴런 하나는 정상이다. 범위를 좁힌 것은 뉴런 수가 아니라 활성화 함수다.

  3. 정답회귀에서는 출력 범위를 막으면 안 되므로 출력층에 활성화 함수를 붙이지 않는다.

    시그모이드를 씌우면 결과가 0과 1 사이에 갇혀 집값을 표현할 수 없다. 은닉층은 대체로 ReLU면 되지만 출력층의 활성화와 손실은 문제 유형이 정한다.

  4. 타깃을 0과 1 사이로 정규화하지 않아 생긴 문제이므로 레이블을 스케일링해야 한다.

    타깃을 정규화하면 학습은 되지만 예측을 되돌리는 단계가 하나 더 붙고 범위 밖의 값을 낼 수 없다는 제약이 남는다. 근본 해법이 아니다.

해설

은닉층의 활성화 함수는 대체로 ReLU로 두면 되지만 출력층의 활성화와 손실 함수는 풀려는 문제가 정하고 둘은 한 쌍으로 움직인다. 이진 분류라면 출력 뉴런 하나에 시그모이드와 이진 교차 엔트로피, 다중 클래스라면 클래스 수만큼의 뉴런에 소프트맥스와 범주형 교차 엔트로피, 회귀라면 활성화 함수 없이 평균제곱오차다. 회귀에 활성화 함수를 붙이지 않는 이유는 출력 범위를 막으면 안 되기 때문이다. 시그모이드를 씌우면 결과가 0과 1 사이에 갇혀 집값 같은 값을 표현할 수 없다. 여기서 예측이 한 값 근처에 몰린 것도 모델이 낼 수 있는 범위 자체가 좁혀진 결과이지 학습이 실패한 것이 아니다.

이 내용 다시 읽기 →
분석과 판단구조
# 입력 1,000개, 뉴런 500개, 샘플 10,000개
for i in range(n_samples):
    for j in range(n_neurons):
        Z_loop[i, j] = np.dot(W[j], X[i]) + b[j]   # 약 6초

Z_vec = X @ W.T + b                                 # 약 0.04초

두 방식이 같은 계산을 하는데 백 배 안팎의 차이가 나는 이유는 무엇인가?

  1. 루프 방식은 중간 결과를 배열에 매번 기록하므로 메모리 접근이 병목이 되기 때문이다.

    행렬 곱도 결과를 배열에 쓴다. 갈리는 것은 기록 자체가 아니라 곱셈과 덧셈을 어떤 층위에서 수행하느냐다.

  2. 정답행렬 곱은 C로 작성된 최적화 루틴을 부르고 파이썬 루프는 반복마다 인터프리터를 거치기 때문이다.

    그 루틴은 캐시 블록과 SIMD와 여러 코어까지 동원한다. 같은 이유로 GPU에서도 유리하다. 행렬 곱은 서로 독립적인 곱셈 덧셈의 묶음이라 코어 수천 개에 그대로 흩뿌릴 수 있다.

  3. 행렬 곱이 수학적으로 더 적은 연산으로 같은 결과를 내는 알고리즘을 쓰기 때문이다.

    일반적인 구현의 연산 횟수는 같다. 차이는 알고리즘이 아니라 그 연산을 실행하는 방식에서 나온다.

  4. 행렬 곱은 부동소수점 정밀도를 낮춰 계산하므로 속도를 얻는 대신 오차가 커지기 때문이다.

    정밀도를 낮추지 않는다. 같은 자료형으로 계산하고 결과도 사실상 같다.

해설

행렬로 묶는 것은 표기의 편의가 아니라 성능의 문제다. NumPy의 행렬 곱은 C로 작성된 저수준 루틴을 호출해 캐시에 맞게 블록을 쪼개고 벡터 명령을 쓰고 코어를 나눠 쓰는데, 파이썬 루프는 반복마다 인터프리터를 거치므로 그 최적화를 하나도 받지 못한다. GPU가 빠른 이유도 결이 같다. 행렬 곱은 서로 독립적인 곱셈 덧셈의 묶음이라 코어 수천 개에 그대로 흩뿌릴 수 있다. 여기에 얻는 것이 하나 더 있다. 샘플 축을 행에 얹으면 순전파 공식을 그대로 두고 여러 샘플을 한 번에 처리하게 되므로 배치 처리가 공짜로 따라온다. 실제 학습이 미니배치 단위로 도는 것도 이 성질 덕분이다.

이 내용 다시 읽기 →
상황 적용진단
직접 구현한 순전파에서 오류가 났다. W = np.random.randn(2, 3) np.dot(W, x) # x는 길이 2 → shapes (2,3) and (2,) not aligned

무엇을 고쳐야 하는가?

  1. x를 (2, 1) 형태로 바꿔 열벡터로 만들면 곱셈이 성립한다.

    가운데 차원이 3과 2로 여전히 어긋난다. 형상을 바꿔도 곱셈 규칙을 만족하지 못한다.

  2. 편향의 길이가 뉴런 수와 달라 생긴 문제이므로 b를 맞춰야 한다.

    오류가 난 지점은 편향을 더하기 전의 행렬 곱이다. 편향 문제라면 다른 메시지가 나온다.

  3. 정답가중치 행렬을 (이전 층, 현재 층) 순으로 만든 것이므로 (현재 층, 이전 층)으로 바꾼다.

    이 곱셈 순서에서는 행렬의 각 행이 뉴런 하나의 가중치 벡터여야 하고 열 수가 입력 개수와 같아야 한다. 전치를 써도 되지만 처음부터 순서를 맞추는 편이 낫다.

  4. 배치 축이 빠져 생긴 문제이므로 입력을 (1, 2)로 바꿔야 한다.

    샘플 하나만 넣을 때도 이 곱셈은 성립해야 한다. 배치 축과 무관한 오류다.

해설

행렬 곱은 앞 행렬의 열 수와 뒤 행렬의 행 수가 같아야 성립한다. 신경망에서는 이 규칙이 세 가지 형태로 반복해서 어긋난다. 가중치 행렬을 이전 층과 현재 층 순으로 만든 경우, 편향의 길이가 현재 층 뉴런 수와 다른 경우, 그리고 샘플 하나로는 되는데 배치를 넣으면 실패하는 경우다. 첫 번째가 가장 흔하고, 이 곱셈 순서에서는 행렬의 각 행이 뉴런 하나의 가중치 벡터여야 하므로 현재 층 뉴런 수 곱하기 이전 층 뉴런 수가 맞다. 층마다 가중치와 활성화의 형상을 찍어 보면 어디서 꼬였는지 대개 한 번에 보이고, 프레임워크로 넘어가도 이 습관은 그대로 쓰인다.

이 내용 다시 읽기 →
분석과 판단함정
이진 교차 엔트로피를 직접 구현했더니 학습 도중 손실이 nan으로 바뀐다. L = -[ y·log(a) + (1-y)·log(1-a) ]

가장 먼저 확인해야 할 것은 무엇인가?

  1. 정답 레이블에 0과 1이 아닌 값이 섞여 있는지 확인한다.

    확인할 값이기는 하지만 그 경우 손실은 유한한 값으로 계산된다. nan을 만드는 것은 로그의 입력이다.

  2. 정답예측 확률이 0이나 1에 정확히 닿아 로그가 발산하는지 확인하고 값을 잘라낸다.

    시그모이드는 이론상 0과 1에 닿지 않지만 부동소수점에서는 반올림으로 닿는다. 아주 작은 여유를 두고 잘라내면 막을 수 있다.

  3. 학습률이 너무 커서 가중치가 발산했는지 확인한다.

    가중치가 발산하면 손실이 커지다가 nan이 되므로 이후 증상일 수 있지만, 로그의 입력을 지키는 것이 먼저다.

  4. 배치 안에 한 클래스만 들어 있어 평균이 정의되지 않는지 확인한다.

    한 클래스만 있어도 각 샘플의 손실이 계산되고 평균도 정의된다.

해설

이진 교차 엔트로피는 정답이 1이면 예측 확률에 로그를 씌운 항만, 0이면 그 여집합에 로그를 씌운 항만 남긴다. 어느 쪽이든 확신을 갖고 틀리면 로그가 발산하면서 손실이 급격히 커지고, 예측이 0.9면 손실이 0.1054인 데 반해 0.1이면 2.3026이 된다. 이 비대칭이 학습을 이끄는 힘이지만 구현에서는 위험이기도 하다. 시그모이드의 출력은 이론상 0과 1에 닿지 않아도 부동소수점에서는 반올림으로 닿을 수 있고, 그 순간 로그가 무한대가 되어 손실이 nan으로 무너진다. 그래서 예측값을 아주 작은 여유를 둔 구간으로 잘라 내는 것이 표준이다. 프레임워크가 제공하는 손실 함수를 쓰면 이 처리가 이미 들어 있고, 활성화와 손실을 한 함수로 묶은 구현은 더 안전하다.

이 내용 다시 읽기 →

연쇄 법칙으로 기울기를 되돌리는 역전파

원문 읽기 →
개념 확인구조

연쇄 법칙은 어느 방향으로 세워도 같은 답을 주는데, 역전파가 굳이 출력 쪽에서 시작하는 이유는 무엇인가?

  1. 손실이 출력에서 계산되므로 미분의 출발점이 그쪽에 있어야 수학적으로 성립하기 때문이다.

    사슬은 어느 쪽 끝에서 세워도 성립한다. 갈리는 것은 성립 여부가 아니라 계산량이다.

  2. 앞쪽 층의 기울기가 뒤쪽 층의 기울기보다 작아 먼저 계산하면 정밀도를 잃기 때문이다.

    크기 차이는 생기지만 계산 순서로 정밀도가 결정되지 않는다. 이유는 중복 계산이다.

  3. 정답앞 층의 사슬이 뒤 층의 사슬을 그대로 포함하므로 뒤에서 구한 값을 그대로 재사용할 수 있기 때문이다.

    두 사슬의 앞부분이 글자 하나까지 같다. 입력층부터 시작하면 이 재사용이 불가능해 층이 깊어질수록 낭비가 제곱으로 불어난다.

  4. 순전파가 남긴 중간값이 뒤쪽 층부터 메모리에서 해제되므로 순서를 맞춰야 하기 때문이다.

    캐시는 역전파가 끝날 때까지 유지된다. 해제 순서가 알고리즘의 방향을 정하지 않는다.

해설

출력에 가까운 가중치의 기울기는 사슬이 짧고, 한 층 앞의 가중치는 그 사슬 뒤에 항이 몇 개 더 붙은 형태가 된다. 두 사슬의 앞부분이 글자 하나까지 같다는 뜻이라, 출력층에서 먼저 구해 두면 그 앞 층에서 그대로 재사용할 수 있다. 입력층부터 시작하면 이 재사용이 불가능해서 뒤쪽 층의 편미분을 계산해 놓고 다음 가중치에서 그중 상당수를 또 계산하게 되고, 층이 깊어질수록 낭비가 제곱으로 불어난다. 역방향으로 훑으면 각 층을 정확히 한 번씩만 지나면서 모든 기울기가 나온다. 순전파와 역전파가 같은 계산 그래프를 반대 방향으로 한 번씩 훑는 구조인 것도 이 때문이다. 앞으로 갈 때는 값이 흐르고 뒤로 올 때는 기울기가 흐른다.

이 내용 다시 읽기 →
상황 적용진단
은닉 뉴런 하나짜리 2층 신경망에서 손 계산한 기울기다. ∂L/∂w2 = -0.1192 ∂L/∂w1 = -0.0143 두 사슬의 앞 두 항은 완전히 같다.

여덟 배 가까운 차이는 어디서 났는가?

  1. 정답뒤쪽 항에서 났다. w1 쪽 사슬에는 1보다 작은 수 세 개의 곱이 더 붙는다.

    가중치 0.6, 시그모이드 도함수 0.2403, 입력 0.5를 곱하면 0.072가 된다. 1보다 작은 수를 곱하는 횟수가 늘수록 값이 깎인다.

  2. w1이 w2보다 큰 값이라 상대적인 변화량이 작게 나온 것이다.

    기울기의 크기는 파라미터 값 자체와 직접 비례하지 않는다. 여기서는 사슬에 곱해지는 항의 개수가 차이를 만들었다.

  3. 손실 함수가 제곱 오차라 출력에 가까운 가중치에 더 큰 벌점이 붙기 때문이다.

    손실 함수의 미분은 두 사슬의 첫 항으로 똑같이 들어간다. 층에 따라 다르게 작용하지 않는다.

  4. 입력이 0.5로 작아 첫 층의 가중합이 작아졌기 때문이다.

    입력의 크기도 한 항으로 들어가지만 그것만으로 여덟 배가 되지 않는다. 세 항의 곱이 함께 만든 결과다.

해설

출력에 가까운 가중치의 기울기는 손실의 미분과 활성화 도함수, 그리고 은닉 출력 하나로 끝난다. 한 층 앞의 가중치는 앞 두 항이 똑같고 그 뒤에 가중치와 활성화 도함수와 입력이 더 곱해진다. 여기서 그 세 항의 곱이 0.072라 기울기가 여덟 배 가까이 작아졌다. 1보다 작은 수를 곱하는 횟수가 늘수록 값이 깎인다는 것이 요점이고, 출력에서 멀수록 기울기가 작아지는 이 경향이 층이 깊어질 때 나타나는 기울기 소실의 씨앗이다. 두 층짜리에서도 여덟 배가 벌어졌으니 층이 열 개면 어떻게 되는지는 곱셈만 해 보면 나온다.

이 내용 다시 읽기 →
상황 적용구조
역전파의 핵심 한 줄이다. dz[l-1] = (W[l])ᵀ · dz[l] ⊙ g'(z[l-1]) ⊙는 원소별 곱이다.

이 식의 두 연산은 각각 무엇을 하는가?

  1. 정답전치 곱이 기울기를 이전 층의 차원으로 되돌리고, 원소별 곱이 그 층 활성화 함수의 기울기를 반영한다.

    순전파에서 가중치를 곱해 앞으로 갔던 만큼 전치를 곱해 뒤로 오는 셈이다. 활성화 함수는 원소마다 적용되므로 그 도함수도 원소마다 곱해진다.

  2. 전치 곱이 활성화 함수를 되돌리고, 원소별 곱이 배치 안의 샘플을 평균 낸다.

    배치 평균은 파라미터 기울기를 구할 때 별도로 나누는 단계에서 이루어진다. 이 식에는 평균이 없다.

  3. 전치 곱이 가중치의 기울기를 구하고, 원소별 곱이 그 값을 정규화한다.

    가중치의 기울기는 이 값과 이전 층 출력의 곱으로 따로 구한다. 이 식은 이전 층으로 넘길 값을 만든다.

  4. 전치 곱이 이전 층의 출력을 복원하고, 원소별 곱이 손실 함수의 미분을 적용한다.

    출력을 복원하지 않고 캐시에 이미 남아 있다. 손실의 미분은 마지막 층의 출발점에만 들어간다.

해설

역전파는 마지막 층에서 출발점을 정하고 나면 두 식의 반복이다. 현재 층의 값에서 그 층의 파라미터 기울기를 뽑고, 같은 값을 이전 층으로 넘긴다. 넘기는 식이 이 한 줄이다. 가중치 행렬의 전치를 곱해 기울기를 이전 층의 차원으로 되돌리고, 그 층 활성화 함수의 도함수를 원소마다 곱한다. 순전파에서 가중치를 곱해 앞으로 갔던 만큼 전치를 곱해 뒤로 오는 셈이다. 구현할 때는 가중치 기울기가 원래 가중치 행렬과 같은 크기로 나오는지 확인하는 것만으로도 전치를 빠뜨렸거나 축을 잘못 잡은 실수를 대부분 거를 수 있다. 이 한 줄에 딥러닝의 고질적인 문제도 통째로 들어 있다. 층마다 곱해지는 도함수가 1보다 작으면 기울기가 사라지고 가중치가 크면 폭발한다.

이 내용 다시 읽기 →
분석과 판단계산
시그모이드 도함수의 최댓값은 0에서의 0.25이고 그 바깥에서는 더 작다. 층을 하나 거칠 때마다 이 값이 한 번씩 곱해진다.

10층을 거치면 기울기는 최대 어느 정도까지 남는가?

  1. 약 0.025다. 기울기가 열 층에 고르게 나뉘어 10분의 1로 줄어든다.

    나눠 받는 것이 아니라 층마다 곱해진다. 곱셈 사슬이라 감소가 기하급수적이다.

  2. 정답약 0.00000095다. 0.25를 열 번 곱한 값이고 사실상 0이다.

    0인 기울기로는 가중치가 움직이지 않으므로 깊은 신경망의 앞부분이 학습을 멈춘다. ReLU의 도함수는 양수 구간에서 정확히 1이라 곱해도 크기가 줄지 않는다.

  3. 약 0.25다. 최댓값이 0.25이므로 몇 층을 거쳐도 그 값이 상한이다.

    상한은 층마다 적용되고 그 값들이 서로 곱해진다. 열 층을 거치면 상한 자체가 훨씬 작아진다.

  4. 약 0.0625다. 처음 두 층에서만 도함수가 곱해지고 이후에는 가중치만 작용한다.

    층마다 활성화 함수가 있으므로 그 도함수도 층마다 곱해진다. 두 번에서 멈추지 않는다.

해설

층을 하나 거칠 때마다 활성화 함수의 도함수가 한 번씩 곱해진다. 시그모이드 도함수의 최댓값이 0.25이므로 아무리 좋아도 층마다 4분의 1로 줄고, 10층이면 100만분의 1 수준이 된다. 0인 기울기로는 가중치가 움직이지 않으므로 깊은 신경망의 앞부분이 학습을 멈추는데 이것이 기울기 소실이다. ReLU가 시그모이드를 밀어낸 가장 큰 이유가 여기 있다. ReLU의 도함수는 양수 구간에서 정확히 1이라 곱해도 크기가 줄지 않는다. 반대쪽으로 터지는 경우도 있다. 가중치가 크면 전치를 곱할 때마다 기울기가 커져서 층마다 두 배씩만 불어나도 10층이면 1000배가 넘고, 업데이트 폭이 폭발하며 손실이 발산한다. 학습 중 갑자기 nan을 보면 대개 이쪽이다.

이 내용 다시 읽기 →
상황 적용운영
역전파를 직접 구현했는데 손실이 잘 줄지 않는다. 코드는 오류 없이 돌아간다. ∂L/∂w ≈ ( L(w+ε) - L(w-ε) ) / 2ε

이 수치 미분을 어떻게 써야 하는가?

  1. 정답구현 직후 두 기울기의 상대 오차를 비교해 검증하고, 학습에는 켜 두지 않는다.

    미분 공식을 하나 틀려도 코드는 잘 돌아가므로 이런 확인이 필요하다. 다만 파라미터 하나마다 순전파를 두 번 돌려야 해서 학습에 켜 두면 감당이 안 된다.

  2. 학습 내내 함께 계산해 두 값의 평균을 기울기로 쓰면 안정성이 올라간다.

    해석적 미분이 정확하므로 평균을 낼 이유가 없다. 비용만 크게 늘어난다.

  3. 역전파 대신 이 방식으로 기울기를 구하면 구현 실수를 원천적으로 없앨 수 있다.

    파라미터마다 순전파를 두 번 돌려야 하므로 파라미터가 수만 개인 신경망에서는 현실적이지 않다.

  4. 손실이 줄지 않는 원인이 학습률이므로 이 값으로 적정 학습률을 추정한다.

    이 식은 기울기를 근사할 뿐 학습률과 무관하다. 먼저 확인할 것은 기울기가 맞느냐다.

해설

미분 공식을 하나 틀려도 코드는 오류 없이 돌아간다. 손실이 안 줄거나 발산할 뿐이라 버그를 찾기가 매우 어렵다. 그래서 구현 직후에는 아주 작은 값으로 파라미터를 양쪽으로 흔들어 수치 미분을 구하고 해석적으로 구한 기울기와 비교한다. 한쪽으로만 흔드는 것보다 양쪽으로 흔드는 중앙 차분이 오차가 작고, 두 기울기 벡터의 차이를 크기의 합으로 나눈 상대 오차가 아주 작으면 통과로 본다. 다만 이것은 디버깅 전용이다. 파라미터 하나마다 순전파를 두 번 돌려야 하므로 파라미터가 수만 개인 신경망에서 학습에 켜 두면 감당이 안 된다. 확인이 끝나면 꺼 두고 해석적 기울기만 쓴다.

이 내용 다시 읽기 →
분석과 판단구조

프레임워크의 자동 미분이 임의의 연산 조합을 다 처리할 수 있는 이유는 무엇인가?

  1. 미리 정의된 층 조합만 지원하고 그 조합마다 기울기 공식을 하드코딩해 두었기 때문이다.

    사용자가 새로 조합한 연산에서도 동작한다. 조합의 목록을 미리 알 필요가 없는 구조다.

  2. 정답각 노드가 자기 지역 미분만 알고 상류에서 온 기울기에 그것을 곱해 하류로 넘기면 되기 때문이다.

    노드는 전체 네트워크의 모양을 알 필요가 없다. 곱셈 노드라면 상대편 값이 지역 미분이고, 그것만으로 사슬이 자동으로 엮인다.

  3. 연산 그래프를 수식으로 전개한 뒤 기호 미분으로 닫힌 형태의 도함수를 구하기 때문이다.

    기호 미분은 식이 커질수록 폭발적으로 길어진다. 자동 미분은 수식을 전개하지 않고 값과 지역 미분만 다룬다.

  4. 수치 미분을 병렬로 계산해 파라미터 수가 많아도 감당할 수 있기 때문이다.

    수치 미분은 파라미터마다 순전파를 두 번 돌려야 해서 비용이 크다. 자동 미분은 해석적 기울기를 구한다.

해설

계산 그래프의 언어로 말하면 각 노드는 자기 지역 미분만 알고 있으면 된다. 곱셈 노드라면 한쪽 입력에 대한 편미분이 상대편 값 그 자체다. 역전파에서 노드가 하는 일은 상류에서 흘러온 기울기에 자기 지역 미분을 곱해 하류로 넘기는 것뿐이고, 전체 네트워크의 모양은 알 필요가 없다. 그래서 사용자가 어떤 순서로 연산을 조합하든 그래프만 기록해 두면 사슬이 자동으로 엮인다. 프레임워크의 자동 미분이 임의의 조합을 처리할 수 있는 이유가 이것이다. 실무에서 이 미분을 손으로 짤 일은 거의 없지만 구조를 알아야 하는 이유는 남는다. 층마다 곱해지는 항이 1보다 작으면 기울기가 사라지고 크면 폭발하는데, ReLU도 가중치 초기화도 배치 정규화도 우회 연결도 전부 그 곱셈 사슬을 1 근처로 붙들어 두려는 시도다.

이 내용 다시 읽기 →

활성화 함수는 왜 ReLU로 정착했나

원문 읽기 →
개념 확인구조
활성화 함수를 지정하지 않고 선형 층만 두 개 쌓았다. z2 = W2(W1·x + b1) + b2 = (W2·W1)x + (W2·b1 + b2)

이 전개가 말해주는 것은 무엇인가?

  1. 두 층의 파라미터가 서로 상쇄되어 학습이 진행되지 않는다.

    학습은 진행되고 손실도 줄어든다. 다만 도달할 수 있는 모델이 한 층짜리와 같을 뿐이다.

  2. 정답층을 몇 개 쌓아도 결과가 한 층짜리 선형 변환과 같아 깊이가 표현력을 늘리지 못한다.

    선형 함수를 아무리 합성해도 선형이다. 비선형 활성화 함수는 이 붕괴를 막는 장치이고, 그것이 있어야 깊이가 의미를 갖는다.

  3. 편향 항이 뒤쪽 층으로 모두 옮겨가므로 앞쪽 층의 편향을 생략해도 된다.

    편향이 하나로 묶이는 것은 이 전개의 부산물이지 요점이 아니다. 문제는 가중치 쪽이 하나로 합쳐진다는 데 있다.

  4. 두 가중치 행렬의 곱이 항상 특이행렬이 되어 정보가 손실된다.

    곱이 특이행렬이 되지 않는 경우가 대부분이다. 손실이 아니라 표현력의 한계가 문제다.

해설

신경망의 한 층은 선형 변환으로 입력을 섞고 활성화 함수를 씌워 내보내는 두 단계다. 앞쪽 절반은 어느 층이나 똑같으므로, 층을 깊게 쌓을 수 있느냐는 뒤에 붙는 함수가 정한다. 활성화 함수가 항등 함수라면 두 층의 출력이 하나로 묶여 한 층짜리 선형 변환과 같아지고, 100층을 쌓아도 표현력이 한 층과 동일하다. 선형 함수를 아무리 합성해도 선형이기 때문이다. 비선형 활성화 함수는 이 붕괴를 막는 장치다. 실무에서 걸리기 쉬운 자리이기도 하다. 주요 프레임워크의 완전 연결 층은 기본값이 활성화 없음이라, 직접 지정하지 않으면 선형 층만 쌓이고 이 붕괴가 그대로 일어난다.

이 내용 다시 읽기 →
상황 적용진단
tanh의 도함수 최댓값은 1로 시그모이드의 네 배다. 그런데도 깊은 망에서는 결국 같은 곳에서 막혔다.

왜 그런가?

  1. 출력이 음수까지 열려 있어 층을 거칠수록 부호가 뒤집히며 기울기가 상쇄되기 때문이다.

    부호 대칭은 오히려 tanh의 장점이다. 시그모이드의 부호 쏠림 문제를 해결한 부분이다.

  2. 정답최댓값 1은 입력이 0일 때뿐이고 절댓값이 조금만 커져도 도함수가 0에 붙는 포화 구간이 남기 때문이다.

    절댓값이 2.5만 넘어도 도함수가 0.03 아래로 떨어진다. 상한을 네 배 올렸을 뿐 포화의 벽 자체는 그대로다.

  3. 지수 계산이 시그모이드보다 두 배 비싸 학습 시간이 늘어나기 때문이다.

    계산 비용은 별개의 단점이고 학습이 막히는 원인이 아니다.

  4. 도함수가 1을 넘는 구간이 있어 기울기가 폭발하기 때문이다.

    tanh 도함수는 1을 넘지 않는다. 최댓값이 정확히 1이다.

해설

tanh는 시그모이드를 위아래로 늘려 원점 대칭으로 만든 함수다. 출력이 음수까지 열려 부호 쏠림이 사라지고 도함수의 최댓값이 1로 올라간다. 그러나 그 최댓값은 입력이 0일 때뿐이고, 절댓값이 2.5만 넘어도 도함수가 0.03 아래로 떨어진다. 상한을 네 배 올렸을 뿐 포화의 벽 자체는 그대로 남아 있어서 깊은 망에서는 결국 같은 곳에서 막혔다. ReLU는 이 문제를 다르게 푼다. 필요한 구간에서 도함수를 정확히 1로 고정해 층을 몇 개 거치든 크기가 줄지 않게 만들고, 대신 반대편 절반을 완전히 포기한다. 활성화 함수를 고르는 문제가 역전파에서 곱해질 수를 얼마로 둘 것인가의 문제라는 말이 이런 뜻이다.

이 내용 다시 읽기 →
상황 적용함정
ReLU 은닉층을 쓰는 망에서 학습률을 크게 잡았더니 일부 뉴런의 출력이 모든 입력에서 0으로 고정됐다.

무슨 일이 일어났고 어떻게 대응하는가?

  1. 정답가중합이 늘 음수가 돼 기울기를 못 받는 상태다. 학습률을 낮추거나 음의 구간에 기울기를 남기는 계열로 바꾼다.

    음의 구간에서 도함수가 0이라 가중치가 갱신되지 않고, 그 상태에서 빠져나올 방법도 없다. 한 번의 큰 업데이트가 뉴런을 이 상태로 밀어넣기 쉽다.

  2. 그 뉴런의 가중치가 0으로 수렴한 것이므로 규제를 약하게 걸면 회복된다.

    가중치가 0이 된 것이 아니라 가중합이 계속 음수인 것이다. 규제 강도와 무관하다.

  3. ReLU의 출력이 희소해지는 정상적인 동작이므로 손댈 필요가 없다.

    절반가량이 0이 되는 것은 정상이지만, 특정 뉴런이 모든 입력에서 0으로 고정되는 것은 그 뉴런이 영구히 죽은 상태다.

  4. 출력층의 활성화 함수와 손실 함수의 짝이 맞지 않아 기울기가 전달되지 않은 것이다.

    짝이 어긋나면 망 전체의 학습이 흔들린다. 일부 뉴런만 고정되는 증상과 맞지 않는다.

해설

ReLU는 음의 구간에서 도함수가 0이다. 어떤 뉴런의 입력이 모든 데이터에서 음수가 되는 상태에 빠지면 그 뉴런은 기울기를 한 방울도 받지 못하고, 가중치가 갱신되지 않으니 그 상태에서 나올 방법도 없다. 영구히 죽은 뉴런이 되는 것이고 이것을 dying ReLU라 부른다. 학습률이 크면 한 번의 큰 업데이트가 뉴런을 이 상태로 밀어넣기 쉬우므로 학습률을 낮추는 것이 첫 대응이고, 음의 구간에 아주 작은 기울기를 남기는 계열로 바꾸는 것이 두 번째다. 그렇게 하면 음수 입력에서도 갱신량이 0이 되지 않아 되돌아 나올 길이 열린다. 그 작은 기울기를 상수로 두지 않고 역전파로 학습시키는 변형도 있고, 층마다 적절한 누출량을 망이 직접 정하는 셈이 된다.

이 내용 다시 읽기 →
분석과 판단구조
두 함수의 정의다. GELU(z) = z · Φ(z) (Φ는 표준정규분포의 누적분포함수) Swish(z) = z · σ(z)

이 형태가 ReLU와 다른 점은 무엇인가?

  1. 출력 범위가 유계라 층을 거칠수록 값이 발산하지 않는다.

    두 함수 모두 양의 방향으로는 무한히 열려 있다. 아래쪽만 유계다.

  2. 도함수가 어디서나 1이라 기울기가 정확히 보존된다.

    도함수의 최댓값이 1을 조금 넘고 구간마다 값이 다르다. 정확히 1로 고정되는 것은 ReLU다.

  3. 정답통과와 차단을 0에서 이분법으로 가르는 대신 입력에 통과 확률을 곱해 경계를 부드럽게 문지른다.

    값이 크면 거의 그대로 나가고 작으면 거의 0이 된다. 경계 부근이 매끄러워 미세한 입력 차이가 출력 차이로 남는다.

  4. 음의 구간에 일정한 기울기를 두어 죽은 뉴런을 원천적으로 막는다.

    일정한 기울기를 두는 것은 누출형 변형의 방식이다. 여기서는 게이팅 값이 입력에 따라 연속적으로 변한다.

해설

ReLU는 0을 기준으로 통과와 차단을 이분법으로 가른다. 이 두 함수는 그 경계를 확률로 문지른다. 입력에 이 값이 통과할 만큼 큰가의 확률을 곱하는 구조라 값이 크면 거의 그대로 나가고 작으면 거의 0이 된다. 경계 부근이 매끄러워 미세한 입력 차이가 출력 차이로 남고, 입력이 살짝 음수인 구간에서 출력이 아주 조금 음수가 되는 비단조 구간도 생긴다. 앞쪽은 정규분포 누적분포함수를 쓰는데 그 계산이 부담이라 실전에서는 근사식을 쓰고, 뒤쪽은 같은 발상을 시그모이드로 더 싸게 구현한 형태다. 트랜스포머 계열에서 앞쪽이 사실상 기본값이고 일부 비전 모델에서는 뒤쪽이 ReLU를 대체해 성능 향상을 보였다.

이 내용 다시 읽기 →
상황 적용구조

시그모이드의 출력이 항상 양수라는 성질이 최적화에 미치는 영향은 무엇인가?

  1. 출력이 확률로 해석되므로 은닉층에서도 각 뉴런의 활성 정도를 확률로 읽을 수 있다.

    은닉층의 출력은 확률로 해석할 근거가 없다. 그리고 이것은 최적화에 미치는 영향도 아니다.

  2. 정답다음 층으로 들어가는 입력의 부호가 한쪽으로 쏠려 한 뉴런의 가중치 기울기가 모두 같은 부호가 된다.

    가중치들이 다 함께 커지거나 다 함께 작아지는 방향으로만 움직여 최적화 경로가 지그재그를 그린다. tanh가 원점 대칭인 것이 이 문제를 없앤다.

  3. 출력이 양수라 다음 층의 가중합이 항상 양수가 되어 포화 구간에 빠르게 진입한다.

    가중치가 음수일 수 있으므로 가중합의 부호는 정해지지 않는다. 포화와는 별개의 문제다.

  4. 손실 함수가 볼록성을 잃어 지역 최솟값이 늘어난다.

    다층 신경망의 손실은 어떤 활성화 함수를 쓰든 볼록하지 않다. 출력 부호와 무관하다.

해설

시그모이드의 출력이 항상 양수이면 다음 층이 받는 입력의 부호가 한쪽으로 쏠린다. 한 뉴런에 들어오는 가중치들의 기울기는 그 입력에 비례하므로 모두 같은 부호가 되고, 가중치들이 다 함께 커지거나 다 함께 작아지는 방향으로만 움직인다. 그 결과 최적화 경로가 지그재그를 그려 수렴이 느려진다. tanh가 원점 대칭이라는 점이 이 문제를 없앤 부분이고, ReLU 이후에도 출력 평균을 0 근처로 두려는 시도가 이어지는 이유이기도 하다. 시그모이드에는 문제가 하나 더 있다. 지수 계산이 비교 연산보다 비싸서 수백만 뉴런에 매 순전파마다 적용되면 무시하기 어려운 비용이 된다. 은닉층에 시그모이드를 쓸 이유는 없고 이진 분류의 출력층에서만 쓴다.

이 내용 다시 읽기 →
분석과 판단판단
ReLU 대신 ELU 계열을 검토하고 있다. ELU: z > 0이면 z, 아니면 α(e^z - 1) SELU: ELU에 고정 상수 두 개를 곱한 형태

이 계열이 얻는 것과 반납하는 것은 무엇인가?

  1. 죽은 뉴런을 완전히 없애는 대신 도함수 최댓값이 1보다 작아져 기울기가 조금씩 줄어든다.

    양의 구간에서는 도함수가 여전히 1이다. 기울기 보존은 그대로 유지된다.

  2. 정답출력 평균이 0에 가까워져 층 사이 신호가 안정되는 대신 지수 계산이 붙어 속도 이점을 일부 반납한다.

    입력이 작아질수록 음수 쪽 값에 부드럽게 수렴하므로 출력 평균이 0 근처로 온다. 대신 지수를 계산해야 해서 비교 하나로 끝나던 이점이 사라진다.

  3. 계산이 더 빨라지는 대신 음의 구간에서 기울기가 0이 되어 죽은 뉴런이 늘어난다.

    두 항목 모두 반대다. 계산은 느려지고 음의 구간에서도 기울기가 남는다.

  4. 출력 범위가 유계가 되어 기울기 폭발을 막는 대신 표현력이 줄어든다.

    양의 방향으로는 무한히 열려 있어 유계가 아니다. 폭발 방지 장치도 아니다.

해설

ELU 계열은 꺾인 직선 대신 지수 곡선으로 음의 구간을 처리한다. 입력이 작아질수록 음수 쪽 상수에 부드럽게 수렴하므로 출력 평균이 0에 가까워지고 그만큼 층 사이 신호가 안정된다. 대신 지수를 계산해야 해서 비교 하나로 끝나던 ReLU의 속도 이점을 일부 반납한다. 여기에 고정 상수 두 개를 곱한 변형은 조건이 맞으면 층 출력이 스스로 정규화되는 성질을 갖지만, 완전 연결 망과 특정 초기화를 요구해서 합성곱이나 트랜스포머 계열에서는 쓰이지 않는다. 결국 은닉층의 출발점은 여전히 ReLU다. 기울기 보존과 계산 비용 두 축에서 동시에 유리한 함수는 이쪽이고, 다른 함수는 ReLU로 학습이 안 될 때 꺼내는 카드다.

이 내용 다시 읽기 →

SGD에서 Adam까지, 옵티마이저는 무엇을 개선해왔나

원문 읽기 →
개념 확인구조

옵티마이저를 SGD에서 Adam으로 바꾸면 무엇이 달라지는가?

  1. 역전파가 더 정확한 기울기를 계산해 준다.

    기울기를 계산하는 절차는 옵티마이저와 무관하다. 어떤 옵티마이저를 쓰든 같은 기울기가 나온다.

  2. 손실 함수의 지형이 완만해져 지역 최솟값이 줄어든다.

    손실 지형은 모델과 데이터가 정한다. 옵티마이저는 그 위를 어떻게 움직일지만 바꾼다.

  3. 정답같은 기울기를 파라미터에 반영하는 규칙이 달라진다.

    그대로 쓸지, 과거와 평균 낼지, 크기로 나눌지를 정하는 것이 전부다. 기울기 자체를 더 정확하게 만드는 일과는 무관하다.

  4. 미니배치 크기가 자동으로 조정되어 갱신 빈도가 달라진다.

    배치 크기는 별도의 하이퍼파라미터다. 옵티마이저가 건드리지 않는다.

해설

옵티마이저는 역전파가 계산해 준 기울기를 어떤 규칙으로 파라미터에 반영할 것인가의 문제다. 같은 기울기를 놓고 그대로 쓸지, 과거와 평균 낼지, 크기로 나눌지를 정하는 것뿐이다. 그 선택은 두 축으로 갈렸다. 방향을 다듬는 축에서 관성을 더하는 방식이 나왔고, 크기를 다듬는 축에서 파라미터마다 보폭을 달리하는 방식이 나왔다. Adam은 두 축을 한 식에 합치고 초기 편향만 따로 보정한 것이고, 그 뒤의 변형들도 대체로 이 두 축 위 어딘가에 있다. 학습률 스케줄은 또 다른 축이다. 어떤 옵티마이저를 고르든 학습률을 시간에 따라 어떻게 움직일지는 따로 정해야 하고, 실무에서 성능 차이를 가르는 것은 옵티마이저 선택보다 이쪽인 경우가 적지 않다.

이 내용 다시 읽기 →
상황 적용구조
Momentum은 기울기를 그대로 쓰지 않고 지수 가중 이동 평균을 속도로 두고 그 속도로 움직인다. v = β·v + (1-β)·∇J, β = 0.9 w = w - α·v

이 평균이 좁은 축의 진동과 골짜기 방향의 전진에 각각 어떻게 작용하는가?

  1. 정답진동 성분은 부호가 매 스텝 뒤집혀 평균에서 상쇄되고, 골짜기 성분은 부호가 같아 누적되며 속도가 붙는다.

    같은 평균 한 번이 두 방향에 정반대로 작용한다. 안장점에서도 기울기가 0에 가까워질 뿐 남은 속도가 관성으로 밀어주므로 멈추지 않고 지나간다.

  2. 진동 성분은 크기가 커서 평균에서 더 큰 비중을 받고, 골짜기 성분은 작아 억제된다.

    방향이 반대다. 크기가 아니라 부호의 일관성이 누적 여부를 정한다.

  3. 두 성분 모두 같은 비율로 줄어들지만 진동 쪽이 먼저 임계값 아래로 내려간다.

    골짜기 성분은 줄지 않고 오히려 커진다. 두 성분에 같은 비율이 적용되지 않는다.

  4. 평균이 기울기의 크기를 정규화해 두 방향의 보폭이 같아진다.

    크기를 정규화하는 것은 기울기 제곱의 평균으로 나누는 다른 방식이다. 여기서는 방향을 다듬는다.

해설

관성을 더하는 방식은 기울기의 지수 가중 이동 평균을 속도로 두고 그 속도로 움직인다. 감쇠율이 0.9면 현재 기울기의 기여는 10%뿐이고 나머지는 과거 방향에서 온다. 이 한 줄이 두 문제를 동시에 건드린다. 좁은 축을 가로지르는 진동은 부호가 매 스텝 뒤집히므로 평균을 내면 서로 상쇄되고, 골짜기를 따라가는 성분은 부호가 계속 같으니 누적되어 속도가 붙는다. 진동은 줄고 전진은 빨라진다. 안장점에서도 마찬가지다. 기울기가 0에 가까워질 뿐 속도에 남은 과거 방향이 관성으로 밀어주므로 멈추지 않고 지나간다. 파라미터가 수백만 개인 공간에서는 지역 최솟값보다 안장점이 압도적으로 많으므로 이 성질이 실제로 값을 한다.

이 내용 다시 읽기 →
상황 적용구조
RMSProp의 갱신식이다. s = β·s + (1-β)·(∇J)² w = w - α / (√s + ε) · ∇J

이 방식이 관성을 더하는 방식과 갈리는 지점은 무엇인가?

  1. 관성 방식이 안장점을 다루고 이쪽은 지역 최솟값을 다룬다.

    지역 최솟값을 직접 다루지는 않는다. 이쪽이 다루는 것은 차원마다 기울기 크기가 다르다는 문제다.

  2. 관성 방식이 과거를 보고 이쪽은 미래 위치의 기울기를 미리 본다.

    앞자리에서 기울기를 구하는 것은 관성 방식의 변형이 하는 일이다. 이 식에는 그런 선행 계산이 없다.

  3. 관성 방식이 학습률을 자동으로 낮추고 이쪽은 배치 크기를 조정한다.

    둘 다 배치 크기를 건드리지 않고, 학습률을 낮추는 것도 이쪽의 동작에 가깝다.

  4. 정답관성 방식이 기울기의 방향을 손보고 이쪽은 크기를 손봐 파라미터마다 보폭을 다르게 한다.

    최근에 크게 흔들린 파라미터는 분모가 커져 보폭이 줄고 거의 움직이지 않던 파라미터는 보폭이 커진다. 진동을 사후에 상쇄하는 대신 애초에 덜 튀게 만든다.

해설

관성을 더하는 방식이 기울기의 방향을 손봤다면 이쪽은 크기를 손본다. 기울기 제곱의 이동 평균을 파라미터마다 따로 들고 다니면서 그 제곱근으로 보폭을 나누므로, 최근에 크게 흔들린 파라미터는 보폭이 줄고 거의 움직이지 않던 파라미터는 보폭이 커진다. 학습률은 여전히 하나지만 각 파라미터가 겪는 실질 학습률은 자기 이력에 맞게 조정된다. 찌그러진 등고선에 대입하면 효과가 분명하다. 좁은 축은 기울기가 크니 보폭이 줄어 진동이 잦아들고, 긴 축은 기울기가 작으니 보폭이 커져 전진이 빨라진다. 앞의 방식이 진동을 사후에 상쇄한다면 이쪽은 애초에 덜 튀게 만드는 셈이다. 두 축이 서로 다른 문제를 다루므로 합칠 수 있고, 그 결과가 Adam이다.

이 내용 다시 읽기 →
분석과 판단계산
Adam은 두 모멘트를 0에서 출발시키고 편향을 보정한다. m̂ = m / (1 - β₁ᵗ), β₁ = 0.9 첫 스텝에서 m₁ = 0.1·g₁이다.

이 보정이 하는 일과 사라지는 시점은 언제인가?

  1. 정답0.1로 나눠 첫 기울기를 그대로 복원하고, 스텝이 쌓이면 분모가 1에 수렴해 저절로 사라진다.

    0에서 출발하므로 초반의 이동 평균은 진짜 평균보다 0쪽으로 끌려 있다. 감쇠율의 거듭제곱이 0으로 가면서 보정이 자연히 꺼진다.

  2. 기울기의 분산을 1로 맞춰 스케일을 정규화하고, 손실이 수렴하면 꺼진다.

    정규화는 2차 모멘트로 나누는 부분이 담당한다. 이 보정은 초기 치우침만 되돌린다.

  3. 학습 초반의 큰 기울기를 눌러 발산을 막고, 학습률 스케줄이 끝나면 꺼진다.

    누르는 것이 아니라 오히려 키운다. 그리고 스케줄과 무관하게 스텝 수만으로 꺼진다.

  4. 두 모멘트의 비율을 맞춰 갱신 방향을 안정시키고, 배치가 한 바퀴 돌면 꺼진다.

    두 모멘트는 각각 자기 감쇠율로 따로 보정된다. 에폭 단위와도 무관하다.

해설

두 모멘트를 0에서 출발시키므로 학습 초반의 이동 평균은 진짜 평균보다 0쪽으로 끌려 있다. 감쇠율이 0.9면 첫 스텝의 1차 모멘트가 실제 기울기의 10분의 1밖에 안 되는데, 같은 값으로 나누면 원래 기울기가 복원된다. 스텝이 쌓이면 감쇠율의 거듭제곱이 0으로 수렴해 분모가 1에 가까워지고 보정은 저절로 사라진다. 여기에 덤이 하나 붙는다. 첫 스텝에서 두 모멘트가 각각 기울기와 기울기의 제곱이 되므로 갱신량이 사실상 부호만 남은 학습률 크기가 된다. 기울기가 100이든 0.001이든 같은 크기로 움직인다는 뜻이고, 기울기 크기가 아주 작은 상수 근처까지 내려가야 비로소 보폭이 줄기 시작한다. Adam에서 학습률이 한 스텝에 파라미터가 움직일 수 있는 최대치에 가까운 의미를 갖는 이유가 여기에 있다.

이 내용 다시 읽기 →
상황 적용구조

AdamW가 weight decay를 기울기에서 빼내 갱신식 끝에 따로 붙인 이유는 무엇인가?

  1. 정답규제 항이 기울기에 섞이면 2차 모멘트로 함께 나눠져 기울기가 큰 파라미터일수록 규제가 약해지기 때문이다.

    규제를 가장 세게 받아야 할 파라미터에서 규제가 가장 약해지는 셈이다. 밖으로 꺼내면 모든 파라미터가 같은 비율로 줄어든다.

  2. 규제 항이 편향 보정에 포함되어 학습 초반에 과도하게 증폭되기 때문이다.

    편향 보정은 초반의 치우침을 되돌릴 뿐 특정 항만 증폭하지 않는다. 문제는 분모 쪽이다.

  3. 규제 항의 미분이 상수라 이동 평균에 넣으면 값이 발산하기 때문이다.

    이 항의 미분은 상수가 아니라 가중치에 비례하고 발산하지도 않는다.

  4. SGD에서도 두 방식이 다른 결과를 내므로 통일된 정의가 필요했기 때문이다.

    SGD에서는 두 방식이 수학적으로 같다. 갈리는 것은 적응적 스케일링이 끼어드는 옵티마이저에서다.

해설

L2 규제는 비용 함수에 가중치 제곱 항을 더하는 것이고 그 미분은 가중치에 비례하는 항이다. SGD에서는 이 항이 갱신식에 그대로 더해지므로 L2 규제와 weight decay가 수학적으로 같다. Adam에서는 같지 않다. 이 항이 기울기에 섞여 들어가면 2차 모멘트의 제곱근으로 함께 나눠지는데, 기울기가 큰 파라미터일수록 분모가 커서 규제가 약해진다. 규제를 가장 세게 받아야 할 파라미터에서 규제가 가장 약해지는 셈이다. AdamW의 해법은 이 항을 기울기에서 빼내 갱신식 끝에 따로 붙이는 것이다. 적응적 스케일링을 거치지 않으므로 모든 파라미터가 같은 비율로 줄어든다. 차이는 한 항의 위치뿐이지만 일반화 성능이 나아졌고 지금은 트랜스포머 계열의 기본값이다.

이 내용 다시 읽기 →
분석과 판단함정
논문에서 본 학습률을 PyTorch의 SGD(momentum=0.9)에 그대로 옮겨 적었더니 학습이 발산한다. 글의 표기 v = β·v + (1-β)·∇J PyTorch v = β·v + ∇J

무엇을 확인해야 하는가?

  1. 감쇠율의 부호가 반대라 속도가 매 스텝 뒤집히는지 확인한다.

    두 표기 모두 감쇠율이 양수로 곱해진다. 부호는 같다.

  2. 정답PyTorch 쪽에 계수가 빠져 실질 학습률이 10배 크므로 학습률을 그만큼 낮춰야 한다.

    수렴 거동은 같지만 속도의 정상 상태 크기가 감쇠율의 여집합으로 나눈 만큼 차이 난다. 감쇠율이 0.9면 정확히 10배다.

  3. PyTorch 구현이 관성을 누적하지 않으므로 별도의 스케줄러를 붙여야 한다.

    누적은 정상적으로 이루어진다. 오히려 계수가 없어 더 크게 누적된다.

  4. 두 식이 수학적으로 다른 알고리즘이므로 관성 계수를 다시 튜닝해야 한다.

    같은 알고리즘의 다른 표기다. 감쇠율은 그대로 두고 학습률만 맞추면 된다.

해설

관성을 더하는 방식에는 표기가 두 가지 있다. 지수 가중 이동 평균 형태로 쓰면 현재 기울기 앞에 감쇠율의 여집합이 곱해지고, 널리 쓰이는 구현에서는 그 계수 없이 기울기를 그대로 더한다. 수렴 거동은 같지만 속도가 도달하는 크기가 그 계수만큼 차이 나므로 실질 학습률이 감쇠율의 여집합으로 나눈 배수만큼 달라진다. 감쇠율이 0.9면 정확히 10배다. 다른 글이나 논문의 학습률을 그대로 옮겨 쓸 때 이 차이를 확인하지 않으면 발산하거나 반대로 거의 움직이지 않는다. 하이퍼파라미터를 옮길 때 이름과 값만 보지 말고 그 값이 어떤 식에 들어가는지부터 확인해야 한다는 사례다.

이 내용 다시 읽기 →

신경망 학습을 안정시키는 가중치 초기화와 BatchNorm, Dropout

원문 읽기 →
개념 확인구조

모든 가중치를 0으로 초기화하면 무엇이 문제인가?

  1. 기울기가 0이 되어 어떤 파라미터도 갱신되지 않는다.

    출력 편향처럼 갱신되는 파라미터가 남고, 시그모이드 계열이면 기울기가 0이 아니라 갱신도 일어난다. 진짜 문제는 갱신 여부가 아니라 모든 뉴런이 똑같이 움직인다는 점이다.

  2. 첫 순전파의 출력이 전부 0이라 손실을 계산할 수 없다.

    편향이 있으면 출력이 0이 아니고, 0이어도 손실은 계산된다.

  3. 정답같은 층의 뉴런이 전부 같은 기울기를 받아 서로 구별되지 않는다.

    출력이 같으니 역전파로 돌아오는 기울기도 같고, 갱신 후에도 여전히 같다. 뉴런 100개를 넣어도 하나짜리 층과 다를 바 없어진다.

  4. 활성화 함수가 포화 구간에서 시작해 기울기가 소실된다.

    입력이 0이면 대부분의 활성화 함수에서 기울기가 가장 큰 자리다. 포화와 반대쪽이다.

해설

모든 가중치를 0으로 두면 같은 층의 뉴런이 전부 같은 입력에 같은 가중치를 곱하니 출력이 같고, 역전파로 돌아오는 기울기도 같아서 갱신 후에도 여전히 같다. 뉴런 100개를 넣어도 하나짜리 층과 다를 바 없어지고 이것을 대칭성 문제라 부른다. 그래서 무작위로 초기화하는데 이번에는 그 값의 크기가 문제가 된다. 층 하나를 지날 때 신호의 크기에 곱해지는 배율이 1보다 크면 층을 쌓을수록 활성값이 폭발해 손실이 무너지고, 1보다 작으면 0으로 수렴해 앞쪽 층에 아무 신호도 닿지 않는다. 좋은 초기화란 이 배율을 1로 맞추는 초기화다. 폭이 256인 층 열 개를 통과시켜 보면 표준편차를 0.01로 고정한 경우 신호가 사실상 사라지고, 배율을 1로 맞춘 경우에만 처음 크기가 유지된다.

이 내용 다시 읽기 →
상황 적용구조
층당 신호 배율은 입력 뉴런 수와 가중치 분산의 곱을 2로 나눈 값이다. Xavier: 분산 = 1/n → 배율 0.5 He: 분산 = 2/n → 배율 1.0

ReLU를 쓰는 층에서 분모의 2가 나오는 이유는 무엇인가?

  1. 정답ReLU가 음수 쪽 절반을 0으로 잘라 제곱 평균이 반으로 줄기 때문이다.

    Xavier는 활성화 함수가 원점 근처에서 거의 선형이라고 가정해 이 손실을 계산에 넣지 않는다. He는 그 절반을 분자의 2로 보상한다.

  2. 순전파와 역전파 양쪽의 분산을 절충하느라 두 값을 평균 내기 때문이다.

    그 절충은 Xavier가 들어오는 뉴런 수와 나가는 뉴런 수를 함께 쓰는 부분에서 나온다. 여기서의 2는 다른 데서 나온다.

  3. 가중치와 편향 두 종류의 파라미터가 각각 분산에 기여하기 때문이다.

    편향은 보통 0으로 초기화하며 이 계산에 들어가지 않는다.

  4. 미니배치의 평균과 분산 두 통계를 함께 추정해야 하기 때문이다.

    배치 통계는 정규화 층의 이야기다. 초기화 계산과 무관하다.

해설

활성값에 가중치를 곱하면 분산이 입력 뉴런 수와 가중치 분산의 곱만큼 커진다. 여기에 ReLU를 통과시키면 음수 쪽 절반이 0으로 잘리므로 제곱 평균이 반으로 준다. 두 효과를 이으면 층을 하나 지날 때마다 신호에 곱해지는 배율이 나오고, 이 배율을 1로 맞추려면 가중치 분산이 입력 뉴런 수 분의 2여야 한다. Xavier는 활성화 함수가 원점 근처에서 거의 선형이라고 가정하고 순전파와 역전파 양쪽에서 분산이 유지되도록 절충한 값이라 이 절반 손실을 계산에 넣지 않았다. 시그모이드와 tanh는 입력이 0 근처일 때 기울기가 거의 일정해 그 가정이 성립하지만 ReLU에는 맞지 않는다. 현대 신경망은 대부분 ReLU 계열을 쓰므로 실질적으로는 He 쪽이 기본값이다.

이 내용 다시 읽기 →
상황 적용구조
BatchNorm은 정규화 뒤에 학습되는 파라미터 두 개를 붙인다. x̂ = (x - μ) / √(σ² + ε) y = γ·x̂ + β

이 두 파라미터가 없으면 무엇이 문제인가?

  1. 정규화 결과의 부호가 뒤집혀 역전파에서 기울기가 반대 방향으로 흐른다.

    정규화는 부호를 뒤집지 않는다. 평균을 빼고 표준편차로 나눌 뿐이다.

  2. 배치마다 다른 통계로 정규화되어 같은 입력에 다른 출력이 나온다.

    그것은 이 두 파라미터와 무관한 성질이고, 오히려 약한 규제로 작용해 도움이 되기도 한다.

  3. 추론 때 쓸 통계가 없어 배치 크기가 1이면 계산이 정의되지 않는다.

    추론용 통계는 학습 중에 이동 평균으로 따로 기록해 둔다. 별개의 문제다.

  4. 정답모든 층의 입력이 0 근처에 몰려 활성화 함수의 비선형 구간을 제대로 쓰지 못한다.

    이 두 파라미터가 학습되므로 극단적으로는 정규화를 통째로 되돌릴 수도 있다. 정규화가 도움이 되는 층에서는 남기고 방해가 되는 층에서는 걷어내는 결정을 망이 직접 하게 만든 장치다.

해설

정규화만 하고 끝내면 모든 층의 입력이 0 근처에 몰려 활성화 함수의 비선형 구간을 제대로 쓰지 못한다. 뒤에 붙는 두 파라미터는 학습되는 값이라, 극단적으로는 배치의 표준편차와 평균을 그대로 학습해 정규화를 통째로 되돌릴 수도 있다. 정규화가 도움이 되는 층에서는 남겨 두고 방해가 되는 층에서는 걷어내는 결정을 망이 직접 하게 만든 장치다. 이 기법의 효과가 정말 층 입력 분포의 이동 때문인지는 논쟁이 있고, 실제 기여가 손실 지형을 매끄럽게 펴서 더 큰 학습률을 견디게 만드는 데 있다는 반론도 있다. 원리를 두고는 설명이 갈리지만 학습이 빨라지고 초기값에 덜 민감해지며 미니배치 통계의 잡음이 약한 규제로 작용한다는 관찰 자체는 함께 인정된다.

이 내용 다시 읽기 →
분석과 판단계산
def dropout_forward(x, p=0.5, training=True):
    if not training:
        return x
    mask = (np.random.rand(*x.shape) > p).astype(float)
    return x * mask / (1 - p)

살아남은 값을 1-p로 나누는 이유는 무엇인가?

  1. 꺼진 뉴런의 기울기를 살아남은 뉴런에 나눠 주어 총 갱신량을 보존하기 위해서다.

    꺼진 뉴런은 그 스텝의 순전파와 역전파 양쪽에서 없는 것으로 친다. 기울기를 옮겨 주지 않는다.

  2. 정답학습 때는 일부만 살아 있고 추론 때는 전부 켜지므로 다음 층이 받는 값의 기댓값을 맞추기 위해서다.

    학습 쪽에서 미리 키워 두면 추론 때는 아무것도 하지 않아도 된다. 이 형태를 역방향 드롭아웃이라 부른다.

  3. 확률 p로 끄는 연산이 분산을 줄이므로 그만큼 되돌리기 위해서다.

    무작위로 끄는 것은 오히려 분산을 늘린다. 여기서 맞추는 것은 분산이 아니라 기댓값이다.

  4. 마스크가 0과 1이라 값의 범위가 좁아지므로 정규화하기 위해서다.

    마스크는 값을 통과시키거나 차단할 뿐 범위를 좁히지 않는다.

해설

학습 중에는 뉴런의 일부만 살아 있는데 추론 때는 전부 켜지므로 다음 층이 받는 값의 크기가 달라진다. 살아남은 값을 살아남을 확률로 나눠 키워 두면 기댓값이 맞춰지고, 추론 때는 아무것도 하지 않아도 된다. 이 형태를 역방향 드롭아웃이라 부르고 오늘날의 표준 구현이다. 비율은 은닉층 기준으로 0.2에서 0.5 사이에서 고른다. 0.5가 가장 다양한 부분망 조합을 만들지만 그만큼 수렴이 느려지므로 낮은 쪽에서 시작해 검증 손실을 보며 조정하는 편이 낫다. 입력층에는 거의 쓰지 않고 출력층에는 쓰지 않는다. 출력층의 값은 그대로 손실 함수에 들어가야 하는데 일부를 꺼버리면 예측 자체가 망가지기 때문이다.

이 내용 다시 읽기 →
상황 적용운영
BatchNorm과 Dropout이 들어간 모델을 배포했다. 같은 입력을 두 번 넣었는데 예측이 서로 다르게 나오고, 시간이 지날수록 정확도가 조금씩 떨어진다.

무엇을 빠뜨렸는가?

  1. 가중치를 저장할 때 이동 평균이 함께 저장되지 않아 추론용 통계가 초기값으로 되돌아간 것이다.

    상태 사전에는 이동 평균도 함께 담긴다. 저장 누락이라면 첫 예측부터 크게 어긋난다.

  2. 정답추론 모드로 전환하지 않아 드롭아웃이 계속 켜져 있고 배치 통계가 계속 갱신되고 있다.

    드롭아웃이 켜져 있으면 같은 입력에 매번 다른 예측이 나온다. 그리고 정규화 층이 배치 통계를 계속 갱신하면서 저장된 이동 평균까지 오염시킨다.

  3. 배치 크기가 1이라 정규화 층의 분산이 0이 되어 출력이 불안정해진 것이다.

    추론 모드에서는 기록해 둔 이동 평균을 쓰므로 배치 크기가 1이어도 문제가 없다.

  4. 가중치 감쇠가 추론 중에도 적용되어 파라미터가 조금씩 줄어드는 것이다.

    가중치 감쇠는 옵티마이저가 갱신할 때만 작동한다. 추론 중에는 파라미터가 변하지 않는다.

해설

드롭아웃과 배치 정규화는 학습과 추론에서 동작이 달라지는 대표적인 두 층이다. 추론 모드로 전환하지 않으면 드롭아웃이 계속 켜져 같은 입력에 매번 다른 예측이 나오고, 정규화 층은 배치 통계를 계속 갱신하면서 저장된 이동 평균까지 오염시킨다. 시간이 지날수록 정확도가 조금씩 떨어지는 증상이 그 오염이다. 정규화 층이 두 모드를 나누는 이유는 분명하다. 학습 때는 미니배치의 통계를 쓰지만 추론 때는 입력이 하나뿐일 수 있어 배치 통계를 구할 수 없으므로, 학습 중에 평균과 분산의 이동 평균을 따로 기록해 두고 추론 때 그 값을 쓴다. 이동 평균의 갱신 비율을 정하는 파라미터가 새 배치 통계에 주는 가중치라는 점도 함께 기억할 만하다. 옵티마이저의 같은 이름 파라미터와 방향이 반대라 값을 그대로 옮기면 의도와 정반대가 된다.

이 내용 다시 읽기 →
분석과 판단판단
새 신경망의 손실이 처음부터 거의 줄지 않는다. 드롭아웃 비율을 낮추고, 배치 정규화를 넣었다 뺐다 하고, 옵티마이저를 바꿔봤지만 여전하다.

어떻게 원인을 좁혀야 하는가?

  1. 규제를 전부 최대로 걸어 과적합 가능성을 배제한 뒤 하나씩 풀어 본다.

    훈련 손실조차 줄지 않는 상황이라 과적합이 아니다. 규제를 더 걸면 상황이 나빠지기만 한다.

  2. 정답샘플 100개짜리 부분 데이터로 과적합이 되는지 먼저 확인한다.

    거기서도 훈련 손실이 0 근처까지 내려가지 않으면 규제가 아니라 모델이나 구현에 문제가 있다는 뜻이다. 과적합이 확인되면 그때 전체 데이터로 옮기고 규제를 하나씩 얹는다.

  3. 에폭 수를 크게 늘려 충분히 학습되는지 본다.

    처음부터 줄지 않는 손실은 오래 돌린다고 내려가지 않는다. 시간만 쓰고 원인은 그대로다.

  4. 모델 크기를 키워 표현력이 부족한지 확인한다.

    확인해 볼 항목이지만 순서가 늦다. 작은 데이터에서 과적합이 되는지부터 보면 표현력 문제인지 구현 문제인지가 먼저 갈린다.

해설

학습이 안 될 때는 순서를 지키면 원인이 좁혀진다. 먼저 샘플 100개짜리 부분 데이터로 과적합이 되는지 본다. 여기서 훈련 손실이 0 근처까지 내려가지 않으면 규제가 아니라 모델이나 구현에 문제가 있다는 뜻이라 규제를 만지는 시도는 전부 헛수고다. 과적합이 확인되면 그때 전체 데이터로 옮기고 규제를 하나씩 얹는다. 증상별로 먼저 볼 곳도 정해져 있다. 손실이 처음부터 안 줄면 학습률과 입력 정규화를, 손실이 무너지면 기울기 폭발을, 훈련은 좋은데 검증이 나쁘면 과적합을, 둘 다 나쁘면 과소적합을 의심한다. 세 기법이 서로 다른 시점의 문제를 맡으므로 하나가 다른 하나를 대신하지 못한다. 증상을 먼저 특정하고 그에 맞는 도구를 꺼내는 편이, 셋을 한꺼번에 넣고 어느 것이 효과가 있었는지 모르는 것보다 낫다.

이 내용 다시 읽기 →

이 페이지는 문항 품질을 점검하는 용도로도 씁니다. 한 화면에서 전부 훑어야 중복된 문항, 쏠린 난이도, 소거법으로 풀리는 선택지가 보입니다.

Thank You for Visiting My Blog, Have a Good Day 😆