Flux Conv layer method error

Hi, I am trying to implement a simple train loop in julia to process images, but can’t make my model work. I create the model using the following code:

model = Chain(
    Conv((3, 3), 3 => 32, relu; pad = (1, 1), bias = false),
    flatten,
    Dense(15488, max_rating),
    softmax
)

I’ve tried to delete some parameters passed to the conv layer, but in any case it just inserts default values and the situation is essentially the same. The model is created correctly, but when i start training through Flux.train! I obtain a method error:

ERROR: LoadError: MethodError: no method matching (::Conv{2, 2, typeof(relu), Array{Float32, 4}, Bool})(::N0f8)

Closest candidates are:
  (::Conv)(::AbstractArray)
   @ Flux ~/.julia/packages/Flux/v79Am/src/layers/conv.jl:197

Stacktrace:
  [1] macro expansion
    @ ~/.julia/packages/Zygote/AS0Go/src/compiler/interface2.jl:0 [inlined]
  [2] _pullback(ctx::Zygote.Context{true}, f::Conv{2, 2, typeof(relu), Array{Float32, 4}, Bool}, args::N0f8)
    @ Zygote ~/.julia/packages/Zygote/AS0Go/src/compiler/interface2.jl:9
  [3] macro expansion
    @ ~/.julia/packages/Flux/v79Am/src/layers/basic.jl:53 [inlined]
  [4] _pullback
    @ ~/.julia/packages/Flux/v79Am/src/layers/basic.jl:53 [inlined]
  [5] _pullback(::Zygote.Context{true}, ::typeof(Flux._applychain), ::Tuple{Conv{2, 2, typeof(relu), Array{Float32, 4}, Bool}, typeof(flatten), Dense{typeof(identity), Matrix{Float32}, Vector{Float32}}, typeof(softmax)}, ::N0f8)
    @ Zygote ~/.julia/packages/Zygote/AS0Go/src/compiler/interface2.jl:0
  [6] _pullback
    @ ~/.julia/packages/Flux/v79Am/src/layers/basic.jl:51 [inlined]
  [7] _pullback(ctx::Zygote.Context{true}, f::Chain{Tuple{Conv{2, 2, typeof(relu), Array{Float32, 4}, Bool}, typeof(flatten), Dense{typeof(identity), Matrix{Float32}, Vector{Float32}}, typeof(softmax)}}, args::N0f8)
    @ Zygote ~/.julia/packages/Zygote/AS0Go/src/compiler/interface2.jl:0
  [8] _pullback
    @ ~/posterior/posterior/train.jl:65 [inlined]
  [9] _pullback(ctx::Zygote.Context{true}, f::typeof(L), args::Base.ReinterpretArray{N0f8, 3, RGB{N0f8}, Matrix{RGB{N0f8}}, true})
    @ Zygote ~/.julia/packages/Zygote/AS0Go/src/compiler/interface2.jl:0
 [10] _apply(::Function, ::Vararg{Any})
    @ Core ./boot.jl:838
 [11] adjoint
    @ ~/.julia/packages/Zygote/AS0Go/src/lib/lib.jl:203 [inlined]
 [12] _pullback
    @ ~/.julia/packages/ZygoteRules/AIbCs/src/adjoint.jl:65 [inlined]
 [13] _pullback
    @ ~/.julia/packages/Flux/v79Am/src/optimise/train.jl:143 [inlined]
 [14] _pullback(::Zygote.Context{true}, ::Flux.Optimise.var"#37#40"{typeof(L), Base.ReinterpretArray{N0f8, 3, RGB{N0f8}, Matrix{RGB{N0f8}}, true}})
    @ Zygote ~/.julia/packages/Zygote/AS0Go/src/compiler/interface2.jl:0
 [15] pullback(f::Function, ps::Zygote.Params{Zygote.Buffer{Any, Vector{Any}}})
    @ Zygote ~/.julia/packages/Zygote/AS0Go/src/compiler/interface.jl:384
 [16] withgradient(f::Function, args::Zygote.Params{Zygote.Buffer{Any, Vector{Any}}})
    @ Zygote ~/.julia/packages/Zygote/AS0Go/src/compiler/interface.jl:132
 [17] macro expansion
    @ ~/.julia/packages/Flux/v79Am/src/optimise/train.jl:142 [inlined]
 [18] macro expansion
    @ ~/.julia/packages/ProgressLogging/6KXlp/src/ProgressLogging.jl:328 [inlined]
 [19] train!(loss::Function, ps::Zygote.Params{Zygote.Buffer{Any, Vector{Any}}}, data::Vector{Base.ReinterpretArray{N0f8, 3, RGB{N0f8}, Matrix{RGB{N0f8}}, true}}, opt::Adam; cb::Flux.var"#throttled#124"{Flux.var"#throttled#120#125"{Bool, Bool, typeof(update_loss!), Int64}})
    @ Flux.Optimise ~/.julia/packages/Flux/v79Am/src/optimise/train.jl:140
 [20] kwcall(::NamedTuple{(:cb,), Tuple{Flux.var"#throttled#124"{Flux.var"#throttled#120#125"{Bool, Bool, typeof(update_loss!), Int64}}}}, ::typeof(Flux.Optimise.train!), loss::Function, ps::Zygote.Params{Zygote.Buffer{Any, Vector{Any}}}, data::Vector{Base.ReinterpretArray{N0f8, 3, RGB{N0f8}, Matrix{RGB{N0f8}}, true}}, opt::Adam)
    @ Flux.Optimise ~/.julia/packages/Flux/v79Am/src/optimise/train.jl:136
 [21] top-level scope
    @ ~/posterior/posterior/train.jl:77
in expression starting at /home/zeio/posterior/posterior/train.jl:75

Could anybody please help with that?

The error message indicates you are attempting to apply a conv operation to a single N0f8 value rather than an array of them. Would you mind showing your loss function implementation? Perhaps there is an extra broadcast operation.

Thanks! It seems that the problem is indeed in the input data. I was passing to the model list of images instead of list of batches. But now there is another error. That’s how I load the input data which are 256x256 images:

posters = (movie -> get_poster_local_path(movie, "assets/posters/resized") |> load |> channelview).(movies)

Then if I view the shape of results via println(size(posters[1])) it outputs (3, 256, 256), which seems to be fine. That’s how I then create minibatches following this tutorial:

function make_minibatch(X, Y, indices)
    X_batch = Array{Float32}(undef, size(X[1])..., length(indices))

    for i in 1:length(indices)
        X_batch[:, :, :, i] = Float32.(X[indices[i]])
    end

    Y_batch = onehotbatch(Y[indices], 1:max_rating)

    return (X_batch, Y_batch)
end

But model complains about the input data:

ERROR: LoadError: DimensionMismatch: Input channels must match! (256 vs. 3)

Should I somehow transpose my images before passing to model, or there is an issue with model configuration?

Yeah, the tutorial doesn’t have that problem because they convert the images to single-channel (grey) images. The image was loaded as (channel, Y, X), you need to permutedims(img, (2,3,1)) to move the channel axis to the end.

Yes, thank you! I’ve added this and also a couple of other changes to the training loop from documentation and now it works.