conv with zero outputsize
- Dominant language
- Julia
- Stars
- 1.4k
- Forks
- 281
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 30
Description
**Is your feature request related to a problem? Please describe.**
*Disclaimer* : This is very much an edge-edge-case, and the only reason I'm posting it is that I don't think it would require much effort to fix and that it might be a desirable behaviour. Please close with prejudice if this is not the case :)
I'm toying around with neural architecture evolution and there are cases when the search policy determines that a layer shall have zero output size. One example is when this is a valid action is when pruning output neurons of what is essentially a concatenation of activations from sevaral layers.
To my surprise it turned out that flux with cpu backend actually supports conv layers with zero output size:
```julia
julia> using Flux
julia> cc = Conv((5,5), 3 => 0)
Conv((5, 5), 3=>0)
julia> cc(ones(Float32, 10,10,3,1))
Tracked 6×6×0×1 Array{Float32,4}
```
Don't know if this is by accident or by design, but the same thing using CuArrays fails:
```julia
julia> ccc = cc |> gpu
Conv((5, 5), 3=>0)
julia> ccc(ones(Float32, 10,10,3,1) |> gpu)
ERROR: CUDNNError(code 3, CUDNN_STATUS_BAD_PARAM)
Stacktrace:
[1] macro expansion at E:\Programs\julia\.julia\packages\CuArrays\eFBar\src\dnn\error.jl:19 [inlined]
[2] cudnnSetFilterNdDescriptor at E:\Programs\julia\.julia\packages\CuArrays\eFBar\src\dnn\libcudnn.jl:58 [inlined]
[3] #FilterDesc#20(::UInt32, ::Type, ::Type, ::NTuple{4,Int64}) at E:\Programs\julia\.julia\packages\CuArrays\eFBar\src\dnn\helpers.jl:59
[4] Type at .\none:0 [inlined]
[5] #FilterDesc#21 at E:\Programs\julia\.julia\packages\CuArrays\eFBar\src\dnn\helpers.jl:69 [inlined]
[6] Type at E:\Programs\julia\.julia\packages\CuArrays\eFBar\src\dnn\helpers.jl:69 [inlined]
[7] #cudnnGetConvolutionForwardWorkspaceSize#9(::Int64, ::Function, ::CuArray{Float32,4}, ::CuArray{Float32,4}, ::CuArray{Float32,4}, ::DenseConvDims{2,(5, 5),3,0,(1, 1),(0, 0, 0, 0),(1, 1),false}) at E:\Programs\julia\.julia\packages\CuArrays\eFBar\src\dnn\libcudnn.jl:287
[8] #cudnnGetConvolutionForwardWorkspaceSize at .\none:0 [inlined]
[9] #conv!#22(::Int64, ::Int64, ::Function, ::CuArray{Float32,4}, ::CuArray{Float32,4}, ::CuArray{Float32,4}, ::DenseConvDims{2,(5, 5),3,0,(1, 1),(0, 0, 0, 0),(1, 1),false}) at E:\Programs\julia\.julia\packages\CuArrays\eFBar\src\dnn\nnlib.jl:48
[10] conv!(::CuArray{Float32,4}, ::CuArray{Float32,4}, ::CuArray{Float32,4}, ::DenseConvDims{2,(5, 5),3,0,(1, 1),(0, 0, 0, 0),(1, 1),false}) at E:\Programs\julia\.julia\packages\CuArrays\eFBar\src\dnn\nnlib.jl:44
[11] macro expansion at E:\Programs\julia\.julia\packages\NNlib\mxWRT\src\conv.jl:114 [inlined]
[12] #conv#97(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::CuArray{Float32,4}, ::CuArray{Float32,4}, ::DenseConvDims{2,(5, 5),3,0,(1, 1),(0, 0, 0, 0),(1, 1),false}) at E:\Programs\julia\.julia\packages\TimerOutputs\7zSea\src\TimerOutput.jl:190
[13] #_forward#524 at E:\Programs\julia\.julia\packages\TimerOutputs\7zSea\src\TimerOutput.jl:198 [inlined]
[14] _forward(::typeof(conv), ::CuArray{Float32,4}, ::TrackedArray{…,CuArray{Float32,4}}, ::DenseConvDims{2,(5, 5),3,0,(1, 1),(0, 0, 0, 0),(1, 1),false}) at .\none:0
[15] #track#1(::Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::typeof(conv), ::CuArray{Float32,4}, ::Vararg{Any,N} where N) at E:\Programs\julia\.julia\packages\Tracker\RRYy6\src\Tracker.jl:51
[16] track at E:\Programs\julia\.julia\packages\Tracker\RRYy6\src\Tracker.jl:51 [inlined]
[17] #conv#522 at E:\Programs\julia\.julia\packages\Tracker\RRYy6\src\lib\array.jl:419 [inlined]
[18] conv at E:\Programs\julia\.julia\packages\Tracker\RRYy6\src\lib\array.jl:419 [inlined]
[19] (::Conv{2,4,typeof(identity),TrackedArray{…,CuArray{Float32,4}},TrackedArray{…,CuArray{Float32,1}}})(::CuArray{Float32,4}) at E:\Programs\julia\.julia\packages\Flux\qXNjB\src\layers\conv.jl:55
[20] top-level scope at none:0
```
**Describe the solution you'd like**
Same output as for the cpu case above.
**Describe alternatives you've considered**
I can search through the model before using it and just remove any layer with zero output (as well as their input layers until I hit the fork). I will probably implement this anyways just to remove clutter and save unnecessary computation.
I could also wrap layers inside a container layer which handles the 0 output case or delegates to the real layer if output size is not zero.
I don't think it is possible to override a method deep inside the call heirarchy (e.g. conv!) and delegate to the original implementation, but if it is would like to know how.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.