Model Templates

We mentioned that we could factor out the repetition of defining affine layers with something like:

function create_affine(in, out)
  W = param(randn(out,in))
  b = param(randn(out))
  @net x -> W * x + b
end

@net type syntax provides a shortcut for this:

@net type MyAffine
  W
  b
  x -> x * W + b
end

# Convenience constructor
MyAffine(in::Integer, out::Integer) =
  MyAffine(randn(out, in), randn(out))

model = Chain(MyAffine(5, 5), MyAffine(5, 5))

model(x1) # [-1.54458,0.492025,0.88687,1.93834,-4.70062]

This is almost exactly how Affine is defined in Flux itself. Using @net type gives us some extra conveniences:

Models in templates

@net models can contain sub-models as well as just array parameters:

@net type TLP
  first
  second
  function (x)
    l1 = σ(first(x))
    l2 = softmax(second(l1))
  end
end

Clearly, the first and second parameters are not arrays here, but should be models themselves, and produce a result when called with an input array x . The Affine layer fits the bill, so we can instantiate TLP with two of them:

model = TLP(Affine(10, 20),
            Affine(20, 15))
x1 = rand(20)
model(x1) # [0.057852,0.0409741,0.0609625,0.0575354 ...

You may recognise this as being equivalent to

Chain(
  Affine(10, 20), σ
  Affine(20, 15), softmax)

Supported syntax

The syntax used to define a forward pass like x -> x*W + b behaves exactly like Julia code for the most part. However, it's important to remember that it's defining a dataflow graph, not a general Julia expression. In practice this means that anything side-effectful, or things like control flow and println s, won't work as expected. In future we'll continue to expand support for Julia syntax and features.