ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [cs231n] 6강 신경망 훈련하기 (2/4, 데이타 전처리와 가중치 초기화 (data preprocessing & weight initialization))
    AI 2021. 3. 10. 19:47

    데이타 전처리에 대해서 얘기를 좀 해보죠. 활성함수를 디자인하는 것은 우리 망의 일부죠. 이제 우리는 망을 훈련시키고 싶고 입력 데이타를 가지고 거기서 부터 훈련을 시작하고 싶습니다.

    일반적으로 우리는 항상 데이타를 전처리합니다. 머신러닝 수업을 들었다면 봤을 법한 건데요. 전처리의 표준적인 형태는 원래 데이타를 취해서 0으로 평균을 맞추고 아마도 정규화를 하는 거겠죠. 표준편차로 정규화하는 거죠.

    왜 우린 이렇게 하고 싶을까요? 0으로 중심을 맞추는 건, 앞서서 모든 입력이 양수인 경우를 얘기했을 때를 기억해 보면, 우리의 가중치 경사가 모두 양수가 되고 우리는 최선이 아닌 차선의 최적화를 얻게 됩니다. 그리고 일반적으로 그게 모두 0이 아니거나 모두 음인 경우에도 어떤 종류의 바이어스 (bias)가 이런 종류의 문제를 일으킬 수 있죠.

    데이타 정규화에 관해서는, 머신러닝 (machine learning) 문제에서는 데이타를 정규화하고 싶을 겁니다. 모든 피쳐 (feature)가 같은 범위에 있어서 동등하게 역할을 하도록 (contribute) 말이죠. 실제에선, 우리가 이 강좌에서 다루는 이미지에 대해서는 대부분의 경우 0으로 중심을 맞추지만, 픽셀값을 정규화하지는 않습니다. 왜냐면 이미지에 대해서는 일반적으로 각각의 위치에서 여러분은 이미 상대적으로 비교할 수 있는 크기 (scale)와 분포를 가지고 있기 때문이죠. 그래서 서로 다른 다양한 피쳐들과 다양한 크기를 가진 일반적인 머신러닝 문제와 비교해 볼 때 이미지 문제에서는 정규화할 필요가 없습니다.

    그리고 머신러닝에서는 주성분 분석 (PCA)나 화이트닝 (whitening)같은 더 복잡한 것들을 볼 수도 있지만, 이미지에서는 일반적으로 0 평균만 쓰죠. 우린 정규화도 안하고 더 복잡한 전처리도 안합니다. 그 이유는 일반적으로 이미지에서는 우리는 모든 입력을 받아 들이고 싶지 않기 때문입니다. 예를 들면, 픽셀 값을 받아 들여서 이걸 우리가 다루는 새로운 종류의 피쳐의 낮은 차원의 공간으로 사영하는 것 말입니다. 우리는 그냥 합성곱 망을 공간적으로 적용하고 싶고 원본 이미지에 대한 공간적 구조를 가지고 싶을 뿐입니다.

    이미지에 대해서 요약을 하면, 일반적으로 우리는 0 평균 전처리를 하고 아니면 전체 평균 이미지를 뺄 수도 있습니다. 그래서 학습 데이타로부터 , 각각의 이미지와 같은 사이즈인 평균 이미지를 계산하는 거죠. 예를 들면, 32 x 32 x 3이면, 여러분은 이 배열의 숫자를 가질 거고 망을 통과시킬 각각의 이미지로부터 그걸 빼는거죠. 훈련시에 결정한 이 배열에 대해서 테스트시에도 같은 작업을 하는 겁니다. 실제에선 우리는 또한 어떤 망에 대해서 채널 (channel)마다의 평균을 빼는 것으로 이걸 하기도 합니다. 그래서 0 중심이 될 전체 평균 이미지를 갖는 대신, 우리는 그냥 채널에 의한 평균을 취할 수 있습니다. 왜냐면, 전체 이미지에 걸쳐서 보면 충분히 비슷하기 때문이죠. 평균 이미지를 빼는 것과 채널당 값을 빼는 것을 비교해 보면 큰 차이가 없습니다. 이게 통과시키거나 다루기 쉽습니다. 여러분은 알렉스넷 (AlexNet) 다음에 나온 VGG 네트워크 같은 데서 볼 수 있습니다. 나중에 여기에 대해서 얘기하겠습니다.

    이제 어떻게 우리 망의 가중치를 초기화하고 싶은지에 대해 얘기해 보죠.

    우리의 표준 2계층 신경망이 있다고 할 때, 우리가 학습하고 싶은 이 모든 가중치들이 있습니다. 우리는 그것들을 어떤 값으로 시작해야 하죠. 그다음 우리는 그것들로부터 경사 업데이트를 사용하여 그것들을 업데이트합니다. 첫번째 질문은, w를 0으로 초기화했을 때 어떤 일이 벌어 질까요? 모든 파라미터를 그냥 0으로 설정하는거죠. 이것의 문제는 뭔가요? 모든 뉴런이 죽을 거라는 대답이 있구요. 업데이트가 전혀되지 않는다구요? 정확히는 그렇지 않구요. 그중 일부는 맞죠. 모든 뉴런이 같은 것을 한다는 점에서는요. 그것들이 모두 죽지는 않을 겁니다. 여러분의 입력 값에 따라서, 뉴런의 어떤 영역에도 있을 수 있죠. 그래서 죽지는 않을거에요. 중요한 점은 그것들이 모두 같은 것을 할 거라는 겁니다. 가중치가 0이니까, 입력이 주어지면, 입력에 대해서 모든 뉴런이 사실 같은 연산을 하게 됩니다. 그리고 그것들 모두가 같은 것을 출력하겠죠. 또한 그것들은 모두 같은 경사를 가질 겁니다. 그로 인해서, 그것들은 모두 같은 식으로 업데이트할거고, 그럼 이제 모든 뉴런들이 같아지는거죠. 이런 걸 원하는게 아니죠. 여러분들은 뉴런들이 다른 것들을 배우길 바랄겁니다. 이것이 모든 것을 동등하게 초기화했을 때 발생하는 문제고, 여기에는 어떤 대칭을 깨는 것이 없죠.

    이것을 개선하기 위해서 시도해 볼 수 있는 첫번째 아이디어는 분포로부터 샘플링할 수 있는 작은 임의의 숫자로 모든 가중치를 설정하는 겁니다. 이 경우에는, 사실 표준 가우시안 (gaussian)에서 샘플링할 건데요. 그러나 우리는 그것의 배율을 조정해서 표준편차가 1의 -2제곱, 즉 0.01이 되도록 할겁니다. 그래서 이건 많은 임의의 작은 가중치를 줍니다.

    이것은 작은 망들에 대해서는 괜찮습니다. 이제 대칭을 깨뜨리게 된거죠. 그러나 더 깊은 망에 대해서는 문제가 있을 겁니다.

    왜 그런지 살펴보죠. 이건 우리가 해 볼 수 있는 실험인데, 더 깊은 망을 취해보는 거죠. 이 경우 10계층 신경망을 초기화해서 이 10계층 각각이 500개의 뉴런을 가지도록 해보죠. 이 경우 탠에이치 비선형성을 사용할 거고, 앞선 슬라이드에서 설명한것 처럼 그걸 작은 임의의 숫자로 초기화 할 겁니다. 여기서 우리는 이 망을 초기화할 거고, 받아들일 임의의 데이타가 있을거고, 그걸 전체 망으로 통과시킬 겁니다. 그리고 각각의 계층에서 그 계층에서 나오는 활성 통계를 볼 겁니다.

    윗쪽은 약간 읽기 어렵겠지만, 각각의 계층에서 평균과 표준편차를 계산하면, 평균은 항상 0에 가깝구요. 출력을 보면, 평균은 항상 0 근처죠. 이건 말이되죠.

    여기를 보면 x와 w의 내적이 있고, 비선형엔 탠에이치를 취했죠 그리고 이 값들을 저장합니다.

    탠에이치는 0중심이기 때문에, 이게 말이 되는 거죠. 그런데 표준편차는 줄어듭니다. 빠르게 0으로 줄어들죠. 만약 이걸 그려본다면, 2번째 행이 시간에 따른 각 계층의 평균과 표준편차를 보여주고 있는데요. 그 아래엔, 일련의 플롯 (plot)이 각 계층에 대해서 활성분포가 어떤지 보여줍니다. 첫번째 계층에서는 여전히 합리적인 가우시안으로 보이는 것이 있죠. 좋은 분포입니다. 그러나 문제는 우리가 이 w로 곱해감에 따라 이작은 숫자들이 각 계층에서 빠르게 줄어들고 이 값들을 무너뜨린다는 겁니다. 우리가 이 값들을 계속 곱하면서요. 그래서 끝에서는 모두 0이 되는데, 원하는 바가 아니죠.

    모든 활성이 0이 됩니다. 이제 역방향을 생각해 볼까요. 우리가 역방향 전달을 한다면, 이것이 우리의 순방향 전달 (forward pass)이라고 가정하고 우리는 경사를 계산하고 싶습니다. 먼저 가중치에 대한 경사가 어떻게 생겼죠? 추측할 수 있나요? 이걸 생각해 보면, 각 계층에서 입력 값이 매우 작습니다. 왜냐면 0 근처에서 모두 무너지니까요. 각 계층에는 아래로 흐르는 업스트림 (upstream) 경사가 있죠. 가중치에 대한 경사를 얻기 위해서는, 그건 업스트림 경사 곱하기 지역 경사를 해야죠. 이 내적에서 대해서 우리는 w 곱하기 x를 하는거죠. 그건 그냥 x가 될 텐데, 그건 입력이죠. 그래서 그건 앞서봤던 것과 비슷한 문제입니다. x가 작기 때문에, 우리의 가중치는 매우 작은 경사가 되고 그것들은 사실 업데이트하지 않는거죠. 이건 망을 관통하는 경사 흐름의 효과를 시도해 보고 생각해 보는 방법입니다. 여러분은 항상 순방향 전달이 뭘하는지 생각해 보고 그리고 내려오는 경사 흐름이 생김에 따라 무슨 일이 벌어지는지 생각해 볼 수 있죠. 그리고 여러 입력에 따라 이것이 가중치에 어떤 영향을 주는지 그리고 그것들에 대한 경사는 어떻게 되는지를 생각해 볼 수 있습니다. 그리고 또한 이 경사를 엮으면서 (chain) 각각의 계층으로부터 거꾸로 흐르는 경사가 무엇인지 생각해 보면, 이건 거꾸로 된 거죠. 거꾸로 흐르는 경사는 이 경우 우리의 업스트림 경사 곱하기 지역 경사는 입력 x에 대한 w가 되죠. 이건 내적이므로, 각 계층에서 거꾸로 가면서, 우리는 사실 업스트림 경사와 우리의 가중치를 곱하는 거죠. 아래로 흐르는 다음 경사를 얻기 위해서요. 그리고 여기서 w를 반복해서 곱하고 있기 때문에, 순방향 전달에서 봤던 것과 동일한 현상을 얻게 됩니다. 즉, 모든 것이 점점 더 작아지는거죠. 그래서 업스트림 경사도 0이 되는 거죠.

    우리의 가중치가 꽤 작으면 문제가 된다고 했었는데. 이때 무슨 일이 생기는지 생각해 보죠. 우리가 가중치를 크게 만들어서 이것을 해결할 수 있는지 생각해 보죠. 그래서 표준 가우시안으로부터 샘플링을 해서 표준편차를 0.01이 아닌 1로 해보죠. 여기서 문제는 뭐죠? 추측해 볼 수 있나요? 만약 우리의 가중치가 모두 크고, 그것을 전달하고 이 w 곱하기 x의 출력을 취해서 탠에이치 비선형성을 통과시킨다면요. 우리가 탠에이치에 여러 입력값을 주었을 때 무슨 일이 벌어지는지 얘기하고 있다는 것을 기억하세요. 문제가 뭐죠? 네, 그건 포화가 될 겁니다. 맞습니다. 이제 우리의 가중치가 클 것이기 때문에, 우리는 항상 탠에이치의 큰 음수나 큰 양수의 포화되는 영역에 있을 겁니다. 실제로, 여기 아래에 있는 각 계층에서의 활성 분포를 본다면 , 그것들은 사실 -1이거나 1이 될 겁니다. 이것은 우리가 앞서 얘기했던 탠에이치가 가지고 있는 문제이죠. 그것들이 포화가 되면, 모든 경사가 0이 될 거고 경사는 업데이트하지 않을 겁니다.

    사실 가중치 초기화를 제대로 하기 어렵습니다. 너무 작으면 무너져버리고 (collapse) 너무 크면 포화되죠. 그래서 이 가중치를 초기화하는 적절한 방법을 알아내는 연구들이 있었고, 사용할 수 있는 좋은 방법 중의 하나는 자비에 초기화 (Xavier initialization)입니다. 이건 2010년 글로롯 (Glorot)의 논문에 있는 건데요. 공식이 뭐냐면, 여기 위의 w를 보면, 우리는 그것들을 표준 가우시안에서 샘플링해서 입력의 숫자만큼 곱합니다. 그다음 수학을 하면, 강의 노트나 논문에서 볼 수 있는데, 어떻게 정확히 동작하는지 알 수 있는데요. 그러나 우리가 그것을 하는 방식은 우리가 입력의 분산이 출력의 분산과 같게 되길 원한다는 것을 명시하는 겁니다. 그다음 가중치가 무엇이 되야 하는지 미분하면, 이 공식을 얻게 될 겁니다. 그리고 직관적으로 이것이 의미하는 바는 적은 수의 입력이 있으면, 우리는 더 작은 수로 나눌 거고 더 큰 가중치를 얻을 거고, 더 큰 가중치가 필요할 겁니다. 왜냐면, 작은 입력으로는, 이것들 각각을 가중치로 곱하고 있는데, 출력에서 더 큰 분산을 얻기 위해서는 더 큰 가중치가 필요하죠. 반대로 많은 입력이 있으면 거꾸로가 되죠. 출력에서 같은 퍼짐 (spread)을 얻으려면 더 작은 가중치를 원합니다. 이것에 대한 더 자세한 사항은 노트를 보길 바랍니다. 각 계층에 대한 입력으로 단위 가우시안을 가지고 싶다면, 이런 종류의 초기화를 훈련시에 사용해서, 초기화를 할 수 있고 각 계층에 대략적으로 단위 가우시안을 갖게 되는 거죠. 여기에 선형 활성이 있다고 가정을 합니다. 즉, 우리가 예를 들어 탠에이치의 활성 영역에 있다고 가정해 보죠. 그것의 유도를 이해하고자 한다면 노트를 보기 바랍니다.

    그런데 문제는 렐루같은 것을 쓰면 이것이 깨진다는 겁니다. 렐루에서 벌어지는 일은, 렐루는 유닛 (unit)의 절반을 죽이기 때문에, 약 절반을 매번 0으로 만들어 버리죠. 이것으로부터 얻는 분산을 절반으로 줄입니다. 그래서 앞에서 유도한 것과 같은 가정을 하면, 맞는 분산을 얻을 수 없죠. 너무 작을 겁니다. 이건 일종의 분포가 무너지면서 발생하는 현상인데, 이 경우 , 점점 더 0을 향해서 정점이 이뤄지고 더 많은 유닛들이 비활성화 됩니다.

    이것을 해결하는 방법은 몇몇 논문에서 지적한 것들로 할 수 있는데, 여러분은 추가적으로 2로 나누기를 통해 해결하려고 할 수 있습니다. 이제 여러분들은 뉴런의 절반이 죽을 거라는 사실에 대해서 조정을 하는거죠. 그래서 여러분의 일종의 동등한 입력이 이 절반 숫자의 입력을 갖는 겁니다. 그래서 이 인수 2로 나누기를 추가하면 이게 훨씬 더 잘 동작합니다. 망의 모든 계층에서 분포도 꽤 좋은 것을 볼 수 있죠.

    실제에선 이런 작은 종류를 훈련시키는데 이것이 매우 중요했습니다. 여러분의 가중치가 무엇인지 주목하는 것은 큰 차이를 만들어 냅니다. 예를 들어, 몇 개의 논문에서 이것이 사실 망 사이의 차이라는 것을 알 수 있습니다. 훈련을 해서 성능이 좋은 경우도 있고 아무것도 일어나지 않는 경우도 있죠.

    적절한 초기화는 여전히 활발히 연구중인 분야입니다. 관심이 있다면, 이 논문들과 자료들을 보세요. 일반적으로 좋은 방법은 자비에 초기화를 사용해서 시작하고, 그다음 다른 종류의 방법들을 생각해 보는 겁니다.

    댓글

Designed by Tistory.