Model nodes
Index
Mill.AbstractMillModel
Mill.ArrayModel
Mill.BagModel
Mill.BagModel
Mill.LazyModel
Mill.LazyModel
Mill.ProductModel
Mill.ProductModel
Mill.modelsummary
Mill.reflectinmodel
API
Mill.AbstractMillModel
— TypeAbstractMillModel
Supertype for any model defined in Mill.jl
.
Mill.ArrayModel
— TypeArrayModel{T} <: AbstractMillModel
A model node for processing ArrayNode
s. It applies a (sub)model m
stored in it to data in an ArrayNode
.
Examples
julia> Random.seed!(0);
julia> n = ArrayNode(randn(Float32, 2, 2))
2×2 ArrayNode{Matrix{Float32}, Nothing}:
0.94... 1.53...
0.13... 0.12...
julia> m = ArrayModel(Dense(2, 2))
ArrayModel(Dense(2 => 2)) 2 arrays, 6 params, 112 bytes
julia> m(n)
2×2 Matrix{Float32}:
-0.50... -0.77...
0.25... 0.49...
See also: AbstractMillModel
, ArrayNode
.
Mill.BagModel
— TypeBagModel{T <: AbstractMillModel, A <: Union{AbstractAggregation, BagCount}, U}
<: AbstractMillModel
A model node for processing AbstractBagNode
s. It first applies its "instance (sub)model" im
on every instance, then performs elementwise segmented aggregation a
and finally applies the final model bm
on the aggregated representation of every bag in the data node.
Examples
julia> Random.seed!(0);
julia> n = BagNode(ArrayNode(randn(Float32, 3, 2)), bags([0:-1, 1:2]))
BagNode 2 obs
╰── ArrayNode(3×2 Array with Float32 elements) 2 obs
julia> m = BagModel(ArrayModel(Dense(3, 2)), SegmentedMeanMax(2), Dense(4, 2))
BagModel ↦ [SegmentedMean(2); SegmentedMax(2)] ↦ Dense(4 => 2) 4 arrays, 14 params, 224 bytes
╰── ArrayModel(Dense(3 => 2)) 2 arrays, 8 params, 120 bytes
julia> m(n)
2×2 Matrix{Float32}:
0.0 1.05...
0.0 0.49...
julia> m(n) == m.bm(m.a(m.im(n.data), n.bags))
true
See also: AbstractMillModel
, AbstractAggregation
, AbstractBagNode
, BagNode
, WeightedBagNode
.
Mill.BagModel
— MethodBagModel(im, a, bm=identity)
Construct a BagModel
from the arguments. im
should be AbstractMillModel
, a
AbstractAggregation
or BagCount
, and bm
ArrayModel
.
It is also possible to pass any function as im
instead of a model node. In that case, it is wrapped into an ArrayNode
.
Examples
julia> m = BagModel(ArrayModel(Dense(3, 2)), SegmentedMeanMax(2), Dense(4, 2))
BagModel ↦ [SegmentedMean(2); SegmentedMax(2)] ↦ Dense(4 => 2) 4 arrays, 14 params, 224 bytes
╰── ArrayModel(Dense(3 => 2)) 2 arrays, 8 params, 120 bytes
julia> m = BagModel(Dense(4, 3), BagCount(SegmentedMean(3)))
BagModel ↦ BagCount(SegmentedMean(3)) ↦ identity 1 arrays, 3 params (all zero), 52 bytes
╰── ArrayModel(Dense(4 => 3)) 2 arrays, 15 params, 148 bytes
See also: AbstractMillModel
, AbstractAggregation
, BagCount
, AbstractBagNode
, BagNode
, WeightedBagNode
.
Mill.ProductModel
— TypeProductModel{T <: Mill.VecOrTupOrNTup{<:AbstractMillModel}, U} <: AbstractMillModel
A model node for processing ProductNode
s. For each subtree of the data node it applies one (sub)model from ms
and then applies m
on the concatenation of results.
Examples
julia> Random.seed!(0);
julia> n = ProductNode(a=ArrayNode([0 1; 2 3]), b=ArrayNode([4 5; 6 7]))
ProductNode 2 obs
├── a: ArrayNode(2×2 Array with Int64 elements) 2 obs
╰── b: ArrayNode(2×2 Array with Int64 elements) 2 obs
julia> m1 = ProductModel(a=ArrayModel(Dense(2, 2)), b=ArrayModel(Dense(2, 2)))
ProductModel ↦ identity
├── a: ArrayModel(Dense(2 => 2)) 2 arrays, 6 params, 112 bytes
╰── b: ArrayModel(Dense(2 => 2)) 2 arrays, 6 params, 112 bytes
julia> m1(n)
4×2 Matrix{Float32}:
-2.36... -3.58...
-2.11... -3.40...
-6.31... -7.61...
-2.54... -2.66...
julia> m2 = ProductModel(a=identity, b=identity)
ProductModel ↦ identity
├── a: ArrayModel(identity)
╰── b: ArrayModel(identity)
julia> m2(n)
4×2 Matrix{Int64}:
0 1
2 3
4 5
6 7
See also: AbstractMillModel
, AbstractProductNode
, ProductNode
.
Mill.ProductModel
— MethodProductModel(ms, m=identity)
ProductModel(m=identity; ms...)
Construct a ProductModel
from the arguments. ms
should an iterable (Tuple
, NamedTuple
or Vector
) of one or more AbstractMillModel
s.
It is also possible to pass any function as elements of ms
. In that case, it is wrapped into an ArrayNode
.
Examples
julia> ProductModel(a=ArrayModel(Dense(2, 2)), b=identity)
ProductModel ↦ identity
├── a: ArrayModel(Dense(2 => 2)) 2 arrays, 6 params, 112 bytes
╰── b: ArrayModel(identity)
julia> ProductModel(Dense(4, 2); a=ArrayModel(Dense(2, 2)), b=Dense(2, 2))
ProductModel ↦ Dense(4 => 2) 2 arrays, 10 params, 128 bytes
├── a: ArrayModel(Dense(2 => 2)) 2 arrays, 6 params, 112 bytes
╰── b: ArrayModel(Dense(2 => 2)) 2 arrays, 6 params, 112 bytes
julia> ProductModel((identity, BagModel(ArrayModel(Dense(2, 2)), SegmentedMean(2), identity)))
ProductModel ↦ identity
├── ArrayModel(identity)
╰── BagModel ↦ SegmentedMean(2) ↦ identity 1 arrays, 2 params (all zero), 48 bytes
╰── ArrayModel(Dense(2 => 2)) 2 arrays, 6 params, 112 bytes
julia> ProductModel(identity)
ProductModel ↦ identity
╰── ArrayModel(identity)
See also: AbstractMillModel
, AbstractProductNode
, ProductNode
.
Mill.LazyModel
— TypeLazyModel{Name, T} <: AbstractMillModel
A model node for processing LazyNode
s. It applies a (sub)model m
stored in it to data of the LazyNode
after calling Mill.unpack2mill
.
Examples
julia> function Mill.unpack2mill(ds::LazyNode{:Sentence})
s = split.(ds.data, " ")
x = NGramMatrix(reduce(vcat, s))
BagNode(x, Mill.length2bags(length.(s)))
end
julia> Random.seed!(0);
julia> n = LazyNode{:Sentence}(["foo", "bar", "baz"])
LazyNode{:Sentence, Vector{String}, Nothing}:
"foo"
"bar"
"baz"
julia> m = LazyModel{:Sentence}(BagModel(Dense(2053, 3), SegmentedMean(3), identity))
LazyModel{Sentence}
╰── BagModel ↦ SegmentedMean(3) ↦ identity 1 arrays, 3 params (all zero), 52 bytes
╰── ArrayModel(Dense(2053 => 3)) 2 arrays, 6_162 params, 24.156 KiB
julia> m(n)
3×3 Matrix{Float32}:
-0.06... -0.03... -0.04...
0.02... 0.00... -0.07...
-0.00... 0.06... -0.07...
See also: AbstractMillModel
, LazyNode
, Mill.unpack2mill
.
Mill.LazyModel
— MethodLazyModel([Name::Symbol], m::AbstractMillModel)
LazyModel{Name}(m::AbstractMillModel)
Construct a new LazyModel
with name Name
, and model m
.
It is also possible to pass any function as m
instead of a model node. In that case, it is wrapped into an ArrayNode
.
Examples
julia> LazyModel{:Sentence}(ArrayModel(Dense(2, 2)))
LazyModel{Sentence}
╰── ArrayModel(Dense(2 => 2)) 2 arrays, 6 params, 112 bytes
julia> LazyModel(:Sentence, Dense(2, 2))
LazyModel{Sentence}
╰── ArrayModel(Dense(2 => 2)) 2 arrays, 6 params, 112 bytes
See also: AbstractMillModel
, LazyNode
, Mill.unpack2mill
.
Mill.reflectinmodel
— Functionreflectinmodel(x::AbstractMillNode, fm=d -> Dense(d, 10), fa=BagCount ∘ SegmentedMeanMax;
fsm=Dict(), fsa=Dict(), single_key_identity=true, single_scalar_identity=true, all_imputing=false)
Build a Mill.jl
model capable of processing x
.
All inner Dense
layers are constructed using fm
, a function accepting input dimension d
and returning a suitable model. All aggregation operators are constructed using fa
in a similar manner.
More fine-grained control can be achieved with fsm
and fsa
keyword arguments, which should be Dict
s of c => f
pairs, where c
is a String
traversal code from HierarchicalUtils.jl
and f
is a function. These definitions override fm
and fa
.
If a ProductNode
with only a single child (subtree) is encountered, its final m
model is instantiated as identity
instead of using fm
and fsm
. This can be controlled with single_key_identity
.
Similarly, if an ArrayNode
contains data X
where size(X, 1)
is 1
, the corresponding model is instantiated as identity
unless single_scalar_identity
is false
.
By default, reflectinmodel
makes first Dense
layers in leafs imputing only if the datatype suggests that missing data is present. This applies to
Array
,SparseMatrixCSC
orSparseVector
,PooledArray
,MaybeHotVector
,MaybeHotMatrix
, andNGramMatrix
types with eltype
of {Union{Missing, T}} where T
. If all_imputing
is true, all leaf Dense
layers in these types are replaced by their imputing variants.
Examples
julia> n1 = ProductNode(a=ArrayNode(NGramMatrix(["a", missing])))
ProductNode 2 obs
╰── a: ArrayNode(2053×2 NGramMatrix with Union{Missing, Int64} elements) 2 obs
julia> n2 = ProductNode((ArrayNode([0 1]), BagNode(ArrayNode([0 1; 2 3]), bags([1:1, 2:2]))))
ProductNode 2 obs
├── ArrayNode(1×2 Array with Int64 elements) 2 obs
╰── BagNode 2 obs
╰── ArrayNode(2×2 Array with Int64 elements) 2 obs
julia> n = ProductNode((n1, n2))
ProductNode 2 obs
├── ProductNode 2 obs
│ ╰── a: ArrayNode(2053×2 NGramMatrix with Union{Missing, Int64} elements) 2 obs
╰── ProductNode 2 obs
├── ArrayNode(1×2 Array with Int64 elements) 2 obs
╰── BagNode 2 obs
╰── ArrayNode(2×2 Array with Int64 elements) 2 obs
julia> reflectinmodel(n)
ProductModel ↦ Dense(20 => 10) 2 arrays, 210 params, 928 bytes
├── ProductModel ↦ identity
│ ╰── a: ArrayModel([postimputing]Dense(2053 => 10)) 3 arrays, 20_550 params, 80.398 KiB
╰── ProductModel ↦ Dense(11 => 10) 2 arrays, 120 params, 568 bytes
├── ArrayModel(identity)
╰── BagModel ↦ BagCount([SegmentedMean(10); SegmentedMax(10)]) ↦ Dense(21 => 10) 4 arrays, 240 params, 1.102 KiB
╰── ArrayModel(Dense(2 => 10)) 2 arrays, 30 params, 208 bytes
julia> reflectinmodel(n, d -> Dense(d, 3), SegmentedMean, all_imputing=true)
ProductModel ↦ Dense(6 => 3) 2 arrays, 21 params, 172 bytes
├── ProductModel ↦ identity
│ ╰── a: ArrayModel([postimputing]Dense(2053 => 3)) 3 arrays, 6_165 params, 24.207 KiB
╰── ProductModel ↦ Dense(4 => 3) 2 arrays, 15 params, 148 bytes
├── ArrayModel([preimputing]Dense(1 => 1)) 3 arrays, 3 params, 140 bytes
╰── BagModel ↦ SegmentedMean(3) ↦ Dense(3 => 3) 3 arrays, 15 params, 188 bytes
╰── ArrayModel([preimputing]Dense(2 => 3)) 3 arrays, 11 params, 172 bytes
julia> printtree(n; trav=true)
ProductNode [""] 2 obs
├── ProductNode ["E"] 2 obs
│ ╰── a: ArrayNode(2053×2 NGramMatrix with Union{Missing, Int64} elements) ["M"] 2 obs
╰── ProductNode ["U"] 2 obs
├── ArrayNode(1×2 Array with Int64 elements) ["Y"] 2 obs
╰── BagNode ["c"] 2 obs
╰── ArrayNode(2×2 Array with Int64 elements) ["e"] 2 obs
julia> reflectinmodel(n, d -> Dense(d, 3), SegmentedMean;
fsm=Dict("e" => d -> Chain(Dense(d, 2), Dense(2, 2))),
fsa=Dict("c" => SegmentedLSE),
single_key_identity=false,
single_scalar_identity=false)
ProductModel ↦ Dense(6 => 3) 2 arrays, 21 params, 172 bytes
├── ProductModel ↦ Dense(3 => 3) 2 arrays, 12 params, 136 bytes
│ ╰── a: ArrayModel([postimputing]Dense(2053 => 3)) 3 arrays, 6_165 params, 24.207 KiB
╰── ProductModel ↦ Dense(6 => 3) 2 arrays, 21 params, 172 bytes
├── ArrayModel(Dense(1 => 3)) 2 arrays, 6 params, 112 bytes
╰── BagModel ↦ SegmentedLSE(2) ↦ Dense(2 => 3) 4 arrays, 13 params, 220 bytes
╰── ArrayModel(Chain(Dense(2 => 2), Dense(2 => 2))) 4 arrays, 12 params, 224 bytes
See also: AbstractMillNode
, AbstractMillModel
, ProductNode
, BagNode
, ArrayNode
.
Mill.modelsummary
— Functionmodelsummary(m::AbstractMillModel)
Print summary of parameters of model m
.
Examples
julia> m = ProductModel(ArrayModel(Dense(2, 3)))
ProductModel ↦ identity
╰── ArrayModel(Dense(2 => 3)) 2 arrays, 9 params, 124 bytes
julia> modelsummary(m)
"Model summary: 2 arrays, 9 params, 124 bytes"
See also: datasummary
.