Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support valid padding in Conv2D #16

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 31 additions & 16 deletions src/net_components/layers/conv2d.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ using JuMP
using ConditionalJuMP

export Conv2d
export Padding

@enum Padding same=1 valid=2

"""
$(TYPEDEF)
Expand All @@ -18,25 +21,30 @@ $(FIELDS)
filter::Array{T, 4}
bias::Array{U, 1}
stride::V
padding::Padding

function Conv2d{T, U, V}(filter::Array{T, 4}, bias::Array{U, 1}, stride::V) where {T<:JuMPReal, U<:JuMPReal, V<:Int64}
function Conv2d{T, U, V}(filter::Array{T, 4}, bias::Array{U, 1}, stride::V, padding::Padding) where {T<:JuMPReal, U<:JuMPReal, V<:Int64}
(filter_height, filter_width, filter_in_channels, filter_out_channels) = size(filter)
bias_out_channels = length(bias)
@assert(
filter_out_channels == bias_out_channels,
"For this convolution layer, number of output channels in filter, $filter_out_channels, does not match number of output channels in bias, $bias_out_channels."
)
return new(filter, bias, stride)
return new(filter, bias, stride, padding)
end

end

function Conv2d(filter::Array{T, 4}, bias::Array{U, 1}, stride::V, padding::Padding) where {T<:JuMPReal, U<:JuMPReal, V<:Int64}
Conv2d{T, U, V}(filter, bias, stride, padding)
end

function Conv2d(filter::Array{T, 4}, bias::Array{U, 1}, stride::V) where {T<:JuMPReal, U<:JuMPReal, V<:Int64}
Conv2d{T, U, V}(filter, bias, stride)
Conv2d{T, U, V}(filter, bias, stride, same)
end

function Conv2d(filter::Array{T, 4}, bias::Array{U, 1}) where {T<:JuMPReal, U<:JuMPReal}
Conv2d(filter, bias, 1)
Conv2d(filter, bias, 1, same)
end

"""
Expand All @@ -59,8 +67,9 @@ end
function Base.show(io::IO, p::Conv2d)
(filter_height, filter_width, filter_in_channels, filter_out_channels) = size(p.filter)
stride = p.stride
padding = p.padding
print(io,
"Conv2d($filter_in_channels, $filter_out_channels, kernel_size=($(filter_height), $(filter_width)), stride=($(stride), $(stride)), padding=same)"
"Conv2d($filter_in_channels, $filter_out_channels, kernel_size=($(filter_height), $(filter_width)), stride=($(stride), $(stride)), padding=$(padding))"
)
end

Expand Down Expand Up @@ -108,27 +117,33 @@ function conv2d(
end
filter = params.filter
stride = params.stride
padding = params.padding

(batch, in_height, in_width, input_in_channels) = size(input)
(filter_height, filter_width, filter_in_channels, filter_out_channels) = size(filter)

@assert(
input_in_channels == filter_in_channels,
input_in_channels == filter_in_channels,
"Number of channels in input, $input_in_channels, does not match number of channels, $filter_in_channels, that filters operate on."
)

out_height = round(Int, in_height/stride, RoundUp)
out_width = round(Int, in_width/stride, RoundUp)
output_size = (batch, out_height, out_width, filter_out_channels)

# Considered using offset arrays here, but could not get it working.

# Calculating appropriate offsets so that center of kernel is matched with
# cell at which correlation is being calculated. Note that tensorflow
# chooses a specific convention for a dimension with even size which we
# replicate here.
filter_height_offset = round(Int, filter_height/2, RoundUp)
filter_width_offset = round(Int, filter_width/2, RoundUp)
if padding == same
out_height = round(Int, in_height/stride, RoundUp)
out_width = round(Int, in_width/stride, RoundUp)
output_size = (batch, out_height, out_width, filter_out_channels)
filter_height_offset = round(Int, filter_height/2, RoundUp)
filter_width_offset = round(Int, filter_width/2, RoundUp)
else
@assert(padding == valid)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than this assertion, what about

Suggested change
@assert(padding == valid)
if padding == same
...
elseif padding == valid
...
else
error("Unknown padding type $padding")
end

out_height = round(Int, (in_height + 1 - filter_height) / stride, RoundUp)
out_width = round(Int, (in_width + 1 - filter_width) / stride, RoundUp)
output_size = (batch, out_height, out_width, filter_out_channels)
filter_height_offset = 1
filter_width_offset = 1
end

W = Base.promote_op(+, V, Base.promote_op(*, T, U))
output = Array{W}(output_size)

Expand Down
10 changes: 6 additions & 4 deletions src/utils/import_weights.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ export get_matrix_params, get_conv_params, get_example_network_params
"""
$(SIGNATURES)

Helper function to import the parameters for a layer carrying out matrix multiplication
Helper function to import the parameters for a layer carrying out matrix multiplication
(e.g. fully connected layer / softmax layer) from `param_dict` as a
[`Linear`](@ref) object.

Expand Down Expand Up @@ -62,16 +62,18 @@ function get_conv_params(
expected_size::NTuple{4, Int};
matrix_name::String = "weight",
bias_name::String = "bias",
expected_stride::Integer = 1
expected_stride::Integer = 1,
padding::Padding = same
)::Conv2d

params = Conv2d(
param_dict["$layer_name/$matrix_name"],
squeeze(param_dict["$layer_name/$bias_name"], 1),
expected_stride
expected_stride,
padding
)

check_size(params, expected_size)

return params
end
end