Xuống dốc: Gradient Descent và hai bước ai cũng bỏ qua
Tính trần chính xác của learning rate, rồi xem tìm kiếm vét cạn 3.600 hướng tự khám phá lại gradient.
Trên trang này
Chương trước kết thúc bằng một thung lũng.
Không phải thung lũng ẩn dụ: một đường cong thật, loss được vẽ theo một tham số duy nhất, đi xuống rồi lại đi lên. Và loss bên dưới nó không được chọn vì gọn gàng — nó được suy ra từ một phát biểu về nhiễu trong các phép đo, và sai số bình phương xuất hiện ở đầu ra như một hệ quả chứ không phải một quy ước.
Vậy ta có một cảnh quan có đáy, và có lý do để tin rằng đáy là nơi đúng để đến. Điều ta chưa có là cách đi tới đó.
Chương này xây một cách như vậy, và đó là thuật toán huấn luyện mọi model trong phần còn lại của khóa này — tất cả, không ngoại lệ, cho đến cả những model có hàng trăm tỷ tham số. Nó nằm gọn trong khoảng hai mươi dòng. Hai phần khó không nằm trong hai mươi dòng đó, và chúng là hai điều mà hầu hết mọi lời giải thích đều bỏ qua:
- Vì sao có dấu trừ. Cập nhật trừ đi gradient. Tutorial nào cũng viết vậy; rất ít tutorial nói vì sao gradient là hướng đi lên, mà đó là sự thật duy nhất khiến dấu trừ không chỉ là một hành động dựa vào niềm tin.
- Bước lớn đến đâu. “Quá lớn thì phân kỳ, quá nhỏ thì chậm” là đúng và vô dụng. Có một con số chính xác, có thể tính được từ loss, và chương này tính nó hai lần — một lần cho một parabol đồ chơi và một lần cho dữ liệu thật.
Bài toán, và vì sao bạn không thể chỉ tìm kiếm
Liên kết đến mục: Bài toán, và vì sao bạn không thể chỉ tìm kiếmNhắc lại để chương này tự đứng vững: tám chi tiết từ băng chuyền của Chương 1, nhưng đặt một câu hỏi khác. Không phải chấp nhận hay loại bỏ — chuyện đó sẽ quay lại sau — mà là dự đoán cân nặng của một chi tiết từ chiều rộng của nó.
import numpy as np
WIDTH = np.array([18.0, 19.5, 20.2, 21.0, 24.0, 25.5, 23.0, 26.0])
WEIGHT = np.array([47.0, 52.0, 49.0, 55.0, 61.0, 66.0, 70.0, 58.0])
x = WIDTH - WIDTH.mean() # 22.15 mm
y = WEIGHT - WEIGHT.mean() # 57.25 gCác phép đo được căn giữa, đúng như trong Chương 1 và vì một lý do sẽ quay lại với lợi ích rõ ràng trước khi chương này kết thúc. Model là một đường thẳng, , và loss là mean squared error mà chương trước đã suy ra:
Hai tham số. Sao không thử thật nhiều giá trị? Ta hãy làm thật — một lưới từ đến và đến , với bước :
grid 501 x 1001 = 501,501 evaluations in 3.67 s
best found: a = 2.1000, b = -0.0000, L = 24.592450Nửa triệu lượt đánh giá để ghim hai con số xuống hai chữ số thập phân — và con số giây đó là thời gian thực trên một máy, nên chạy lại có thể rơi vào bất kỳ đâu từ ba đến sáu; số lượt đánh giá và điểm tối thiểu mới là phần tái lập được. Đến cuối chương này, gradient descent đạt bốn chữ số thập phân trong tám bước và đáp án float64 đầy đủ trong ba mươi sáu bước.
Nhưng tốc độ không phải lập luận chính, và đây là điểm quyết định cả khóa học. Grid search tốn lượt đánh giá cho tham số với giá trị mỗi tham số. Với một nghìn giá trị trên mỗi trục:
| model | tham số | lượt đánh giá lưới |
|---|---|---|
| đường thẳng này | 2 | |
| mạng XOR của Chương 5 | 9 | |
| một mạng nhiều lớp nhỏ | 20.000 |
Hàng thứ ba không phải một con số lớn, mà là một con số vô nghĩa — trong vũ trụ quan sát được chỉ có khoảng nguyên tử. Tìm kiếm không chậm đi khi model lớn lên; nó ngừng tồn tại. Mọi thứ tiếp theo tồn tại vì bảng đó.
Đạo hàm là một phép đo bạn có thể thực hiện
Liên kết đến mục: Đạo hàm là một phép đo bạn có thể thực hiệnCố định trong chốc lát để chỉ còn một tham số và một đường cong, đúng là bức tranh mà chương trước để lại. Lấy một điểm trên đó, , và hỏi: nếu tôi nhích một lượng nhỏ , loss dịch chuyển bao nhiêu trên mỗi đơn vị dịch chuyển?
Tỷ số đó là độ tăng trên độ chạy — độ dốc của đường thẳng đi qua hai điểm trên đường cong. Khi co lại, hai điểm trượt lại gần nhau và đường thẳng trở thành tiếp tuyến. Độ dốc của nó là đạo hàm : tốc độ loss thay đổi trên mỗi đơn vị thay đổi của . Không phải xấp xỉ của thứ gì, cũng không phải một đại lượng vô cùng nhỏ. Chỉ là giới hạn của các tỷ số bình thường.
Đáng để chạy thử, vì các con số nói điều mà định nghĩa không nói:
def loss1(a):
return np.mean((a * x - y) ** 2)
for h in [1.0, 1e-2, 1e-4, 1e-6, 1e-8, 1e-10, 1e-12, 1e-14]:
q = (loss1(1.0 + h) - loss1(1.0)) / h
print(f"h = {h:<8.0e} slope estimate = {q:.10f} error = {abs(q + 16.385):.3e}")h = 1e+00 slope estimate = -8.9400000000 error = 7.445e+00
h = 1e-02 slope estimate = -16.3105500000 error = 7.445e-02
h = 1e-04 slope estimate = -16.3842555001 error = 7.445e-04
h = 1e-06 slope estimate = -16.3849925556 error = 7.444e-06
h = 1e-08 slope estimate = -16.3850003787 error = 3.787e-07
h = 1e-10 slope estimate = -16.3850444324 error = 4.443e-05
h = 1e-12 slope estimate = -16.3851154866 error = 1.155e-04
h = 1e-14 slope estimate = -17.0530256582 error = 6.680e-01Hai điều xảy ra ở đây và cả hai đều chịu tải.
Sai số không chỉ mơ hồ tỷ lệ với — nó đúng bằng . Chia cho một trăm, sai số cũng chia cho một trăm, lần nào cũng đúng đến bốn chữ số có nghĩa. Hằng số đó không phải trang trí: nó là một nửa đạo hàm bậc hai của loss, và là lần xuất hiện đầu tiên của một ý tưởng ở hai mục nữa — rằng gần một điểm, một đường cong trông như một đường thẳng cộng thêm một hiệu chỉnh tỷ lệ với .
Rồi mẫu hình bị phá vỡ. Dưới , ước lượng trở nên tệ hơn, và tại nó sai ngay ở chữ số thứ hai. Không có chuyện toán học nào xảy ra; chiếc hộp floating-point của chương trước đã xảy ra. và giống nhau ở mười chữ số đầu, trừ chúng đi sẽ phá hủy các chữ số đó, rồi chia phần đổ nát cho một số rất nhỏ sẽ khuếch đại những gì còn lại. Có một tốt nhất — ở đây quanh , xấp xỉ căn bậc hai của machine epsilon — và đi nhỏ hơn không phải cẩn thận hơn, mà là kém hơn. Hãy nhớ điều đó; một hàm ở cuối chương này phụ thuộc vào nó.
Độ dốc chính xác, từ giải tích thay vì đo đạc, là . Vậy ta có thể ngừng đo và bắt đầu suy ra.
Hợp thành, và quy tắc dây chuyền
Liên kết đến mục: Hợp thành, và quy tắc dây chuyềnĐây là ý tưởng mà phần còn lại của khóa học được xây trên đó, được nói một lần, thẳng thắn.
Hợp thành hai hàm là đưa một hàm vào hàm kia: . Không hơn.
Một mạng sâu không giống như một hợp thành. Nó chính là một hợp thành. Một lớp là một hàm; xếp chồng các lớp là hợp thành chúng; “độ sâu” là số hàm trong chuỗi. Khi Chương 5 xây một mạng, nó đang xây và không gì khác. Điều đó nghĩa là quy tắc giải tích quan trọng nhất với mục đích của ta là quy tắc lấy đạo hàm của một hợp thành:
Các tốc độ nhân với nhau. Nếu thay đổi nhanh gấp ba lần , và thay đổi nhanh gấp đôi , thì thay đổi nhanh gấp sáu lần . Đó là toàn bộ nội dung, và đó là lý do một tín hiệu đi ngược qua mười lớp bị nhân với mười con số — cũng là lý do Chương 6 dành một mục cho chuyện gì xảy ra khi các con số đó đều nhỏ hơn một một chút.
Dùng nó trên loss của ta. Viết phần dư là , để . Mỗi phụ thuộc vào thông qua hàm bên trong , có đạo hàm là . Quy tắc dây chuyền, từng hạng một:
Các ký hiệu cong đó đánh dấu đạo hàm riêng: lấy đạo hàm theo một biến và coi mọi biến khác là hằng số. Không có gì mới xảy ra — vẫn là cùng giới hạn như trước, chỉ lấy dọc theo một trục. Gom các đạo hàm riêng vào một vector và bạn có gradient:
Tại điểm , vector đó là . Hai con số. Câu hỏi là chúng có nghĩa gì, và đây là bước đầu tiên mọi người bỏ qua.
Vì sao gradient chỉ lên dốc
Liên kết đến mục: Vì sao gradient chỉ lên dốcGradient là một vector các độ dốc dọc theo các trục. Đó là tất cả những gì ta đã chứng minh. Không hiển nhiên — và không nên hiển nhiên — rằng ghép chúng thành một vector lại tạo ra thứ chỉ về một hướng cụ thể nào đó.
Vậy hãy định nghĩa thứ ta thật sự muốn. Chọn một vector đơn vị , một hướng. Đạo hàm theo hướng là tốc độ loss thay đổi khi bạn đi theo hướng đó:
Quy tắc dây chuyền biến nó thành thứ có thể tính được. Đi dọc theo làm thay đổi với tốc độ và với tốc độ , và các đóng góp cộng lại:
Tốc độ thay đổi theo bất kỳ hướng nào là tích vô hướng của gradient với hướng đó. Và giờ là điểm chốt, chỉ một dòng hình học. Viết tích vô hướng bằng góc giữa hai vector,
vì có độ dài 1. Thứ duy nhất bạn điều khiển là , lớn nhất tại và nhỏ nhất khi quay nửa vòng, độ. Vì vậy:
- Dốc lên nhanh nhất là theo chính , và độ dốc ở đó đúng bằng .
- Dốc xuống nhanh nhất là theo , và độ dốc ở đó là .
- Vuông góc với gradient, loss không thay đổi chút nào. Đó là lý do các đường trên bản đồ đường đồng mức cắt gradient ở góc vuông.
Đó là dấu trừ. Không phải quy ước, không phải đổi dấu do ai đó chọn: hướng giảm nhanh nhất là gradient âm vì đạt nhỏ nhất khi quay nửa vòng, và không vì lý do nào khác.
Vì đây là một khẳng định về mọi hướng, hãy kiểm tra nó với mọi hướng. Lấy mẫu 3.600 hướng, mỗi một phần mười độ, và đo từng hướng bằng cách nhích một chút:
theta = np.array([1.0, 4.0])
g = grad(theta)
print("gradient ", g)
print("its length ", np.linalg.norm(g))
print("its angle ", np.degrees(np.arctan2(g[1], g[0])) % 360, "degrees")
best = max(
((loss(theta + 1e-6 * u) - loss(theta - 1e-6 * u)) / 2e-6, np.degrees(ang))
for ang, u in (
(a, np.array([np.cos(a), np.sin(a)])) for a in np.arange(3600) * 2 * np.pi / 3600
)
)
print("steepest slope", best[0], "at", best[1], "degrees")gradient [-16.385 8. ]
its length 18.23371122399386
its angle 153.97598928042032 degrees
steepest slope 18.233709624837502 at 154.0 degreesMột phép tìm kiếm không biết gì về gradient, trên 3.600 hướng, tìm thấy hướng leo dốc nhất ở 154,0 độ — chính là hướng của gradient, trong sai số độ phân giải 0,1 độ của tìm kiếm. Và độ dốc nó tìm được ở đó, 18,2337, là độ dài của gradient đến sáu chữ số. Định lý không phải một câu chuyện về gradient có nghĩa gì; nó là một sự thật đo được, và đó là phép đo.
Vì sao một bước nhỏ xuống dốc thật sự có ích
Liên kết đến mục: Vì sao một bước nhỏ xuống dốc thật sự có íchGiờ là bước bị bỏ qua thứ hai. Ta biết hướng nào là xuống. Điều đó không kéo theo rằng đi theo hướng đó sẽ làm giảm loss, vì “xuống” là một phát biểu về một cú nhích vô cùng nhỏ còn một bước thì không vô cùng nhỏ.
Cây cầu là tuyến tính hóa. Gần một điểm, một hàm trơn là tiếp tuyến của nó cộng thêm một hiệu chỉnh:
Đó là khai triển Taylor bậc nhất. Phần bị bỏ đi là độ cong — cùng hạng đã làm ước lượng trong bảng độ dốc sai đúng bằng . Đặt vào bước ta định đi, :
Loss giảm . Mọi phần trong đó đều không âm, nên lời hứa là thật — với đủ nhỏ, vì hạng bị bỏ qua tăng như và cuối cùng nuốt mất nó. Đó là toàn bộ lý thuyết. Đây là lời hứa được giữ, rồi bị phá vỡ:
eta = 0.2 promised 66.49364500 delivered -16.01619240 ratio -0.240868
eta = 0.1 promised 33.24682250 delivered 12.61936315 ratio 0.379566
eta = 0.01 promised 3.32468225 delivered 3.11840766 ratio 0.937957
eta = 0.001 promised 0.33246822 delivered 0.33040548 ratio 0.993796
eta = 0.0001 promised 0.03324682 delivered 0.03322620 ratio 0.999380
eta = 1e-05 promised 0.00332468 delivered 0.00332448 ratio 0.999938Đọc từ dưới lên. Khi co lại, mức giảm thực nhận hội tụ về mức giảm được hứa — tỷ lệ 0,99938, rồi 0,99994 — tức định lý Taylor đang đúng. Đọc từ trên xuống thì tại , mức “giảm” thực nhận là âm mười sáu. Bước đi xuống dốc và loss tăng lên.
Vậy quy tắc cập nhật là
và nó đi kèm một điều kiện không ai nói, rằng phải đủ nhỏ. Đủ nhỏ so với cái gì, chính xác, là mục tiếp theo.
Learning rate có một trần, và trần đó tính được
Liên kết đến mục: Learning rate có một trần, và trần đó tính đượcBắt đầu với thung lũng đơn giản nhất, , trong đó . Một bước gradient descent là
Vị trí được nhân với ở mỗi bước. Đó là một cấp số nhân, và cấp số nhân có đúng một quy tắc: chúng co lại khi hệ số nhân có giá trị tuyệt đối nhỏ hơn 1 và lớn lên trong trường hợp ngược lại. Vậy , tức .
Biên nằm đúng tại . Không phải “quanh 1”, không phải “1 thường là quá lớn”. Tại , hệ số nhân là và điểm sẽ nảy qua lại giữa và mãi mãi, không tiến gần cũng không thoát xa. Dưới nó thì hội tụ; trên nó thì phân kỳ. Khoảng này lại tách ở , nơi hệ số nhân đổi dấu: dưới đó thì tiến đến đơn điệu, trên đó điểm vượt quá và luân phiên hai phía, còn đúng tại hệ số nhân là 0 và một bước duy nhất đáp xuống cực tiểu.
Bốn chế độ, từ bốn dòng đại số. Hãy tự vượt qua các biên:
Và giờ là trường hợp thú vị:
Giờ là quy tắc tổng quát, rơi ra từ cùng lập luận. Hệ số nhân thật ra là , và gần một cực tiểu, một loss nhiều tham số có một con số như vậy cho mỗi hướng — các trị riêng của ma trận đạo hàm bậc hai. Mọi hướng phải ổn định cùng lúc, nên trần được đặt bởi trị lớn nhất:
Với , , trần là 1, đúng như ta vừa suy ra. Với băng chuyền của ta, ma trận đạo hàm bậc hai là với là ma trận input hai cột, và các trị riêng của nó là 2 và 14,89, nên trần là . Đó là một dự đoán có năm chữ số có nghĩa. Kiểm tra nó:
lr=0.1343 -> L = 24.5924
lr=0.13431 -> L = 24.5924
lr=0.13432 -> L = 4707.8 BLEW UP
lr=0.13433 -> L = 4.00452e+16 BLEW UP
lr=0.1344 -> L = 1.18229e+107 BLEW UPNăm chữ số thập phân trùng khớp giữa một dòng đại số tuyến tính và một trăm nghìn vòng lặp for.
Và đây là nơi Chương 1 quay lại. Mọi thứ ở trên dùng các phép đo đã căn giữa. Chạy đoạn code y hệt trên milimét và gam thô, các trị riêng là 0,0298 và 998,1 thay vì 2 và 14,89. Trần sụp từ 0,134 xuống 0,002004 — cũng chính xác như vậy, hội tụ tại lr=0.002003 và nổ tung tại lr=0.002004.
Tệ hơn trần là tỷ lệ giữa các trị riêng. Số điều kiện đo thung lũng lệch khỏi hình tròn đến đâu: một rãnh dài và mỏng buộc rate phải đủ nhỏ cho các vách dốc, rồi đáy rãnh cũng bị đi với tốc độ bò đó. Của ta đi từ 7,44 khi căn giữa lên 33.452 khi thô. Với rate tốt nhất mà mỗi phiên bản có thể dùng:
| feature | số điều kiện | rate tốt nhất | số bước để cách tối ưu trong 1% |
|---|---|---|---|
| đã căn giữa | 7,44 | 0,1184 | 10 |
| milimét và gam thô | 33.452 | 0,0020037 | 79.513 |
Cùng dữ liệu, cùng code, cùng đáp án cuối cùng — và nhiều hơn tám nghìn lần công việc, chỉ vì không ai trừ đi trung bình. Trong Chương 1, cùng thiếu sót đó khiến perceptron tốn số epoch gấp sáu nghìn lần, và chẩn đoán khi đó là hình học: dữ liệu trôi xa khỏi gốc tọa độ. Ở đây cũng là cùng hình học đó trong bộ đồ tối ưu hóa, và đó là lý do chuẩn hóa input không phải lời khuyên vệ sinh mà là số học.1
Hai mươi dòng
Liên kết đến mục: Hai mươi dòngKhông có gì ở trên cần thư viện. Đây là toàn bộ optimiser.
def loss(theta):
a, b = theta
return np.mean((a * x + b - y) ** 2)
def grad(theta):
a, b = theta
residual = a * x + b - y
return np.array([np.mean(2 * residual * x), np.mean(2 * residual)])
def descend(theta, lr, steps):
theta = np.array(theta, dtype=float)
for _ in range(steps):
theta = theta - lr * grad(theta)
return theta
theta = descend([0.0, 0.0], lr=0.05, steps=60)
print(theta, loss(theta))[ 2.10040296e+00 -2.76445533e-15] 24.592448791134984Đáp án least-squares dạng đóng cho tám điểm này là , , với loss . Vòng lặp tìm được nó đến tám chữ số có nghĩa mà không biết rằng dạng đóng tồn tại — điều này quan trọng, vì từ Chương 5 trở đi sẽ không còn dạng đóng.
Quỹ đạo, vì xem nó mới là điểm chính:
0 a=0.000000 b=0.000000 L=57.437500
1 a=1.563750 b=0.000000 L=26.736582
2 a=1.963288 b=-0.000000 L=24.732418
5 a=2.098116 b=-0.000000 L=24.592488
10 a=2.100400 b=-0.000000 L=24.592449
60 a=2.100403 b=-0.000000 L=24.592449Phần lớn quãng đường được đi trong hai bước đầu, vì gradient lớn nhất khi bạn ở xa đáy nhất và co lại khi bạn tiến gần. Gradient descent tự động chậm lại gần một cực tiểu. Đó là một tính năng và, trong Chương 6, cũng là một vấn đề.
Còn nơi nào độ dốc bằng không
Liên kết đến mục: Còn nơi nào độ dốc bằng khôngLập luận đến đây có một lỗ hổng. Bước đi dừng khi , và ta vẫn gọi đó là “cực tiểu”. Một điểm có gradient bằng không là một điểm tới hạn, và là cực tiểu chỉ là một trong các cách để trở thành điểm như vậy:
- một cực tiểu cục bộ: lên dốc theo mọi hướng, nhưng có thể không phải điểm thấp nhất kiểu đó ở mọi nơi;
- một cực đại cục bộ: xuống dốc theo mọi hướng;
- một điểm yên ngựa: lên dốc theo vài hướng và xuống dốc theo các hướng khác. Bề mặt có , bằng không tại gốc tọa độ, nơi hàm là cực tiểu dọc theo trục và đồng thời là cực đại dọc theo trục .
Gradient descent không thể phân biệt chúng, vì nó chỉ nhìn gradient, và gradient bằng không ở cả ba.
Đường thẳng của ta có một điểm tới hạn và nó là đáp án — loss squared-error trên một model tuyến tính là lồi, một cái bát duy nhất, và descent trên nó không thể thất bại trong việc tìm cực tiểu toàn cục. Tính chất đó không sống sót khi chạm vào khóa học này. Loss của một neural network không lồi, và từ Chương 5 trở đi “cực tiểu” không phải một thứ tồn tại: có nhiều cực tiểu, với các độ sâu khác nhau, và bạn nhận được cái nào phụ thuộc vào nơi bạn bắt đầu. Đó là một câu và vẫn chỉ là một câu, vì lý thuyết thì lớn còn hệ quả thực tế thì nhỏ.
Bạn có thể thấy toàn bộ hệ quả trên một đường cong. Lấy , có hai thung lũng với độ sâu khác nhau:
x = -1.046681 f(x) = -0.352386 minimum
x = 0.101031 f(x) = 0.005026 maximum
x = 0.945649 f(x) = -0.152639 minimumRơi vào thung lũng nông làm loss tệ hơn 56,7%, và thuật toán không có cách nào biết, vì từ bên trong một thung lũng, mọi hướng đều lên dốc. Không có bản sửa nào cho chuyện này trong gradient descent và cũng sẽ không có. Trong thực tế, điều có tồn tại là phát hiện rằng nó ít quan trọng hơn rất nhiều so với bức tranh này gợi ý — trong số chiều rất cao của một mạng thật, hầu hết điểm tới hạn hóa ra là điểm yên ngựa chứ không phải bẫy,2 và Chương 5 đo xem một mạng nhỏ thật sự bị kẹt thường xuyên đến đâu.
Bước rẻ hơn: stochastic, minibatch, momentum
Liên kết đến mục: Bước rẻ hơn: stochastic, minibatch, momentumCó một điều về grad ở trên nên làm bạn khó chịu: nó cộng trên toàn bộ dataset cho mỗi bước. Tám chi tiết thì không là gì. Một triệu là một triệu phép tính gradient để dịch chuyển tham số một lần.
Lối thoát là gradient là một trung bình, và một trung bình có thể được ước lượng từ một mẫu. Tính nó trên một nhúm ngẫu nhiên — một minibatch — rồi bước theo đó. Ước lượng có nhiễu; nó cũng không chệch, và hàng trăm bước rẻ có nhiễu đánh bại một bước chính xác đắt đỏ. Trên một trăm nghìn chi tiết tổng hợp, đếm gradient trên từng ví dụ thay vì số bước:
| phương pháp | số bước để cách tối ưu trong 0,1% | gradient trên từng ví dụ |
|---|---|---|
| full batch | 7 | 700.000 |
| minibatch 32 | 100 | 3.200 |
| từng ví dụ một | 17.580 | 17.580 |
Ít hơn hai trăm mười chín lần phép tính để tới cùng nơi. Và cực đoan — từng ví dụ một, phép xấp xỉ stochastic nguyên thủy của Robbins và Monro3 — không phải người thắng: nó tệ hơn năm lần so với batch 32, vì 32 ví dụ gần như không tốn thêm gì so với một ví dụ trên phần cứng nhân ma trận, trong khi nhiễu giảm theo căn bậc hai của kích thước batch. Đánh đổi đó là lý do mọi script huấn luyện bạn từng đọc sẽ có batch_size trong đó.
Momentum là bản sửa rẻ còn lại, và nó nhắm thẳng vào rãnh. Trong một thung lũng có số điều kiện tệ, các bước zig-zag qua hướng hẹp trong khi bò dọc theo hướng dài. Momentum giữ một trung bình chạy của các gradient quá khứ, để các thành phần dao động triệt tiêu còn thành phần nhất quán tích lũy:4
Hai dòng bổ sung. Trên băng chuyền thô chưa căn giữa — số điều kiện 33.452, trường hợp tệ nhất ta có — tại rate tốt nhất mà descent thường có thể dùng:
momentum beta=0.0 -> 79,513 steps to 1%
momentum beta=0.9 -> 1,609 steps to 1%
momentum beta=0.99 -> 461 steps to 1%Nhanh hơn 172 lần nhờ hai dòng code. Chương 6 biến điều này thành Adam; cơ chế đã ở đây rồi.
Phép kiểm bạn sẽ cần trong Chương 5
Liên kết đến mục: Phép kiểm bạn sẽ cần trong Chương 5Mọi gradient trong chương này được suy ra bằng tay và vì thế có thể sai. Cách sửa là bảng độ dốc từ đầu chương: đo đạo hàm bằng số và so sánh. Dùng sai phân trung tâm, , giúp khử hạng sai số dẫn đầu và chính xác hơn rất nhiều với cùng .
def numeric_grad(f, theta, h=1e-5):
theta = np.asarray(theta, dtype=float)
out = np.zeros_like(theta)
for i in range(theta.size):
bump = np.zeros_like(theta)
bump[i] = h
out[i] = (f(theta + bump) - f(theta - bump)) / (2 * h)
return out
def gradcheck(f, df, theta, h=1e-5):
analytic = np.asarray(df(theta), dtype=float)
numeric = numeric_grad(f, theta, h)
return np.max(np.abs(analytic - numeric) / np.maximum(1e-8, np.abs(analytic) + np.abs(numeric)))Dạng tương đối của phép so sánh rất quan trọng: chênh lệch tuyệt đối là thảm họa trên một gradient có cỡ và không đáng kể trên một gradient có cỡ .
relative error: 1.8929136036763527e-11
with 2 dropped: 0.33333333331650744Dòng đầu là gradient suy ra bằng tay ở trên. Dòng thứ hai là cùng hàm đó nhưng bỏ sót hệ số 2 ở một thành phần — một lỗi gõ một ký tự — và phép kiểm bắt ngay lập tức. Bất cứ gì dưới khoảng là khớp; bất cứ gì trên là bug. Hãy giữ hàm này: Chương 5 dùng nó để debug một engine automatic differentiation, và nó là lý do duy nhất để một gradient sai có thể được tìm ra.
Tiếp theo là gì
Liên kết đến mục: Tiếp theo là gìMọi thứ trong chương này dựa trên một giả định chưa từng được nói ra: rằng bạn có thể viết xuống.
Với một đường thẳng có hai tham số, đó là một dòng đại số. Nó gần như ngay lập tức không còn là một dòng nữa. Hãy hỏi một hệ thống đại số ký hiệu đạo hàm của loss của một mạng theo một trọng số lớp đầu tiên, cho một ví dụ, rồi đếm số phép tính trong đáp án:
| mạng | số phép toán trong một đạo hàm riêng |
|---|---|
| bốn hidden unit, một lớp | 40 |
| bốn hidden unit, hai lớp | 301 |
| bốn hidden unit, ba lớp | 1.717 |
Hàng thứ ba là một mạng có 57 tham số — nhỏ đến mức chỉ là một chú thích trong Chương 6 — và viết gradient của nó ra bằng tay nghĩa là khoảng 97.869 phép toán cho một ví dụ huấn luyện. Không có ký hiệu nào cứu được chuyện này. Thứ cứu được là quan sát rằng quy tắc dây chuyền áp dụng cho một hợp thành có cấu trúc khổng lồ, rằng cùng các đại lượng trung gian xuất hiện lặp đi lặp lại, và rằng tính chúng theo đúng thứ tự sẽ lấy được tất cả đạo hàm với chi phí xấp xỉ một lượt forward pass. Đó là Chương 5.
Nhưng trước hết có một vấn đề nhỏ hơn, và nó đang chờ ngay phía trước.
Giờ ta có một cỗ máy sẽ lăn xuống dốc trên bất kỳ loss khả vi nào. Hướng nó vào câu hỏi ban đầu của băng chuyền — chấp nhận hay loại bỏ, target là 1 hoặc 0 — đặt một sigmoid ở đầu ra để nó dự đoán xác suất, rồi tối thiểu hóa squared error. Nó sẽ chạy. Nó cũng sẽ gần như không nhúc nhích khi nó sai nhất, và gradient nói vì sao:
| output | dự đoán | sự thật | gradient với squared error | gradient với cross-entropy |
|---|---|---|---|---|
| 0.5000 | 1 | |||
| 0.1192 | 1 | |||
| 0.0025 | 1 | |||
| 1 |
Một model sai một cách tự tin, thảm họa — dự đoán 0,0000454 khi đáp án là 1 — tạo ra gradient squared-error bằng . Nó không hề biết mình đang gặp rắc rối. Cột còn lại, từ một loss ta chưa suy ra, báo 1,0: mức khẩn cấp tối đa, đúng nơi nó xứng đáng xuất hiện.
Điều đó đặt ra câu hỏi mở đầu chương tiếp theo. Chương trước nói rằng một loss là một giả định về nhiễu, và squared error giả định nhiễu Gaussian. Một câu trả lời có-không có mô hình nhiễu nào — và loss nào xuất hiện khi bạn chạy cùng phép suy ra trên nó?
Nguồn và phương pháp
Liên kết đến mục: Nguồn và phương phápPhương pháp này còn cũ hơn tất cả các nguồn trên: Cauchy đã mô tả nó trong một ghi chú gửi Académie des Sciences năm 1847, như một cách giải các hệ phương trình bằng cách đi xuống dốc trên tổng các phần dư bình phương của chúng. Cũng đáng đọc song song với chương này: An overview of gradient descent optimization algorithms của Sebastian Ruder (arXiv:1609.04747), bao quát momentum đến Adam trong mười bốn trang dễ đọc; chương 3 của Numerical Optimization (ấn bản 2, Springer, 2006) của Nocedal và Wright, trong đó định lý 3.3 đưa ra tốc độ hội tụ của steepest descent trên một hàm bậc hai theo số điều kiện — đó là lý thuyết phía sau việc vì sao conditioning quyết định số bước, dù sách xử lý line search thay vì trần với bước cố định được đo ở trên; hoặc §5.8 và §7.1 của Mathematics for Machine Learning của Deisenroth, Faisal và Ong cho cùng nền tảng với ít máy móc hơn; §6.1 của Understanding Deep Learning của Prince và §4.3 của Deep Learning của Goodfellow, Bengio và Courville; Dive into Deep Learning §12.1–12.3, có phân tích minibatch với nhiều phép đo hơn mức có chỗ ở đây; và chương 4 của Hands-On Machine Learning (ấn bản 3) của Géron, phần thực dụng nhất về learning rate như một thứ bạn tinh chỉnh thay vì suy ra. Ghi chú MIT 6.390 đặt gradient descent trước phân loại, như khóa học này làm và vì cùng lý do.
Tài liệu tham khảo
Liên kết đến mục: Tài liệu tham khảo-
LeCun, Y., Bottou, L., Orr, G. B. và Müller, K.-R. Efficient BackProp, trong Neural Networks: Tricks of the Trade (Springer, 1998), tr. 9–50. Mục 4.3 đưa ra khuyến nghị và mục 5.1 đưa ra lập luận dùng trong hộp chi tiết ở trên: căn giữa và co giãn input làm thay đổi các trị riêng của ma trận đạo hàm bậc hai, và do đó thay đổi số bước, không chỉ sự thoải mái về số học. ↩
-
Dauphin, Y. N., Pascanu, R., Gulcehre, C., Cho, K., Ganguli, S. và Bengio, Y. Identifying and attacking the saddle point problem in high-dimensional non-convex optimization, arXiv:1406.2572 (2014). Lập luận rằng trong không gian nhiều chiều, các điểm tới hạn áp đảo là điểm yên ngựa chứ không phải cực tiểu cục bộ, vì một cực tiểu đòi hỏi mọi hướng trong hàng nghìn hướng đều cong lên cùng lúc. ↩
-
Robbins, H. và Monro, S. A Stochastic Approximation Method. Annals of Mathematical Statistics 22(3), tr. 400–407 (1951). Bài báo thiết lập rằng một ước lượng có nhiễu của gradient là đủ, miễn là step size co lại theo đúng cách. ↩
-
Polyak, B. T. Some methods of speeding up the convergence of iteration methods. USSR Computational Mathematics and Mathematical Physics 4(5), tr. 1–17 (1964). Phương pháp heavy-ball, chính là cập nhật momentum ở trên, hai mươi hai năm trước khi backpropagation đến với lĩnh vực này. ↩