Kích thước đầu ra và số tham số
Kích thước đầu ra và số tham số
Bài trước dạy cửa sổ trượt tính ra con số gì. Bài này trả lời câu hỏi đi ngay sau đó: đưa ảnh cỡ này qua lớp này thì ra cỡ bao nhiêu, và tốn bao nhiêu.
Ở bài phép tích chập bạn đã thấy mỗi ô đầu ra sinh ra thế nào. Nhưng lúc dựng mạng thật thì câu hỏi đầu tiên lại là câu khác: tôi ghép lớp này vào đây thì tensor đi ra có hình dạng gì, và nó thêm bao nhiêu tham số vào mô hình. Trả lời sai câu đó thì mã sẽ báo lỗi hình dạng, hoặc tệ hơn là không báo gì mà mạng cứ nặng lên mãi.
Cả bài này chỉ xoay quanh hai phép đếm. Một là số học kích thước, tính riêng cho từng chiều. Hai là số tham số, và nó không phụ thuộc vào ảnh to hay nhỏ. Chính chỗ tách rời đó là ý tưởng lớn của tích chập, và cuối bài bạn sẽ thấy nó bằng một con số cụ thể chứ không phải bằng một câu khen.
same quyết định, đang là 1 mỗi bên| Lớp | Vào | Ra | Tham số | Cộng dồn | Phép nhân cộng |
|---|---|---|---|---|---|
| 1 | 224×224×3 | 224×224×64 | 1.792 | 1.792 | 86,7 triệu |
| 2 | 224×224×64 | 224×224×64 | 36.928 | 38.720 | 1,8 tỉ |
| 3 | 224×224×64 | 224×224×64 | 36.928 | 75.648 | 1,8 tỉ |
| 4 | 224×224×64 | 224×224×64 | 36.928 | 112.576 | 1,8 tỉ |
Công thức kích thước, từng số hạng một
Với mỗi chiều, gọi vào là cỡ đầu vào, đệm là số ô 0 thêm vào mỗi bên:
ra = floor((vào + 2×đệm - giãn×(nhân-1) - 1) / bước) + 1
Đọc nó theo nghĩa hình học thì dễ nhớ hơn nhiều. Cụm giãn×(nhân-1) + 1 là
tầm với của cửa sổ: một nhân 3 với độ giãn 2 chỉ có 3 điểm chạm nhưng
trải dài 5 ô. Lấy trục đã đệm trừ đi tầm với, ta được đoạn mà điểm bắt đầu của
cửa sổ còn có thể rơi vào. Chia cho bước rồi cộng 1 vì vị trí đầu tiên cũng
tính là một vị trí.
Vài mốc nên thuộc lòng, bạn gõ lại vào sim để kiểm:
32với nhân3, bước1, đệm1cho ra đúng32. Đây là lớp conv kinh điển của VGG, nó giữ nguyên cỡ.- Cũng nhân
3nhưng bước2, đệm1thì32co còn16. Bước nhảy 2 là cách giảm cỡ mà không cần pooling. - Nhân
5, bước1, không đệm thì32còn28, mất 4 ô. - Nhân
3với độ giãn2, không đệm, cũng cho28. Cùng cỡ với nhân5, mà chỉ tốn 9 trọng số thay vì 25.
Chú ý cái floor. Khi bước không chia hết đoạn còn lại, phần dư bị vứt đi.
Sim hiện luôn con số đó ở ô hàng hoặc cột bỏ rơi ở mép, và tô cam mấy ô cuối
của dải cửa sổ. Thư viện thật cũng vứt đúng như vậy, chỉ khác là nó không nói gì
cả. Bạn thử vào = 10, nhân 3, bước 3, không đệm: ra 3, và một cột bên
phải không bao giờ nằm dưới cửa sổ nào.
Ba chế độ đệm, và chỗ same không làm được
valid nghĩa là không đệm gì, ảnh cứ co lại. same nghĩa là đệm sao cho cỡ ra
bằng cỡ vào. Muốn thế, ở bước 1, ta cần tổng đệm hai bên đúng bằng
tầm với - 1, tức mỗi bên (tầm với - 1) / 2. Với nhân lẻ thì luôn chia được:
nhân 3 đệm 1, nhân 5 đệm 2, nhân 7 đệm 3.
Có hai chỗ same gãy, và sim nói thẳng cả hai:
- Bước lớn hơn 1 thì cách đệm ở trên không giữ được cỡ, vì mỗi bước nhảy đã
ăn mất một phần trục: đầu ra rơi đúng vào
ceil(vào / bước). Đó là quy ước mà TensorFlow gọi làSAME, còn PyTorch thì từ chối luôn:padding='same'vớistride > 1là lỗi. Nhưng đừng đọc câu đó thành "không số đệm nào cứu được": nới đệm ra ngoài quy ước(k-1)/2thì vẫn có cấu hình giữ nguyên cỡ, chẳng hạn vào3, nhân3, bước2, đệm2cho đầu ra đúng3. Trong lưới quét của cổng kiểm có 7 cấu hình như vậy. Câu trên chỉ đúng dưới ràng buộcđệm = (k-1)/2, và ràng buộc đó là lựa chọn của thư viện chứ không phải một định luật của phép tích chập. - Nhân chẵn thì phải đệm lệch. Nhân
4cần tổng đệm3, mà 3 không chia đôi được. Thư viện thật xử lý bằng cách đệm thêm một cột bên phải. Sim này chỉ đệm đối xứng, nên nó đệm1mỗi bên và báo trước rằng đầu ra sẽ hụt một ô. Nói ra vẫn hơn là lặng lẽ cho một con số mà bạn tưởng làsame.
Cái giá tham số, và vì sao nó không phụ thuộc vào ảnh
tham số = kênh_ra × (kênh_vào / nhóm) × nhân × nhân + (bias ? kênh_ra : 0)
Nhìn kỹ vế phải: không có vào, không có bước, không có đệm, không có
giãn. Một lớp conv 3×3 từ 3 kênh ra 64 kênh tốn đúng chừng ấy trọng số dù
bạn cho nó ảnh 32×32 hay 4096×4096. Ảnh to hơn chỉ làm số phép tính tăng
lên, chứ không làm mô hình nặng thêm một byte nào.
Ở trạng thái mặc định của sim, lớp đó là 64 × 3 × 3 × 3 + 64 = 1.792 tham số.
Một nghìn bảy trăm chín hai. Bây giờ hỏi ngược lại: nếu thay nó bằng một lớp
kết nối đầy đủ sinh ra đúng chừng ấy đầu ra từ đúng chừng ấy đầu vào thì tốn
bao nhiêu? Khối vào có 224 × 224 × 3 = 150.528 số, khối ra có
224 × 224 × 64 = 3.211.264 số, và nối đầy đủ nghĩa là mỗi cặp một trọng số:
150.528 × 3.211.264 + 3.211.264 = 483.388.358.656
Bốn trăm tám ba tỉ. Chia cho 1.792 ra đúng 269.747.968, tức lớp tích chập rẻ
hơn khoảng 270 triệu lần. Con số đó là toàn bộ lý do người ta dùng tích
chập: cùng một nhân 3×3 được dùng lại ở mọi vị trí trên ảnh, thay vì mỗi vị
trí có một bộ trọng số riêng. Người ta gọi đó là chia sẻ trọng số, và bạn
vừa nhìn thấy nó đắt rẻ ra sao bằng số.
Kéo cỡ nhân lên 7 rồi nhìn lại tỉ lệ. Nó tụt xuống, nhưng vẫn còn hàng chục
triệu lần. Kéo kênh ra lên cũng vậy. Không có cách nào làm lớp nối đầy đủ
thắng được, vì tham số của nó tăng theo tích của hai khối, còn tham số của
lớp tích chập thì không dính gì tới cỡ ảnh.
Nhóm, và tại sao độ giãn miễn phí
Chia nhóm là cắt kênh vào thành nhiều chồng độc lập, mỗi bộ lọc chỉ nhìn một
chồng. Số tham số vì thế chia đúng theo số nhóm. Trường hợp cực đoan là
nhóm = kênh vào = kênh ra, gọi là depthwise: mỗi kênh có nhân riêng và không
trộn với kênh nào khác. Bấm lớp mẫu MobileNet để thấy 32 kênh, nhân 3×3, chỉ
tốn 288 trọng số, trong khi lớp 3×3 dày đặc cùng hình dạng tốn 9.216, gấp
32 lần. Lưu ý sim chặn cấu hình mà kênh vào không chia hết cho số nhóm, vì đó là
lỗi chứ không phải một lựa chọn.
Độ giãn thì khác hẳn: nó chỉ kéo các điểm chạm xa nhau ra, không thêm điểm
chạm nào. Nhìn dải cửa sổ trong sim khi bạn đổi độ giãn từ 1 sang 3: cửa
sổ thưa ra, tầm với dài ra, mà số ô đậm vẫn là 3. Nên nó mua được vùng nhìn rộng
mà không trả thêm một trọng số nào. Cái phải trả là các ô nằm giữa hai điểm chạm
bị bỏ qua hoàn toàn.
Xếp chồng
Bảng cuối sim xếp đúng lớp bạn đang cấu hình lên nhau 4 lần. Ở mặc định, vì bước
1 và đệm same, bản đồ đứng yên 224×224 suốt cả bốn lớp, và tổng tham số
cộng dồn là 112.576. Đó chính là kiểu VGG: các lớp conv giữ nguyên cỡ, việc
thu nhỏ giao cho pooling. Đổi bước nhảy sang 2 và nhìn
lại: 224 thành 112, rồi 56, 28, 14. Số tham số mỗi lớp không đổi một
chút nào, nhưng số phép nhân cộng thì tụt rất nhanh, vì có ít ô đầu ra hơn để
tính.
Kích thước ra là floor((vào + 2×đệm - giãn×(nhân-1) - 1) / bước) + 1, còn số
tham số là kênh_ra × kênh_vào/nhóm × nhân × nhân cộng bias. Hai công thức
không dùng chung biến nào: bước nhảy, đệm và độ giãn đổi hình dạng chứ không
đổi số tham số, còn cỡ ảnh thì không đổi cả hai. Vì thế một lớp 3×3 tốn
1.792 tham số ở chỗ mà lớp nối đầy đủ tương đương tốn 483 tỉ.
Nó đếm đúng kích thước, số tham số và số phép nhân cộng, và bạn kiểm lại được
từng số hạng. Nó không nói được cấu hình nào học tốt hơn: rẻ hơn không có
nghĩa là chính xác hơn, và chuyện đó chỉ thực nghiệm mới trả lời được. Nó cũng
bỏ qua bộ nhớ kích hoạt lúc huấn luyện, tức các bản đồ đặc trưng phải giữ
lại cho lượt lan truyền ngược. Với lớp mặc định, riêng một bản đồ ra
224×224×64 đã là hơn 3 triệu số cho mỗi ảnh trong lô, thường lớn hơn bộ nhớ
trọng số rất nhiều. Đừng đọc ô "tham số" như là toàn bộ chi phí bộ nhớ.
- 1Ảnh vào 32×32, nhân 3×3, bước nhảy 2, đệm 1, độ giãn 1. Bản đồ ra cỡ bao nhiêu?
- 2Tăng thứ nào sau đây thì số tham số của lớp KHÔNG đổi?
- 3Nhân 3×3 với độ giãn 2 tốn bao nhiêu trọng số so với nhân 3×3 thường, cùng số kênh?