Model nodes

Index

API

Mill.ArrayModelType
ArrayModel{T} <: AbstractMillModel

A 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, 104 bytes
julia> m(n)
2×2 Matrix{Float32}:
 -0.50... -0.77...
  0.25...  0.49...

See also: AbstractMillModel, ArrayNode.

source
Mill.BagModelType
BagModel{T <: AbstractMillModel, A <: Union{AbstractAggregation, BagCount}, U}
    <: AbstractMillModel

A 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, 96 bytes
  ╰── ArrayNode(3×2 Array with Float32 elements)  # 2 obs, 72 bytes

julia> m = BagModel(ArrayModel(Dense(3, 2)), SegmentedMeanMax(2), Dense(4, 2))
BagModel ↦ [SegmentedMean(2); SegmentedMax(2)] ↦ Dense(4 => 2)  # 4 arrays, 14 params, 216 bytes
  ╰── ArrayModel(Dense(3 => 2))  # 2 arrays, 8 params, 112 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.

source
Mill.BagModelMethod
BagModel(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, 216 bytes
  ╰── ArrayModel(Dense(3 => 2))  # 2 arrays, 8 params, 112 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, 140 bytes

See also: AbstractMillModel, AbstractAggregation, BagCount, AbstractBagNode, BagNode, WeightedBagNode.

source
Mill.ProductModelType
ProductModel{T <: Mill.VecOrTupOrNTup{<:AbstractMillModel}, U} <: AbstractMillModel

A 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, 16 bytes
  ├── a: ArrayNode(2×2 Array with Int64 elements)  # 2 obs, 80 bytes
  ╰── b: ArrayNode(2×2 Array with Int64 elements)  # 2 obs, 80 bytes

julia> m1 = ProductModel(a=ArrayModel(Dense(2, 2)), b=ArrayModel(Dense(2, 2)))
ProductModel ↦ identity
  ├── a: ArrayModel(Dense(2 => 2))  # 2 arrays, 6 params, 104 bytes
  ╰── b: ArrayModel(Dense(2 => 2))  # 2 arrays, 6 params, 104 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.

source
Mill.ProductModelMethod
ProductModel(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, 104 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, 120 bytes
  ├── a: ArrayModel(Dense(2 => 2))  # 2 arrays, 6 params, 104 bytes
  ╰── b: ArrayModel(Dense(2 => 2))  # 2 arrays, 6 params, 104 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, 104 bytes

julia> ProductModel(identity)
ProductModel ↦ identity
  ╰── ArrayModel(identity)

See also: AbstractMillModel, AbstractProductNode, ProductNode.

source
Mill.LazyModelType
LazyModel{Name, T} <: AbstractMillModel

A 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)))
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.148 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.

