Một bộ dò nét dùng lại trên cả ảnh
Chương 5 · Bài 5.1
MLP trải cả ảnh thành một vector.
Khi nét đổi vị trí, MLP có thể phải học lại nhiều trọng số.
Ta muốn đọc cửa sổ nhỏ.
Cùng kernel, nhiều vị trí.
Convolution toán học lật kernel 180∘.
Conv2d làm cross-correlation: nhân thẳng.
Kernel học được: lật hay không như nhau.
Kernel đề cho sẵn: tính không lật.
Hỏi nhanh
Hàng ảnh [0, 0, 5, 5] có một cạnh chuyển từ tối sang sáng. Kernel [-1, 1], stride 1, không padding. Conv2d của PyTorch cho ra kết quả nào?
Cửa sổ thứ hai là [0, 5], nhân thẳng với [-1, 1] được 5. Ra −5 là lật kernel như convolution trong toán.
Hỏi nhanh
Ảnh xám 64×64, kernel 3×3, không padding, stride 1, đầu ra 62×62. Nếu mỗi vị trí đầu ra có một kernel riêng thay vì dùng chung, lớp này cần bao nhiêu trọng số, bỏ qua bias?
Có 3844 vị trí đầu ra, mỗi vị trí một kernel 9 số, nên cần 34596 trọng số. Lớp conv thường chỉ cần 9.
Phỏng theoCMU 10-601 · Exam 3 Practice · Q1.4(a)
Ô trên trái là 1×1+2×0+0×0+1×2=3.
Ô bên phải là 2×1+0×0+1×0+3×2=8.
Chỉ đọc cửa sổ nằm trọn trong ảnh, không lật kernel, như Conv2d.
def correlate_valid(image, kernel):
height, width = image.shape
kh, kw = kernel.shape
result = np.zeros((height - kh + 1, width - kw + 1))
for row in range(result.shape[0]):
for col in range(result.shape[1]):
window = image[row:row + kh, col:col + kw]
result[row, col] = np.sum(window * kernel)
return result
feature_map = correlate_valid(image, kernel)
print(feature_map)
Kết quả[[3. 8.]
[2. 1.]]
Ô 8 lớn nhất: cửa sổ ấy có số lớn trên đường chéo, đúng chỗ kernel có trọng số dương.
Hỏi nhanh
Ta muốn một kernel 2×2 cho số dương với cửa sổ nét chéo [1001], nhưng cho 0 với mọi vùng nền đều màu [cccc]. Chọn kernel nào?
Kernel có tổng trọng số bằng 0 cho 0 với nền đều, và cho 2 với nét chéo.
Padding thêm vành quanh ảnh.
Stride quyết định mỗi lần dịch bao nhiêu ô.
Dilation giãn vị trí kernel.
Kernel 3, dilation 2 phủ 5 ô.
p là padding, s là stride, còn d là dilation.
Giữ kích thước khi s=1: 2p=d(k−1).
Hỏi nhanh
Ảnh dài 8 ô, kernel 3, padding 0, stride 2, dilation 1. Đầu ra dài bao nhiêu?
⌊(8−3)/2⌋+1=3: các vị trí bắt đầu là 0, 2, 4.
Hỏi nhanh
Conv có kernel 3, dilation 2, stride 1. Padding đối xứng bằng bao nhiêu thì giữ nguyên chiều dài đầu vào?
Kernel phủ d(k−1)+1=5 ô, nên cần 2p=4, tức p=2.
Input có shape (N,Cin,H,W).
Một kernel tạo một kênh đầu ra và đọc toàn bộ Cin kênh đầu vào.
RGB, 8 kênh đầu ra, kernel 3×3:
8(3⋅9+1)=224 tham số.
Số tham số không phụ thuộc H,W của ảnh.
rgb_layer = nn.Conv2d(3, 8, 3, padding=1)
print(sum(parameter.numel() for parameter in rgb_layer.parameters()))
print(tuple(rgb_layer(torch.zeros(2, 3, 7, 7)).shape))
Kết quả224
(2, 8, 7, 7)
Padding 1 giữ 7×7; hai ảnh, tám kênh.
Hỏi nhanh
nn.Conv2d(16, 32, kernel_size=(3, 5)) có weight.shape là gì?
Trục đầu là số kernel, 32, và mỗi kernel đọc đủ 16 kênh vào, cao 3, rộng 5.
Hỏi nhanh
Lớp nn.Conv2d(3, 8, 3, padding=1) chạy trên ảnh 7×7, rồi chạy trên ảnh 70×70. Số tham số và số phép nhân thay đổi thế nào?
Số tham số chỉ phụ thuộc Cin, Cout, k, nên vẫn là 224. Phép nhân tỉ lệ với số vị trí đầu ra, từ 49 lên 4900, tức gấp 100 lần.
Max pooling trả về 8. Average pooling trả về 3.5.
Không có trọng số học. Global pooling: cả map còn một số.
left = torch.tensor([[[[0., 4., 0., 0.]]]])
right = torch.tensor([[[[0., 0., 4., 0.]]]])
pool = nn.MaxPool2d((1, 2))
print(pool(left).flatten().tolist())
print(pool(right).flatten().tolist())
Kết quả[4.0, 0.0]
[0.0, 4.0]
Đỉnh 4 dịch sang cửa sổ thứ hai: pooling không bất biến dịch tuyệt đối.
Hỏi nhanh
Max pooling trên một cửa sổ 2×2 chỉ trả về số 8. Từ đó có khôi phục duy nhất được bốn ô ban đầu không?
Nhiều cửa sổ khác nhau có cùng giá trị lớn nhất, nên giảm kích thước là mất thông tin. Biết thêm trung bình cũng vẫn có vô số cách chia.
window = y.detach().clone().requires_grad_(True)
nn.MaxPool2d(2)(window).sum().backward()
print(window.grad[0, 0].tolist())
Kết quả[[0.0, 1.0], [0.0, 0.0]]
Max: chỉ ô thắng nhận gradient. Average: chia đều 1/4.
Hỏi nhanh
MaxPool1d(kernel_size=2, stride=1) trên [1, 9, 3] cho ra [9, 9]. Lấy tổng đầu ra rồi gọi backward(). Gradient về đầu vào là gì?
Ô 9 thắng ở cả hai cửa sổ chồng nhau, mỗi cửa sổ gửi về gradient 1, nên tổng là 2.
r: số ô input trong vùng nhìn; j: khoảng cách trên input giữa hai vị trí output kề nhau. Bắt đầu r=j=1.
rmới=r+(k−1)dj,jmới=sjConv 3, stride 1: r=3, j=1. Pool 2, stride 2: r=4, j=2. Conv 3, stride 1: r=8, j=2; cả ba lớp dùng dilation 1.
Hai lớp 3×3 nhìn 5×5.
18 trọng số thay vì 25 mỗi cặp kênh, thêm một activation.
Lớp nông: map lớn, cạnh, nét.
Lớp sâu: map nhỏ, thô, tổ hợp lớn.
Hỏi nhanh
Một conv kernel 3 stride 2, tiếp theo là một conv kernel 3 stride 1, cả hai có dilation 1. Một ô ở lớp thứ hai nhìn bao nhiêu ô đầu vào theo mỗi chiều?
Lớp đầu cho r=3, j=2. Lớp hai thêm (3−1)⋅2=4, nên r=7.
Conv stride 1: ảnh dịch, map dịch theo (đồng biến).
Bất biến chỉ có sau phép gộp vị trí.
Không tự bất biến với xoay, tỉ lệ, ánh sáng.
Đề cần tọa độ: đừng gộp hết vị trí.
Hỏi nhanh
Một bộ dò nét đã học tốt trên những ảnh chỉ có nét dựng đứng, ở đủ mọi vị trí. Ảnh test bị xoay 90∘ nên nét thành nằm ngang. Nhiều khả năng chuyện gì xảy ra?
Dùng chung kernel chỉ giúp khi mẫu dịch chỗ, còn xoay thì làm đổi chính mẫu cục bộ. Muốn bền với phép xoay, cần dữ liệu hoặc augmentation có xoay (bài 5.3).
(H, W, C) → permute, kiểm một pixel.Luyện đề 1
Một đội thay một conv 7×7, 64 kênh vào, 64 kênh ra, bằng ba conv 3×3 từ 64 sang 64 nối tiếp, stride 1, có ReLU ở giữa. So với lớp cũ, bỏ qua bias, điều nào đúng?
Ba lớp 3×3 cho vùng nhìn 7×7, với 110592 trọng số so với 200704, khoảng 55%.
Luyện đề 2
Một conv 1D có một bộ lọc, và zj lớn nghĩa là có mẫu cần tìm ở vị trí j. Mạng A cho ra σ(maxjzj), mạng B cho ra σ(minjzj). Đầu ra cao nghĩa là “mẫu có ở mọi vị trí” ở mạng nào, và nghĩa là “mẫu có ở ít nhất một vị trí” ở mạng nào?
Min cao chỉ khi mọi zj đều cao, tức mẫu có ở mọi vị trí. Max cao thì chỉ cần một zj cao.
Phỏng theoMIT 6.036 · Final, Spring 2022 · Q8
Luyện đề 3
Mỗi mẫu là một tensor (64, 64, 2): vector lực (Fx,Fy) đo trên lưới 64×64. Phải dự đoán tọa độ nguồn (xs,ys) cùng 100 giá trị cường độ. Một đội dùng các conv stride 1, rồi global average pooling, rồi Linear ra 102 số, và lỗi tọa độ rất cao. Thay đổi nào nhắm đúng nguyên nhân?
Global average pooling gộp mọi vị trí, nên đặc trưng gần như không đổi khi nguồn dịch chỗ. Bỏ global pooling, flatten map để Linear đọc được vị trí.
Cửa sổ nhỏ và trọng số chung giúp dò cùng một tín hiệu ở nhiều vị trí.
Pooling lấy biểu diễn gọn hơn nhưng làm mất một phần chi tiết vị trí.
Làm 10 câu kiểm tra cuối bài trên trang bài học.
Chạy notebook; đổi stride và padding, đoán trước shape đầu ra rồi kiểm lại.