I'm trying to calculate the laplacian of neural network. This is my code:
using Flux
using Zygote
model = Chain(Dense(2,5,sigmoid), Dense(5,1))
function laplace(x)
a, b = size(x)
Δ = Zygote.Buffer(zeros(b))
deriv2 = sum(Diagonal(ones(a*b)).*Zygote.hessian(v -> sum(model(v)), x), dims=1)
for i=1:b
for j=1:a
Δ[i] += deriv2[(i-1)*a+j]
end
end
return copy(Δ)
end
gradient(x -> sum(laplace(x)), rand(2,5))
I'll see the same error even if I define a function like this:
function function(x)
return sum(Zygote.hessian(v -> sum(model(v)), x))
end
gradient(x -> function(x), rand(2,5))
Why do I get this error?
Related
I'm new to Julia and I have some difficulties with the programming with types approach.
I wanted to load a 3D mesh from a file to practice and I have made some custom types to store it.
Here are my types:
struct Vertex
x::Number
y::Number
z::Number
Vertex(x::Number, y::Number, z::Number) = new(x, y, z)
Vertex(t::Tuple{Number, Number, Number}) = new(t[1], t[2], t[3])
Vertex(x::Number, y::Number) = new(x, y, 0)
Vertex(t::Tuple{Number, Number}) = new(t[1], t[2], 0)
Vertex(x::Number) = new(x, 0, 0)
Vertex(t::Tuple{Number}) = new(t[1], 0, 0)
Vertex() = new(0, 0, 0)
Vertex(t::Tuple{}) = new(0, 0, 0)
end
struct Mesh
t::Vector{Vertex} # List of triangles
f::Vector{Vertex} # List of faces
n::Vector{Vertex} # List of normals
Mesh(t::Vertex, f::Vertex) = new([t], [f], [])
Mesh(t::Vector{Vertex}, f::Vector{Vertex}, n::Vector{Vertex}) = new(t, f, n)
Mesh(t::Vector{Vertex}, f::Vector{Vertex}, n::Vector) = new(t, f, n)
Mesh(t::Vector, f::Vector, n::Vector) = new(t, f, n)
#Mesh(t::Triangle) = new([t], [])
#Mesh(t::Vector{Triangle}) = new(t, [])
end
I can effectively load a mesh in my Mesh type.
Now, I would like to plot it using the method plot_trisurf from PyPlot. However, this method expect an array of arrays and I'm not sure my way of doing it is the right way:
function plotMesh(M)
Xv = map(e -> e.x, M.t[:])
Yv = map(e -> e.x, M.t[:])
Zv = map(e -> e.x, M.t[:])
Fv = map(e -> (e.x, e.y, e.z), M.f[:])
plot_trisurf(Xv, Yv, Zv, triangles=Fv, alpha=1)
gca()[:projection] = "3d"
end
Q:
The Xv, Yv, Zv doesn't feel right at the moment,
and the Fv do not work at all. [Corrected -> see Edit]
What it the best way of doing this?
Is my type design correct? or should I change it to something more suitable?
Thanks
[edit]
After some more tests I finally managed to make it work, however I'm still not sure if it is the best way to do things in Julia nor if my type system is a good one.
function plotMesh(M::Mesh)
Xv = map(e -> e.x, M.t[:])
Yv = map(e -> e.y, M.t[:])
Zv = map(e -> e.z, M.t[:])
Fv = map(e -> [Int(e.x)-1, Int(e.y)-1, Int(e.z)-1], M.f[:])
print(size(Xv))
print(size(Fv))
plot_trisurf(Xv, Yv, Zv, triangles=Fv)
gca()[:projection] = "3d"
end
First 3D plot in Julia
[edit]
The vertices and normals are (in general) floats and the faces are integers.
The object I'm using is bunny.obj
and my code for loading the object in the structures is:
function read_obj(filename::String)
v = []
f = []
n = []
tof(x) = parse(Float64, x)
open(filename) do file
for line in eachline(file)
l = split(line, ' ')
if l[1] ∈ ["v", "f", "n"]
values = (tof(l[2]), tof(l[3]), tof(l[4]))
if l[1] == "v"
push!(v, Vertex(values))
elseif l[1] == "f"
faces = (Int(values[1]), Int(values[2]), Int(values[3]))
push!(f, Vertex(faces))
elseif l[1] == "n"
push!(n, Vertex(values))
end
end
end
end
return Mesh(v, f, n)
end
My way of loading the object is surely not the best way of doing it. If you have any material to improve my skills feel free to share :)
First I would change the definition of Vertex like this (it seems below you require entries to be integers, if not, you can change Integer to Number)
struct Vertex{T<:Integer}
x::T
y::T
z::T
end
Vertex(x::T=0, y::T=zero(T)) where {T<:Integer} = Vertex(x,y,zero(T))
Vertex(t::Tuple) = Vertex(t...)
Next in Mesh you can use StructArrays.jl package like this (this way you can easily access fields of Vertex as vectors):
using StructArrays
struct Mesh{S<:StructArray, T}
t::S
f::S
n::S
function Mesh(t::Vector{T}, f::Vector{T}, n::Vector{T}) where {T<:Vertex}
st, sf, sn = StructArray(t), StructArray(f), StructArray(n)
new{typeof(st), T}(st, sf, sn)
end
end
Mesh(t::T, f::T) where {T<:Vertex} = Mesh([t], [f], T[])
now you can define the plotting function for example as:
function plotMesh(M::Mesh{S, T}) where {S,T}
Fv = eachrow([M.f.x M.f.y M.f.z] .- one(T))
print(size(M.t.x))
print(size(Fv))
plot_trisurf(M.t.x, M.t.y, M.t.z, triangles=Fv)
gca()[:projection] = "3d"
end
Note 1: All codes make sure that all the structures operate on concrete types so that the code will be faster than using abstract types (like Number). Also I make sure that all entries have the same type.
Note 2: I have written this from my head as you did not provide data to test the code against (so please let me know if anything fails in this code). Strictly speaking you do not have to use StructArrays.jl to achieve the goal, but I hope that you will agree that using them gives you a more readable code.
Can I add type information to arguments that are functions?
Consider the following example:
function f{T} (func, x::Int)
output = Dict{Int, Any}()
output[x] = func(x)
return output
end
I don't like that I have to say Any for the value type of the dictionary. I'd much rather do the following:
function f{T} (func::Function{Int->T}, x::Int)
output = Dict{Int, T}()
output[x] = func(x)
return output
end
Can I provide type hints of functions like this? I kind of want to say the following
f :: (Int -> T), Int -> Dict{Int, T}
Not currently. We may add something along those lines in the future, however.
This is not an answer to the main question, but more a really ugly workaround the Any in the Dict issue:
function f(func, x::Int)
T = code_typed(func, (Int,))[1].args[3].typ
output = Dict{Int, T}()
output[x] = func(x)
return output
end
That is probably not efficient and will probably work only on simple cases (which do not even include anonymous functions) like
>>> g(x) = x*2
>>> typeof(f(g, 1234))
Dict{Int64,Int64}
>>> h(x) = x > zero(x) ? x : nothing
>>> typeof(f(h, 1234))
Dict{Int64,Union(Int64,Nothing)}
EDIT:
This works better:
function f(func, x::Int)
[x => func(x)]
end
>>> dump( f(x->2x, 3) )
Dict{Int64,Int64} len 1
3: Int64 6
The following code throws an "UndefVarError: g not defined"
function asdf()
if true
f(t) = t
else
g(t) = t
f(t) = g(t)
end
return f
end
w = asdf()
w(1)
but by replacing f(t) = g(t) by f = g, it works. Why?
This is a known bug https://github.com/JuliaLang/julia/issues/15602.
The short recommendation is not to define a function that goes to method table twice in the body of a function. Instead use a variable to which you assign two different functions (with different names or anonymous) in branches.
What you should do until this is fixed is:
function asdf()
if true
f = t -> t
else false
g(t) = t
f = g(t)
end
return f
end
I use code like this:
p = _belineInterpolateGrid( map( p -> sin(norm(p)), grid ), grid )
f = open("/data/test.function", "w")
serialize( f, p )
close(f)
p0 = deserialize( open("/data/test.function", "r") )
where _belineInterpolateGrid is
function _belineInterpolateGrid(PP, Grid)
...
P = Array(Function, N-1, M-1);
...
poly = (x,y) -> begin
i_x, i_y = i(x, y);
return P[i_x, i_y](x, y);
end
return poly
And now, since some of v0.4, a have an error:
ERROR: MethodError: `convert` has no method matching
convert(::Type{LambdaStaticData}, ::Array{Any,1})
This may have arisen from a call to the constructor LambdaStaticData(...),
since type constructors fall back to convert methods.
Closest candidates are:
call{T}(::Type{T}, ::Any)
convert{T}(::Type{T}, ::T)
...
in deserialize at serialize.jl:435
Why It's happend? Is it bug and how to fix it?
This looks like a bug in Julia to me, and it looks like it has been fixed as of v0.4.6. Try upgrading to that version or newer and see if the problem persists.
You're returning a lambda, that's why. Can't tell if it's a bug (you can serialize a lambda but you can't deserialize it?).
You can avoid this by defining your "get interpolation at x,y" as a type:
import Base: getindex
type MyPoly
thepoly
end
function getindex(p::MyPoly, x::Int, y::Int)
p.thepoly[x+5*y]
end
function getindex(p::MyPoly, I...)
p.thepoly[I...]
end
function call(p::MyPoly, v)
#collect helps keep eltype(ans) == Int
powered_v = map( i->v^i, collect(
take(countfrom(),size(p.thepoly,1))))
powered_v.*p.thepoly
end
p=MyPoly(collect(1:10))
println(p[1])
f = open("serializedpoly", "w")
serialize( f, p)
close(f)
p0 = deserialize( open("serializedpoly", "r"))
println(p[1,1])
v=call(p, 4) #evaluate poly on 4
EDIT: added extension for call
Can I add type information to arguments that are functions?
Consider the following example:
function f{T} (func, x::Int)
output = Dict{Int, Any}()
output[x] = func(x)
return output
end
I don't like that I have to say Any for the value type of the dictionary. I'd much rather do the following:
function f{T} (func::Function{Int->T}, x::Int)
output = Dict{Int, T}()
output[x] = func(x)
return output
end
Can I provide type hints of functions like this? I kind of want to say the following
f :: (Int -> T), Int -> Dict{Int, T}
Not currently. We may add something along those lines in the future, however.
This is not an answer to the main question, but more a really ugly workaround the Any in the Dict issue:
function f(func, x::Int)
T = code_typed(func, (Int,))[1].args[3].typ
output = Dict{Int, T}()
output[x] = func(x)
return output
end
That is probably not efficient and will probably work only on simple cases (which do not even include anonymous functions) like
>>> g(x) = x*2
>>> typeof(f(g, 1234))
Dict{Int64,Int64}
>>> h(x) = x > zero(x) ? x : nothing
>>> typeof(f(h, 1234))
Dict{Int64,Union(Int64,Nothing)}
EDIT:
This works better:
function f(func, x::Int)
[x => func(x)]
end
>>> dump( f(x->2x, 3) )
Dict{Int64,Int64} len 1
3: Int64 6