-
-
Notifications
You must be signed in to change notification settings - Fork 16
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
Example in README does not work correctly? #21
Comments
Oh weird. Taking a look now |
Same problem with Click to show output:```julia julia> using Metalhead, Metalhead.Flux, Torchjulia> vgg = VGG19() julia> tvgg = Flux.fmap(Torch.to_tensor, vgg) julia> ip = rand(Float32, 224, 224, 3, 1) [:, :, 2, 1] = [:, :, 3, 1] = julia> tip = tensor(ip, dev = 0) [:, :, 2, 1] = [:, :, 3, 1] = julia> vgg(ip) julia> tvgg(tip) julia> ip == convert(Array, tip) julia> versioninfo(; verbose = true) Memory: 187.5776710510254 GB (172788.265625 MB free) julia> import Pkg julia> Pkg.status() julia> Pkg.status(; mode = Pkg.PKGMODE_MANIFEST)
|
Interesting, could you run specifically with the |
Could you explain how to do that? |
Note the |
Hmm, not able to reproduce. julia> tresnet2(tip)
1000×5 Tensor{Float32,2}:
0.000490387 2.8881e-18 … 9.43812e-11 2.06312e-6
2.59334e-14 1.0 1.0 0.0783882
0.684608 5.45478e-13 1.51907e-9 5.58125e-5
0.314902 6.37972e-18 1.99655e-8 0.000203497
2.20994e-15 1.11982e-15 4.3811e-22 0.92135
5.03003e-17 0.0756458 … 0.000474865 3.06938e-8 |
I tried both of these: tresnet = Flux.fmap(Torch.to_tensor, resnet) tresnet = Flux.fmap(Torch.to_tensor, resnet.layers) Unfortunately, in both of these cases, |
Also, the dimension of Click to show output:julia> typeof(ip)
Array{Float32,4}
julia> ndims(ip)
4
julia> size(ip)
(224, 224, 3, 1)
julia> typeof(tip)
Tensor{Float32,4}
julia> ndims(tip)
4
julia> size(tip)
(224, 224, 3, 1)
julia> typeof(resnet(ip))
Array{Float32,2}
julia> ndims(resnet(ip))
2
julia> size(resnet(ip))
(1000, 1)
julia> typeof(tresnet(tip))
Tensor{Float32,2}
julia> ndims(tresnet(tip))
2
julia> size(tresnet(tip))
(1000, 1) |
Does converting it back to an |
Ah, yes, that should be fixed on master. |
julia> tresnet(tip)
1000×1 Tensor{Float32,2}:
1.0
1.0
1.0
1.0
1.0
1.0
1.0
⋮
1.0
1.0
1.0
1.0
1.0
1.0
1.0
julia> convert(Array, tresnet(tip))
1000×1 Array{Float32,2}:
1.0
1.0
1.0
1.0
1.0
1.0
1.0
⋮
1.0
1.0
1.0
1.0
1.0
1.0
1.0 |
Let me do |
So... on julia> using Metalhead, Metalhead.Flux, Torch
julia> resnet = ResNet();
julia> tresnet = Flux.fmap(Torch.to_tensor, resnet.layers);
julia> ip = rand(Float32, 224, 224, 3, 1);
julia> tip = tensor(ip, dev = 0);
julia> resnet(ip)
1000×1 Array{Float32,2}:
0.00087634224
0.000810427
0.0006268254
0.0007971713
0.001212693
0.0013046135
0.0007224348
⋮
0.00033712923
0.0006899684
0.00080008985
0.0007252848
0.0007919692
0.0016419729
0.001108708
julia> tresnet(tip)
ERROR: MethodError: no method matching conv(::Tensor{Float32,4}, ::Tensor{Float32,4}, ::Tensor{Float32,1}, ::DenseConvDims{2,(1, 1),64,64,(1, 1),(0, 0, 0, 0),(1, 1),false}; stride=1, pad=0, dilation=1)
Closest candidates are:
conv(::Tensor{xT,N}, ::Tensor{T,N}, ::Tensor{T,N} where N, ::DenseConvDims{M,K,C_in,C_out,S,P,D,F}; stride, pad, dilation) where {T, N, xT, M, K, C_in, C_out, S, P, D, F} at /users/daluthge/.julia/packages/Torch/W539X/src/nnlib.jl:10
conv(::Tensor, ::Tensor, ::DenseConvDims; stride, pad, dilation) at /users/daluthge/.julia/packages/Torch/W539X/src/nnlib.jl:15
conv(::Any, ::AbstractArray{T,N}; stride, pad, dilation, flipped) where {T, N} at /users/daluthge/.julia/packages/NNlib/FAI3o/src/conv.jl:174
...
Stacktrace:
[1] conv(::Tensor{Float32,4}, ::Tensor{Float32,4}, ::DenseConvDims{2,(1, 1),64,64,(1, 1),(0, 0, 0, 0),(1, 1),false}; stride::Int64, pad::Int64, dilation::Int64) at /users/daluthge/.julia/packages/Torch/W539X/src/nnlib.jl:16
[2] conv(::Tensor{Float32,4}, ::Tensor{Float32,4}, ::DenseConvDims{2,(1, 1),64,64,(1, 1),(0, 0, 0, 0),(1, 1),false}) at /users/daluthge/.julia/packages/Torch/W539X/src/nnlib.jl:15
[3] (::Conv{2,2,typeof(identity),Tensor{Float32,4},Tensor{Float32,1}})(::Tensor{Float32,4}) at /users/daluthge/.julia/packages/Flux/Fj3bt/src/layers/conv.jl:61
[4] (::Metalhead.ResidualBlock)(::Tensor{Float32,4}) at /users/daluthge/.julia/packages/Metalhead/RZn9O/src/resnet.jl:26
[5] applychain(::Tuple{Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,MeanPool{2,4},Metalhead.var"#103#104",Dense{typeof(identity),Tensor{Float32,2},Tensor{Float32,1}},typeof(softmax)}, ::Tensor{Float32,4}) at /users/daluthge/.julia/packages/Flux/Fj3bt/src/layers/basic.jl:36 (repeats 3 times)
[6] (::Chain{Tuple{Conv{2,2,typeof(identity),Tensor{Float32,4},Tensor{Float32,1}},MaxPool{2,2},Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,Metalhead.ResidualBlock,MeanPool{2,4},Metalhead.var"#103#104",Dense{typeof(identity),Tensor{Float32,2},Tensor{Float32,1}},typeof(softmax)}})(::Tensor{Float32,4}) at /users/daluthge/.julia/packages/Flux/Fj3bt/src/layers/basic.jl:38
[7] top-level scope at REPL[6]:1 |
Oh oops, let me check that out. Sorry about that! |
Seems to have broken in #19 |
I tried on julia> tresnet(tip)
1000×1 Tensor{Float32,2}:
1.0
1.0
1.0
1.0
1.0
1.0
1.0
⋮
1.0
1.0
1.0
1.0
1.0
1.0
1.0 |
Let me try and reproduce on a different machine. |
I'm able to reproduce this issue as well, MWE follows: using NNlib
using Torch
ip = permutedims(Float32[1 2 3])
tip = Torch.to_tensor(ip) # 0 => GPU:0 in Torch
println("Default")
@show op = softmax(ip)
println("Torch")
# This line fails because dims=1
# @show top = softmax(tip) |> collect
@show top = softmax(tip, dims=0) |> collect
@assert op ≈ top In short, torch dimensions start at 0, so the default dim of 1 was incorrectly calculating softmax along the batch dimension instead of the label dim. This also applies to mean, sum and any other method using dimension indices. @dhairyagandhi96 should this indexing match julia's 1-based dims? If so, I can put in a PR for the aforementioned methods. |
It should, I'd appreciate a PR It had seemed handled, in the tests I had run earlier. Do add this to the test suite. |
@DilumAluthge could you confirm that omitting the |
Sorry, I'm very new to everything related to Flux, Metalhead, etc. In the README example, how would I modify the example to omit the softmax layer? |
Instead of just patching a certain set of methods, would it be better to have a robust way of automatically converting between Julia's 1-based indexing and Python's/C++'s 0-based indexing whenever you convert a Julia (Flux, Metalhead, etc.) model to a PyTorch model? |
So, I had a crack at doing just this while trying to make sum and mean work. Turns out it's a much deeper rabbit hole than expected! To elaborate, the current On a more general note, maybe it would help to deduplicate some of the work here with ThArrays.jl? For example, I noticed that they already have a stride-aware tensor constructor (see https://github.com/TuringLang/ThArrays.jl/blob/05bd5ceb2d358dee7be1fe3242d796805313b7e5/csrc/torch_capi_tensor.cpp#L40), a pretty complete device API, etc. |
We can check the API with For the What do we currently lack from our device API? Some choices to turn off |
you just need to call the forward pass with |
Using |
I guess the question is whether or not possible to avoid lines like Line 25 in e658fa2
from_blob , I was able to get pretty close to Base semantics locally:
# Performs error checking and converts singleton dimensions to tuples
function _normalize_dims(t, dims)
inds = collect(reduced_indices(t, dims))
eachindex(inds)[length.(inds) .== 1] .- 1
end
function Statistics.mean(t::Tensor{T,N}; dims = :) where {T,N}
ptr = Ref(Ptr{Cvoid}())
if dims isa Colon
atg_mean(ptr, t.ptr, options[T])
Tensor{T,0}(ptr[], on(t))
else
# To match Julia's behaviour, we always keep dimensions when dims != :
atg_mean1(ptr, t.ptr, dims, length(dims), true, options[T])
Tensor{T,N-length(dims)}(ptr[], on(t))
end
end
function Statistics.sum(t::Tensor{T,N}; dims = :) where {T,N}
ptr = Ref(Ptr{Cvoid}())
if dims isa Colon
atg_sum(ptr, t.ptr, options[T])
Tensor{T,0}(ptr[], on(t))
else
@show dims = _normalize_dims(t, dims)
atg_sum1(ptr, t.ptr, dims, length(dims), true, options[T])
Tensor{T,N-length(dims)}(ptr[], on(t))
end
end |
Absolutely! Reversing the dimensions every time seems error prone. Ideally we'd have a more automatic solution that can interface with the binary with minimal handling on that side since changes there would be harder to debug. |
Maybe PR the dims change? |
Will see if I can find some time later tomorrow, will probably hack the from_blob/tensor constructor changes first so that size reversal can be completely excised from the implementation (no more |
I have a naive |
Add a look at the c++ -> c wrapper and I think |
Yeah, that would be fine. |
should be fixed on master |
I'm getting a weird result when I run the example in the README. Specifically, the output of
tresnet(tip)
produces all ones, while the output ofresnet(ip)
seems to produce the correct output.Click to show output:
The text was updated successfully, but these errors were encountered: