강에서 떨림의 크기가 로 정해진다는 것을 봤습니다. 그러면 둘을 같은 배수로 키우면 떨림이 그대로입니다.
강 문제 에서 이 규칙이 실제로 들었습니다. 그런데 배치 에서 깨졌습니다.
이 강의는 그 상한이 어디서 오는지, 어디까지 배치를 키울 값이 있는지, 그리고 배치로 못 고치는 것은 무엇인지를 봅니다.
문제. 상한을 찾습니다.
() 어디서 상한이 오는지 정리하세요.
() 전체 배치에서 확인하세요.
() 미니배치에서 얼마나 낮아지는지 보세요.
생각의 실마리. 이차형식에서 한 걸음은 오차에 를 곱합니다. 절댓값이 보다 커지면 오차가 늘어납니다.
풀이. () 정리합니다.
| 무엇 | 무엇이 정하나 | 조건 |
|---|---|---|
| 이차형식 | 절댓값이 보다 작아야 함 | |
| 가장 큰 고윳값 | 가장 먼저 터짐 | 그 방향이 상한을 정함 |
| 상한 | 전체 배치 기준 | |
| 잡음이 있으면 | 상한이 더 낮아짐 | 미니배치는 더 조심 |
이 자료의 헤세 고윳값은 최소 최대 입니다. 전체 배치의 이론 상한은 입니다.
() 전체 배치에서 확인합니다.
| 학습률 | 이론 상한 대비 | 걸음 뒤 손실 | 어떻게 되나 |
|---|---|---|---|
| 수렴 | |||
| 수렴 | |||
| 수렴 | |||
| 발산 | 발산 | ||
| 발산 | 발산 |
상한 대비 까지는 수렴하고 부터 발산합니다.
경계가 이론이 말한 자리와 정확히 맞습니다. 강 심화 에서 예고한 상한이 여기서 확인됩니다.
() 미니배치에서 얼마나 낮아지는지 봅니다.
| 배치 크기 | 발산 안 한 최대 학습률 | 전체 배치 상한 대비 |
|---|---|---|
배치 만 상한의 배에서 이미 터집니다. 부터는 격자 끝인 배까지 견딥니다.
잡음이 상한을 낮추는 효과는 아주 작은 배치에서만 뚜렷합니다. 강 문제 에서 본 것이 여기서 더 좁은 구간의 이야기로 드러납니다.
이 문제에서 배우는 것. 학습률 상한은 잡음이 아니라 손실면의 곡률이 정합니다. 미니배치의 잡음은 그 상한을 조금 더 낮출 뿐이고, 근본은 입니다.
확인 1-1. 학습률 상한을 정하는 것이 무엇인지 쓰세요.
답. 헤세의 가장 큰 고윳값이고 상한은 그 역수의 두 배입니다.
확인 1-2. 검산에서 상한 대비 과 일 때 어떻게 되는지 쓰세요.
답. 은 수렴하고 는 발산합니다.
확인 1-3. 검산에서 배치 가 견딘 최대 학습률의 상한 대비를 쓰세요.
답. 입니다.
문제. 규칙의 한계를 봅니다.
() 규칙을 적으세요.
() 같은 표본 예산에서 적용하세요.
() 상한에서 자르면 어떤지 보세요.
() 제곱근 규칙과 견주세요.
생각의 실마리. 떨림이 이므로 둘을 같이 키우면 떨림이 그대로입니다. 그런데 에는 천장이 있습니다.
풀이. () 규칙을 적습니다.
| 무엇 | 무엇인가 | 어디서 |
|---|---|---|
| 무엇을 하나 | 배치를 배 하면 학습률도 배 | 떨림 비를 지킴 |
| 왜 되나 | 떨림이 | 강 문제 |
| 언제 깨지나 | 학습률이 상한에 닿을 때 | 문제 의 상한 |
| 그 지점 | 임계 배치 크기 | 더 키워도 안 빨라짐 |
() 같은 표본 예산에서 적용합니다. 기준은 배치 에 학습률 입니다.
| 배치 크기 | 규칙이 말하는 학습률 | 걸음 수 | 초과손실 |
|---|---|---|---|
| 발산 | |||
| 발산 |
배치 와 은 초과손실이 근처로 거의 같습니다. 규칙이 듣습니다.
에서 이미 세 배 나빠지고 부터는 발산합니다. 학습률이 상한의 배를 넘어서면서 규칙이 깨집니다.
임계 배치 크기가 과 사이에 있습니다.
() 상한에서 자르면 어떤지 봅니다. 상한의 퍼센트인 에서 자릅니다.
| 배치 크기 | 자르기 전 학습률 | 실제 쓴 학습률 | 초과손실 |
|---|---|---|---|
자르면 발산이 사라집니다. 은 오히려 보다 낫습니다.
그런데 에서는 걸음이 번뿐이라 도착을 못 합니다.
학습률이 상한에 눌린 뒤로는 배치를 키우면 걸음 수만 줄어듭니다. 계산은 그대로인데 얻는 것이 없습니다.
() 제곱근 규칙과 견줍니다.
| 배치 크기 | 선형 규칙 학습률 | 선형 초과손실 | 제곱근 규칙 학습률 | 제곱근 초과손실 |
|---|---|---|---|---|
| 발산 | ||||
| 발산 |
이 자료에서는 제곱근 규칙이 배치 부터 까지 모두 낫습니다.
조건수가 라 선형 규칙이 금방 상한에 닿기 때문입니다.
에서는 제곱근 규칙도 무너집니다. 걸음이 번뿐이기 때문입니다.
어느 규칙이 옳은가가 아니라 상한에 닿았는지가 문제입니다. 상한에서 먼 구간에서는 선형이 맞고, 가까워지면 어떤 규칙도 안 됩니다.
이 문제에서 배우는 것. 선형 스케일링은 떨림에 대한 규칙이지 안정성에 대한 규칙이 아닙니다. 상한이라는 다른 제약이 먼저 걸리면 규칙 자체가 무의미해집니다.
확인 2-1. 선형 스케일링이 깨지는 조건을 쓰세요.
답. 학습률이 상한에 닿을 때입니다.
확인 2-2. 검산에서 배치 과 의 선형 규칙 초과손실을 쓰세요.
답. 과 입니다.
확인 2-3. 검산에서 배치 의 선형과 제곱근 초과손실을 쓰세요.
답. 와 입니다.
문제. 어디까지 키울지 정합니다.
() 무엇을 뜻하는지 정리하세요.
() 목표에 닿는 걸음 수를 세세요.
() 걸음 수가 얼마나 줄었는지 보세요.
() 잡음 대 신호 비로 예측하세요.
생각의 실마리. 배치를 키우면 한 걸음이 정확해집니다. 그런데 이미 충분히 정확하면 더 키워도 얻는 것이 없습니다.
풀이. () 정리합니다.
| 구간 | 무슨 일 | 뜻 |
|---|---|---|
| 작은 배치 구간 | 배치를 키우면 걸음이 줄음 | 계산에 비례해 이득 |
| 임계 배치 크기 | 이득이 꺾이는 자리 | 잡음과 신호가 같아짐 |
| 큰 배치 구간 | 키워도 걸음이 안 줄음 | 계산만 낭비 |
| 무엇이 정하나 | 잡음 나누기 신호 | 강 문제 |
() 초과손실 에 처음 닿는 걸음 수를 셉니다. 학습률은 배치마다 최적을 고릅니다.
| 배치 크기 | 고른 학습률 | 걸음 수 | 본 표본 수 |
|---|---|---|---|
배치를 에서 로 천 배 키우는 사이 걸음 수는 에서 으로 세 배 남짓만 줄었습니다.
본 표본 수는 에서 으로 삼백 배 늘었습니다.
() 걸음 수가 얼마나 줄었는지 봅니다.
| 배치 크기 | 걸음 수 | 앞 배치 대비 줄어든 비 | 이상적이면 |
|---|---|---|---|
| 기준 | 기준 | ||
셋째 열이 에서 로 계속 올라갑니다.
배치 에서 로 네 배 키우면 걸음이 배가 됩니다. 사실상 안 줄었고 계산만 네 배 쓴 것입니다.
() 잡음 대 신호 비로 예측합니다.
한 표본 그래디언트의 분산 합은 이고 전체 그래디언트 노름 제곱은 입니다.
| 배치 크기 | 잡음 나누기 신호 | 어느 구간인가 |
|---|---|---|
| 잡음이 큼 | ||
| 잡음이 큼 | ||
| 신호가 큼 | ||
| 신호가 큼 | ||
| 신호가 큼 | ||
| 신호가 큼 |
예측한 임계 배치 크기가 입니다. ()에서 에서 사이에 꺾임이 있었으니 예측과 관측이 맞습니다.
비가 을 넘는 구간에서는 배치를 키우는 것이 곧바로 이득입니다. 아래로 내려가면 이미 그래디언트가 충분히 정확해 더 키울 값이 줄어듭니다.
이 문제에서 배우는 것. 임계 배치 크기는 자료가 정하는 값입니다. 그래디언트의 잡음과 신호를 재면 학습을 돌려 보기 전에 대략 알 수 있고, 그 위로는 계산을 늘려도 시간이 안 줄어듭니다.
확인 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. 큰 배치 학습의 실무 기법을 정리하세요.
| 기법 | 무엇을 하나 |
|---|---|
| 준비 구간 | 처음에 학습률을 천천히 올립니다 |
| 층별 학습률 | 층마다 노름에 맞춰 조절합니다 |
| 라스 최적화기 | 가중치 노름 대비 갱신 노름을 맞춥니다 |
| 배치를 키워 감 | 처음에 작게 나중에 크게 |
넷째 줄이 임계 배치 크기의 직접적 응용입니다. 학습 초기에는 그래디언트가 크고 잡음 비가 낮아 작은 배치로 충분하고, 최적점에 가까워지면 신호가 작아져 큰 배치가 필요해집니다.
심화 4. 실제 신경망에서 임계 배치 크기를 재는 법을 정리하세요.
| 무엇 | 어떻게 |
|---|---|
| 두 배치로 추정 | 작은 배치와 큰 배치의 그래디언트 |
| 노름 제곱의 차 | 잡음 흔적을 뺌 |
| 학습 중에 잼 | 값이 계속 변함 |
셋째 줄이 중요합니다. 임계 배치 크기는 고정된 값이 아니라 학습이 진행되며 커집니다. 문제 은 한 지점에서 잰 값입니다.
심화 5. 조건수를 줄이는 방법들을 정리하세요.
| 방법 | 무엇을 하나 | 어디서 |
|---|---|---|
| 눈금 맞추기 | 열마다 표준화 | 강 |
| 배치 정규화 | 층 출력을 정규화 | 강 |
| 층 정규화 | 표본마다 정규화 | 강 |
| 좌표별 학습률 | 아담 | 강 |
| 이차 방법 | 헤세를 씀 | 강 |
문제 의 ()에서 첫 줄이 배치보다 스무 배 크게 들었습니다.
둘째 줄과 셋째 줄이 신경망의 답입니다. 층을 지나며 조건수가 나빠지는 것을 층마다 되돌립니다.
심화 6. 이 강의가 다음 강의로 어떻게 이어지는지 정리하세요.
| 이 강의에서 | 다음에서 |
|---|---|
| 잡음이 병목 | 강 분산 감소 |
| 조건수가 병목 | 강 초기화 |
| 층마다 정규화 | 강과 강 |
| 좌표별 학습률 | 강 아담 |
| 큰 배치 병렬 | 강 데이터 병렬 |
강은 배치를 키우지 않고 잡음을 줄이는 방법을 봅니다. 임계 배치 크기가 낮으면 배치를 키워도 소용없으므로 다른 길이 필요합니다.
정답.
| 기호 | 읽는 법 | 뜻 |
|---|---|---|
| 학습률 상한 | learning rate bound | 넘으면 발산하는 값입니다 |
| 조건수 | condition number | 최대 고윳값 나누기 최소 고윳값입니다 |
| 선형 스케일링 | linear scaling rule | 배치를 배 하면 학습률도 배 합니다 |
| 제곱근 스케일링 | square-root scaling | 배치를 배 하면 학습률을 배 합니다 |
| 임계 배치 크기 | critical batch size | 더 키워도 걸음이 안 줄어드는 크기입니다 |
| 잡음 대 신호 비 | noise-to-signal ratio | 그래디언트 분산을 노름 제곱으로 나눈 값입니다 |
| 학습률 훑기 | learning rate range test | 짧게 돌려 상한을 찾습니다 |
| 라스 | LARS | 층마다 갱신 크기를 맞추는 최적화기입니다 |
| 준비 구간 | warmup | 처음에 학습률을 올립니다 |
| 고유분해 | eigendecomposition | 대칭행렬을 방향과 곡률로 나눕니다 |
다음은 238강 그래디언트 잡음과 분산 감소입니다. 이 강의에서 배치를 키워도 안 되는 자리가 있다는 것을 봤습니다. 다음 강의는 배치를 안 키우고 잡음을 줄이는 방법을 봅니다.
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("237강 배치 크기와 학습률의 관계 코드 검산")
print("=" * 78)
rng = np.random.default_rng(20237)
n, p = 4000, 10
X = rng.normal(0, 1, (n, p))
for j in range(p):
X[:, j] *= 10.0 ** (1.2 * j / (p - 1))
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, mu = float(ev.max()), float(ev.min())
def loss(b):
r = X @ b - y
return float((r ** 2).mean() / 2)
opt = loss(bstar)
def gmb(b, idx):
Xi = X[idx]
return Xi.T @ (Xi @ b - y[idx]) / len(idx)
def run(B, lr, steps, seed, tail=1000):
rr = np.random.default_rng(seed)
b = np.zeros(p)
acc = []
for t in range(steps):
idx = rr.integers(0, n, B)
b -= lr * gmb(b, idx)
if not np.all(np.isfinite(b)):
return float('inf')
if t >= steps - tail:
acc.append(loss(b) - opt)
v = float(np.mean(acc))
return v if np.isfinite(v) else float('inf')
print()
print("문제 1. 학습률의 상한")
print()
print(" (1) 어디서 상한이 오는지 정리합니다")
rows = [
("이차형식", "1 빼기 학습률 곱 고윳값", "절댓값이 1 보다 작아야 함"),
("가장 큰 고윳값", "가장 먼저 터짐", "그 방향이 상한을 정함"),
("상한", "2 나누기 최대 고윳값", "전체 배치 기준"),
("잡음이 있으면", "상한이 더 낮아짐", "미니배치는 더 조심"),
]
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(" 이 자료의 헤세 고윳값은 최소 %.6f 최대 %.6f 입니다" % (mu, Lsm))
print(" 전체 배치의 이론 상한은 %.6f 입니다" % (2.0 / Lsm))
print()
print(" (2) 전체 배치에서 상한을 확인합니다")
print(" " + rl("학습률", 12) + " " + rl("이론 상한 대비", 16) + " " + rl("200 걸음 뒤 손실", 18) + " " + "어떻게 되나")
old = np.seterr(over='ignore', invalid='ignore')
for lr in [0.5 * (2.0 / Lsm), 0.9 * (2.0 / Lsm), 0.98 * (2.0 / Lsm), 1.02 * (2.0 / Lsm), 1.10 * (2.0 / Lsm)]:
b = np.zeros(p)
for _ in range(200):
b -= lr * (X.T @ (X @ b - y) / n)
if not np.all(np.isfinite(b)):
break
v = loss(b) - opt if np.all(np.isfinite(b)) else float('inf')
ok = np.isfinite(v) and v < 1e6
print(" " + rl("%.6f" % lr, 12) + " " + rl("%.6f" % (lr / (2.0 / Lsm)), 16) + " " + rl("%.10f" % v if ok else "발산", 18) + " " + ("수렴" if ok else "발산"))
np.seterr(**old)
print(" 이론 상한은 %.6f 입니다" % (2.0 / Lsm))
print(" 상한 대비 0.98 까지는 수렴하고 1.02 부터 발산합니다")
print(" 경계가 이론이 말한 자리와 정확히 맞습니다")
print(" 236강 심화 4 에서 예고한 상한이 여기서 확인됩니다")
print()
print(" (3) 미니배치에서 상한이 얼마나 낮아지는지 봅니다")
print(" 배치를 바꿔 가며 발산하지 않는 가장 큰 학습률을 찾습니다")
print(" " + rl("배치 크기", 12) + " " + rl("발산 안 한 최대 학습률", 24) + " " + rl("전체 배치 상한 대비", 22))
cands = [q * (2.0 / Lsm) for q in [0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.98]]
old = np.seterr(over='ignore', invalid='ignore')
crit = {}
for B in [4, 16, 64, 256, 4000]:
best = 0.0
for lr in cands:
v = run(B, lr, 4000, 31, tail=500)
if np.isfinite(v) and v < 1e3:
best = lr
crit[B] = best
print(" " + rl("%d" % B, 12) + " " + rl("%.6f" % best, 24) + " " + rl("%.6f" % (best / (2.0 / Lsm)), 22))
np.seterr(**old)
print(" 배치 4 만 상한의 0.7 배에서 이미 터집니다")
print(" 16 부터는 격자 끝인 0.98 배까지 견딥니다")
print(" 잡음이 상한을 낮추는 효과는 아주 작은 배치에서만 뚜렷합니다")
print(" 235강 문제 5 에서 본 것이 여기서 더 좁은 구간의 이야기로 드러납니다")
print()
print("문제 2. 선형 스케일링이 어디까지 되는가")
print()
print(" (1) 규칙을 적습니다")
rows = [
("무엇을 하나", "배치를 k 배 하면 학습률도 k 배", "떨림 비를 지킴"),
("왜 되나", "떨림이 학습률 나누기 배치", "236강 문제 1"),
("언제 깨지나", "학습률이 상한에 닿을 때", "문제 1 의 상한"),
("그 지점", "임계 배치 크기", "더 키워도 안 빨라짐"),
]
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) 같은 표본 예산에서 규칙을 적용합니다")
budget = 256000
lr_base, B_base = 0.05 * (2.0 / Lsm), 4
print(" 표본 방문을 %d 번으로 맞추고 기준을 배치 %d 학습률 %.6f 로 둡니다" % (budget, B_base, lr_base))
print(" " + rl("배치 크기", 12) + " " + rl("규칙이 말하는 학습률", 22) + " " + rl("걸음 수", 12) + " " + rl("초과손실", 16))
old = np.seterr(over='ignore', invalid='ignore')
for B in [4, 16, 64, 256, 1024]:
lr = lr_base * (B / B_base)
v = run(B, lr, budget // B, 41, tail=min(500, budget // B))
txt = "%.10f" % v if np.isfinite(v) and v < 1e3 else "발산"
print(" " + rl("%d" % B, 12) + " " + rl("%.6f" % lr, 22) + " " + rl("%d" % (budget // B), 12) + " " + rl(txt, 16))
np.seterr(**old)
print(" 배치 4 와 16 은 초과손실이 0.016 근처로 거의 같습니다. 규칙이 듣습니다")
print(" 64 에서 이미 세 배 나빠지고 256 부터는 발산합니다")
print(" 학습률이 상한의 0.8 배를 넘어서면서 규칙이 깨집니다")
print(" 임계 배치 크기가 16 과 64 사이에 있습니다")
print()
print(" (3) 학습률을 상한에서 자르면 어떻게 되는지 봅니다")
cap = 0.9 * (2.0 / Lsm)
print(" 학습률을 상한의 90 퍼센트인 %.6f 에서 자릅니다" % cap)
print(" " + rl("배치 크기", 12) + " " + rl("자르기 전 학습률", 20) + " " + rl("실제 쓴 학습률", 18) + " " + rl("초과손실", 16))
for B in [4, 16, 64, 256, 1024]:
lr = min(lr_base * (B / B_base), cap)
v = run(B, lr, budget // B, 42, tail=min(500, budget // B))
txt = "%.10f" % v if np.isfinite(v) and v < 1e3 else "발산"
print(" " + rl("%d" % B, 12) + " " + rl("%.6f" % (lr_base * (B / B_base)), 20) + " " + rl("%.6f" % lr, 18) + " " + rl(txt, 16))
print(" 자르면 발산이 사라집니다. 256 은 오히려 64 보다 낫습니다")
print(" 그런데 1024 에서는 걸음이 250 번뿐이라 도착을 못 합니다")
print(" 학습률이 상한에 눌린 뒤로는 배치를 키우면 걸음 수만 줄어듭니다")
print()
print(" (4) 제곱근 규칙과 견줍니다")
print(" 배치를 k 배 할 때 학습률을 k 의 제곱근 배 하는 규칙도 있습니다")
print(" " + rl("배치 크기", 12) + " " + rl("선형 규칙 학습률", 20) + " " + rl("선형 초과손실", 18) + " " + rl("제곱근 규칙 학습률", 22) + " " + rl("제곱근 초과손실", 18))
old = np.seterr(over='ignore', invalid='ignore')
for B in [4, 16, 64, 256, 1024]:
k = B / B_base
lr1 = lr_base * k
lr2 = lr_base * np.sqrt(k)
v1 = run(B, lr1, budget // B, 43, tail=min(500, budget // B))
v2 = run(B, lr2, budget // B, 43, tail=min(500, budget // B))
t1 = "%.8f" % v1 if np.isfinite(v1) and v1 < 1e3 else "발산"
t2 = "%.8f" % v2 if np.isfinite(v2) and v2 < 1e3 else "발산"
print(" " + rl("%d" % B, 12) + " " + rl("%.6f" % lr1, 20) + " " + rl(t1, 18) + " " + rl("%.6f" % lr2, 22) + " " + rl(t2, 18))
np.seterr(**old)
print(" 이 자료에서는 제곱근 규칙이 배치 16 부터 256 까지 모두 낫습니다")
print(" 조건수가 %.1f 라 선형 규칙이 금방 상한에 닿기 때문입니다" % (Lsm / mu))
print(" 1024 에서는 제곱근 규칙도 무너집니다. 걸음이 250 번뿐이기 때문입니다")
print(" 어느 규칙이 옳은가가 아니라 상한에 닿았는지가 문제입니다")
print()
print("문제 3. 임계 배치 크기")
print()
print(" (1) 무엇을 뜻하는지 정리합니다")
rows = [
("작은 배치 구간", "배치를 키우면 걸음이 줄음", "계산에 비례해 이득"),
("임계 배치 크기", "이득이 꺾이는 자리", "잡음과 신호가 같아짐"),
("큰 배치 구간", "키워도 걸음이 안 줄음", "계산만 낭비"),
("무엇이 정하나", "잡음 나누기 신호", "235강 문제 5"),
]
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) 목표 손실에 닿는 걸음 수를 셉니다")
target = 0.05
print(" 초과손실 %.4f 에 처음 닿는 걸음 수를 셉니다" % target)
print(" 학습률은 배치마다 최적을 골라 씁니다")
grid = [q * (2.0 / Lsm) for q in [0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 0.95]]
def steps_to(B, lr, seed, cap_steps=200000):
rr = np.random.default_rng(seed)
b = np.zeros(p)
for t in range(1, cap_steps + 1):
idx = rr.integers(0, n, B)
b -= lr * gmb(b, idx)
if not np.all(np.isfinite(b)):
return None
if loss(b) - opt < target:
return t
return None
old = np.seterr(over='ignore', invalid='ignore')
res3 = []
print(" " + rl("배치 크기", 12) + " " + rl("고른 학습률", 14) + " " + rl("걸음 수", 12) + " " + rl("본 표본 수", 14))
for B in [2, 8, 32, 128, 512, 2048]:
best = None
for lr in grid:
s = steps_to(B, lr, 51)
if s is not None and (best is None or s < best[1]):
best = (lr, s)
if best is None:
print(" " + rl("%d" % B, 12) + " " + rl("없음", 14) + " " + rl("못 닿음", 12) + " " + rl("없음", 14))
else:
res3.append((B, best[0], best[1]))
print(" " + rl("%d" % B, 12) + " " + rl("%.6f" % best[0], 14) + " " + rl("%d" % best[1], 12) + " " + rl("%d" % (B * best[1]), 14))
np.seterr(**old)
print(" 배치를 키우면 걸음 수가 줄어듭니다")
print(" 그런데 본 표본 수는 계속 늘어납니다")
print(" 걸음 수가 더 안 줄기 시작하는 자리가 임계 배치 크기입니다")
print()
print(" (3) 걸음 수가 얼마나 줄었는지 봅니다")
print(" " + rl("배치 크기", 12) + " " + rl("걸음 수", 12) + " " + rl("앞 배치 대비 줄어든 비", 24) + " " + rl("이상적이면", 14))
prev = None
for B, lr, st in res3:
if prev is None:
print(" " + rl("%d" % B, 12) + " " + rl("%d" % st, 12) + " " + rl("기준", 24) + " " + rl("기준", 14))
else:
print(" " + rl("%d" % B, 12) + " " + rl("%d" % st, 12) + " " + rl("%.6f" % (st / float(prev[2])), 24) + " " + rl("%.6f" % (prev[0] / float(B)), 14))
prev = (B, lr, st)
print(" 셋째 열이 넷째 열에 가까우면 배치를 키운 만큼 걸음이 줄었다는 뜻입니다")
print(" 뒤로 갈수록 셋째 열이 1 에 가까워집니다")
print(" 배치를 네 배 해도 걸음이 거의 안 줄면 계산만 네 배 쓴 것입니다")
print()
print(" (4) 잡음 대 신호 비로 임계점을 예측합니다")
print(" 최적점에서 조금 떨어진 자리에서 잽니다")
b_probe = bstar + 0.3 * rng.normal(0, 1, p)
g_full = X.T @ (X @ b_probe - y) / n
sig2 = float((g_full ** 2).sum())
gi = np.array([X[i:i + 1].T @ (X[i:i + 1] @ b_probe - y[i:i + 1]) / 1 for i in range(n)]).reshape(n, p)
var1 = float(gi.var(axis=0).sum())
Bcrit = var1 / sig2
print(" 한 표본 그래디언트의 분산 합은 %.6f 입니다" % var1)
print(" 전체 그래디언트 노름 제곱은 %.6f 입니다" % sig2)
print(" 둘의 비가 %.6f 이고 이것이 예측하는 임계 배치 크기입니다" % Bcrit)
print(" " + rl("배치 크기", 12) + " " + rl("잡음 나누기 신호", 20) + " " + "어느 구간인가")
for B in [2, 8, 32, 128, 512, 2048]:
ratio = var1 / B / sig2
print(" " + rl("%d" % B, 12) + " " + rl("%.6f" % ratio, 20) + " " + ("잡음이 큼" if ratio > 1 else "신호가 큼"))
print(" 비가 1 을 넘는 구간에서는 배치를 키우는 것이 곧바로 이득입니다")
print(" 1 아래로 내려가면 이미 그래디언트가 충분히 정확해 더 키울 값이 줄어듭니다")
print()
print("문제 4. 조건수와 방향별 차이")
print()
print(" (1) 무엇이 문제인지 정리합니다")
rows = [
("방향마다 곡률이 다름", "고윳값이 다름", "조건수가 큼"),
("학습률은 하나", "가장 가파른 방향이 정함", "완만한 방향은 느림"),
("걸음 수", "조건수에 비례", "느린 방향을 기다림"),
("해결", "좌표마다 다른 학습률", "247강 아담"),
]
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(" 이 자료의 조건수는 %.6f 입니다" % (Lsm / mu))
print()
print(" (2) 방향마다 얼마나 빨리 줄어드는지 봅니다")
evals, evecs = np.linalg.eigh(H)
lr_t = 0.9 * (2.0 / Lsm)
b = np.zeros(p)
snap = {}
for t in range(1, 601):
b -= lr_t * (X.T @ (X @ b - y) / n)
if t in (10, 50, 200, 600):
snap[t] = (evecs.T @ (b - bstar)).copy()
d0 = evecs.T @ (np.zeros(p) - bstar)
print(" 전체 배치로 학습률 %.6f 를 씁니다" % lr_t)
print(" " + rl("고윳값", 12) + " " + rl("10 걸음", 14) + " " + rl("50 걸음", 14) + " " + rl("200 걸음", 14) + " " + rl("600 걸음", 14))
for j in [0, 1, len(evals) // 2, len(evals) - 1]:
row = [abs(snap[t][j]) / abs(d0[j]) for t in (10, 50, 200, 600)]
print(" " + rl("%.6f" % evals[j], 12) + " " + rl("%.8f" % row[0], 14) + " " + rl("%.8f" % row[1], 14) + " " + rl("%.8f" % row[2], 14) + " " + rl("%.8f" % row[3], 14))
print(" 값은 처음 오차 대비 남은 비율입니다")
print(" 고윳값이 큰 방향은 열 걸음 만에 거의 사라집니다")
print(" 고윳값이 작은 방향은 600 걸음 뒤에도 상당히 남아 있습니다")
print()
print(" (3) 조건수를 바꿔 가며 걸음 수를 셉니다")
print(" 변수마다 크기를 다르게 해 조건수를 조절합니다")
print(" " + rl("퍼짐 지수", 12) + " " + rl("조건수", 12) + " " + rl("초과손실 0.01 까지 걸음", 26) + " " + rl("조건수 대비", 14))
for sc in [0.0, 0.6, 1.2, 1.8]:
Xc = rng.normal(0, 1, (n, p))
for j in range(p):
Xc[:, j] *= 10.0 ** (sc * j / (p - 1))
yc = Xc @ beta
Hc = Xc.T @ Xc / n
evc = np.linalg.eigvalsh(Hc)
kc = float(evc.max() / evc.min())
bsc = np.linalg.solve(Hc, Xc.T @ yc / n)
optc = float(((Xc @ bsc - yc) ** 2).mean() / 2)
lrc = 0.9 * 2.0 / float(evc.max())
bb = np.zeros(p)
hit = None
for t in range(1, 20001):
bb -= lrc * (Xc.T @ (Xc @ bb - yc) / n)
if float(((Xc @ bb - yc) ** 2).mean() / 2) - optc < 0.01:
hit = t
break
print(" " + rl("%.4f" % sc, 12) + " " + rl("%.6f" % kc, 12) + " " + rl("%d" % hit if hit else "못 닿음", 26) + " " + rl("%.6f" % (hit / kc) if hit else "없음", 14))
print(" 조건수가 커지면 걸음 수가 함께 커집니다")
print(" 넷째 열이 어느 정도 안정되어 걸음 수가 대략 조건수에 비례합니다")
print(" 배치를 키워도 이 부분은 안 좋아집니다. 잡음이 아니라 모양의 문제이기 때문입니다")
print()
print(" (4) 배치와 조건수 중 무엇이 병목인지 가립니다")
print(" 같은 자료에서 배치만 키운 것과 조건수를 낮춘 것을 견줍니다")
Xs = X / X.std(axis=0)
Hs = Xs.T @ Xs / n
evs = np.linalg.eigvalsh(Hs)
ys = Xs @ beta + rng.normal(0, 1.0, n)
bss = np.linalg.solve(Hs, Xs.T @ ys / n)
opts = float(((Xs @ bss - ys) ** 2).mean() / 2)
print(" 원래 조건수는 %.6f 이고 열마다 표준화하면 %.6f 입니다" % (Lsm / mu, float(evs.max() / evs.min())))
print(" 학습률은 각 자료의 상한을 기준으로 다시 고릅니다")
def steps_to_s(Xm, ym, optm, B, lr, seed, cap=100000):
rr = np.random.default_rng(seed)
b = np.zeros(p)
for t in range(1, cap + 1):
idx = rr.integers(0, len(ym), B)
Xi = Xm[idx]
b -= lr * (Xi.T @ (Xi @ b - ym[idx]) / B)
if not np.all(np.isfinite(b)):
return None
if float(((Xm @ b - ym) ** 2).mean() / 2) - optm < 0.05:
return t
return None
old = np.seterr(over='ignore', invalid='ignore')
print(" " + rw("무엇을 했나", 24) + " " + rl("배치", 8) + " " + rl("고른 학습률", 14) + " " + rl("걸음 수", 12))
for nm, Xm, ym, optm, B, Lm in [("그대로 배치 16", X, y, opt, 16, Lsm), ("배치만 256 으로", X, y, opt, 256, Lsm),
("표준화하고 배치 16", Xs, ys, opts, 16, float(evs.max()))]:
best = None
for q in [0.05, 0.1, 0.2, 0.4, 0.6, 0.8, 0.95]:
lr = q * (2.0 / Lm)
st = steps_to_s(Xm, ym, optm, B, lr, 61)
if st is not None and (best is None or st < best[1]):
best = (lr, st)
print(" " + rw(nm, 24) + " " + rl("%d" % B, 8) + " " + rl("%.6f" % best[0] if best else "없음", 14) + " " + rl("%d" % best[1] if best else "못 닿음", 12))
np.seterr(**old)
print(" 표준화 한 번이 배치를 열여섯 배 키운 것보다 크게 듭니다")
print(" 228강 문제 2 의 눈금 맞추기가 여기서 다시 나옵니다")
print(" 배치를 키우기 전에 조건수부터 보는 것이 순서입니다")
print()
print("문제 5. 실무에서 쓰기")
print()
print(" (1) 순서를 정리합니다")
rows = [
("먼저", "메모리에 맞는 배치를 정합니다"),
("다음", "짧게 돌려 학습률 상한을 찾습니다"),
("다음", "그 아래에서 가장 큰 값을 씁니다"),
("배치를 바꾸면", "선형 규칙으로 학습률을 옮깁니다"),
("상한에 닿으면", "거기서 자르고 배치를 더 안 키웁니다"),
]
w = [max(pw(r[i]) for r in rows + [("순서", "무엇을 하나")]) for i in range(2)]
print(" " + rw("순서", w[0]) + " " + "무엇을 하나")
for r in rows:
print(" " + rw(r[0], w[0]) + " " + r[1])
print()
print(" (2) 학습률 훑기를 해 봅니다")
print(" 100 걸음만 돌려 손실이 어떻게 되는지 봅니다")
print(" 시작 손실은 %.8f 입니다" % loss(np.zeros(p)))
print(" " + rl("학습률", 12) + " " + rl("100 걸음 손실", 18) + " " + "판정")
old = np.seterr(over='ignore', invalid='ignore')
best_lr, best_v = None, None
for lr in [q * (2.0 / Lsm) for q in [0.05, 0.2, 0.4, 0.6, 0.8, 1.0, 1.3]]:
rr = np.random.default_rng(71)
b = np.zeros(p)
for _ in range(100):
idx = rr.integers(0, n, 64)
b -= lr * gmb(b, idx)
if not np.all(np.isfinite(b)):
break
v = loss(b) if np.all(np.isfinite(b)) else float('inf')
ok = np.isfinite(v) and v < 1e6
if ok and (best_v is None or v < best_v):
best_lr, best_v = lr, v
if not ok:
txt = "발산"
elif v > loss(np.zeros(p)):
txt = "되올라감"
else:
txt = "내려감"
print(" " + rl("%.6f" % lr, 12) + " " + rl("%.8f" % v if ok else "터짐", 18) + " " + txt)
np.seterr(**old)
print(" 가장 낮은 손실을 낸 학습률은 %.6f 이고 이론 상한의 %.4f 배입니다" % (best_lr, best_lr / (2.0 / Lsm)))
print(" 상한의 0.8 배에서 1.0 배로 가는 사이에 손실이 1.12 에서 8.31 로 일곱 배 나빠집니다")
print(" 발산 직전에 이미 크게 나빠지므로 터지는 것만 피하면 되는 것이 아닙니다")
print(" 실무에서는 가장 좋았던 값에서 조금 낮춘 값을 씁니다. 100 걸음은 짧기 때문입니다")
print(" 236강 문제 5 에서 본 되올라감도 함께 봐야 합니다")
print()
print(" (3) 배치를 바꿀 때 무엇을 함께 바꾸는지 봅니다")
print(" 배치 64 학습률 %.6f 를 기준으로 옮겨 봅니다" % best_lr)
print(" " + rl("새 배치", 12) + " " + rl("선형 규칙", 14) + " " + rl("상한에서 자른 값", 20) + " " + rl("초과손실", 16))
old = np.seterr(over='ignore', invalid='ignore')
for B in [16, 64, 256, 1024]:
lr_lin = best_lr * B / 64.0
lr_use = min(lr_lin, cap)
v = run(B, lr_use, 128000 // B, 72, tail=min(500, 128000 // B))
txt = "%.10f" % v if np.isfinite(v) and v < 1e3 else "발산"
print(" " + rl("%d" % B, 12) + " " + rl("%.6f" % lr_lin, 14) + " " + rl("%.6f" % lr_use, 20) + " " + rl(txt, 16))
np.seterr(**old)
print(" 64 에서 이미 16 보다 나쁩니다. 학습률이 상한의 0.8 배라 떨림이 크기 때문입니다")
print(" 256 부터는 학습률이 상한에 눌리고 걸음 수만 줄어 크게 나빠집니다")
print(" 기준 학습률을 상한 가까이 잡으면 배치를 키울 여지가 아예 없습니다")
print()
print(" (4) 이 강의를 한 장으로 모읍니다")
rows = [
("학습률 상한은", "2 나누기 최대 고윳값입니다"),
("미니배치는", "그보다 낮은 자리에서 이미 터집니다"),
("선형 규칙은", "상한에 닿을 때까지만 됩니다"),
("임계 배치 크기는", "잡음 나누기 신호가 1 이 되는 자리입니다"),
("그 위로는", "계산만 늘고 걸음은 안 줄어듭니다"),
("조건수가 크면", "배치를 키워도 안 좋아집니다"),
("그때는", "눈금을 맞추거나 좌표별 학습률을 씁니다"),
]
w = [max(pw(r[i]) for r in rows + [("무엇", "한 줄로")]) for i in range(2)]
print(" " + rw("무엇", w[0]) + " " + "한 줄로")
for r in rows:
print(" " + rw(r[0], w[0]) + " " + r[1])
print(" 238강은 잡음 자체를 줄이는 방법을 봅니다")
print()
print("=" * 78)
print("검산 끝")
print("=" * 78)
# ==============================================================================
# 237강 배치 크기와 학습률의 관계 코드 검산
# ==============================================================================
#
# 문제 1. 학습률의 상한
#
# (1) 어디서 상한이 오는지 정리합니다
# 무엇 무엇이 정하나 조건
# 이차형식 1 빼기 학습률 곱 고윳값 절댓값이 1 보다 작아야 함
# 가장 큰 고윳값 가장 먼저 터짐 그 방향이 상한을 정함
# 상한 2 나누기 최대 고윳값 전체 배치 기준
# 잡음이 있으면 상한이 더 낮아짐 미니배치는 더 조심
# 이 자료의 헤세 고윳값은 최소 0.957383 최대 254.109580 입니다
# 전체 배치의 이론 상한은 0.007871 입니다
#
# (2) 전체 배치에서 상한을 확인합니다
# 학습률 이론 상한 대비 200 걸음 뒤 손실 어떻게 되나
# 0.003935 0.500000 0.3475112630 수렴
# 0.007084 0.900000 0.0973351758 수렴
# 0.007713 0.980000 0.0758995624 수렴
# 0.008028 1.020000 발산 발산
# 0.008658 1.100000 발산 발산
# 이론 상한은 0.007871 입니다
# 상한 대비 0.98 까지는 수렴하고 1.02 부터 발산합니다
# 경계가 이론이 말한 자리와 정확히 맞습니다
# 236강 심화 4 에서 예고한 상한이 여기서 확인됩니다
#
# (3) 미니배치에서 상한이 얼마나 낮아지는지 봅니다
# 배치를 바꿔 가며 발산하지 않는 가장 큰 학습률을 찾습니다
# 배치 크기 발산 안 한 최대 학습률 전체 배치 상한 대비
# 4 0.005509 0.700000
# 16 0.007713 0.980000
# 64 0.007713 0.980000
# 256 0.007713 0.980000
# 4000 0.007713 0.980000
# 배치 4 만 상한의 0.7 배에서 이미 터집니다
# 16 부터는 격자 끝인 0.98 배까지 견딥니다
# 잡음이 상한을 낮추는 효과는 아주 작은 배치에서만 뚜렷합니다
# 235강 문제 5 에서 본 것이 여기서 더 좁은 구간의 이야기로 드러납니다
#
# 문제 2. 선형 스케일링이 어디까지 되는가
#
# (1) 규칙을 적습니다
# 무엇 무엇인가 어디서
# 무엇을 하나 배치를 k 배 하면 학습률도 k 배 떨림 비를 지킴
# 왜 되나 떨림이 학습률 나누기 배치 236강 문제 1
# 언제 깨지나 학습률이 상한에 닿을 때 문제 1 의 상한
# 그 지점 임계 배치 크기 더 키워도 안 빨라짐
#
# (2) 같은 표본 예산에서 규칙을 적용합니다
# 표본 방문을 256000 번으로 맞추고 기준을 배치 4 학습률 0.000394 로 둡니다
# 배치 크기 규칙이 말하는 학습률 걸음 수 초과손실
# 4 0.000394 64000 0.0167824285
# 16 0.001574 16000 0.0159915203
# 64 0.006296 4000 0.0518736672
# 256 0.025186 1000 발산
# 1024 0.100744 250 발산
# 배치 4 와 16 은 초과손실이 0.016 근처로 거의 같습니다. 규칙이 듣습니다
# 64 에서 이미 세 배 나빠지고 256 부터는 발산합니다
# 학습률이 상한의 0.8 배를 넘어서면서 규칙이 깨집니다
# 임계 배치 크기가 16 과 64 사이에 있습니다
#
# (3) 학습률을 상한에서 자르면 어떻게 되는지 봅니다
# 학습률을 상한의 90 퍼센트인 0.007084 에서 자릅니다
# 배치 크기 자르기 전 학습률 실제 쓴 학습률 초과손실
# 4 0.000394 0.000394 0.0150343806
# 16 0.001574 0.001574 0.0162287868
# 64 0.006296 0.006296 0.0414117260
# 256 0.025186 0.007084 0.0231293304
# 1024 0.100744 0.007084 1.1196292033
# 자르면 발산이 사라집니다. 256 은 오히려 64 보다 낫습니다
# 그런데 1024 에서는 걸음이 250 번뿐이라 도착을 못 합니다
# 학습률이 상한에 눌린 뒤로는 배치를 키우면 걸음 수만 줄어듭니다
#
# (4) 제곱근 규칙과 견줍니다
# 배치를 k 배 할 때 학습률을 k 의 제곱근 배 하는 규칙도 있습니다
# 배치 크기 선형 규칙 학습률 선형 초과손실 제곱근 규칙 학습률 제곱근 초과손실
# 4 0.000394 0.01266021 0.000394 0.01266021
# 16 0.001574 0.01801023 0.000787 0.00812006
# 64 0.006296 0.04800289 0.001574 0.00432672
# 256 0.025186 발산 0.003148 0.02500983
# 1024 0.100744 발산 0.006296 0.88608866
# 이 자료에서는 제곱근 규칙이 배치 16 부터 256 까지 모두 낫습니다
# 조건수가 265.4 라 선형 규칙이 금방 상한에 닿기 때문입니다
# 1024 에서는 제곱근 규칙도 무너집니다. 걸음이 250 번뿐이기 때문입니다
# 어느 규칙이 옳은가가 아니라 상한에 닿았는지가 문제입니다
#
# 문제 3. 임계 배치 크기
#
# (1) 무엇을 뜻하는지 정리합니다
# 구간 무슨 일 뜻
# 작은 배치 구간 배치를 키우면 걸음이 줄음 계산에 비례해 이득
# 임계 배치 크기 이득이 꺾이는 자리 잡음과 신호가 같아짐
# 큰 배치 구간 키워도 걸음이 안 줄음 계산만 낭비
# 무엇이 정하나 잡음 나누기 신호 235강 문제 5
#
# (2) 목표 손실에 닿는 걸음 수를 셉니다
# 초과손실 0.0500 에 처음 닿는 걸음 수를 셉니다
# 학습률은 배치마다 최적을 골라 씁니다
# 배치 크기 고른 학습률 걸음 수 본 표본 수
# 2 0.003148 831 1662
# 8 0.006296 431 3448
# 32 0.007477 302 9664
# 128 0.007477 250 32000
# 512 0.007477 242 123904
# 2048 0.007477 240 491520
# 배치를 키우면 걸음 수가 줄어듭니다
# 그런데 본 표본 수는 계속 늘어납니다
# 걸음 수가 더 안 줄기 시작하는 자리가 임계 배치 크기입니다
#
# (3) 걸음 수가 얼마나 줄었는지 봅니다
# 배치 크기 걸음 수 앞 배치 대비 줄어든 비 이상적이면
# 2 831 기준 기준
# 8 431 0.518652 0.250000
# 32 302 0.700696 0.250000
# 128 250 0.827815 0.250000
# 512 242 0.968000 0.250000
# 2048 240 0.991736 0.250000
# 셋째 열이 넷째 열에 가까우면 배치를 키운 만큼 걸음이 줄었다는 뜻입니다
# 뒤로 갈수록 셋째 열이 1 에 가까워집니다
# 배치를 네 배 해도 걸음이 거의 안 줄면 계산만 네 배 쓴 것입니다
#
# (4) 잡음 대 신호 비로 임계점을 예측합니다
# 최적점에서 조금 떨어진 자리에서 잽니다
# 한 표본 그래디언트의 분산 합은 12719.501994 입니다
# 전체 그래디언트 노름 제곱은 1261.885791 입니다
# 둘의 비가 10.079757 이고 이것이 예측하는 임계 배치 크기입니다
# 배치 크기 잡음 나누기 신호 어느 구간인가
# 2 5.039878 잡음이 큼
# 8 1.259970 잡음이 큼
# 32 0.314992 신호가 큼
# 128 0.078748 신호가 큼
# 512 0.019687 신호가 큼
# 2048 0.004922 신호가 큼
# 비가 1 을 넘는 구간에서는 배치를 키우는 것이 곧바로 이득입니다
# 1 아래로 내려가면 이미 그래디언트가 충분히 정확해 더 키울 값이 줄어듭니다
#
# 문제 4. 조건수와 방향별 차이
#
# (1) 무엇이 문제인지 정리합니다
# 무엇 무엇인가 결과
# 방향마다 곡률이 다름 고윳값이 다름 조건수가 큼
# 학습률은 하나 가장 가파른 방향이 정함 완만한 방향은 느림
# 걸음 수 조건수에 비례 느린 방향을 기다림
# 해결 좌표마다 다른 학습률 247강 아담
# 이 자료의 조건수는 265.420979 입니다
#
# (2) 방향마다 얼마나 빨리 줄어드는지 봅니다
# 전체 배치로 학습률 0.007084 를 씁니다
# 고윳값 10 걸음 50 걸음 200 걸음 600 걸음
# 0.957383 0.93421582 0.71160025 0.25641555 0.01685905
# 1.834254 0.87740906 0.52000866 0.07312103 0.00039096
# 21.739062 0.18782588 0.00023376 0.00000000 0.00000000
# 254.109580 0.10737418 0.00001427 0.00000000 0.00000000
# 값은 처음 오차 대비 남은 비율입니다
# 고윳값이 큰 방향은 열 걸음 만에 거의 사라집니다
# 고윳값이 작은 방향은 600 걸음 뒤에도 상당히 남아 있습니다
#
# (3) 조건수를 바꿔 가며 걸음 수를 셉니다
# 변수마다 크기를 다르게 해 조건수를 조절합니다
# 퍼짐 지수 조건수 초과손실 0.01 까지 걸음 조건수 대비
# 0.0000 1.173182 9 7.671441
# 0.6000 15.551169 22 1.414685
# 1.2000 246.428666 344 1.395941
# 1.8000 4216.860656 5879 1.394165
# 조건수가 커지면 걸음 수가 함께 커집니다
# 넷째 열이 어느 정도 안정되어 걸음 수가 대략 조건수에 비례합니다
# 배치를 키워도 이 부분은 안 좋아집니다. 잡음이 아니라 모양의 문제이기 때문입니다
#
# (4) 배치와 조건수 중 무엇이 병목인지 가립니다
# 같은 자료에서 배치만 키운 것과 조건수를 낮춘 것을 견줍니다
# 원래 조건수는 265.420979 이고 열마다 표준화하면 1.114823 입니다
# 학습률은 각 자료의 상한을 기준으로 다시 고릅니다
# 무엇을 했나 배치 고른 학습률 걸음 수
# 그대로 배치 16 16 0.007477 269
# 배치만 256 으로 256 0.007477 241
# 표준화하고 배치 16 16 0.379991 13
# 표준화 한 번이 배치를 열여섯 배 키운 것보다 크게 듭니다
# 228강 문제 2 의 눈금 맞추기가 여기서 다시 나옵니다
# 배치를 키우기 전에 조건수부터 보는 것이 순서입니다
#
# 문제 5. 실무에서 쓰기
#
# (1) 순서를 정리합니다
# 순서 무엇을 하나
# 먼저 메모리에 맞는 배치를 정합니다
# 다음 짧게 돌려 학습률 상한을 찾습니다
# 다음 그 아래에서 가장 큰 값을 씁니다
# 배치를 바꾸면 선형 규칙으로 학습률을 옮깁니다
# 상한에 닿으면 거기서 자르고 배치를 더 안 키웁니다
#
# (2) 학습률 훑기를 해 봅니다
# 100 걸음만 돌려 손실이 어떻게 되는지 봅니다
# 시작 손실은 206.31361079 입니다
# 학습률 100 걸음 손실 판정
# 0.000394 4.04523167 내려감
# 0.001574 1.98095541 내려감
# 0.003148 1.51793002 내려감
# 0.004722 1.23613032 내려감
# 0.006296 1.12368821 내려감
# 0.007871 8.31489343 내려감
# 0.010232 터짐 발산
# 가장 낮은 손실을 낸 학습률은 0.006296 이고 이론 상한의 0.8000 배입니다
# 상한의 0.8 배에서 1.0 배로 가는 사이에 손실이 1.12 에서 8.31 로 일곱 배 나빠집니다
# 발산 직전에 이미 크게 나빠지므로 터지는 것만 피하면 되는 것이 아닙니다
# 실무에서는 가장 좋았던 값에서 조금 낮춘 값을 씁니다. 100 걸음은 짧기 때문입니다
# 236강 문제 5 에서 본 되올라감도 함께 봐야 합니다
#
# (3) 배치를 바꿀 때 무엇을 함께 바꾸는지 봅니다
# 배치 64 학습률 0.006296 를 기준으로 옮겨 봅니다
# 새 배치 선형 규칙 상한에서 자른 값 초과손실
# 16 0.001574 0.001574 0.0144070423
# 64 0.006296 0.006296 0.0509754539
# 256 0.025186 0.007084 0.6192714268
# 1024 0.100744 0.007084 1.8047373257
# 64 에서 이미 16 보다 나쁩니다. 학습률이 상한의 0.8 배라 떨림이 크기 때문입니다
# 256 부터는 학습률이 상한에 눌리고 걸음 수만 줄어 크게 나빠집니다
# 기준 학습률을 상한 가까이 잡으면 배치를 키울 여지가 아예 없습니다
#
# (4) 이 강의를 한 장으로 모읍니다
# 무엇 한 줄로
# 학습률 상한은 2 나누기 최대 고윳값입니다
# 미니배치는 그보다 낮은 자리에서 이미 터집니다
# 선형 규칙은 상한에 닿을 때까지만 됩니다
# 임계 배치 크기는 잡음 나누기 신호가 1 이 되는 자리입니다
# 그 위로는 계산만 늘고 걸음은 안 줄어듭니다
# 조건수가 크면 배치를 키워도 안 좋아집니다
# 그때는 눈금을 맞추거나 좌표별 학습률을 씁니다
# 238강은 잡음 자체를 줄이는 방법을 봅니다
#
# ==============================================================================
# 검산 끝
# ==============================================================================