type Transformation
self :: Function
deriv :: Function
end
import Core.eval
function eval(transformation :: Transformation)
transformation.self
end
function deriv(transformation :: Transformation)
transformation.deriv
end
function sigmoid(x)
1. / (1. + exp(-x)) - 0.5
end
function dsigmoid(x)
exp(-x) / (1. + exp(-x))^2
end
Sigmoid = Transformation(sigmoid, dsigmoid)
Identity = Transformation(identity, one)
Transformation(identity,one)
function calc_norm(array :: Matrix{Float64})
sqrt(sumabs2(array)/size(array, 1))
end
function calc_norm(vector :: Array{Float64, 1})
sqrt(sumabs2(vector))
end
function restriction(vector)
vector / (calc_norm(vector)+0.001)
end
function init(a...)
restriction(randn(a...))
end
const DefaultRate = 0.01
type Class
type_len :: Int64
feature_len :: Int64
feature_matrix :: Matrix{Float64}
feature_transformation :: Transformation
learning_rate :: Float64
end
LClass(type_len, feature_len, learning_rate = DefaultRate) =
Class(type_len, feature_len, init(feature_len, type_len), Identity, learning_rate)
SClass(type_len, feature_len, learning_rate = DefaultRate) =
Class(type_len, feature_len, init(feature_len, type_len), Sigmoid, learning_rate)
Class(type_len, feature_len, feature_transformation = Sigmoid, learning_rate = DefaultRate) =
Class(type_len, feature_len, init(feature_len, type_len), feature_transformation, learning_rate)
type Object
class :: Class
value :: Array{Float64, 1}
end
Object(class :: Class) = Object(class, init(class.type_len))
function feature(obj :: Object)
class = obj.class
eval(class.feature_transformation).(class.feature_matrix * obj.value)
end
type DFunction
in_classes :: Array{Class, 1}
out_class :: Class
f_matrix :: Matrix{Float64}
f_transformation :: Transformation
learning_rate :: Float64
end
function LFunction(in_classes :: Array{Class, 1}, out_class :: Class, learning_rate = DefaultRate)
in_len = sum([class.feature_len for class in in_classes])
out_len = out_class.type_len
DFunction(in_classes, out_class, init(out_len, in_len), Identity, learning_rate)
end
function SFunction(in_classes :: Array{Class, 1}, out_class :: Class, learning_rate = DefaultRate)
in_len = sum([class.feature_len for class in in_classes])
out_len = out_class.type_len
DFunction(in_classes, out_class, init(out_len, in_len), Sigmoid, learning_rate)
end
function DFunction(in_classes :: Array{Class, 1}, out_class :: Class, f_transformation = Sigmoid, learning_rate = DefaultRate)
in_len = sum([class.feature_len for class in in_classes])
out_len = out_class.type_len
DFunction(in_classes, out_class, init(out_len, in_len), f_transformation, learning_rate)
end
function apply(func :: DFunction, objs :: Array{Object, 1})
inputs = vcat(feature.(objs)...)
outputs = eval(func.f_transformation).(func.f_matrix * inputs)
Object(func.out_class, outputs)
end
function apply!(func :: DFunction, in_objs :: Array{Object, 1}, out_obj :: Object)
inputs = vcat(feature.(in_objs)...)
out_obj.value .= eval(func.f_transformation).(func.f_matrix * inputs)
end
apply! (generic function with 1 method)
Sensor = Class(5, 10)
sensor = Object(Sensor)
Action = Class(6, 12)
action = Object(Action)
act = DFunction([Sensor, Sensor, Action], Action)
apply(act, [sensor, sensor, action])
Object(Class(6,12,[-0.0952685 0.123531 … 0.0617522 -0.432929; -0.391715 0.464444 … 0.121159 -0.2601; … ; -0.350052 -0.275652 … -0.0239876 0.488634; 0.367416 0.503514 … 0.0262668 0.457226],Transformation(sigmoid,dsigmoid),0.01),[-0.0138375,0.047348,-0.0206478,0.0537356,-0.000992343,0.0128627])
type Tree
op
value
subtrees :: Array{Tree, 1}
end
function _bottom_up(func :: Function, tree :: Tree, dict :: Dict)
function f()
func(tree, [_bottom_up(func, t, dict) for t in tree.subtrees])
end
get!(f, dict, tree)
end
## bottom_up(func :: Function, tree :: Tree) = _bottom_up(func, tree, Dict())
function bottom_up(func :: Function, tree :: Tree)
func(tree, [bottom_up(func, t) for t in tree.subtrees])
end
bottom_up (generic function with 1 method)
function init_node!(op :: Object, value :: Dict)
## value[:value] = Array{Float64, 1}(op.class.type_len)
value[:pre_feature] = Array{Float64, 1}(op.class.feature_len)
value[:post_feature] = Array{Float64, 1}(op.class.feature_len)
end
function lens_split(x :: Array, lens :: Array{Int64, 1})
ind = cumsum(lens)
n = length(ind)
ind = [0; ind]
[view(x, (ind[i]+1):ind[i+1]) for i in 1:n]
end
function init_node!(op :: DFunction, value :: Dict)
value[:pre_matrix] = Array{Float64, 1}(size(op.f_matrix, 2))
value[:pre_transform] = Array{Float64, 1}(op.out_class.type_len)
value[:value] = Array{Float64, 1}(op.out_class.type_len)
value[:pre_feature] = Array{Float64, 1}(op.out_class.feature_len)
value[:post_feature] = Array{Float64, 1}(op.out_class.feature_len)
value[:inputs] = lens_split(value[:pre_matrix], [c.feature_len for c in op.in_classes])
value[:d] = Array{Float64, 1}(size(op.f_matrix, 2))
value[:ds] = lens_split(value[:d], [c.feature_len for c in op.in_classes])
end
function _init_tree!(tree :: Tree, _)
init_node!(tree.op, tree.value)
tree
end
function init_tree!(tree :: Tree)
bottom_up(_init_tree!, tree)
end
function eval_node!(op :: Object, value :: Dict, value_list)
value[:value] = op.value
A_mul_B!(value[:pre_feature], op.class.feature_matrix, op.value)
value[:post_feature] .= eval(op.class.feature_transformation).(value[:pre_feature])
end
function eval_node!(op :: DFunction, value :: Dict, value_list)
i = 1
for v in value_list
value[:inputs][i] .= v[:post_feature]
i += 1
end
## value[:pre_matrix] .= vcat([v[:post_feature] for v in value_list]...)
A_mul_B!(value[:pre_transform], op.f_matrix, value[:pre_matrix])
value[:value] .= eval(op.f_transformation).(value[:pre_transform])
A_mul_B!(value[:pre_feature], op.out_class.feature_matrix, value[:value])
value[:post_feature] .= eval(op.out_class.feature_transformation).(value[:pre_feature])
end
function _eval_tree!(tree :: Tree, _)
eval_node!(tree.op, tree.value, (t.value for t in tree.subtrees))
tree
end
function eval_tree!(tree :: Tree)
bottom_up(_eval_tree!, tree)
end
eval_tree! (generic function with 1 method)
Sensor = Class(5, 10)
sensor = Object(Sensor)
Action = Class(6, 12)
action = Object(Action)
act = DFunction([Sensor, Action], Action)
tree = Tree(act, Dict(), [Tree(sensor, Dict(), []), Tree(action, Dict(), [])])
init_tree!(tree)
eval_tree!(tree).value[:value] - apply(act, [sensor, action]).value
6-element Array{Float64,1}: 0.0 0.0 0.0 0.0 0.0 0.0
function bp_transformation!(transformation :: Transformation, inputs :: Array{Float64, 1}, d)
for i in 1:length(inputs)
d[i] = deriv(transformation)(inputs[i]) * d[i]
end
## d .= deriv(transformation).(inputs) .* d
end
function bp_matrix!(inputs :: Array{Float64, 1}, matrix :: Matrix{Float64}, d, step)
## step = 0.01
## dmatrix = reshape(d, (length(d), 1)) * reshape(inputs, (1, length(inputs)))
## matrix[:, :] += step * reshape(d, (length(d), 1)) * reshape(inputs, (1, length(inputs)))
for i in 1:size(matrix, 1)
for j in 1:size(matrix, 2)
matrix[i, j] = matrix[i, j] + step * d[i] * inputs[j]
end
end
matrix' * d
end
function bp_class!(class :: Class, value :: Dict, d)
bp_transformation!(class.feature_transformation, value[:pre_feature], d)
bp_matrix!(value[:value], class.feature_matrix, d, class.learning_rate)
end
function bp_function!(op :: DFunction, value :: Dict, d :: Array{Float64, 1})
bp_transformation!(op.f_transformation, value[:pre_transform], d)
bp_matrix!(value[:pre_matrix], op.f_matrix, d, op.learning_rate)
end
function bp_tree!(tree :: Tree, d :: Array{Float64, 1})
if typeof(tree.op) == DFunction
tree.value[:d] .= bp_function!(tree.op, tree.value, d)
## ds = lens_split(d, [c.feature_len for c in tree.op.in_classes])
for i in 1:length(tree.subtrees)
bp_tree!(tree.subtrees[i], bp_class!(tree.op.in_classes[i], tree.subtrees[i].value, tree.value[:ds][i]))
end
## dds = map(bp_class!, tree.op.in_classes, [t.value for t in tree.subtrees], tree.value[:ds])
## foreach(bp_tree!, tree.subtrees, dds)
end
end
bp_tree! (generic function with 1 method)
Sensor = Class(5, 10)
sensor = Object(Sensor)
Action = Class(6, 12)
action = Object(Action)
act = DFunction([Sensor, Action], Action)
tree = Tree(act, Dict(), [Tree(sensor, Dict(), []), Tree(action, Dict(), [])])
init_tree!(tree)
d = ones(6) - eval_tree!(tree).value[:value]
for i in 1:5000
d = ones(6) - eval_tree!(tree).value[:value]
bp_tree!(tree, d)
end
ones(6) - eval_tree!(tree).value[:value]
6-element Array{Float64,1}: 0.520171 0.519918 0.519255 0.519372 0.520931 0.522424
function toTree(op)
Tree(op, Dict(), [])
end
function toTree(skeleton :: Array)
op = skeleton[1]
subs = skeleton[2:end]
Tree(op, Dict(), [toTree(s) for s in subs])
end
function add!(dict :: Dict, dict1 :: Dict)
for key in keys(dict1)
dict[key] = vcat(get!(dict, key, []), dict1[key])
end
dict
end
function _index(tree :: Tree, inds :: Array)
ind = Dict(tree.op => [tree])
for ind1 in inds
add!(ind, ind1)
end
ind
end
index(tree :: Tree) = bottom_up(_index, tree)
type Axiom
tree1 :: Tree
tree2 :: Tree
index :: Dict
end
Axiom(tree1 :: Tree, tree2 :: Tree) = Axiom(tree1, tree2, add!(index(tree1), index(tree2)))
Axiom(skeleton1, skeleton2) = Axiom(toTree(skeleton1), toTree(skeleton2))
function push!(index :: Dict, ops :: Array)
n = length(ops)
for i in 1:n
for t in index[i]
t.op = ops[i]
end
end
end
function push!(index :: Dict, ops :: Dict)
for key in keys(ops)
if haskey(index, key)
ts = index[key]
for t in ts
t.op = ops[key]
end
end
end
end
function push!(axiom :: Axiom, ops)
push!(axiom.index, variables)
end
function train!(axiom :: Axiom, variables)
push!(axiom.index, variables)
init_tree!(axiom.tree1)
init_tree!(axiom.tree2)
d = eval_tree!(axiom.tree2).value[:value] - eval_tree!(axiom.tree1).value[:value]
bp_tree!(axiom.tree1, d)
bp_tree!(axiom.tree2, -d)
end
function train!(axiom :: Axiom, variables :: Array, n :: Int64)
push!(axiom.index, variables)
init_tree!(axiom.tree1)
init_tree!(axiom.tree2)
for i in 1:n
d = eval_tree!(axiom.tree2).value[:value] - eval_tree!(axiom.tree1).value[:value]
bp_tree!(axiom.tree1, d)
bp_tree!(axiom.tree2, -d)
end
end
train! (generic function with 2 methods)
Sensor = Class(5, 10)
sensor = Object(Sensor)
Action = Class(6, 12)
action = Object(Action)
act = DFunction([Sensor], Action)
invact = DFunction([Action], Sensor)
axiom = Axiom([1, [2, 3]], 3)
Axiom(Tree(1,Dict{Any,Any}(),Tree[Tree(2,Dict{Any,Any}(),Tree[Tree(3,Dict{Any,Any}(),Tree[])])]),Tree(3,Dict{Any,Any}(),Tree[]),Dict(2=>Tree[Tree(2,Dict{Any,Any}(),Tree[Tree(3,Dict{Any,Any}(),Tree[])])],3=>Tree[Tree(3,Dict{Any,Any}(),Tree[]),Tree(3,Dict{Any,Any}(),Tree[])],1=>Tree[Tree(1,Dict{Any,Any}(),Tree[Tree(2,Dict{Any,Any}(),Tree[Tree(3,Dict{Any,Any}(),Tree[])])])]))
@time train!(axiom, [invact, act, sensor], 10000)
eval_tree!(axiom.tree2).value[:value] - eval_tree!(axiom.tree1).value[:value]
0.222576 seconds (2.14 M allocations: 42.585 MB, 2.45% gc time)
5-element Array{Float64,1}: -0.00211209 0.0980249 0.0193965 0.00262933 -0.183088
Profile.clear()
@profile train!(axiom, [invact, act, sensor], 1000)
## Profile.print()
Profile.print(format = :flat)
Count File Line Function 23 ./<missing> -1 anonymous 1 ./In[1] 21 dsigmoid(::Float64) 26 ./In[4] 17 bottom_up(::#_eval_tree!, ::Tree) 11 ./In[5] 54 _eval_tree!(::Tree, ::Array{Tree,1}) 1 ./In[5] 36 eval_node!(::Object, ::Dict{Any,Any... 4 ./In[5] 37 eval_node!(::Object, ::Dict{Any,Any... 2 ./In[5] 47 eval_node!(::DFunction, ::Dict{Any,... 1 ./In[5] 48 eval_node!(::DFunction, ::Dict{Any,... 2 ./In[5] 50 eval_node!(::DFunction, ::Dict{Any,... 3 ./In[7] 21 bp_class!(::Class, ::Dict{Any,Any},... 1 ./In[7] 22 bp_class!(::Class, ::Dict{Any,Any},... 2 ./In[7] 26 bp_function!(::DFunction, ::Dict{An... 3 ./In[7] 27 bp_function!(::DFunction, ::Dict{An... 1 ./In[7] 14 bp_matrix!(::Array{Float64,1}, ::Ar... 3 ./In[7] 17 bp_matrix!(::Array{Float64,1}, ::Ar... 5 ./In[7] 3 bp_transformation!(::Transformation... 6 ./In[7] 32 bp_tree!(::Tree, ::Array{Float64,1}) 10 ./In[7] 35 bp_tree!(::Tree, ::Array{Float64,1}) 13 ./In[9] 76 train!(::Axiom, ::Array{Any,1}, ::I... 10 ./In[9] 77 train!(::Axiom, ::Array{Any,1}, ::I... 1 ./abstractarray.jl 159 stride(::Array{Float64,2}, ::Int64) 13 ./array.jl 307 collect(::Base.Generator{Array{Tree... 2 ./array.jl 308 collect(::Base.Generator{Array{Tree... 3 ./linalg/blas.jl 454 gemv!(::Char, ::Float64, ::Array{Fl... 3 ./linalg/matmul.jl 88 A_mul_B!(::Array{Float64,1}, ::Arra... 2 ./linalg/matmul.jl 114 Ac_mul_B 4 ./linalg/matmul.jl 230 gemv!(::Array{Float64,1}, ::Char, :... 24 ./loading.jl 441 include_string(::String, ::String) 23 ./profile.jl 16 macro expansion; 2 ./subarray.jl 169 setindex! 24 ./task.jl 360 (::IJulia.##9#15)() 24 ...IJulia/src/eventloop.jl 8 eventloop(::ZMQ.Socket) 24 .../src/execute_request.jl 169 execute_request(::ZMQ.Socket, ::IJu...
diagm(ones(3))
3×3 Array{Float64,2}: 1.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 1.0