source
Mill.LazyModelMethod
LazyModel([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, 104 bytes

julia> LazyModel(:Sentence, Dense(2, 2))
LazyModel{Sentence}
  ╰── ArrayModel(Dense(2 => 2))  # 2 arrays, 6 params, 104 bytes

See also: AbstractMillModel, LazyNode, Mill.unpack2mill.

source
Mill.reflectinmodelFunction
reflectinmodel(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

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, 32 bytes
  ╰── a: ArrayNode(2053×2 NGramMatrix with Union{Missing, Int64} elements)  # 2 obs, 129 bytes

julia> n2 = ProductNode((ArrayNode([0 1]), BagNode(ArrayNode([0 1; 2 3]), bags([1:1, 2:2]))))
ProductNode  # 2 obs, 24 bytes
  ├── ArrayNode(1×2 Array with Int64 elements)  # 2 obs, 64 bytes
  ╰── BagNode  # 2 obs, 96 bytes
        ╰── ArrayNode(2×2 Array with Int64 elements)  # 2 obs, 80 bytes

julia> n = ProductNode((n1, n2))
ProductNode  # 2 obs, 56 bytes
  ├── ProductNode  # 2 obs, 32 bytes
  │     ╰── a: ArrayNode(2053×2 NGramMatrix with Union{Missing, Int64} elements)  # 2 obs, 129 bytes
  ╰── ProductNode  # 2 obs, 24 bytes
        ├── ArrayNode(1×2 Array with Int64 elements)  # 2 obs, 64 bytes
        ╰── BagNode  # 2 obs, 96 bytes
              ╰── ArrayNode(2×2 Array with Int64 elements)  # 2 obs, 80 bytes

julia> reflectinmodel(n)
ProductModel ↦ Dense(20 => 10)  # 2 arrays, 210 params, 920 bytes
  ├── ProductModel ↦ identity
  │     ╰── a: ArrayModel([postimputing]Dense(2053 => 10))  # 3 arrays, 20_550 params, 80.391 KiB
  ╰── ProductModel ↦ Dense(11 => 10)  # 2 arrays, 120 params, 560 bytes
        ├── ArrayModel(identity)
        ╰── BagModel ↦ BagCount([SegmentedMean(10); SegmentedMax(10)]) ↦ Dense(21 => 10)  # 4 arrays, 240 params, 1.094 KiB
              ╰── ArrayModel(Dense(2 => 10))  # 2 arrays, 30 params, 200 bytes

julia> reflectinmodel(n, d -> Dense(d, 3), SegmentedMean, all_imputing=true)
ProductModel ↦ Dense(6 => 3)  # 2 arrays, 21 params, 164 bytes
  ├── ProductModel ↦ identity
  │     ╰── a: ArrayModel([postimputing]Dense(2053 => 3))  # 3 arrays, 6_165 params, 24.199 KiB
  ╰── ProductModel ↦ Dense(4 => 3)  # 2 arrays, 15 params, 140 bytes
        ├── ArrayModel([preimputing]Dense(1 => 1))  # 3 arrays, 3 params, 132 bytes
        ╰── BagModel ↦ SegmentedMean(3) ↦ Dense(3 => 3)  # 3 arrays, 15 params, 180 bytes
              ╰── ArrayModel([preimputing]Dense(2 => 3))  # 3 arrays, 11 params, 164 bytes

julia> printtree(n; trav=true)
ProductNode [""]  # 2 obs, 56 bytes
  ├── ProductNode ["E"]  # 2 obs, 32 bytes
  │     ╰── a: ArrayNode(2053×2 NGramMatrix with Union{Missing, Int64} elements) ["M"]  # 2 obs, 129 bytes
  ╰── ProductNode ["U"]  # 2 obs, 24 bytes
        ├── ArrayNode(1×2 Array with Int64 elements) ["Y"]  # 2 obs, 64 bytes
        ╰── BagNode ["c"]  # 2 obs, 96 bytes
              ╰── ArrayNode(2×2 Array with Int64 elements) ["e"]  # 2 obs, 80 bytes

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, 164 bytes
  ├── ProductModel ↦ Dense(3 => 3)  # 2 arrays, 12 params, 128 bytes
  │     ╰── a: ArrayModel([postimputing]Dense(2053 => 3))  # 3 arrays, 6_165 params, 24.199 KiB
  ╰── ProductModel ↦ Dense(6 => 3)  # 2 arrays, 21 params, 164 bytes
        ├── ArrayModel(Dense(1 => 3))  # 2 arrays, 6 params, 104 bytes
        ╰── BagModel ↦ SegmentedLSE(2) ↦ Dense(2 => 3)  # 4 arrays, 13 params, 212 bytes
              ╰── ArrayModel(Chain(Dense(2 => 2), Dense(2 => 2)))  # 4 arrays, 12 params, 208 bytes

See also: AbstractMillNode, AbstractMillModel, ProductNode, BagNode, ArrayNode.

source
Mill.modelsummaryFunction
modelsummary(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, 116 bytes

julia> modelsummary(m)
"Model summary: 2 arrays, 9 params, 116 bytes"

See also: datasummary.

source