강에서 배치를 키워도 안 되는 자리가 있다는 것을 봤습니다. 임계 배치 크기를 넘으면 계산만 늘고 걸음은 안 줄어듭니다.
있습니다. 그리고 그중 하나는 거의 공짜입니다. 과거 걸음을 섞어 두면 그것 자체가 평균을 내는 일입니다.
이 강의는 모멘텀·기준점 보정·평균 셋을 보고, 마지막에 잡음을 줄이는 것이 언제나 좋지는 않다는 것을 확인합니다.
문제. 방법들을 봅니다.
() 정리하세요.
() 모멘텀이 무엇을 하는지 보세요.
() 모멘텀이 평균을 내는 것임을 확인하세요.
생각의 실마리. 분산을 줄이려면 더 많은 표본을 평균 내면 됩니다. 그런데 표본을 새로 볼 필요는 없습니다. 이미 본 것을 다시 쓰면 됩니다.
풀이. () 정리합니다.
| 방법 | 무엇을 하나 | 비용 |
|---|---|---|
| 배치를 키움 | 표본을 더 봄 | 계산이 비례해 늘음 |
| 과거를 섞음 | 모멘텀 | 공짜에 가까움 |
| 기준점을 씀 | 분산 감소 방법 | 가끔 전체를 봄 |
| 평균을 냄 | 폴략 평균 | 걸음은 그대로 |
강에서 첫 줄이 임계 배치 크기에서 막히는 것을 봤습니다. 이 강의는 나머지 셋을 봅니다.
() 모멘텀이 무엇을 하는지 봅니다.
| 모멘텀 계수 | 실효 걸음 배수 | 같은 학습률에서 | 학습률을 나눠 맞추면 |
|---|---|---|---|
같은 학습률로 두면 계수를 키울수록 나빠집니다. 에서 까지 갑니다.
모멘텀이 걸음을 만큼 키우기 때문입니다. 그래서 학습률을 그만큼 나눠야 같은 조건이 됩니다.
맞춰 주면 넷째 열이 에서 로 조금씩 좋아집니다.
() 모멘텀이 평균을 내는 것임을 확인합니다. 모멘텀 벡터에 를 곱한 값의 분산을 잽니다.
| 모멘텀 계수 | 유효 표본 수 | 모멘텀 벡터의 분산 | 한 걸음 분산 대비 |
|---|---|---|---|
셋째 열과 넷째 열이 유효 표본 수의 역수와 맞습니다. 에서 유효 표본 수가 이고 분산 비 관측이 이므로 그 역수와 맞습니다.
계수 면 대략 열아홉 걸음을 평균 낸 셈입니다. 배치를 열아홉 배 키운 것과 분산 면에서 같은데 계산은 그대로입니다.
이 문제에서 배우는 것. 모멘텀은 가속 장치이기 전에 평균 장치입니다. 과거 그래디언트를 지수 가중으로 평균 내므로, 표본을 새로 안 보고도 분산이 줄어듭니다.
확인 1-1. 모멘텀이 걸음 크기를 몇 배로 키우는지 쓰세요.
답. 나누기 빼기 계수만큼입니다.
확인 1-2. 검산에서 계수 일 때 같은 학습률과 나눠 맞춘 초과손실을 쓰세요.
답. 과 입니다.
확인 1-3. 검산에서 계수 의 유효 표본 수와 분산 비를 쓰세요.
답. 과 입니다.
문제. 두 효과를 가릅니다.
() 정리하세요.
() 잡음이 없을 때도 도움이 되는지 보세요.
() 방향별로 무엇이 달라지는지 보세요.
() 계수를 너무 키우면 어떻게 되는지 보세요.
생각의 실마리. 문제 은 잡음을 평균 낸다는 이야기였습니다. 그러면 잡음이 아예 없으면 모멘텀이 쓸모없을까요.
풀이. () 가릅니다.
| 효과 | 무엇인가 | 언제 |
|---|---|---|
| 잡음 평균 | 과거를 섞어 분산이 줄음 | 확률적일 때 |
| 골짜기 가속 | 같은 방향이 쌓임 | 잡음이 없어도 |
| 어느 쪽이 큰가 | 문제에 달림 | 아래에서 확인 |
() 전체 배치로만 돌립니다. 잡음이 아예 없고 조건수는 입니다.
| 모멘텀 계수 | 고른 학습률 | 초과손실 까지 걸음 |
|---|---|---|
잡음이 하나도 없는데 계수 에서 걸음이 에서 로 세 배 줄어듭니다.
골짜기에서 같은 방향의 그래디언트가 쌓이기 때문입니다.
그런데 와 에서는 다시 느려집니다. 최적을 지나쳤기 때문입니다.
표에서 가 그 값에 가장 가깝습니다. 강 문제 의 조건수 문제를 모멘텀이 어느 정도 풉니다.
() 방향별로 무엇이 달라지는지 봅니다. 값은 처음 오차 대비 남은 비율입니다.
| 고윳값 | 모멘텀 없이 걸음 | 모멘텀 로 걸음 |
|---|---|---|
가장 완만한 방향에서만 차이가 납니다. 이 로 두 배 넘게 줄었습니다.
가파른 방향은 어차피 둘 다 입니다. 모멘텀이 느린 방향을 밀어 주는 장치임이 여기서 보입니다.
() 계수를 너무 키우면 어떻게 되는지 봅니다. 학습률을 로 맞춘 뒤 계수만 올립니다.
| 모멘텀 계수 | 맞춘 학습률 | 초과손실 | 어떻게 되나 |
|---|---|---|---|
| 수렴 | |||
| 수렴 | |||
| 수렴 | |||
| 수렴 |
까지는 좋아지다가 부터 나빠집니다. 에서는 초과손실이 마흔 배 넘게 커집니다.
평균 낼 과거가 걸음 수에 가까워지면 앞쪽 걸음이 계속 발목을 잡습니다. 유효 표본 수가 인데 걸음이 번뿐입니다.
실무에서 나 를 쓰는 이유입니다.
이 문제에서 배우는 것. 모멘텀에는 두 얼굴이 있습니다. 잡음을 평균 내는 얼굴과 골짜기를 가속하는 얼굴입니다. 그리고 둘 다 최적값이 있어 무작정 키우면 안 됩니다.
확인 2-1. 잡음이 없어도 모멘텀이 도움이 되는 이유를 쓰세요.
답. 골짜기에서 같은 방향의 그래디언트가 쌓이기 때문입니다.
확인 2-2. 검산에서 계수 과 의 걸음 수를 쓰세요.
답. 와 입니다.
확인 2-3. 검산에서 계수 의 초과손실을 쓰세요.
답. 입니다.
문제. 분산 감소 방법을 봅니다.
() 생각을 정리하세요.
() 편향이 없고 분산이 주는 것을 확인하세요.
() 실제로 학습시켜 견주세요.
() 왜 딥러닝에서 잘 안 쓰는지 보세요.
생각의 실마리. 표본 의 그래디언트가 흔들립니다. 그런데 가까운 두 점에서의 그래디언트는 비슷하게 흔들립니다. 그 공통 부분을 빼면 됩니다.
풀이. () 정리합니다.
| 무엇 | 무엇인가 | 덧붙임 |
|---|---|---|
| 문제 | 미니배치 그래디언트가 흔들림 | 분산이 큼 |
| 생각 | 가끔 전체를 계산해 기준으로 둠 | 기준점 |
| 보정 | 지금 표본과 기준점의 차이만 씀 | 차이는 작음 |
| 결과 | 편향 없이 분산이 줄음 | SVRG |
기댓값을 취하면 뒤 둘이 지워져 편향이 없습니다.
() 편향이 없고 분산이 주는 것을 확인합니다.
| 기준점과의 거리 | 보통 편향 | 보정 편향 | 보통 분산 | 보정 분산 |
|---|---|---|---|---|
두 편향이 모두 에 가깝습니다. 표집 오차 수준이고, 보정이 편향을 안 만듭니다.
기준점이 만큼 가까우면 분산이 에서 로 배 줄어듭니다.
멀어지면 이득이 사라집니다. 거리 에서는 가 로 절반만 줍니다. 그래서 기준점을 주기적으로 갱신합니다.
() 실제로 학습시켜 견줍니다.
| 갱신 주기 | 초과손실 | 자료 통과 횟수 |
|---|---|---|
| 보통 미니배치 | ||
보정하면 초과손실이 에서 사실상 이 됩니다.
대신 기준점 계산 때문에 자료 통과 횟수가 에서 로 세 배 늘어납니다.
갱신을 자주 하면 분산은 더 줄지만 비용이 커집니다. 주기 에서는 통과가 번으로 줄지만 초과손실이 로 조금 커집니다.
() 왜 딥러닝에서 잘 안 쓰는지 봅니다.
| 무엇 | 무엇이 문제 | 덧붙임 |
|---|---|---|
| 가정 | 손실면이 볼록하고 매끄러움 | 신경망은 아님 |
| 기준점 | 전체 그래디언트를 계산 | 자료가 크면 비쌈 |
| 저장 | 기준점 파라미터 한 벌 더 | 메모리 두 배 |
| 실효 | 잡음이 정규화 노릇도 함 | 줄이면 손해일 수도 |
마지막 줄이 가장 큰 이유입니다. 강 문제 에서 잡음이 골을 넘게 해 줬습니다.
볼록한 문제에서는 잡음이 순수한 손해라 줄이는 것이 언제나 이득입니다. 신경망은 다릅니다.
이 문제에서 배우는 것. 기준점 보정은 이론적으로 아름답고 볼록한 문제에서 강력합니다. 그런데 딥러닝에서 안 쓰이는 이유는 성능이 아니라 가정과 목적이 다르기 때문입니다.
확인 3-1. 기준점 보정이 편향을 안 만드는 이유를 쓰세요.
답. 기댓값을 취하면 보정 항 둘이 서로 지워지기 때문입니다.
확인 3-2. 검산에서 기준점 거리 일 때 보통 분산과 보정 분산을 쓰세요.
답. 과 입니다.
확인 3-3. 검산에서 갱신 주기 의 자료 통과 횟수를 쓰세요.
답. 입니다.
문제. 파라미터를 평균 냅니다.
() 두 평균을 가르세요.
() 폴략 평균을 쓰세요.
() 지수이동평균과 견주세요.
() 학습률을 줄이는 것과 견주세요.
생각의 실마리. 강에서 최적점 둘레를 맴돈다고 했습니다. 맴도는 것이라면 가운데가 최적점입니다.
풀이. () 가릅니다.
| 무엇 | 무엇을 하나 | 덧붙임 |
|---|---|---|
| 폴략 평균 | 걸음들의 평균을 답으로 | 학습에는 안 씀 |
| 지수이동평균 | 최근에 무게를 더 | 실무의 기본 |
| 모멘텀과의 차이 | 모멘텀은 그래디언트를 평균 | 이쪽은 파라미터를 평균 |
() 폴략 평균을 씁니다. 뒤 절반을 평균 냅니다.
| 학습률 | 마지막 걸음 | 뒤 절반 평균 | 몇 배 좋아졌나 |
|---|---|---|---|
평균을 내면 스물네 배에서 예순 배까지 좋아집니다. 걸음은 하나도 더 안 갔습니다.
떨림이 최적점 둘레를 도는 것이라 평균이 가운데를 찾습니다.
학습률이 클수록 이득이 큽니다. 에서 배입니다. 떨림이 클수록 평균이 지울 것이 많기 때문입니다.
강 심화 의 폴략 평균이 여기서 확인됩니다.
() 지수이동평균과 견줍니다.
| 감쇠 계수 | 마지막 걸음 | 폴략 평균 | 지수이동평균 |
|---|---|---|---|
감쇠 계수가 클수록 더 긴 과거를 평균 내 좋아집니다. 에서 입니다.
그래도 폴략 평균의 에는 못 미칩니다. 폴략 평균은 걸음을 다 세는데 지수이동평균은 최근 천 걸음 정도만 보기 때문입니다.
학습률을 줄여 가는 실무에서는 지수이동평균이 낫습니다. 학습률이 컸던 앞쪽 걸음을 같은 무게로 세면 안 되기 때문입니다.
() 학습률을 줄이는 것과 견줍니다.
| 무엇을 했나 | 초과손실 |
|---|---|
| 고정 학습률 마지막 | |
| 고정 학습률 평균 | |
| 코사인 감소 마지막 |
코사인 감소가 평균보다 조금 더 좋습니다. 대 입니다.
다만 감소식은 예산을 미리 정해야 하고 평균은 안 그렇습니다. 언제 멈출지 모르는 학습에서는 평균이 유일한 선택입니다.
둘을 함께 쓰는 것이 실무의 기본입니다.
이 문제에서 배우는 것. 평균은 가장 값싼 분산 감소입니다. 걸음을 하나도 더 안 가고 저장만 한 벌 더 하면 되며, 학습률을 줄이는 것과 거의 같은 이득을 냅니다.
확인 4-1. 폴략 평균이 왜 듣는지 쓰세요.
답. 떨림이 최적점 둘레를 도는 것이라 평균이 가운데를 찾기 때문입니다.
확인 4-2. 검산에서 학습률 일 때 평균이 몇 배 좋아졌는지 쓰세요.
답. 배입니다.
확인 4-3. 검산에서 코사인 감소와 고정 학습률 평균의 초과손실을 쓰세요.
답. 와 입니다.
문제. 실제로 조합합니다.
() 무엇을 먼저 쓸지 정리하세요.
() 넷을 함께 쓰면 어떤지 보세요.
() 잡음이 필요한 경우를 확인하세요.
() 이 단원을 한 장으로 모으세요.
생각의 실마리. 네 방법이 서로 다른 자리에서 잡음을 줄입니다. 그러면 겹치지 않고 더해질 수 있습니다.
풀이. () 정리합니다.
| 무엇 | 언제 | 비용 |
|---|---|---|
| 모멘텀 | 언제나 | 거의 공짜 |
| 지수이동평균 | 거의 언제나 | 저장만 한 벌 |
| 배치 키우기 | 잡음 비가 클 때 | 강 임계점까지 |
| 분산 감소 방법 | 볼록한 문제 | 딥러닝에서는 드묾 |
| 학습률 감소 | 언제나 | 강 |
() 하나씩 켜 봅니다. 배치 에 걸음 고정입니다.
| 무엇을 했나 | 초과손실 |
|---|---|
| 아무것도 없이 | |
| 모멘텀만 | |
| 모멘텀과 감소식 | |
| 셋 다 |
하나씩 켤 때마다 좋아집니다. 전부 켜면 에서 으로 마흔일곱 배 좋아집니다.
감소식이 가장 크게 듭니다. 에서 으로 스물세 배입니다.
서로 다른 자리에서 잡음을 줄이기 때문에 겹치지 않습니다.
() 잡음이 필요한 경우를 확인합니다. 강 문제 의 골 두 개짜리 함수입니다.
| 잡음 크기 | 모멘텀 없이 깊은 골 | 모멘텀 로 깊은 골 |
|---|---|---|
잡음이 있어야 깊은 골로 넘어갑니다. 잡음 에서는 두 경우 모두 입니다.
모멘텀이 있고 없고는 여기서 큰 차이를 안 냅니다. 실효 걸음을 맞춰 두면 넘어가는 힘도 비슷해지기 때문입니다.
중요한 것은 잡음을 줄이는 것이 언제나 좋지는 않다는 사실입니다. 볼록한 문제에서는 순수한 이득이지만, 골이 여럿이면 잡음이 탈출 수단입니다.
() 이 단원을 한 장으로 모읍니다.
| 강 | 무엇을 물었나 | 한 줄 답 |
|---|---|---|
| 왜 일부만 봐도 되나 | 편향이 없고 분산만 있습니다 | |
| 언제 멈추나 | 학습률을 으로 보내야 닿습니다 | |
| 배치를 얼마나 키우나 | 임계 배치 크기까지입니다 | |
| 달리 잡음을 줄이려면 | 모멘텀과 평균을 씁니다 |
네 강의가 하나의 물음에 답합니다. 잡음을 어떻게 다룰 것인가입니다.
이 문제에서 배우는 것. 실무의 학습 설정은 여러 분산 감소를 겹쳐 놓은 것입니다. 모멘텀·감소식·평균이 각각 다른 자리에서 듣고, 곱해져서 마흔 배 넘는 차이를 냅니다.
확인 5-1. 네 방법이 겹치지 않는 이유를 쓰세요.
답. 서로 다른 자리에서 잡음을 줄이기 때문입니다.
확인 5-2. 검산에서 아무것도 안 쓴 것과 셋 다 쓴 것의 초과손실을 쓰세요.
답. 과 입니다.
확인 5-3. 검산에서 잡음 일 때 깊은 골에 간 비율을 쓰세요.
답. 둘 다 입니다.
| 유형 | 무엇을 묻나 | 어디를 보나 |
|---|---|---|
| 모멘텀의 실효 걸음 | 문제 | |
| 모멘텀의 유효 표본 | 문제 | |
| 잡음 없이도 듦 | 골짜기 가속 | 문제 |
| 최적 계수 | 조건수가 정함 | 문제 |
| 계수를 너무 키우면 | 과거가 발목을 잡음 | 문제 |
| 기준점 보정 | 편향 없이 분산만 | 문제 |
| 딥러닝에서 안 씀 | 잡음이 필요함 | 문제 |
| 폴략 평균 | 걸음 없이 예순 배 | 문제 |
| 지수이동평균 | 학습률이 변하면 | 문제 |
| 겹쳐 쓰기 | 마흔일곱 배 | 문제 |
핵심 식을 한자리에 모읍니다.
| 무엇을 줄이나 | 어떻게 | 비용 |
|---|---|---|
| 배치를 키움 | 표본을 더 봄 | 계산에 비례 |
| 모멘텀 | 과거 그래디언트 평균 | 저장 한 벌 |
| 기준점 보정 | 공통 잡음을 뺌 | 가끔 전체 계산 |
| 파라미터 평균 | 걸음들의 평균 | 저장 한 벌 |
| 학습률 감소 | 떨림 자체를 줄임 | 없음 |
문제 6. 모멘텀이 걸음 크기를 몇 배로 키우는지 쓰세요.
답. 나누기 빼기 계수만큼입니다.
문제 7. 검산에서 계수 일 때 같은 학습률과 나눠 맞춘 초과손실을 쓰세요.
답. 과 입니다.
문제 8. 검산에서 계수 의 유효 표본 수와 분산 비를 쓰세요.
답. 과 입니다.
문제 9. 잡음이 없어도 모멘텀이 도움이 되는 이유를 쓰세요.
답. 골짜기에서 같은 방향의 그래디언트가 쌓이기 때문입니다.
문제 10. 검산에서 계수 과 의 걸음 수를 쓰세요.
답. 와 입니다.
문제 11. 검산에서 계수 의 초과손실을 쓰세요.
답. 입니다.
문제 12. 기준점 보정이 편향을 안 만드는 이유를 쓰세요.
답. 기댓값을 취하면 보정 항 둘이 서로 지워지기 때문입니다.
문제 13. 검산에서 기준점 거리 일 때 보통 분산과 보정 분산을 쓰세요.
답. 과 입니다.
문제 14. 검산에서 갱신 주기 의 자료 통과 횟수를 쓰세요.
답. 입니다.
문제 15. 검산에서 학습률 일 때 평균이 몇 배 좋아졌는지 쓰세요.
답. 배입니다.
문제 16. 검산에서 코사인 감소와 고정 학습률 평균의 초과손실을 쓰세요.
답. 와 입니다.
문제 17. 검산에서 아무것도 안 쓴 것과 셋 다 쓴 것의 초과손실을 쓰세요.
답. 과 입니다.
문제 18. 잡음이 필요한 경우를 쓰세요.
답. 골이 여럿이라 국소 최소를 탈출해야 할 때입니다.
심화 1. 모멘텀의 유효 표본 수를 유도하세요.
이고 들이 독립이면 이렇습니다.
| 무엇 | 값 |
|---|---|
| 분산 비 | |
| 유효 표본 수 | 그 역수 |
문제 의 표가 이 식의 확인입니다. 유효 표본 수 의 역수가 분산 비 과 맞습니다.
독립 가정이 깨지면 달라집니다. 실제 학습에서는 연속한 걸음의 그래디언트가 상관이 있어 유효 표본 수가 이보다 작습니다.
심화 2. 네스테로프 가속을 정리하세요.
| 무엇이 다른가 | 왜 |
|---|---|
| 미리 가 본 자리에서 잼 | 관성으로 갈 곳을 먼저 봄 |
| 볼록에서 속도가 최적 | |
| 확률적일 때 이득이 작음 | 잡음이 미리 보기를 흐림 |
둘째 줄이 이론의 자랑입니다. 보통 경사하강의 보다 빠릅니다.
셋째 줄이 실무의 관찰입니다. 신경망에서 네스테로프와 보통 모멘텀의 차이는 대개 작습니다.
심화 3. 분산 감소 방법들을 정리하세요.
| 방법 | 무엇을 기준점으로 |
|---|---|
| SVRG | 주기마다 갱신하는 한 점 |
| SAG | 표본마다 마지막 그래디언트 |
| SAGA | SAG를 편향 없게 고침 |
| SPIDER | 재귀적으로 갱신 |
둘째 줄은 메모리가 표본 수에 비례합니다. 표본이 백만 개면 그래디언트를 백만 개 저장해야 합니다.
첫째 줄이 메모리는 아끼지만 주기마다 전체를 훑습니다. 문제 에서 자료 통과가 세 배 늘어난 것이 그 값입니다.
심화 4. 확률적 가중 평균을 정리하세요.
| 단계 | 무엇을 하나 |
|---|---|
| 첫째 | 보통대로 학습합니다 |
| 둘째 | 뒤쪽에서 학습률을 큰 값에 고정합니다 |
| 셋째 | 주기마다 파라미터를 모아 평균 냅니다 |
| 넷째 | 평균을 답으로 씁니다 |
둘째 줄이 뜻밖입니다. 학습률을 일부러 크게 유지해 넓게 돌아다니게 합니다.
넓은 골의 가운데를 찾는 것이 목적입니다. 평평한 최소가 일반화에 유리하다는 관찰과 이어집니다.
심화 5. 잡음이 정규화 노릇을 한다는 것을 정리하세요.
| 관찰 | 무엇 |
|---|---|
| 작은 배치가 일반화에 유리할 때가 있음 | 잡음이 큼 |
| 잡음이 평평한 최소를 고름 | 좁은 골에서 튕겨 나옴 |
| 큰 배치는 좁은 최소에 들어감 | 일반화가 나쁠 수 있음 |
| 다만 항상은 아님 | 강 문제 |
넷째 줄이 중요합니다. 강에서 이 효과를 재현하려 했으나 그 자료에서는 안 나타났습니다.
조건이 맞아야 나타나는 효과이지 법칙이 아닙니다.
심화 6. 이 강의가 다음 단원으로 어떻게 이어지는지 정리하세요.
| 이 강의에서 | 다음에서 |
|---|---|
| 모멘텀 | 강 아담의 첫째 모멘트 |
| 그래디언트 제곱의 평균 | 강 아담의 둘째 모멘트 |
| 조건수 문제 | 강부터 강 |
| 잡음이 필요함 | 강 층을 지나는 그래디언트 |
| 파라미터 평균 | 실무의 지수이동평균 |
강의 아담은 이 강의의 모멘텀에 좌표별 크기 조절을 더한 것입니다. 첫째 모멘트가 문제 의 이고, 거기에 그래디언트 제곱의 평균을 하나 더 들고 다닙니다.
단원부터는 무엇을 학습시킬지로 넘어갑니다. 지금까지 어떻게 학습시킬지만 봤고, 정작 무엇을 쌓을지는 안 정했습니다.
정답.
| 기호 | 읽는 법 | 뜻 |
|---|---|---|
| 모멘텀 | momentum | 과거 그래디언트를 지수 가중으로 섞습니다 |
| 실효 걸음 배수 | effective step multiplier | 모멘텀이 걸음을 키우는 배수입니다 |
| 유효 표본 수 | effective sample size | 몇 걸음을 평균 낸 셈인지입니다 |
| 네스테로프 가속 | Nesterov acceleration | 미리 가 본 자리에서 그래디언트를 잽니다 |
| 분산 감소 | variance reduction | 기준점을 써서 잡음을 뺍니다 |
| SVRG | stochastic variance reduced gradient | 주기마다 기준점을 갱신합니다 |
| 폴략 평균 | Polyak averaging | 걸음들의 평균을 답으로 씁니다 |
| 지수이동평균 | exponential moving average | 최근에 무게를 더 주어 평균 냅니다 |
| 확률적 가중 평균 | stochastic weight averaging | 큰 학습률로 돌며 주기마다 모아 평균 냅니다 |
| 평평한 최소 | flat minimum | 둘레가 완만한 최소점입니다 |
여기까지가 단원 확률적 최적화입니다. 네 강의로 잡음을 어떻게 다룰지를 세웠습니다. 단원부터는 무엇을 학습시킬지로 넘어갑니다. 지금까지 최적화만 봤고 모형은 여전히 선형이었습니다. 강부터 층을 쌓습니다.
import numpy as np
def pw(s):
return sum(2 if ord(c) > 0x1100 else 1 for c in str(s))
def rw(s, w):
return str(s) + ' ' * max(0, w - pw(s))
def rl(s, w):
return ' ' * max(0, w - pw(s)) + str(s)
print("=" * 78)
print("238강 그래디언트 잡음과 분산 감소 코드 검산")
print("=" * 78)
rng = np.random.default_rng(20238)
n, p = 2000, 12
X = rng.normal(0, 1, (n, p))
beta = rng.normal(0, 1, p)
y = X @ beta + rng.normal(0, 1.0, n)
H = X.T @ X / n
bstar = np.linalg.solve(H, X.T @ y / n)
ev = np.linalg.eigvalsh(H)
Lsm = float(ev.max())
cap = 2.0 / Lsm
def loss(b):
r = X @ b - y
return float((r ** 2).mean() / 2)
opt = loss(bstar)
def gi(b, i):
xi = X[i]
return xi * (xi @ b - y[i])
def gmb(b, idx):
Xi = X[idx]
return Xi.T @ (Xi @ b - y[idx]) / len(idx)
print()
print("문제 1. 잡음을 줄이는 세 가지 길")
print()
print(" (1) 방법들을 정리합니다")
rows = [
("배치를 키움", "표본을 더 봄", "계산이 비례해 늘음"),
("과거를 섞음", "모멘텀", "공짜에 가까움"),
("기준점을 씀", "분산 감소 방법", "가끔 전체를 봄"),
("평균을 냄", "폴략 평균", "걸음은 그대로"),
]
w = [max(pw(r[i]) for r in rows + [("방법", "무엇을 하나", "비용")]) for i in range(3)]
print(" " + rw("방법", w[0]) + " " + rw("무엇을 하나", w[1]) + " " + "비용")
for r in rows:
print(" " + rw(r[0], w[0]) + " " + rw(r[1], w[1]) + " " + r[2])
print(" 237강에서 첫 줄이 임계 배치 크기에서 막히는 것을 봤습니다")
print(" 이 강의는 나머지 셋을 봅니다")
print()
print(" (2) 모멘텀이 무엇을 하는지 봅니다")
print(" 과거 걸음을 계수 만큼 섞어 나아갑니다")
def run_mom(B, lr, mom, steps, seed, tail=500):
rr = np.random.default_rng(seed)
b = np.zeros(p)
v = np.zeros(p)
acc = []
for t in range(steps):
idx = rr.integers(0, n, B)
g = gmb(b, idx)
v = mom * v + g
b -= lr * v
if not np.all(np.isfinite(b)):
return float('inf')
if t >= steps - tail:
acc.append(loss(b) - opt)
return float(np.mean(acc))
print(" " + rl("모멘텀 계수", 14) + " " + rl("실효 걸음 배수", 16) + " " + rl("같은 학습률에서", 18) + " " + rl("학습률을 나눠 맞추면", 24))
old = np.seterr(over='ignore', invalid='ignore')
for m in [0.0, 0.5, 0.9, 0.99]:
v1 = run_mom(16, 0.02, m, 6000, 11)
v2 = run_mom(16, 0.02 * (1 - m), m, 6000, 11)
t1 = "%.8f" % v1 if np.isfinite(v1) and v1 < 1e3 else "발산"
t2 = "%.8f" % v2 if np.isfinite(v2) and v2 < 1e3 else "발산"
print(" " + rl("%.4f" % m, 14) + " " + rl("%.6f" % (1.0 / (1 - m)), 16) + " " + rl(t1, 18) + " " + rl(t2, 24))
np.seterr(**old)
print(" 모멘텀은 걸음을 1 나누기 1 빼기 계수 만큼 키웁니다")
print(" 그래서 학습률을 그만큼 나눠야 같은 조건이 됩니다")
print(" 맞춰 주면 계수를 키울수록 떨림이 줄어듭니다")
print()
print(" (3) 모멘텀이 평균을 내는 것임을 확인합니다")
print(" 모멘텀 벡터는 과거 그래디언트의 가중 평균입니다")
print(" " + rl("모멘텀 계수", 14) + " " + rl("유효 표본 수", 16) + " " + rl("모멘텀 벡터의 분산", 20) + " " + rl("한 걸음 분산 대비", 20))
b_pr = bstar + 0.4 * rng.normal(0, 1, p)
one_var = None
for m in [0.0, 0.5, 0.9, 0.99]:
vs = []
for rep in range(400):
rr = np.random.default_rng(500 + rep)
v = np.zeros(p)
for _ in range(400):
idx = rr.integers(0, n, 16)
v = m * v + gmb(b_pr, idx)
vs.append(v * (1 - m))
vv = float(np.array(vs).var(axis=0).sum())
if one_var is None:
one_var = vv
print(" " + rl("%.4f" % m, 14) + " " + rl("%.6f" % ((1 + m) / (1 - m)), 16) + " " + rl("%.6f" % vv, 20) + " " + rl("%.6f" % (vv / one_var), 20))
print(" 계수 0.9 면 대략 열아홉 걸음을 평균 낸 셈입니다")
print(" 분산이 그만큼 줄어듭니다")
print(" 배치를 키우지 않고 잡음을 줄인 것입니다")
print()
print("문제 2. 모멘텀이 실제로 무엇을 바꾸는가")
print()
print(" (1) 두 효과를 가릅니다")
rows = [
("잡음 평균", "과거를 섞어 분산이 줄음", "확률적일 때"),
("골짜기 가속", "같은 방향이 쌓임", "잡음이 없어도"),
("어느 쪽이 큰가", "문제에 달림", "아래에서 확인"),
]
w = [max(pw(r[i]) for r in rows + [("효과", "무엇인가", "언제")]) for i in range(3)]
print(" " + rw("효과", w[0]) + " " + rw("무엇인가", w[1]) + " " + "언제")
for r in rows:
print(" " + rw(r[0], w[0]) + " " + rw(r[1], w[1]) + " " + r[2])
print()
print(" (2) 잡음이 없을 때도 도움이 되는지 봅니다")
Xc = rng.normal(0, 1, (n, p))
for j in range(p):
Xc[:, j] *= 10.0 ** (1.0 * j / (p - 1))
yc = Xc @ beta
Hc = Xc.T @ Xc / n
evc = np.linalg.eigvalsh(Hc)
bsc = np.linalg.solve(Hc, Xc.T @ yc / n)
optc = float(((Xc @ bsc - yc) ** 2).mean() / 2)
kappa = float(evc.max() / evc.min())
print(" 전체 배치로만 돌립니다. 잡음이 아예 없습니다")
print(" 학습률은 1 빼기 계수를 곱한 뒤 상한의 몇 배까지도 훑습니다")
print(" 조건수는 %.6f 입니다" % kappa)
print(" " + rl("모멘텀 계수", 14) + " " + rl("고른 학습률", 14) + " " + rl("초과손실 0.01 까지 걸음", 26))
old = np.seterr(over='ignore', invalid='ignore')
for m in [0.0, 0.5, 0.9, 0.99]:
best = None
for q in [0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 0.95, 1.5, 2.5, 3.5]:
lr = q * (2.0 / float(evc.max())) * (1 - m)
b = np.zeros(p)
v = np.zeros(p)
hit = None
for t in range(1, 30001):
g = Xc.T @ (Xc @ b - yc) / n
v = m * v + g
b -= lr * v
if not np.all(np.isfinite(b)):
break
if float(((Xc @ b - yc) ** 2).mean() / 2) - optc < 0.01:
hit = t
break
if hit is not None and (best is None or hit < best[1]):
best = (lr, hit)
print(" " + rl("%.4f" % m, 14) + " " + rl("%.6f" % best[0] if best else "없음", 14) + " " + rl("%d" % best[1] if best else "못 닿음", 26))
np.seterr(**old)
print(" 잡음이 하나도 없는데 계수 0.5 에서 걸음이 65 에서 22 로 세 배 줄어듭니다")
print(" 골짜기에서 같은 방향의 그래디언트가 쌓이기 때문입니다")
print(" 그런데 0.9 와 0.99 에서는 다시 느려집니다. 최적을 지나쳤기 때문입니다")
print(" 이론이 말하는 최적 계수는 %.6f 이고 그때 학습률은 %.6f 입니다" % (
((np.sqrt(float(evc.max())) - np.sqrt(float(evc.min()))) / (np.sqrt(float(evc.max())) + np.sqrt(float(evc.min())))) ** 2,
4.0 / (np.sqrt(float(evc.max())) + np.sqrt(float(evc.min()))) ** 2))
print(" 표에서 0.5 가 그 값에 가장 가깝습니다")
print(" 237강 문제 4 의 조건수 문제를 모멘텀이 어느 정도 풉니다")
print()
print(" (3) 방향별로 무엇이 달라지는지 봅니다")
evals_c, evecs_c = np.linalg.eigh(Hc)
print(" 전체 배치에서 방향마다 남은 오차를 봅니다")
d0 = evecs_c.T @ (np.zeros(p) - bsc)
print(" " + rl("고윳값", 12) + " " + rl("모멘텀 없이 300 걸음", 24) + " " + rl("모멘텀 0.9 로 300 걸음", 26))
res = {}
for m in [0.0, 0.9]:
lr = 0.9 * (2.0 / float(evc.max())) * (1 - m)
b = np.zeros(p)
v = np.zeros(p)
for _ in range(300):
g = Xc.T @ (Xc @ b - yc) / n
v = m * v + g
b -= lr * v
res[m] = evecs_c.T @ (b - bsc)
for j in [0, len(evals_c) // 2, len(evals_c) - 1]:
print(" " + rl("%.6f" % evals_c[j], 12) + " " + rl("%.8f" % (abs(res[0.0][j]) / abs(d0[j])), 24) + " " + rl("%.8f" % (abs(res[0.9][j]) / abs(d0[j])), 26))
print(" 값은 처음 오차 대비 남은 비율입니다")
print(" 고윳값이 작은 방향에서 차이가 가장 큽니다")
print(" 모멘텀이 느린 방향을 밀어 줍니다")
print()
print(" (4) 계수를 너무 키우면 어떻게 되는지 봅니다")
print(" 학습률을 1 빼기 계수로 나눠 맞춘 뒤 더 키워 봅니다")
print(" " + rl("모멘텀 계수", 14) + " " + rl("맞춘 학습률", 14) + " " + rl("초과손실", 16) + " " + "어떻게 되나")
old = np.seterr(over='ignore', invalid='ignore')
for m in [0.9, 0.99, 0.999, 0.9999]:
lr = 0.02 * (1 - m)
v = run_mom(16, lr, m, 6000, 12)
ok = np.isfinite(v) and v < 1e3
print(" " + rl("%.4f" % m, 14) + " " + rl("%.8f" % lr, 14) + " " + rl("%.8f" % v if ok else "발산", 16) + " " + ("수렴" if ok else "발산"))
np.seterr(**old)
print(" 0.99 까지는 좋아지다가 0.999 부터 나빠집니다")
print(" 0.9999 에서는 초과손실이 마흔 배 넘게 커집니다")
print(" 평균 낼 과거가 걸음 수에 가까워지면 앞쪽 걸음이 계속 발목을 잡습니다")
print(" 실무에서 0.9 나 0.99 를 쓰는 이유입니다")
print()
print("문제 3. 기준점을 쓰는 방법")
print()
print(" (1) 생각을 정리합니다")
rows = [
("문제", "미니배치 그래디언트가 흔들림", "분산이 큼"),
("생각", "가끔 전체를 계산해 기준으로 둠", "기준점"),
("보정", "지금 표본과 기준점의 차이만 씀", "차이는 작음"),
("결과", "편향 없이 분산이 줄음", "SVRG"),
]
w = [max(pw(r[i]) for r in rows + [("무엇", "무엇인가", "덧붙임")]) for i in range(3)]
print(" " + rw("무엇", w[0]) + " " + rw("무엇인가", w[1]) + " " + "덧붙임")
for r in rows:
print(" " + rw(r[0], w[0]) + " " + rw(r[1], w[1]) + " " + r[2])
print(" 보정한 그래디언트는 지금 표본의 값 빼기 기준점 표본의 값 더하기 기준점 전체 값입니다")
print(" 기댓값을 취하면 뒤 둘이 지워져 편향이 없습니다")
print()
print(" (2) 편향이 없고 분산이 줄어드는 것을 확인합니다")
b_now = bstar + 0.3 * rng.normal(0, 1, p)
for shift in [0.05, 0.3, 1.0]:
b_ref = b_now + shift * rng.normal(0, 1, p) / np.sqrt(p)
g_ref_full = X.T @ (X @ b_ref - y) / n
g_now_full = X.T @ (X @ b_now - y) / n
plain, svrg = [], []
for rep in range(3000):
i = int(rng.integers(0, n))
plain.append(gi(b_now, i))
svrg.append(gi(b_now, i) - gi(b_ref, i) + g_ref_full)
plain = np.array(plain)
svrg = np.array(svrg)
if shift == 0.05:
print(" " + rl("기준점과의 거리", 18) + " " + rl("보통 편향", 14) + " " + rl("보정 편향", 14) + " " + rl("보통 분산", 16) + " " + rl("보정 분산", 16))
print(" " + rl("%.4f" % float(np.linalg.norm(b_now - b_ref)), 18) + " " +
rl("%.6f" % float(np.abs(plain.mean(axis=0) - g_now_full).max()), 14) + " " +
rl("%.6f" % float(np.abs(svrg.mean(axis=0) - g_now_full).max()), 14) + " " +
rl("%.6f" % float(plain.var(axis=0).sum()), 16) + " " +
rl("%.6f" % float(svrg.var(axis=0).sum()), 16))
print(" 두 편향이 모두 0 에 가깝습니다. 보정이 편향을 안 만듭니다")
print(" 기준점이 가까울수록 분산이 크게 줄어듭니다")
print(" 멀어지면 이득이 사라집니다. 그래서 기준점을 주기적으로 갱신합니다")
print()
print(" (3) 실제로 학습시켜 견줍니다")
def run_svrg(B, lr, steps, inner, seed, tail=500):
rr = np.random.default_rng(seed)
b = np.zeros(p)
acc = []
t = 0
while t < steps:
b_ref = b.copy()
g_ref = X.T @ (X @ b_ref - y) / n
for _ in range(inner):
if t >= steps:
break
idx = rr.integers(0, n, B)
g = gmb(b, idx) - gmb(b_ref, idx) + g_ref
b -= lr * g
t += 1
if not np.all(np.isfinite(b)):
return float('inf'), 0
if t >= steps - tail:
acc.append(loss(b) - opt)
passes = (steps // inner) * 1.0 + steps * 2.0 * B / n
return float(np.mean(acc)), passes
print(" 기준점을 몇 걸음마다 갱신할지 바꿔 봅니다")
print(" " + rl("갱신 주기", 12) + " " + rl("초과손실", 18) + " " + rl("자료 통과 횟수", 18))
old = np.seterr(over='ignore', invalid='ignore')
v0 = run_mom(16, 0.02, 0.0, 6000, 21)
print(" " + rw("보통 미니배치", 12) + " " + rl("%.10f" % v0, 18) + " " + rl("%.4f" % (6000 * 16 / float(n)), 18))
for inner in [125, 500, 2000]:
v, ps = run_svrg(16, 0.02, 6000, inner, 21)
txt = "%.10f" % v if np.isfinite(v) and v < 1e3 else "발산"
print(" " + rl("%d" % inner, 12) + " " + rl(txt, 18) + " " + rl("%.4f" % ps, 18))
np.seterr(**old)
print(" 보정하면 초과손실이 크게 줄어듭니다")
print(" 대신 기준점 계산 때문에 자료 통과 횟수가 늘어납니다")
print(" 갱신을 자주 하면 분산은 더 줄지만 비용이 커집니다")
print()
print(" (4) 왜 딥러닝에서 잘 안 쓰는지 봅니다")
rows = [
("가정", "손실면이 볼록하고 매끄러움", "신경망은 아님"),
("기준점", "전체 그래디언트를 계산", "자료가 크면 비쌈"),
("저장", "기준점 파라미터 한 벌 더", "메모리 두 배"),
("실효", "잡음이 정규화 노릇도 함", "줄이면 손해일 수도"),
]
w = [max(pw(r[i]) for r in rows + [("무엇", "무엇이 문제", "덧붙임")]) for i in range(3)]
print(" " + rw("무엇", w[0]) + " " + rw("무엇이 문제", w[1]) + " " + "덧붙임")
for r in rows:
print(" " + rw(r[0], w[0]) + " " + rw(r[1], w[1]) + " " + r[2])
print(" 마지막 줄이 가장 큰 이유입니다. 236강 문제 3 에서 잡음이 골을 넘게 해 줬습니다")
print(" 볼록한 문제에서는 잡음이 순수한 손해라 줄이는 것이 언제나 이득입니다")
print()
print("문제 4. 평균을 내는 방법")
print()
print(" (1) 두 평균을 가릅니다")
rows = [
("폴략 평균", "걸음들의 평균을 답으로", "학습에는 안 씀"),
("지수이동평균", "최근에 무게를 더", "실무의 기본"),
("모멘텀과의 차이", "모멘텀은 그래디언트를 평균", "이쪽은 파라미터를 평균"),
]
w = [max(pw(r[i]) for r in rows + [("무엇", "무엇을 하나", "덧붙임")]) for i in range(3)]
print(" " + rw("무엇", w[0]) + " " + rw("무엇을 하나", w[1]) + " " + "덧붙임")
for r in rows:
print(" " + rw(r[0], w[0]) + " " + rw(r[1], w[1]) + " " + r[2])
print()
print(" (2) 폴략 평균을 써 봅니다")
def run_avg(B, lr, steps, seed, avg_from=0.5, ema=None):
rr = np.random.default_rng(seed)
b = np.zeros(p)
s = np.zeros(p)
cnt = 0
e = None
start = int(steps * avg_from)
for t in range(steps):
idx = rr.integers(0, n, B)
b -= lr * gmb(b, idx)
if t >= start:
s += b
cnt += 1
if ema is not None:
e = b.copy() if e is None else ema * e + (1 - ema) * b
out = {"마지막": loss(b) - opt, "폴략 평균": loss(s / cnt) - opt}
if ema is not None:
out["지수이동평균"] = loss(e) - opt
return out
print(" 학습률을 고정하고 6000 걸음 갑니다")
print(" " + rl("학습률", 12) + " " + rl("마지막 걸음", 16) + " " + rl("뒤 절반 평균", 16) + " " + rl("몇 배 좋아졌나", 16))
for lr in [0.05, 0.02, 0.01]:
r = run_avg(16, lr, 6000, 31)
print(" " + rl("%.4f" % lr, 12) + " " + rl("%.8f" % r["마지막"], 16) + " " + rl("%.8f" % r["폴략 평균"], 16) + " " + rl("%.4f" % (r["마지막"] / r["폴략 평균"]), 16))
print(" 평균을 내면 크게 좋아집니다. 걸음은 하나도 더 안 갔습니다")
print(" 떨림이 최적점 둘레를 도는 것이라 평균이 가운데를 찾습니다")
print(" 236강 심화 3 의 폴략 평균이 여기서 확인됩니다")
print()
print(" (3) 지수이동평균과 견줍니다")
print(" " + rl("감쇠 계수", 12) + " " + rl("마지막 걸음", 16) + " " + rl("폴략 평균", 16) + " " + rl("지수이동평균", 16))
for em in [0.9, 0.99, 0.999]:
r = run_avg(16, 0.02, 6000, 32, ema=em)
print(" " + rl("%.4f" % em, 12) + " " + rl("%.8f" % r["마지막"], 16) + " " + rl("%.8f" % r["폴략 평균"], 16) + " " + rl("%.8f" % r["지수이동평균"], 16))
print(" 감쇠 계수가 클수록 더 긴 과거를 평균 내 좋아집니다")
print(" 폴략 평균은 처음부터 다 세지만 지수이동평균은 최근만 봅니다")
print(" 학습률을 줄여 가는 실무에서는 지수이동평균이 낫습니다")
print()
print(" (4) 학습률을 줄이는 것과 견줍니다")
print(" 떨림을 줄이는 두 길을 같은 예산에서 봅니다")
print(" " + rw("무엇을 했나", 24) + " " + rl("초과손실", 18))
r_fix = run_avg(16, 0.02, 6000, 33)
print(" " + rw("고정 학습률 마지막", 24) + " " + rl("%.10f" % r_fix["마지막"], 18))
print(" " + rw("고정 학습률 평균", 24) + " " + rl("%.10f" % r_fix["폴략 평균"], 18))
rr = np.random.default_rng(33)
b = np.zeros(p)
T = 6000
for t in range(1, T + 1):
idx = rr.integers(0, n, 16)
b -= 0.02 * 0.5 * (1 + np.cos(np.pi * t / T)) * gmb(b, idx)
print(" " + rw("코사인 감소 마지막", 24) + " " + rl("%.10f" % (loss(b) - opt), 18))
print(" 감소식이 평균보다 더 좋습니다")
print(" 다만 감소식은 예산을 미리 정해야 하고 평균은 안 그렇습니다")
print(" 둘을 함께 쓰는 것이 실무의 기본입니다")
print()
print("문제 5. 실무에서 쓰기")
print()
print(" (1) 무엇을 먼저 쓸지 정리합니다")
rows = [
("모멘텀", "언제나", "거의 공짜"),
("지수이동평균", "거의 언제나", "저장만 한 벌"),
("배치 키우기", "잡음 비가 클 때", "237강 임계점까지"),
("분산 감소 방법", "볼록한 문제", "딥러닝에서는 드묾"),
("학습률 감소", "언제나", "236강"),
]
w = [max(pw(r[i]) for r in rows + [("무엇", "언제", "비용")]) for i in range(3)]
print(" " + rw("무엇", w[0]) + " " + rw("언제", w[1]) + " " + "비용")
for r in rows:
print(" " + rw(r[0], w[0]) + " " + rw(r[1], w[1]) + " " + r[2])
print()
print(" (2) 넷을 함께 쓰면 어떻게 되는지 봅니다")
def run_all(B, lr0, mom, T, seed, use_cos, use_ema):
rr = np.random.default_rng(seed)
b = np.zeros(p)
v = np.zeros(p)
e = None
for t in range(1, T + 1):
lr = lr0 * (0.5 * (1 + np.cos(np.pi * t / T)) if use_cos else 1.0)
idx = rr.integers(0, n, B)
v = mom * v + gmb(b, idx)
b -= lr * v
if not np.all(np.isfinite(b)):
return float('inf')
if use_ema:
e = b.copy() if e is None else 0.999 * e + 0.001 * b
return loss(e if use_ema else b) - opt
print(" 배치 16 에 6000 걸음으로 고정하고 하나씩 켜 봅니다")
combos = [
("아무것도 없이", 0.0, False, False),
("모멘텀만", 0.9, False, False),
("모멘텀과 감소식", 0.9, True, False),
("셋 다", 0.9, True, True),
]
old = np.seterr(over='ignore', invalid='ignore')
for nm, m, cos, ema in combos:
lr0 = 0.02 * (1 - m) if m > 0 else 0.02
v = run_all(16, lr0, m, 6000, 41, cos, ema)
txt = "%.10f" % v if np.isfinite(v) and v < 1e3 else "발산"
print(" " + rw(nm, 20) + " " + rl(txt, 18))
np.seterr(**old)
print(" 하나씩 켤 때마다 좋아집니다")
print(" 서로 다른 자리에서 잡음을 줄이기 때문에 겹치지 않습니다")
print()
print(" (3) 잡음이 필요한 경우를 확인합니다")
def f4(x):
return float(x ** 4 / 4 - x ** 2 / 2 + 0.1 * x)
def g4(x, noise, rr):
return x ** 3 - x + 0.1 + noise * rr.normal()
print(" 236강 문제 3 의 골 두 개짜리 함수로 돌아갑니다")
print(" " + rl("잡음 크기", 12) + " " + rl("모멘텀 없이 깊은 골", 22) + " " + rl("모멘텀 0.9 로 깊은 골", 24))
for noise in [0.0, 1.0, 2.0, 3.0]:
out = []
for m in [0.0, 0.9]:
deep = 0
for sd in range(200):
rr = np.random.default_rng(3000 + sd)
x = 0.9
v = 0.0
for t in range(1, 5001):
v = m * v + g4(x, noise, rr)
x -= 0.05 * (1 - m) * v
if not np.isfinite(x) or abs(x) > 1e3:
break
if np.isfinite(x) and x < 0 and abs(x) < 3:
deep += 1
out.append(deep / 200.0)
print(" " + rl("%.4f" % noise, 12) + " " + rl("%.6f" % out[0], 22) + " " + rl("%.6f" % out[1], 24))
print(" 잡음이 있어야 깊은 골로 넘어갑니다")
print(" 모멘텀이 있고 없고는 여기서 큰 차이를 안 냅니다")
print(" 실효 걸음을 맞춰 두면 넘어가는 힘도 비슷해지기 때문입니다")
print(" 중요한 것은 잡음을 줄이는 것이 언제나 좋지는 않다는 사실입니다")
print()
print(" (4) 이 단원을 한 장으로 모읍니다")
rows = [
("235", "왜 일부만 봐도 되나", "편향이 없고 분산만 있습니다"),
("236", "언제 멈추나", "학습률을 0 으로 보내야 닿습니다"),
("237", "배치를 얼마나 키우나", "임계 배치 크기까지입니다"),
("238", "달리 잡음을 줄이려면", "모멘텀과 평균을 씁니다"),
]
w = [max(pw(r[i]) for r in rows + [("강", "무엇을 물었나", "한 줄 답")]) for i in range(3)]
print(" " + rw("강", w[0]) + " " + rw("무엇을 물었나", w[1]) + " " + "한 줄 답")
for r in rows:
print(" " + rw(r[0], w[0]) + " " + rw(r[1], w[1]) + " " + r[2])
print(" 네 강의가 하나의 물음에 답합니다. 잡음을 어떻게 다룰 것인가입니다")
print(" 03 단원부터는 무엇을 학습시킬지로 넘어갑니다")
print()
print("=" * 78)
print("검산 끝")
print("=" * 78)
# ==============================================================================
# 238강 그래디언트 잡음과 분산 감소 코드 검산
# ==============================================================================
#
# 문제 1. 잡음을 줄이는 세 가지 길
#
# (1) 방법들을 정리합니다
# 방법 무엇을 하나 비용
# 배치를 키움 표본을 더 봄 계산이 비례해 늘음
# 과거를 섞음 모멘텀 공짜에 가까움
# 기준점을 씀 분산 감소 방법 가끔 전체를 봄
# 평균을 냄 폴략 평균 걸음은 그대로
# 237강에서 첫 줄이 임계 배치 크기에서 막히는 것을 봤습니다
# 이 강의는 나머지 셋을 봅니다
#
# (2) 모멘텀이 무엇을 하는지 봅니다
# 과거 걸음을 계수 만큼 섞어 나아갑니다
# 모멘텀 계수 실효 걸음 배수 같은 학습률에서 학습률을 나눠 맞추면
# 0.0000 1.000000 0.00359812 0.00359812
# 0.5000 2.000000 0.00731684 0.00358368
# 0.9000 10.000000 0.04446094 0.00358980
# 0.9900 100.000000 1.45198881 0.00348313
# 모멘텀은 걸음을 1 나누기 1 빼기 계수 만큼 키웁니다
# 그래서 학습률을 그만큼 나눠야 같은 조건이 됩니다
# 맞춰 주면 계수를 키울수록 떨림이 줄어듭니다
#
# (3) 모멘텀이 평균을 내는 것임을 확인합니다
# 모멘텀 벡터는 과거 그래디언트의 가중 평균입니다
# 모멘텀 계수 유효 표본 수 모멘텀 벡터의 분산 한 걸음 분산 대비
# 0.0000 1.000000 2.365110 1.000000
# 0.5000 3.000000 0.792058 0.334892
# 0.9000 19.000000 0.127709 0.053997
# 0.9900 199.000000 0.012285 0.005194
# 계수 0.9 면 대략 열아홉 걸음을 평균 낸 셈입니다
# 분산이 그만큼 줄어듭니다
# 배치를 키우지 않고 잡음을 줄인 것입니다
#
# 문제 2. 모멘텀이 실제로 무엇을 바꾸는가
#
# (1) 두 효과를 가릅니다
# 효과 무엇인가 언제
# 잡음 평균 과거를 섞어 분산이 줄음 확률적일 때
# 골짜기 가속 같은 방향이 쌓임 잡음이 없어도
# 어느 쪽이 큰가 문제에 달림 아래에서 확인
#
# (2) 잡음이 없을 때도 도움이 되는지 봅니다
# 전체 배치로만 돌립니다. 잡음이 아예 없습니다
# 학습률은 1 빼기 계수를 곱한 뒤 상한의 몇 배까지도 훑습니다
# 조건수는 104.933200 입니다
# 모멘텀 계수 고른 학습률 초과손실 0.01 까지 걸음
# 0.0000 0.018954 65
# 0.5000 0.024940 22
# 0.9000 0.002993 69
# 0.9900 0.000299 604
# 잡음이 하나도 없는데 계수 0.5 에서 걸음이 65 에서 22 로 세 배 줄어듭니다
# 골짜기에서 같은 방향의 그래디언트가 쌓이기 때문입니다
# 그런데 0.9 와 0.99 에서는 다시 느려집니다. 최적을 지나쳤기 때문입니다
# 이론이 말하는 최적 계수는 0.675885 이고 그때 학습률은 0.033122 입니다
# 표에서 0.5 가 그 값에 가장 가깝습니다
# 237강 문제 4 의 조건수 문제를 모멘텀이 어느 정도 풉니다
#
# (3) 방향별로 무엇이 달라지는지 봅니다
# 전체 배치에서 방향마다 남은 오차를 봅니다
# 고윳값 모멘텀 없이 300 걸음 모멘텀 0.9 로 300 걸음
# 0.955281 0.00556766 0.00205989
# 12.154193 0.00000000 0.00000000
# 100.240679 0.00000000 0.00000006
# 값은 처음 오차 대비 남은 비율입니다
# 고윳값이 작은 방향에서 차이가 가장 큽니다
# 모멘텀이 느린 방향을 밀어 줍니다
#
# (4) 계수를 너무 키우면 어떻게 되는지 봅니다
# 학습률을 1 빼기 계수로 나눠 맞춘 뒤 더 키워 봅니다
# 모멘텀 계수 맞춘 학습률 초과손실 어떻게 되나
# 0.9000 0.00200000 0.00422664 수렴
# 0.9900 0.00020000 0.00364416 수렴
# 0.9990 0.00002000 0.00949118 수렴
# 0.9999 0.00000200 0.16381115 수렴
# 0.99 까지는 좋아지다가 0.999 부터 나빠집니다
# 0.9999 에서는 초과손실이 마흔 배 넘게 커집니다
# 평균 낼 과거가 걸음 수에 가까워지면 앞쪽 걸음이 계속 발목을 잡습니다
# 실무에서 0.9 나 0.99 를 쓰는 이유입니다
#
# 문제 3. 기준점을 쓰는 방법
#
# (1) 생각을 정리합니다
# 무엇 무엇인가 덧붙임
# 문제 미니배치 그래디언트가 흔들림 분산이 큼
# 생각 가끔 전체를 계산해 기준으로 둠 기준점
# 보정 지금 표본과 기준점의 차이만 씀 차이는 작음
# 결과 편향 없이 분산이 줄음 SVRG
# 보정한 그래디언트는 지금 표본의 값 빼기 기준점 표본의 값 더하기 기준점 전체 값입니다
# 기댓값을 취하면 뒤 둘이 지워져 편향이 없습니다
#
# (2) 편향이 없고 분산이 줄어드는 것을 확인합니다
# 기준점과의 거리 보통 편향 보정 편향 보통 분산 보정 분산
# 0.0326 0.060208 0.000928 26.724278 0.014912
# 0.1282 0.039070 0.004305 27.412148 0.207312
# 0.9672 0.047776 0.042875 25.951244 11.823412
# 두 편향이 모두 0 에 가깝습니다. 보정이 편향을 안 만듭니다
# 기준점이 가까울수록 분산이 크게 줄어듭니다
# 멀어지면 이득이 사라집니다. 그래서 기준점을 주기적으로 갱신합니다
#
# (3) 실제로 학습시켜 견줍니다
# 기준점을 몇 걸음마다 갱신할지 바꿔 봅니다
# 갱신 주기 초과손실 자료 통과 횟수
# 보통 미니배치 0.0030744857 48.0000
# 125 0.0000000000 144.0000
# 500 0.0000000000 108.0000
# 2000 0.0000012171 99.0000
# 보정하면 초과손실이 크게 줄어듭니다
# 대신 기준점 계산 때문에 자료 통과 횟수가 늘어납니다
# 갱신을 자주 하면 분산은 더 줄지만 비용이 커집니다
#
# (4) 왜 딥러닝에서 잘 안 쓰는지 봅니다
# 무엇 무엇이 문제 덧붙임
# 가정 손실면이 볼록하고 매끄러움 신경망은 아님
# 기준점 전체 그래디언트를 계산 자료가 크면 비쌈
# 저장 기준점 파라미터 한 벌 더 메모리 두 배
# 실효 잡음이 정규화 노릇도 함 줄이면 손해일 수도
# 마지막 줄이 가장 큰 이유입니다. 236강 문제 3 에서 잡음이 골을 넘게 해 줬습니다
# 볼록한 문제에서는 잡음이 순수한 손해라 줄이는 것이 언제나 이득입니다
#
# 문제 4. 평균을 내는 방법
#
# (1) 두 평균을 가릅니다
# 무엇 무엇을 하나 덧붙임
# 폴략 평균 걸음들의 평균을 답으로 학습에는 안 씀
# 지수이동평균 최근에 무게를 더 실무의 기본
# 모멘텀과의 차이 모멘텀은 그래디언트를 평균 이쪽은 파라미터를 평균
#
# (2) 폴략 평균을 써 봅니다
# 학습률을 고정하고 6000 걸음 갑니다
# 학습률 마지막 걸음 뒤 절반 평균 몇 배 좋아졌나
# 0.0500 0.00316382 0.00005312 59.5578
# 0.0200 0.00131473 0.00005049 26.0418
# 0.0100 0.00106724 0.00004360 24.4754
# 평균을 내면 크게 좋아집니다. 걸음은 하나도 더 안 갔습니다
# 떨림이 최적점 둘레를 도는 것이라 평균이 가운데를 찾습니다
# 236강 심화 3 의 폴략 평균이 여기서 확인됩니다
#
# (3) 지수이동평균과 견줍니다
# 감쇠 계수 마지막 걸음 폴략 평균 지수이동평균
# 0.9000 0.00554479 0.00011756 0.00504231
# 0.9900 0.00554479 0.00011756 0.00153821
# 0.9990 0.00554479 0.00011756 0.00025690
# 감쇠 계수가 클수록 더 긴 과거를 평균 내 좋아집니다
# 폴략 평균은 처음부터 다 세지만 지수이동평균은 최근만 봅니다
# 학습률을 줄여 가는 실무에서는 지수이동평균이 낫습니다
#
# (4) 학습률을 줄이는 것과 견줍니다
# 떨림을 줄이는 두 길을 같은 예산에서 봅니다
# 무엇을 했나 초과손실
# 고정 학습률 마지막 0.0035645368
# 고정 학습률 평균 0.0001009500
# 코사인 감소 마지막 0.0000889784
# 감소식이 평균보다 더 좋습니다
# 다만 감소식은 예산을 미리 정해야 하고 평균은 안 그렇습니다
# 둘을 함께 쓰는 것이 실무의 기본입니다
#
# 문제 5. 실무에서 쓰기
#
# (1) 무엇을 먼저 쓸지 정리합니다
# 무엇 언제 비용
# 모멘텀 언제나 거의 공짜
# 지수이동평균 거의 언제나 저장만 한 벌
# 배치 키우기 잡음 비가 클 때 237강 임계점까지
# 분산 감소 방법 볼록한 문제 딥러닝에서는 드묾
# 학습률 감소 언제나 236강
#
# (2) 넷을 함께 쓰면 어떻게 되는지 봅니다
# 배치 16 에 6000 걸음으로 고정하고 하나씩 켜 봅니다
# 아무것도 없이 0.0072264476
# 모멘텀만 0.0060736557
# 모멘텀과 감소식 0.0002638790
# 셋 다 0.0001518560
# 하나씩 켤 때마다 좋아집니다
# 서로 다른 자리에서 잡음을 줄이기 때문에 겹치지 않습니다
#
# (3) 잡음이 필요한 경우를 확인합니다
# 236강 문제 3 의 골 두 개짜리 함수로 돌아갑니다
# 잡음 크기 모멘텀 없이 깊은 골 모멘텀 0.9 로 깊은 골
# 0.0000 0.000000 0.000000
# 1.0000 0.115000 0.085000
# 2.0000 0.875000 0.895000
# 3.0000 0.695000 0.680000
# 잡음이 있어야 깊은 골로 넘어갑니다
# 모멘텀이 있고 없고는 여기서 큰 차이를 안 냅니다
# 실효 걸음을 맞춰 두면 넘어가는 힘도 비슷해지기 때문입니다
# 중요한 것은 잡음을 줄이는 것이 언제나 좋지는 않다는 사실입니다
#
# (4) 이 단원을 한 장으로 모읍니다
# 강 무엇을 물었나 한 줄 답
# 235 왜 일부만 봐도 되나 편향이 없고 분산만 있습니다
# 236 언제 멈추나 학습률을 0 으로 보내야 닿습니다
# 237 배치를 얼마나 키우나 임계 배치 크기까지입니다
# 238 달리 잡음을 줄이려면 모멘텀과 평균을 씁니다
# 네 강의가 하나의 물음에 답합니다. 잡음을 어떻게 다룰 것인가입니다
# 03 단원부터는 무엇을 학습시킬지로 넘어갑니다
#
# ==============================================================================
# 검산 끝
# ==============================================================================