|
1 | 1 | # Shape Inference
|
2 | 2 |
|
3 |
| -To help you generate models in an automated fashion, [`Flux.outputsize`](@ref) lets you |
4 |
| -calculate the size returned produced by layers for a given size input. |
5 |
| -This is especially useful for layers like [`Conv`](@ref). |
| 3 | +Flux has some tools to help generate models in an automated fashion, by inferring the size |
| 4 | +of arrays that layers will recieve, without doing any computation. |
| 5 | +This is especially useful for convolutional models, where the same [`Conv`](@ref) layer |
| 6 | +accepts any size of image, but the next layer may not. |
6 | 7 |
|
7 |
| -It works by passing a "dummy" array into the model that preserves size information without running any computation. |
8 |
| -`outputsize(f, inputsize)` works for all layers (including custom layers) out of the box. |
9 |
| -By default, `inputsize` expects the batch dimension, |
10 |
| -but you can exclude the batch size with `outputsize(f, inputsize; padbatch=true)` (assuming it to be one). |
| 8 | +The higher-level one is a macro [`@autosize`](@ref) which acts on the code defining the layers, |
| 9 | +and replaces each appearance of `_` with the relevant size. A simple example might be: |
11 | 10 |
|
12 |
| -Using this utility function lets you automate model building for various inputs like so: |
13 | 11 | ```julia
|
14 |
| -""" |
15 |
| - make_model(width, height, inchannels, nclasses; |
16 |
| - layer_config = [16, 16, 32, 32, 64, 64]) |
| 12 | +@autosize (28, 28, 1, 32) Chain(Conv((3, 3), _ => 5, relu, stride=2), Flux.flatten, Dense(_ => 10)) |
| 13 | +``` |
| 14 | + |
| 15 | +The size may be provided at runtime, like `@autosize (sz..., 1, 32) Chain(Conv(`..., but the |
| 16 | +layer constructors must be explicitly written out -- the macro sees the code as written. |
| 17 | + |
| 18 | +This relies on a lower-level function [`outputsize`](@ref Flux.outputsize), which you can also use directly: |
| 19 | + |
| 20 | +```julia |
| 21 | +c = Conv((3, 3), 1 => 5, relu, stride=2) |
| 22 | +Flux.outputsize(c, (28, 28, 1, 32)) # returns (13, 13, 5, 32) |
| 23 | +``` |
| 24 | + |
| 25 | +The function `outputsize` works by passing a "dummy" array into the model, which propagates through very cheaply. |
| 26 | +It should work for all layers, including custom layers, out of the box. |
17 | 27 |
|
18 |
| -Create a CNN for a given set of configuration parameters. |
| 28 | +An example of how to automate model building is this: |
| 29 | +```julia |
| 30 | +""" |
| 31 | + make_model(width, height, [inchannels, nclasses; layer_config]) |
19 | 32 |
|
20 |
| -# Arguments |
21 |
| -- `width`: the input image width |
22 |
| -- `height`: the input image height |
23 |
| -- `inchannels`: the number of channels in the input image |
24 |
| -- `nclasses`: the number of output classes |
25 |
| -- `layer_config`: a vector of the number of filters per each conv layer |
| 33 | +Create a CNN for a given set of configuration parameters. Arguments: |
| 34 | +- `width`, `height`: the input image size in pixels |
| 35 | +- `inchannels`: the number of channels in the input image, default `1` |
| 36 | +- `nclasses`: the number of output classes, default `10` |
| 37 | +- Keyword `layer_config`: a vector of the number of filters per layer, default `[16, 16, 32, 64]` |
26 | 38 | """
|
27 |
| -function make_model(width, height, inchannels, nclasses; |
28 |
| - layer_config = [16, 16, 32, 32, 64, 64]) |
29 |
| - # construct a vector of conv layers programmatically |
30 |
| - conv_layers = [Conv((3, 3), inchannels => layer_config[1])] |
31 |
| - for (infilters, outfilters) in zip(layer_config, layer_config[2:end]) |
32 |
| - push!(conv_layers, Conv((3, 3), infilters => outfilters)) |
| 39 | +function make_model(width, height, inchannels = 1, nclasses = 10; |
| 40 | + layer_config = [16, 16, 32, 64]) |
| 41 | + # construct a vector of conv layers: |
| 42 | + conv_layers = Any[Conv((5, 5), inchannels => layer_config[1], relu, pad=SamePad())] |
| 43 | + for (inch, outch) in zip(layer_config, layer_config[2:end]) |
| 44 | + push!(conv_layers, Conv((3, 3), inch => outch, sigmoid, stride=2)) |
33 | 45 | end
|
34 | 46 |
|
35 |
| - # compute the output dimensions for the conv layers |
36 |
| - # use padbatch=true to set the batch dimension to 1 |
37 |
| - conv_outsize = Flux.outputsize(conv_layers, (width, height, nchannels); padbatch=true) |
| 47 | + # compute the output dimensions after these conv layers: |
| 48 | + conv_outsize = Flux.outputsize(conv_layers, (width, height, inchannels); padbatch=true) |
38 | 49 |
|
39 |
| - # the input dimension to Dense is programatically calculated from |
40 |
| - # width, height, and nchannels |
41 |
| - return Chain(conv_layers..., Dense(prod(conv_outsize) => nclasses)) |
| 50 | + # use this to define appropriate Dense layer: |
| 51 | + last_layer = Dense(prod(conv_outsize) => nclasses) |
| 52 | + return Chain(conv_layers..., last_layer) |
42 | 53 | end
|
| 54 | + |
| 55 | +make_model(28, 28, 3, layer_config = [8, 17, 33, 65]) |
43 | 56 | ```
|
44 | 57 |
|
| 58 | +### Listing |
| 59 | + |
45 | 60 | ```@docs
|
| 61 | +Flux.@autosize |
46 | 62 | Flux.outputsize
|
47 | 63 | ```
|
0 commit comments