Model nodes
Index
Mill.AbstractMillModelMill.ArrayModelMill.BagModelMill.BagModelMill.LazyModelMill.LazyModelMill.ProductModelMill.ProductModelMill.modelsummaryMill.reflectinmodel
API
Mill.AbstractMillModel — TypeAbstractMillModelSupertype for any model defined in Mill.jl.
Mill.ArrayModel — TypeArrayModel{T} <: AbstractMillModelA model node for processing ArrayNodes. 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 bytesjulia> 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}
    <: AbstractMillModelA model node for processing AbstractBagNodes. 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))
trueSee 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 bytesSee also: AbstractMillModel, AbstractAggregation, BagCount,     AbstractBagNode, BagNode, WeightedBagNode.
Mill.ProductModel — TypeProductModel{T <: Mill.VecOrTupOrNTup{<:AbstractMillModel}, U} <: AbstractMillModelA model node for processing ProductNodes. 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 bytesjulia> 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  7See 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 AbstractMillModels.
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} <: AbstractMillModelA model node for processing LazyNodes. 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)))
endjulia> 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 KiBjulia> 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 bytesSee 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 Dicts 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,SparseMatrixCSCorSparseVector,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 bytesSee 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.