function zeropad(a::AbstractArray{T,N}, pad_width::NTuple{N,Tuple{Int,Int}}) where {T,N}
sizes = [b+p1+p2 for (b,(p1,p2))=zip(size(a),pad_width)]
r = zeros(T, sizes...)
ranges = [p1+1:p1+b for (b,(p1,_))=zip(size(a),pad_width)]
r[ranges...] = a
r
end
@inline zeropad(a::AbstractArray{T,N}, pad_width::Tuple{Int,Int}...) where {T,N} = zeropad(a, pad_width)
zeropad (generic function with 2 methods)
function im2col(input_data::AbstractArray{T,4}, filter_w::Int, filter_h::Int, stride::Int=1, pad::Int=0) where {T}
W, H, C, N = size(input_data)
out_h = (H + 2pad - filter_h) ÷ stride + 1
out_w = (W + 2pad - filter_w) ÷ stride + 1
img = pad==0 ? input_data : zeropad(input_data, (pad, pad), (pad, pad), (0, 0), (0, 0))
col = zeros(T, (out_w, out_h, filter_w, filter_h, C, N))
for y = 1:filter_h
y_max = y + stride*out_h - 1
for x = 1:filter_w
x_max = x + stride*out_w - 1
col[:, :, x, y, :, :] = img[x:stride:x_max, y:stride:y_max, :, :]
end
end
reshape(permutedims(col, (3, 4, 5, 1, 2, 6)), filter_w*filter_h*C, out_w*out_h*N)
end
im2col (generic function with 3 methods)
function col2im(col::AbstractArray{T,2}, input_shape::NTuple{4,Int}, filter_h::Int, filter_w::Int, stride::Int=1, pad::Int=0) where {T}
W, H, C, N = input_shape
out_h = (H + 2pad - filter_h) ÷ stride + 1
out_w = (W + 2pad - filter_w) ÷ stride + 1
_col = permutedims(reshape(col, filter_w, filter_h, C, out_w, out_h, N), (4, 5, 1, 2, 3, 6))
img = zeros(T, (W + 2*pad + stride - 1, H + 2*pad + stride - 1, C, N))
for y = 1:filter_h
y_max = y + stride*out_h - 1
for x = 1:filter_w
x_max = x + stride*out_w - 1
img[x:stride:x_max, y:stride:y_max, :, :] += _col[:, :, x, y, :, :]
end
end
return img[pad+1:pad+W, pad+1:pad+H, :, :]
end
col2im (generic function with 3 methods)
x1 = rand(Float32, (7, 7, 3, 1));
size(x1)
(7, 7, 3, 1)
col1 = im2col(x1, 5, 5, 1, 0);
size(col1)
(75, 9)
x2 = rand(Float32, (7, 7, 3, 10));
col2 = im2col(x2, 5, 5, 1, 0);
size(col2)
(75, 90)
type Convolution{T}
W::AbstractArray{T,4}
b::AbstractArray{T,1}
stride::Int
pad::Int
(::Type{Convolution})(
W::AbstractArray{T,4},
b::AbstractArray{T,1},
stride::Int=1,
pad::Int=0) where {T} = new{T}(W, b, stride, pad)
end
function forward(self::Convolution{T}, x::AbstractArray{T,4}) where {T}
FW, FH, C, FN = size(self.W)
W, H, C, N = size(x)
out_h = 1 + (H + 2*self.pad - FH) ÷ self.stride
out_w = 1 + (W + 2*self.pad - FW) ÷ self.stride
col = im2col(x, FH, FW, self.stride, self.pad)
col_w = reshape(self.W, (:, FN)).'
out = col_w * col .+ self.b
return permutedims(reshape(out, (:, out_w, out_h, N)), (2, 3, 1, 4))
end
forward (generic function with 1 method)
type Pooling{T}
pool_h::Int
pool_w::Int
stride::Int
pad::Int
(::Type{Pooling{T}})(pool_h::Int, pool_w::Int, stride::Int=1, pad::Int=0) where {T} =
new{T}(pool_h, pool_w, stride, pad)
end
function forward(self::Pooling{T}, x::AbstractArray{T,4}) where {T}
W, H, C, N = size(x)
out_h = 1 + (H - self.pool_h) ÷ self.stride
out_w = 1 + (W - self.pool_w) ÷ self.stride
col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)
col = reshape(col, (self.pool_h*self.pool_w, :))
out = maximum(col, 1)
return permutedims(reshape(out, (C, out_w, out_h, N)), (2, 3, 1, 4))
end
forward (generic function with 2 methods)
P0 = reshape([1,2,3,0,0,1,2,4,1,0,4,2,3,2,0,1,3,0,6,5,4,2,4,3,3,0,1,0,2,3,3,1,4,2,1,2,0,1,0,4,3,0,6,2,4,2,4,3],
(4,4,3))
4×4×3 Array{Int64,3}: [:, :, 1] = 1 0 1 3 2 1 0 2 3 2 4 0 0 4 2 1 [:, :, 2] = 3 4 3 2 0 2 0 3 6 4 1 3 5 3 0 1 [:, :, 3] = 4 0 3 4 2 1 0 2 1 0 6 4 2 4 2 3
pool0 = Pooling{Int}(2, 2, 2, 0)
Pooling{Int64}(2, 2, 2, 0)
forward(pool0, reshape(P0, (4, 4, 3, 1)))
2×2×3×1 Array{Int64,4}: [:, :, 1, 1] = 2 3 4 4 [:, :, 2, 1] = 4 3 6 3 [:, :, 3, 1] = 4 4 4 6
im2col(reshape(P0, (4, 4, 3, 1)), 2, 2, 2, 0)
12×4 Array{Int64,2}: 1 3 1 4 2 0 0 2 0 2 3 0 1 4 2 1 3 6 3 1 0 5 0 0 4 4 2 3 2 3 3 1 4 1 3 6 2 2 0 2 0 0 4 4 1 4 2 3
reshape(im2col(reshape(P0, (4, 4, 3, 1)), 2, 2, 2, 0), (2*2, :))
4×12 Array{Int64,2}: 1 3 4 3 6 1 1 3 3 4 1 6 2 0 2 0 5 2 0 0 0 2 0 2 0 4 0 2 4 0 3 2 4 0 3 4 1 2 1 4 3 4 2 3 2 1 1 3
o0 = maximum(reshape(im2col(reshape(P0, (4, 4, 3, 1)), 2, 2, 2, 0), (2*2, :)), 1)
1×12 Array{Int64,2}: 2 4 4 4 6 4 3 3 4 4 3 6
permutedims(reshape(o0, (3, 2, 2, :)), (2, 3, 1, 4))
2×2×3×1 Array{Int64,4}: [:, :, 1, 1] = 2 3 4 4 [:, :, 2, 1] = 4 3 6 3 [:, :, 3, 1] = 4 4 4 6
X0 = reshape(P0, (4, 4, 3, 1))
4×4×3×1 Array{Int64,4}: [:, :, 1, 1] = 1 0 1 3 2 1 0 2 3 2 4 0 0 4 2 1 [:, :, 2, 1] = 3 4 3 2 0 2 0 3 6 4 1 3 5 3 0 1 [:, :, 3, 1] = 4 0 3 4 2 1 0 2 1 0 6 4 2 4 2 3
conv0 = Convolution(rand(-2:2, 3, 3, 3, 3), rand(-2:2, 3), 1, 1)
Convolution{Int64}([0 2 -2; -1 1 -2; 0 0 -1] [-1 -2 2; -2 -1 -1; -2 0 -1] [1 1 0; 2 1 2; 2 -1 2] [-1 -2 -2; 0 -2 0; 1 -2 -1] [0 -2 2; -2 0 -1; 1 0 1] [2 -2 -1; 2 1 2; -1 2 -2] [-2 -1 -1; 1 0 1; -2 -2 2] [-1 2 -1; -1 2 0; 1 -1 0] [-2 2 2; -2 2 2; -2 0 0], [-2, -2, 1], 1, 1)
forward(conv0, X0)
4×4×3×1 Array{Int64,4}: [:, :, 1, 1] = -7 -1 -12 0 1 -6 -24 11 -5 -21 7 6 -9 -18 17 6 [:, :, 2, 1] = -5 3 -4 -4 -14 -10 -18 -10 -23 -14 -9 2 -11 -33 -19 -3 [:, :, 3, 1] = 13 -6 22 -2 9 0 5 -13 21 11 -1 3 32 11 12 0
im2col(X0, 3, 3, 1, 1)
27×16 Array{Int64,2}: 0 0 0 0 0 1 2 3 0 0 1 2 0 1 0 4 0 0 0 0 1 2 3 0 0 1 2 4 1 0 4 2 0 0 0 0 2 3 0 0 1 2 4 0 0 4 2 0 0 1 2 3 0 0 1 2 0 1 0 4 0 3 2 0 1 2 3 0 0 1 2 4 1 0 4 2 3 2 0 1 2 3 0 0 1 2 4 0 0 4 2 0 2 0 1 0 0 0 1 2 0 1 0 4 0 3 2 0 0 0 0 0 0 1 2 4 1 0 4 2 3 2 0 1 0 0 0 0 1 2 4 0 0 4 2 0 2 0 1 0 0 0 0 0 0 0 0 0 0 3 0 6 0 4 2 4 0 3 0 1 0 0 0 0 3 0 6 5 4 2 4 3 3 0 1 0 0 0 0 0 0 6 5 0 2 4 3 0 0 1 0 0 0 3 0 6 0 4 2 4 0 3 0 1 0 2 3 3 ⋮ ⋮ ⋮ ⋮ 0 4 2 4 0 3 0 1 0 2 3 3 0 0 0 0 4 2 4 3 3 0 1 0 2 3 3 1 0 0 0 0 2 4 3 0 0 1 0 0 3 3 1 0 0 0 0 0 0 0 0 0 0 4 2 1 0 0 1 0 0 3 0 6 0 0 0 0 4 2 1 2 0 1 0 4 3 0 6 2 0 0 0 0 2 1 2 0 1 0 4 0 0 6 2 0 0 4 2 1 0 0 1 0 0 3 0 6 0 4 2 4 4 2 1 2 0 1 0 4 3 0 6 2 4 2 4 3 2 1 2 0 1 0 4 0 0 6 2 0 2 4 3 0 0 0 1 0 0 3 0 6 0 4 2 4 0 0 0 0 0 1 0 4 3 0 6 2 4 2 4 3 0 0 0 0 1 0 4 0 0 6 2 0 2 4 3 0 0 0 0 0
reshape(conv0.W, (:, 3))
27×3 Array{Int64,2}: 0 -1 -2 -1 0 1 0 1 -2 2 -2 -1 1 -2 0 0 -2 -2 -2 -2 -1 -2 0 1 -1 -1 2 -1 0 -1 -2 -2 -1 -2 1 1 -2 -2 2 ⋮ 2 2 -1 -1 -1 0 -1 1 0 1 2 -2 2 2 -2 2 -1 -2 1 -2 2 1 1 2 -1 2 0 0 -1 2 2 2 2 2 -2 0
reshape(conv0.W, (:, 3)).' * im2col(X0, 3, 3, 1, 1)
3×16 Array{Int64,2}: -5 3 -3 -7 1 -4 -19 -16 -10 -22 9 19 2 13 8 8 -3 -12 -21 -9 5 -8 -12 -31 -2 -16 -7 -17 -2 -8 4 -1 12 8 20 31 -7 -1 10 10 21 4 -2 11 -3 -14 2 -1
o1 = reshape(conv0.W, (:, 3)).' * im2col(X0, 3, 3, 1, 1) .+ conv0.b
3×16 Array{Int64,2}: -7 1 -5 -9 -1 -6 -21 -18 -12 -24 7 17 0 11 6 6 -5 -14 -23 -11 3 -10 -14 -33 -4 -18 -9 -19 -4 -10 2 -3 13 9 21 32 -6 0 11 11 22 5 -1 12 -2 -13 3 0
permutedims(reshape(o1, (3, 4, 4, :)), (2, 3, 1, 4))
4×4×3×1 Array{Int64,4}: [:, :, 1, 1] = -7 -1 -12 0 1 -6 -24 11 -5 -21 7 6 -9 -18 17 6 [:, :, 2, 1] = -5 3 -4 -4 -14 -10 -18 -10 -23 -14 -9 2 -11 -33 -19 -3 [:, :, 3, 1] = 13 -6 22 -2 9 0 5 -13 21 11 -1 3 32 11 12 0