Вывод формы
Flux содержит инструменты, которые помогают автоматически генерировать модели, определяя размер массивов, которые будут получать слои, без выполнения каких-либо вычислений. Это особенно полезно для сверточных моделей, где один и тот же слой Conv
принимает любой размер изображения, но следующий слой может этого не делать.
Инструментом более высокого уровня является макрос @autosize
, который работает с кодом, определяющим слои, и заменяет каждое вхождение _
соответствующим размером. В этом простом примере возвращается модель с Dense(845 => 10)
в качестве последнего слоя:
@autosize (28, 28, 1, 32) Chain(Conv((3, 3), _ => 5, relu, stride=2), Flux.flatten, Dense(_ => 10))
julia
Входной размер может быть указан во время выполнения, например @autosize (sz..., 1, 32) Chain(Conv(
…, но все конструкторы слоя, содержащие _
, должны быть четко прописаны — макрос видит код в том виде, в котором он написан.
Этот макрос применяет функцию более низкого уровня outputsize
, которую также можно использовать напрямую:
c = Conv((3, 3), 1 => 5, relu, stride=2)
Flux.outputsize(c, (28, 28, 1, 32)) # возвращает (13, 13, 5, 32)
julia
Функция outputsize
работает, передавая модели фиктивный массив, распространение которого требует минимальных ресурсов. Она должна работать для всех слоев, включая пользовательские, без дополнительной подготовки.
Ниже приведен пример автоматизации построения модели.
"""
make_model(width, height, [inchannels, nclasses; layer_config])
Create a CNN for a given set of configuration parameters. Arguments:
- `width`, `height`: the input image size in pixels
- `inchannels`: the number of channels in the input image, default `1`
- `nclasses`: the number of output classes, default `10`
- Keyword `layer_config`: a vector of the number of channels per layer, default `[16, 16, 32, 64]`
"""
function make_model(width, height, inchannels = 1, nclasses = 10;
layer_config = [16, 16, 32, 64])
# создание вектора слоев:
conv_layers = []
push!(conv_layers, Conv((5, 5), inchannels => layer_config[1], relu, pad=SamePad()))
for (inch, outch) in zip(layer_config, layer_config[2:end])
push!(conv_layers, Conv((3, 3), inch => outch, sigmoid, stride=2))
end
# вычисление выходных размеров после этих слоев свертки:
conv_outsize = Flux.outputsize(conv_layers, (width, height, inchannels); padbatch=true)
# используйте для определения соответствующего слоя Dense
last_layer = Dense(prod(conv_outsize) => nclasses)
return Chain(conv_layers..., Flux.flatten, last_layer)
end
m = make_model(28, 28, 3, layer_config = [9, 17, 33, 65])
Flux.outputsize(m, (28, 28, 3, 42)) == (10, 42) == size(m(randn(Float32, 28, 28, 3, 42)))
# вывод
true
julia
Или же при использовании макроса определение make_model
может заканчиваться следующим:
# вычисление выходных измерений и построение соответствующего слоя Dense: return @autosize (width, height, inchannels, 1) Chain(conv_layers..., Flux.flatten, Dense(_ => nclasses)) end