Встроенные типы слоев
Если вы начали изучать это руководство с самого начала, то вам уже встречался базовый слой Dense
и вы уже видели, как объединять слои с помощью Chain
. Эти базовые слои служат основой почти для всех нейронных сетей.
На примере слоя Dense
хорошо виден ряд особенностей.
-
Он содержит функцию активации, которая транслируется через выход. Поскольку данная трансляция может совмещаться с другими операциями, такой подход более эффективен по сравнению с отдельным применением функции активации.
-
Он имеет именованный аргумент
init
, который принимает функцию, действующую какrand
. То есть вызовinit(2,3,4)
должен создавать массив соответствующего размера. Во Flux есть множество таких встроенных функций. Все они создают массив в памяти ЦП, который затем при желании можно перенести с помощью функцииgpu
. -
Вектор смещений всегда инициализируется с помощью
Flux.zeros32
. Именованный аргументbias=false
отключает это поведение, то есть смещения всегда будут оставаться равными нулю. -
Он аннотируется с помощью
@functor
, то есть функцииparams
будет доступно содержимое, а функцияgpu
будет перемещать массивы в память GPU.
В свою очередь, объект Chain
сам по себе не содержит параметров, но связывает другие слои. В разделе о слоях потока данных представлены другие слои наподобие этого.
Полносвязные слои
#
Flux.Dense
— Type
Dense(in => out, σ=identity; bias=true, init=glorot_uniform)
Dense(W::AbstractMatrix, [bias, σ])
Создает традиционный полносвязный слой, прямой проход которого задается следующим образом:
y = σ.(W * x .+ bias)
Входной параметр x
должен представлять собой вектор длиной in
или пакет векторов, представленный в виде матрицы in × N
либо массива с size(x,1) == in
. Результат y
будет вектором длиной out
или пакетом с size(y) == (out, size(x)[2:end]...)
Именованный аргумент bias=false
отключает обучаемое смещение для слоя. Весовая матрица инициализируется следующим образом: W = init(out, in)
. При этом вызывается функция, переданная в именованном аргументе init
. По умолчанию это функция glorot_uniform
. Весовую матрицу и (или) вектор смещений (длиной out
) также можно предоставить явным образом.
Примеры
julia> d = Dense(5 => 2)
Dense(5 => 2) # 12 параметров
julia> d(rand32(5, 64)) |> size
(2, 64)
julia> d(rand32(5, 6, 4, 64)) |> size # обрабатывается как три пакетных измерения
(2, 6, 4, 64)
julia> d1 = Dense(ones(2, 5), false, tanh) # используется предоставленная весовая матрица
Dense(5 => 2, tanh; bias=false) # 10 параметров
julia> d1(ones(5))
2-element Vector{Float64}:
0.9999092042625951
0.9999092042625951
julia> Flux.params(d1) # обучаемое смещение отсутствует
Params([[1.0 1.0 … 1.0 1.0; 1.0 1.0 … 1.0 1.0]])
#
Flux.Bilinear
— Type
Bilinear((in1, in2) => out, σ=identity; bias=true, init=glorot_uniform)
Bilinear(W::AbstractArray, [bias, σ])
Создает слой с полной связью между двумя входами и выходом, который в остальном аналогичен Dense
. Если x
и y
— векторы, результат представляет собой еще один вектор z
, для всех i ∈ 1:out
в котором верно следующее:
z[i] = σ(x' * W[i,:,:] * y + bias[i])
Если x
и y
— матрицы, каждый столбец в результате z = B(x, y)
имеет такую форму, причем B
— это билинейный слой.
Если второй вход y
не задан, он принимается равным x
, то есть B(x) == B(x, x)
.
Два входа можно также предоставить в виде кортежа, Bx, y == B(x, y)
, который принимается в качестве входных данных Chain
.
Если два входа имеют одинаковый размер (in1 == in2
), вызов можно записать так: Bilinear(in => out, σ)
.
Инициализация происходит так же, как для слоя Dense
, с W = init(out, in1, in2)
. Вектор смещений по умолчанию имеет вид zeros(Float32, out)
; аргумент bias=false
отключает обучаемое смещение. Каждый из этих параметров можно задать явным образом.
Примеры
julia> x, y = randn(Float32, 5, 32), randn(Float32, 5, 32);
julia> B = Flux.Bilinear((5, 5) => 7)
Bilinear(5 => 7) # 182 параметра
julia> B(x) |> size # взаимодействия на основе одного входа
(7, 32)
julia> B(x,y) == B((x,y)) # два входа, могут быть заданы в виде кортежа
true
julia> sc = SkipConnection(
Chain(Dense(5 => 20, tanh), Dense(20 => 9, tanh)),
Flux.Bilinear((9, 5) => 3, bias=false),
); # используется в качестве рекомбинатора, второй вход пропущен
julia> sc(x) |> size
(3, 32)
julia> Flux.Bilinear(rand(4,8,16), false, tanh) # выходом является первое измерение веса
Bilinear((8, 16) => 4, tanh; bias=false) # 512 параметров
#
Flux.Scale
— Type
Scale(size::Integer..., σ=identity; bias=true, init=ones32)
Scale(scale::AbstractArray, [bias, σ])
Создает поэлементный слой, прямой проход которого задается следующим образом:
y = σ.(scale .* x .+ bias)
При этом используется операция .*
вместо умножения матриц *
в Dense
. Обучаемый масштаб и смещение инициализируются посредством init(size...)
и zeros32(size...)
; по умолчанию init=ones32
. Вы можете указать функцию init
, отключить обучаемое смещение с помощью bias=false
или предоставить массивы явным образом.
Используется LayerNorm
с affine=true
.
Примеры
julia> a = Flux.Scale(2)
Scale(2) # 4 параметра
julia> Flux.params(a)
Params([Float32[1.0, 1.0], Float32[0.0, 0.0]])
julia> a([1 2 3])
2×3 Matrix{Float32}:
1.0 2.0 3.0
1.0 2.0 3.0
julia> b = Flux.Scale([1 2 3 4], false, abs2)
Scale(1, 4, abs2; bias=false) # 4 параметра
julia> b([1, 10])
2×4 Matrix{Int64}:
1 4 9 16
100 400 900 1600
julia> Flux.params(b)
Params([[1 2 3 4]])
Слой Scale
, возможно, и не является полносвязным, но его можно представить как Dense(Diagonal(s.weights), s.bias)
, а тип Diagonal
из LinearAlgebra — это матрица, в которой содержится множество нулей.
Совместимость: Flux ≤ 0.12
В старых версиях Flux допускались только вызовы |
Сверточные модели
Эти слои служат для построения сверточных нейронных сетей (CNN).
Все они принимают изображения в так называемом порядке WHCN: пакет из 32 цветных изображений, каждое размером 50 x 50 пикселей, будет иметь размер size(x) == (50, 50, 3, 32)
. У одного изображения в оттенках серого размер будет size(x) == (28, 28, 1, 1)
.
Помимо изображений, то есть двумерных данных, они также работают с одномерными данными. Например, стереофоническая запись с 1000 точек дискретизации может иметь размер size(x) == (1000, 2, 1)
. Эти слои также работают с трехмерными данными, ndims(x) == 5
, где последние два измерения опять же соответствуют каналу и пакету.
Работа с шагами и заполнением хорошо проиллюстрирована в статье Дюмулена (Dumoulin) и Визина (Visin).
#
Flux.Conv
— Type
Conv(filter, in => out, σ = identity;
stride = 1, pad = 0, dilation = 1, groups = 1, [bias, init])
Стандартный сверточный слой. filter
— это кортеж целых чисел, определяющий размер сверточного ядра, а in
и out
задают количество входных и выходных каналов.
Данные изображения должны храниться в порядке WHCN (ширина, высота, каналы, пакет). То есть изображение размером 100×100 в модели RGB будет представлять собой массив 100×100×3×1
, а пакет из 50 таких изображений — массив 100×100×3×50
. При этом количество пространственных измерений N = 2
, поэтому ядро должно иметь размер, например, (5,5)
, то есть кортеж из двух целых чисел.
Для сверток по N
измерениям признаков этот слой требует на входе массива с ndims(x) == N+2
, где size(x, N+1) == in
— это количество входных каналов, а size(x, ndims(x))
— это (как и всегда) количество наблюдений в пакете. В таком случае:
-
filter
должно быть кортежем изN
целых чисел. -
Значениями именованных аргументов
stride
иdilation
должны быть одновременно либо целые числа, либо кортежи изN
целых чисел. -
Именованный аргумент
pad
определяет количество элементов, добавляемых к границам массива данных. Его значением может быть:-
одно целое число для равномерного заполнения со всех сторон;
-
кортеж из
N
целых чисел для одинакового заполнения в начале и конце каждого пространственного измерения; -
кортеж из
2*N
целых чисел для асимметричного заполнения; -
одинарное значение
SamePad()
для расчета заполнения таким образом, чтобыsize(output,d) == size(x,d) / stride
(possibly rounded) for each spatial dimension.
-
-
Именованный аргумент
groups
должен иметь значение типаInt
. Он задает количество групп, на которые делится свертка.
Именованные аргументы для управления инициализацией слоя:
-
init
- функция для генерирования начальных весов. Значение по умолчанию —glorot_uniform
. -
bias
- начальный вектор смещений по умолчанию содержит одни нули. Можно полностью отключить обучаемое смещение, присвоив этому аргументу значениеfalse
, либо передать другой вектор, напримерbias = randn(Float32, out)
.
См. также описание ConvTranspose
, DepthwiseConv
и CrossCor
.
Примеры
julia> xs = rand32(100, 100, 3, 50); # пакет из 50 изображений в модели RGB
julia> layer = Conv((5,5), 3 => 7, relu; bias = false)
Conv((5, 5), 3 => 7, relu, bias=false) # 525 параметров
julia> layer(xs) |> size
(96, 96, 7, 50)
julia> Conv((5,5), 3 => 7; stride = 2)(xs) |> size
(48, 48, 7, 50)
julia> Conv((5,5), 3 => 7; stride = 2, pad = SamePad())(xs) |> size
(50, 50, 7, 50)
julia> Conv((1,1), 3 => 7; pad = (20,10,0,0))(xs) |> size
(130, 100, 7, 50)
julia> Conv((5,5), 3 => 7; stride = 2, dilation = 4)(xs) |> size
(42, 42, 7, 50)
#
Flux.Conv
— Method
Conv(weight::AbstractArray, [bias, activation; stride, pad, dilation])
Создает сверточный слой с указанными весом и смещением. Принимает те же именованные аргументы и имеет те же значения по умолчанию, что и Conv(k::NTuple{N,Integer}, ch::Pair{<:Integer,<:Integer}, σ; ...)
.
julia> weight = rand(3, 4, 5);
julia> bias = zeros(5);
julia> layer = Conv(weight, bias, sigmoid) # ожидает 1 пространственное измерение
Conv((3,), 4 => 5, σ) # 65 параметров
julia> layer(randn(100, 4, 64)) |> size
(98, 5, 64)
julia> Flux.params(layer) |> length
2
#
Flux.ConvTranspose
— Type
ConvTranspose(filter, in => out, σ=identity; stride=1, pad=0, dilation=1, [bias, init])
Стандартный транспонированный сверточный слой. filter
— это кортеж целых чисел, определяющий размер сверточного ядра, а in
и out
задают количество входных и выходных каналов.
Обратите внимание: чтобы попытаться обеспечить соблюдение условия size(output,d) == size(x,d) * stride
в данном случае, можно задать pad=SamePad()
.
Параметры контролируются дополнительными именованными аргументами со значениями по умолчанию init=glorot_uniform
и bias=true
.
Более подробное описание именованных аргументов см. в описании Conv
.
Примеры
julia> xs = rand32(100, 100, 3, 50); # пакет из 50 изображений в модели RGB
julia> layer = ConvTranspose((5,5), 3 => 7, relu)
ConvTranspose((5, 5), 3 => 7, relu) # 532 parameters
julia> layer(xs) |> size
(104, 104, 7, 50)
julia> ConvTranspose((5,5), 3 => 7, stride=2)(xs) |> size
(203, 203, 7, 50)
julia> ConvTranspose((5,5), 3 => 7, stride=3, pad=SamePad())(xs) |> size
(300, 300, 7, 50)
#
Flux.ConvTranspose
— Method
ConvTranspose(weight::AbstractArray, [bias, activation; stride, pad, dilation, groups])
Создает слой ConvTranspose с указанными весом и смещением. Принимает те же именованные аргументы и имеет те же значения по умолчанию, что и ConvTranspose(k::NTuple{N,Integer}, ch::Pair{<:Integer,<:Integer}, σ; ...)
.
Примеры
julia> weight = rand(3, 4, 5);
julia> bias = zeros(4);
julia> layer = ConvTranspose(weight, bias, sigmoid)
ConvTranspose((3,), 5 => 4, σ) # 64 parameters
julia> layer(randn(100, 5, 64)) |> size # транспонированная свертка увеличивает размер измерения (повышающая дискретизация)
(102, 4, 64)
julia> Flux.params(layer) |> length
2
#
Flux.CrossCor
— Type
CrossCor(filter, in => out, σ=identity; stride=1, pad=0, dilation=1, [bias, init])
Стандартный взаимнокорреляционный слой. filter
— это кортеж целых чисел, определяющий размер сверточного ядра, а in
и out
задают количество входных и выходных каналов.
Параметры контролируются дополнительными именованными аргументами со значениями по умолчанию init=glorot_uniform
и bias=true
.
Более подробное описание именованных аргументов см. в описании Conv
.
Примеры
julia> xs = rand(Float32, 100, 100, 3, 50); # пакет из 50 изображений в модели RGB
julia> layer = CrossCor((5,5), 3 => 6, relu; bias=false)
CrossCor((5, 5), 3 => 6, relu, bias=false) # 450 параметров
julia> layer(xs) |> size
(96, 96, 6, 50)
julia> CrossCor((5,5), 3 => 7, stride=3, pad=(2,0))(xs) |> size
(34, 32, 7, 50)
#
Flux.CrossCor
— Method
CrossCor(weight::AbstractArray, [bias, activation; stride, pad, dilation])
Создает слой CrossCor с указанными весом и смещением. Принимает те же именованные аргументы и имеет те же значения по умолчанию, что и CrossCor(k::NTuple{N,Integer}, ch::Pair{<:Integer,<:Integer}, σ; ...)
.
Примеры
julia> weight = rand(3, 4, 5);
julia> bias = zeros(5);
julia> layer = CrossCor(weight, bias, relu)
CrossCor((3,), 4 => 5, relu) # 65 параметров
julia> layer(randn(100, 4, 64)) |> size
(98, 5, 64)
#
Flux.DepthwiseConv
— Function
DepthwiseConv(filter, in => out, σ=identity; stride=1, pad=0, dilation=1, [bias, init])
DepthwiseConv(weight::AbstractArray, [bias, activation; stride, pad, dilation])
Возвращает поканальный сверточный слой, то есть слой Conv
с количеством групп, равным количеству входных каналов.
Описание аргументов см. в описании Conv
.
Примеры
julia> xs = rand(Float32, 100, 100, 3, 50); # пакет из 50 изображений в модели RGB
julia> layer = DepthwiseConv((5,5), 3 => 6, relu; bias=false)
Conv((5, 5), 3 => 6, relu, groups=3, bias=false) # 150 параметров
julia> layer(xs) |> size
(96, 96, 6, 50)
julia> DepthwiseConv((5, 5), 3 => 9, stride=2, pad=2)(xs) |> size
(50, 50, 9, 50)
#
Flux.SamePad
— Type
SamePad()
При передаче в качестве параметра в сверточные (и подобные им) слои приводит к выбору такого заполнения, что размеры входа и выхода будут согласованы (для первых N
измерений, ядра или окна) при stride==1
. При stride≠1
размер выхода равен ceil(input_size/stride)
.
Примеры
julia> xs = rand32(100, 100, 3, 50); # пакет изображений
julia> layer = Conv((2,2), 3 => 7, pad=SamePad())
Conv((2, 2), 3 => 7, pad=(1, 0, 1, 0)) # 91 параметр
julia> layer(xs) |> size # обратите внимание, что при таком заполнении измерения остаются такими же
(100, 100, 7, 50)
julia> layer2 = Conv((2,2), 3 => 7)
Conv((2, 2), 3 => 7) # 91 параметр
julia> layer2(xs) |> size # выходное измерение изменяется, так как заполнение не было аналогичным
(99, 99, 7, 50)
julia> layer3 = Conv((5, 5), 3 => 7, stride=2, pad=SamePad())
Conv((5, 5), 3 => 7, pad=2, stride=2) # 532 parameters
julia> layer3(xs) |> size # размер выхода = `ceil(input_size/stride)` = 50
(50, 50, 7, 50)
#
Flux.flatten
— Function
flatten(x)
Действует аналогично функции MLUtils.flatten
, которая является предпочтительной, так как данный метод существует только в целях обратной совместимости.
MultiHeadAttention
Базовые блоки, необходимые для реализации архитектур преобразователей. См. также описание функциональных аналогов в разделе, посвященном примитиву Attention из NNlib.
Подвыборка
Данные слои часто используются после сверточного слоя и сокращают размер его выходных данных. У них нет обучаемых параметров.
#
Flux.AdaptiveMaxPool
— Type
AdaptiveMaxPool(out::NTuple)
Адаптивный пулинговый слой со взятием максимума. Необходимый размер окна вычисляется так, что для выхода size(y)[1:N] == out
.
На входе ожидается массив с ndims(x) == N+2
, то есть с измерениями каналов и пакетов после N
измерений признаков, где N = length(out)
.
См. также описание MaxPool
и AdaptiveMeanPool
.
Примеры
julia> xs = rand(Float32, 100, 100, 3, 50); # пакет из 50 изображений в модели RGB
julia> AdaptiveMaxPool((25, 25))(xs) |> size
(25, 25, 3, 50)
julia> MaxPool((4,4))(xs) ≈ AdaptiveMaxPool((25, 25))(xs)
true
#
Flux.MaxPool
— Type
MaxPool(window::NTuple; pad=0, stride=window)
Пулинговый слой со взятием максимума, в котором все пиксели в блоке размером window
заменяются единицей.
На входе ожидается массив с ndims(x) == N+2
, то есть с измерениями каналов и пакетов после N
измерений признаков, где N = length(window)
.
По умолчанию размер окна — это также шаг в каждом измерении. Именованный аргумент pad
принимает те же значения, что и для слоя Conv
, включая SamePad()
.
См. также описание Conv
, MeanPool
, AdaptiveMaxPool
и GlobalMaxPool
.
Примеры
julia> xs = rand(Float32, 100, 100, 3, 50); # пакет из 50 изображений в модели RGB
julia> m = Chain(Conv((5, 5), 3 => 7, pad=SamePad()), MaxPool((5, 5), pad=SamePad()))
Chain(
Conv((5, 5), 3 => 7, pad=2), # 532 parameters
MaxPool((5, 5), pad=2),
)
julia> m[1](xs) |> size
(100, 100, 7, 50)
julia> m(xs) |> size
(20, 20, 7, 50)
julia> layer = MaxPool((5,), pad=2, stride=(3,)) # одномерное окно
MaxPool((5,), pad=2, stride=3)
julia> layer(rand(Float32, 100, 7, 50)) |> size
(34, 7, 50)
#
Flux.GlobalMaxPool
— Type
GlobalMaxPool()
Глобальный пулинговый слой со взятием максимума.
Преобразует входные данные в форме (w,h,c,b) в форму (1,1,c,b), выполняя подвыборку со взятием максимума применительно к полным картам признаков в форме (w,h).
См. также описание MaxPool
и GlobalMeanPool
.
julia> xs = rand(Float32, 100, 100, 3, 50);
julia> m = Chain(Conv((3,3), 3 => 7), GlobalMaxPool());
julia> m(xs) |> size
(1, 1, 7, 50)
julia> GlobalMaxPool()(rand(3,5,7)) |> size # сохраняет 2 измерения
(1, 5, 7)
#
Flux.AdaptiveMeanPool
— Type
AdaptiveMeanPool(out::NTuple)
Адаптивный пулинговый слой со взятием среднего значения. Необходимый размер окна вычисляется так, что для выхода size(y)[1:N] == out
.
На входе ожидается массив с ndims(x) == N+2
, то есть с измерениями каналов и пакетов после N
измерений признаков, где N = length(out)
.
См. также описание MaxPool
и AdaptiveMaxPool
.
Примеры
julia> xs = rand(Float32, 100, 100, 3, 50); # пакет из 50 изображений в модели RGB
julia> AdaptiveMeanPool((25, 25))(xs) |> size
(25, 25, 3, 50)
julia> MeanPool((4,4))(xs) ≈ AdaptiveMeanPool((25, 25))(xs)
true
#
Flux.MeanPool
— Type
MeanPool(window::NTuple; pad=0, stride=window)
Пулинговый слой со взятием среднего значения, в котором все пиксели в блоке размера window
усредняются.
На входе ожидается массив с ndims(x) == N+2
, то есть с измерениями каналов и пакетов после N
измерений признаков, где N = length(window)
.
По умолчанию размер окна — это также шаг в каждом измерении. Именованный аргумент pad
принимает те же значения, что и для слоя Conv
, включая SamePad()
.
См. также описание функций Conv
, MaxPool
и AdaptiveMeanPool
.
Примеры
julia> xs = rand(Float32, 100, 100, 3, 50);
julia> m = Chain(Conv((5,5), 3 => 7), MeanPool((5,5), pad=SamePad()))
Chain(
Conv((5, 5), 3 => 7), # 532 parameters
MeanPool((5, 5), pad=2),
)
julia> m[1](xs) |> size
(96, 96, 7, 50)
julia> m(xs) |> size
(20, 20, 7, 50)
#
Flux.GlobalMeanPool
— Type
GlobalMeanPool()
Глобальный пулинговый слой со взятием среднего значения.
Преобразует входные данные в форме (w,h,c,b) в форму (1,1,c,b), выполняя подвыборку со взятием среднего значения применительно к полным картам признаков в форме (w,h).
julia> xs = rand(Float32, 100, 100, 3, 50);
julia> m = Chain(Conv((3,3), 3 => 7), GlobalMeanPool());
julia> m(xs) |> size
(1, 1, 7, 50)
Повышающая дискретизация
Такие слои, действующие противоположно слоям подвыборки, увеличивают размер массива. У них нет обучаемых параметров.
#
Flux.Upsample
— Type
Upsample(mode = :nearest; [scale, size])
Upsample(scale, mode = :nearest)
Слой повышающей дискретизации. Необходимо задать один из двух именованных аргументов:
Если scale
— число, оно применяется ко всем измерениям входных данных, кроме двух последних (измерений каналов и пакетов). Значением также может быть кортеж для управления измерениями по отдельности. Именованный аргумент size
также может принимать кортеж для указания начальных измерений результата напрямую.
В настоящее время поддерживаются следующие режимы (mode
) повышающей дискретизации и соответствующие методы NNlib:
-
:nearest
->NNlib.upsample_nearest
-
:bilinear
->NNlib.upsample_bilinear
-
:trilinear
->NNlib.upsample_trilinear
Примеры
julia> m = Upsample(scale = (2, 3))
Upsample(:nearest, scale = (2, 3))
julia> m(ones(2, 2, 1, 1)) |> size
(4, 6, 1, 1)
julia> m = Upsample(:bilinear, size = (4, 5))
Upsample(:bilinear, size = (4, 5))
julia> m(ones(2, 2, 1, 1)) |> size
(4, 5, 1, 1)
#
Flux.PixelShuffle
— Type
PixelShuffle(r::Int)
Слой перемешивания пикселей с коэффициентом увеличения масштаба r
. Обычно применяется для генерирования изображений в более высоком разрешении при увеличении их масштаба.
См. описание NNlib.pixel_shuffle
.
Примеры
julia> p = PixelShuffle(2);
julia> xs = [2row + col + channel/10 for row in 1:2, col in 1:2, channel in 1:4, n in 1:1]
2×2×4×1 Array{Float64, 4}:
[:, :, 1, 1] =
3.1 4.1
5.1 6.1
[:, :, 2, 1] =
3.2 4.2
5.2 6.2
[:, :, 3, 1] =
3.3 4.3
5.3 6.3
[:, :, 4, 1] =
3.4 4.4
5.4 6.4
julia> p(xs)
4×4×1×1 Array{Float64, 4}:
[:, :, 1, 1] =
3.1 3.3 4.1 4.3
3.2 3.4 4.2 4.4
5.1 5.3 6.1 6.3
5.2 5.4 6.2 6.4
julia> xs = [3row + col + channel/10 for row in 1:2, col in 1:3, channel in 1:4, n in 1:1]
2×3×4×1 Array{Float64, 4}:
[:, :, 1, 1] =
4.1 5.1 6.1
7.1 8.1 9.1
[:, :, 2, 1] =
4.2 5.2 6.2
7.2 8.2 9.2
[:, :, 3, 1] =
4.3 5.3 6.3
7.3 8.3 9.3
[:, :, 4, 1] =
4.4 5.4 6.4
7.4 8.4 9.4
julia> p(xs)
4×6×1×1 Array{Float64, 4}:
[:, :, 1, 1] =
4.1 4.3 5.1 5.3 6.1 6.3
4.2 4.4 5.2 5.4 6.2 6.4
7.1 7.3 8.1 8.3 9.1 9.3
7.2 7.4 8.2 8.4 9.2 9.4
Векторные представления
Эти слои принимают индекс (или несколько индексов) и возвращают вектор (или несколько векторов). Одними из возможных векторных представлений являются обучаемые параметры.
#
Flux.Embedding
— Type
Embedding(in => out; init=randn32)
Таблица поиска, в которой хранятся векторные представления измерения out
для словаря размером in
в виде обучаемой матрицы.
Этот слой часто применяется для хранения векторных представлений слов и их извлечения по индексам. Входными данными для этого слоя могут быть индекс словаря в 1:in
, массив индексов или соответствующая кодировка onehot encoding
.
Для индексов x
результат имеет размер (out, size(x)...)
, благодаря чему допустимо несколько измерений пакетов. Для прямой унитарной кодировки ohx
результат имеет размер (out, size(ohx)[2:end]...)
.
Примеры
julia> emb = Embedding(26 => 4, init=Flux.identity_init(gain=22))
Embedding(26 => 4) # 104 параметра
julia> emb(2) # один столбец примерных весов (в данном случае не случайных)
4-element Vector{Float32}:
0.0
22.0
0.0
0.0
julia> emb([3, 1, 20, 14, 4, 15, 7]) # индексы словаря в диапазоне 1:26
4×7 Matrix{Float32}:
0.0 22.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0
22.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 22.0 0.0 0.0
julia> ans == emb(Flux.onehotbatch("cat&dog", 'a':'z', 'n'))
true
julia> emb(rand(1:26, (10, 1, 12))) |> size # три измерения пакетов
(4, 10, 1, 12)
#
Flux.EmbeddingBag
— Type
EmbeddingBag(in => out, reduction=mean; init=Flux.randn32)
Таблица поиска, в которой хранятся векторные представления измерения out
для словаря размером in
. Отличается от Embedding
тем, что вместо применения к одному индексу словаря всегда применяется к вектору индексов, который называется мультимножеством. Отдельные векторные представления сводятся к единице с помощью mean
или какой-либо иной функции.
Вместо применения к одному мультимножеству, например x::Vector{Int}
, этот слой также может работать с несколькими:
-
При применении к вектору мультимножеств создается матрица, столбцы которой представляют собой приведенные векторы. В более общем случае при применении к
x::Array{Vector{Int}}
результат имеет размер(out, size(x)...)
. -
Любой массив целых чисел более высокого ранга рассматривается как коллекция мультимножеств, каждое из которых располагается по первому измерению. Таким образом, при
e::EmbeddingBag
иx::Array{Int,N}
результатом будетmapslices(e, x; dims=1)
. Этот метод эффективнее, но требует, чтобы все мультимножества были одинаковой длины. -
Вектор мультимножеств можно также получить путем разделения вектора индексов в заданных точках. В таком случае слой принимает два входных объекта, каждый из которых представляет собой вектор целых чисел. Подробные сведения см. ниже.
Мультимножество можно эквивалентно представить как OneHotMatrix
. Их коллекция или один массив OneHotArray
более высокого ранга также создают стек векторных представлений. Подробные сведения см. ниже.
Примеры
julia> vocab_size = 26; # внедрение в 3 измерения с неслучайными векторами:
julia> eb = EmbeddingBag(vocab_size => 3, init=Flux.identity_init(gain=100))
EmbeddingBag(26 => 3) # 78 параметров
julia> eb([2]) # одно мультимножество из 1 элемента
3-element Vector{Float32}:
0.0
100.0
0.0
julia> eb([3,3,1]) # одно мультимножество из 3 элементов, одно усредненное векторное представление
3-element Vector{Float32}:
33.333332
0.0
66.666664
julia> eb([[3,1,3], [2,1]]) # два мультимножества
3×2 Matrix{Float32}:
33.3333 50.0
0.0 50.0
66.6667 0.0
julia> eb([1 1 1 1; 1 2 3 4]) # 4 мультимножества по 2 элемента, eachcol([1 1 1 1; 1 2 3 4])
3×4 Matrix{Float32}:
100.0 50.0 50.0 50.0
0.0 50.0 0.0 0.0
0.0 0.0 50.0 0.0
julia> eb(rand(1:26, 10, 5, 5)) |> size # 25 мультимножество по 10 элементов
(3, 5, 5)
Другим способом задания «множества мультимножеств из множества элементов» является передача вектора data
(в диапазоне 1:in
) и вектора at
, указывающего, в каких точках его следует разделить на мультимножества. Первое мультимножество начинается с data[at[1]]
, второе — с data[at[2]]
и т. д., без перекрытий и оставшихся элементов (поэтому требуется at[1]==1
).
julia> data = [11, 1, 12, 2, 13, 3, 14];
julia> Flux._splitat(data, [1, 4]) |> println # внутренняя функция, выполняет data[1:3], data[4:end]
[[11, 1, 12], [2, 13, 3, 14]]
julia> eb(data, [1, 4]) # два мультимножества из 3 и 4 элементов
3×2 Matrix{Float32}:
33.3333 0.0
0.0 25.0
0.0 25.0
Наконец, каждое мультимножество можно также представить как OneHotMatrix
.
julia> eb(Flux.onehotbatch("bba", 'a':'z')) # то же, что и [2,2,1], одно мультимножество из 3 элементов
3-element Vector{Float32}:
33.333332
66.666664
0.0
julia> eb([Flux.onehotbatch("bba", 'a':'z'), Flux.onehotbatch("cc", 'a':'z')]) # два мультимножества
3×2 Matrix{Float32}:
33.3333 0.0
66.6667 0.0
0.0 100.0
Слои потока данных или контейнеры
Базовый объект Chain(F, G, H)
применяет содержащиеся в нем слои по порядку, что равносильно H ∘ G ∘ F
. Во Flux есть и другие слои, которые также содержат слои, но соединенные более сложным образом: SkipConnection
обеспечивает остаточную связь ResNet.
#
Flux.Chain
— Type
Chain(layers...)
Chain(name = layer, ...)
Объединяет несколько слоев или функций для поочередного вызова применительно к указанным входным данным. Поддерживает индексирование и создание срезов (m[2]
, m[1:end-1]
), а если заданы имена, то m[:name] == m[1]
и т. д.
Примеры
julia> m = Chain(x -> x^2, x -> x+1);
julia> m(5) == 26
true
julia> m = Chain(Dense(10 => 5, tanh), Dense(5 => 2));
julia> x = rand32(10, 32);
julia> m(x) == m[2](m[1](x))
true
julia> m2 = Chain(enc = Chain(Flux.flatten, Dense(10 => 5, tanh)),
dec = Dense(5 => 2));
julia> m2(x) == (m2[:dec] ∘ m2[:enc])(x)
true
Для больших моделей есть специальный нестабильный по типу путь, позволяющий ускорить компиляцию. Для его использования можно предоставить вектор слоев Chain([layer1, layer2, ...])
. Однако будьте осторожны: эта функция пока имеет экспериментальный характер.
#
Flux.activations
— Function
activations(c::Chain, input)
Действует аналогично вызову Chain
, но сохраняет результат каждого слоя в выходных данных.
Примеры
julia> using Flux: activations
julia> c = Chain(x -> x + 1, x -> x * 2, x -> x ^ 3);
julia> activations(c, 1)
(2, 4, 64)
#
Flux.Maxout
— Type
Maxout(layers...)
Maxout(f, n_alts)
Содержит несколько внутренних слоев, каждый из которых принимает одни и те же входные данные. Результатом является поэлементный максимум выходов внутренних слоев.
Можно не определять слои по отдельности, а предоставить создающую их функцию без аргументов и количество создаваемых слоев.
Результат применения функции Maxout к линейным плотным слоям соответствует теореме об универсальной аппроксимации. См. работу Гудфеллоу (Goodfellow), Варда-Фарли (Warde-Farley), Мирзы (Mirza), Курвиля (Courville) и Бенжио (Bengio) — Maxout Networks https://arxiv.org/abs/1302.4389.
См. также сведения о приведении с помощью других операторов в описании Parallel
.
Примеры
julia> m = Maxout(x -> abs2.(x), x -> x .* 3);
julia> m([-2 -1 0 1 2])
1×5 Matrix{Int64}:
4 1 0 3 6
julia> m3 = Maxout(() -> Dense(5 => 7, tanh), 3)
Maxout(
Dense(5 => 7, tanh), # 42 параметра
Dense(5 => 7, tanh), # 42 параметра
Dense(5 => 7, tanh), # 42 параметра
) # Всего: 6 массивов, 126 параметров, 888 байтов.
julia> Flux.outputsize(m3, (5, 11))
(7, 11)
#
Flux.SkipConnection
— Type
SkipConnection(layer, connection)
Создает связь с пропуском, которая состоит из слоя или объекта Chain
с последовательностью слоев и связи напрямую между входом и выходом блока, посредством предоставленного пользователем вызова с двумя аргументами. Первый аргумент вызова распространяется через слой layer
, а второй представляет неизменяемый, «пропускаемый» вход.
Простейший тип связи ResNet — SkipConnection(layer, +)
. Вот более сложный пример:
julia> m = Conv((3,3), 4 => 7, pad=(1,1));
julia> x = ones(Float32, 5, 5, 4, 10);
julia> size(m(x)) == (5, 5, 7, 10)
true
julia> sm = SkipConnection(m, (mx, x) -> cat(mx, x, dims=3));
julia> size(sm(x)) == (5, 5, 11, 10)
true
#
Flux.Parallel
— Type
Parallel(connection, layers...)
Parallel(connection; name = layer, ...)
Создает слой, который передает входной массив по каждому пути в layers
перед приведением выхода с помощью connection
.
Вызов с одним входом x
эквивалентен connection([l(x) for l in layers]...)
. При вызове с несколькими входами в каждый слой передается один из них, то есть Parallel(+, f, g)(x, y) = f(x) + g(y)
.
Как и в случае с Chain
, подслоям можно присвоить имена с помощью конструктора с именованными аргументами. Обращаться к ним можно по индексам: m[1] == m[:name]
— это первый слой.
См. также описание типа SkipConnection
, который аналогичен identity
, но имеет один аргумент Parallel
, и типа Maxout
, который выполняет приведение путем трансляции max
.
Примеры
julia> model = Chain(Dense(3 => 5),
Parallel(vcat, Dense(5 => 4), Chain(Dense(5 => 7), Dense(7 => 4))),
Dense(8 => 17));
julia> model(rand32(3)) |> size
(17,)
julia> model2 = Parallel(+; α = Dense(10, 2, tanh), β = Dense(5, 2))
Parallel(
+,
α = Dense(10 => 2, tanh), # 22 параметра
β = Dense(5 => 2), # 12 параметров
) # Всего: 4 массива, 34 параметра, 392 байта.
julia> model2(rand32(10), rand32(5)) |> size
(2,)
julia> model2[:α](rand32(10)) |> size
(2,)
julia> model2[:β] == model2[2]
true
#
Flux.PairwiseFusion
— Type
PairwiseFusion(connection, layers...)
Аргументы
-
connection
: функция, принимающая два входа и объединяющая их в один выход -
layers
: слои, выходы которых следует объединить
Входные данные
Поведение этого слоя зависит от типа входных данных.
-
Если вход
x
— это кортеж длиной N, соответствующей количеству слоевlayers
(либо если на входе передан объектxs
из Nx
),
каждый слой принимает новый вход x[i]
, объединенный с предыдущим выходом y[i-1]
с помощью connection
. Таким образом, выражение (y1, y2, y3) = PairwiseFusion(connection, layer1, layer2, layer3)x1, x2, x3
можно представить такой схемой:
x1 → layer1 → y1 ↘ connection → layer2 → y2 ↘ x2 ↗ connection → layer3 → y3 x3 ↗
-
или записать в следующем виде:
y1 = layer1(x1) y2 = layer2(connection(y1, x2)) y3 = layer3(connection(y2, x3))
-
Если вход только один, каждый слой принимает один и тот же вход
x
, объединенный с предыдущим выходом. Таким образом, выражениеy = PairwiseFusion(connection, layers...)(x)
соответствует следующему коду:
y[1] == layers[1](x)
for i in 2:length(layers)
y[i] == connection(layers[i](y[i-1]), x)
end
Возвращаемые значения
Кортеж длиной N с результатом каждого слияния (в примере выше это будет (y1
, y2
, …, yN
)).
Рекуррентные модели
Во многом похожи на описанные выше базовые слои, но могут применяться для обработки данных последовательностей (а также других структурированных данных).
#
Flux.RNN
— Function
RNN(in => out, σ = tanh)
Самый базовый рекуррентный слой; по сути действует как слой Dense
, но на каждом временном шаге выход подается обратно на вход.
Аргументы in
и out
описывают размер векторов признаков, передаваемых в качестве входа и выхода. Таким образом, функция принимает вектор длиной in
или пакет векторов, представленный в виде матрицы in x B
, и выдает вектор длиной out
или пакет векторов размером out x B
.
Данный конструктор представляет собой синтаксический сахар для Recur(RNNCell(a...))
, то есть вызовы RNN производятся с сохранением состояния. Обратите внимание, что форма состояния может изменяться в зависимости от входов, поэтому при изменении размера пакета между вызовами вывода желательно сбрасывать модель с помощью reset!
. См. примеры ниже.
Примеры
julia> r = RNN(3 => 5)
Recur(
RNNCell(3 => 5, tanh), # 50 параметров
) # Всего: 4 обучаемых массива, 50 параметров,
# плюс 1 необучаемый, 5 параметров, суммарный размер 432 байта.
julia> r(rand(Float32, 3)) |> size
(5,)
julia> Flux.reset!(r);
julia> r(rand(Float32, 3, 10)) |> size # размер пакета 10
(5, 10)
Если не вызвать
|
Примечание.
RNNCell
можно создать напрямую, задав нелинейную функцию, внутренние матрицы Wi
и Wh
, вектор смещений b
и обучаемое исходное состояние state0
. Матрицы Wi
и Wh
могут быть разных типов, но если Wh
имеет форму dxd
, матрица Wi
должна иметь форму dxN
.
julia> using LinearAlgebra
julia> r = Flux.Recur(Flux.RNNCell(tanh, rand(5, 4), Tridiagonal(rand(5, 5)), rand(5), rand(5, 1)))
julia> r(rand(4, 10)) |> size # размер пакета 10
(5, 10)
#
Flux.LSTM
— Function
LSTM(in => out)
Рекуррентный слой сети с долговременной и кратковременной памятью . Похож на RNN, но, как правило, требует большего объема памяти по сравнению с последовательностями.
Аргументы in
и out
описывают размер векторов признаков, передаваемых в качестве входа и выхода. Таким образом, функция принимает вектор длиной in
или пакет векторов, представленный в виде матрицы in x B
, и выдает вектор длиной out
или пакет векторов размером out x B
.
Данный конструктор представляет собой синтаксический сахар для Recur(LSTMCell(a...))
, то есть вызовы LSTM производятся с сохранением состояния. Обратите внимание, что форма состояния может изменяться в зависимости от входов, поэтому при изменении размера пакета между вызовами вывода желательно сбрасывать модель с помощью reset!
. См. примеры ниже.
В этой статье дается хороший обзор внутренних принципов работы.
Примеры
julia> l = LSTM(3 => 5)
Recur(
LSTMCell(3 => 5), # 190 параметров
) # Всего: 5 обучаемых массивов, 190 параметров,
# плюс 2 необучаемых, 10 параметров, суммарный размер 1,062 КиБ.
julia> l(rand(Float32, 3)) |> size
(5,)
julia> Flux.reset!(l);
julia> l(rand(Float32, 3, 10)) |> size # размер пакета 10
(5, 10)
Если не вызвать |
Примечание.
LSTMCell
можно создать напрямую, задав нелинейную функцию, внутренние матрицы Wi
и Wh
, вектор смещений b
и обучаемое исходное состояние state0
. Матрицы Wi
и Wh
могут быть разных типов. См. пример в описании RNN
.
#
Flux.GRU
— Function
GRU(in => out)
Слой управляемого рекуррентного блока. Похож на RNN, но, как правило, требует большего объема памяти по сравнению с последовательностями. Реализует вариант, предложенный в версии 1 работы по ссылке.
Целочисленные аргументы in
и out
описывают размер векторов признаков, передаваемых в качестве входа и выхода. Таким образом, функция принимает вектор длиной in
или пакет векторов, представленный в виде матрицы in x B
, и выдает вектор длиной out
или пакет векторов размером out x B
.
Данный конструктор представляет собой синтаксический сахар для Recur(GRUCell(a...))
, то есть вызовы GRU производятся с сохранением состояния. Обратите внимание, что форма состояния может изменяться в зависимости от входов, поэтому при изменении размера пакета между вызовами вывода желательно сбрасывать модель с помощью reset!
. См. примеры ниже.
В этой статье дается хороший обзор внутренних принципов работы.
Примеры
julia> g = GRU(3 => 5)
Recur(
GRUCell(3 => 5), # 140 параметров
) # Всего: 4 обучаемых массива, 140 параметров,
# плюс 1 необучаемый, 5 параметров, суммарный размер 792 байта.
julia> g(rand(Float32, 3)) |> size
(5,)
julia> Flux.reset!(g);
julia> g(rand(Float32, 3, 10)) |> size # размер пакета 10
(5, 10)
Если не вызвать |
Примечание.
GRUCell
можно создать напрямую, задав нелинейную функцию, внутренние матрицы Wi
и Wh
, вектор смещений b
и обучаемое исходное состояние state0
. Матрицы Wi
и Wh
могут быть разных типов. См. пример в описании RNN
.
#
Flux.GRUv3
— Function
GRUv3(in => out)
Слой управляемого рекуррентного блока. Похож на RNN, но, как правило, требует большего объема памяти по сравнению с последовательностями. Реализует вариант, предложенный в версии 3 работы по ссылке.
Аргументы in
и out
описывают размер векторов признаков, передаваемых в качестве входа и выхода. Таким образом, функция принимает вектор длиной in
или пакет векторов, представленный в виде матрицы in x B
, и выдает вектор длиной out
или пакет векторов размером out x B
.
Данный конструктор представляет собой синтаксический сахар для Recur(GRUv3Cell(a...))
, то есть вызовы GRUv3 производятся с сохранением состояния. Обратите внимание, что форма состояния может изменяться в зависимости от входов, поэтому при изменении размера пакета между вызовами вывода желательно сбрасывать модель с помощью reset!
. См. примеры ниже.
В этой статье дается хороший обзор внутренних принципов работы.
Примеры
julia> g = GRUv3(3 => 5)
Recur(
GRUv3Cell(3 => 5), # 140 параметров
) # Всего: 5 обучаемых массивов, 140 параметров,
# плюс 1 необучаемый, 5 параметров, суммарный размер 848 байтов.
julia> g(rand(Float32, 3)) |> size
(5,)
julia> Flux.reset!(g);
julia> g(rand(Float32, 3, 10)) |> size # размер пакета 10
(5, 10)
Если не вызвать |
Примечание.
GRUv3Cell
можно создать напрямую, задав нелинейную функцию, внутренние матрицы Wi
, Wh
и Wh_h
, вектор смещений b
и обучаемое исходное состояние state0
. Матрицы Wi
, Wh
и Wh_h
могут быть разных типов. См. пример в описании RNN
.
#
Flux.Recur
— Type
Recur(cell)
Recur
принимает рекуррентную ячейку и делает ее ячейкой с сохранением состояния, управляя скрытым состоянием в фоновом режиме. Аргумент cell
должен представлять собой модель в следующей форме:
h, y = cell(h, x...)
Например, вот рекуррентная сеть, сохраняющая промежуточную сумму входов:
Примеры
julia> accum(h, x) = (h + x, x)
accum (generic function with 1 method)
julia> rnn = Flux.Recur(accum, 0)
Recur(accum)
julia> rnn(2)
2
julia> rnn(3)
3
julia> rnn.state
5
Также поддерживается свертка трехмерного массива с измерениями (features, batch, time)
:
julia> accum(h, x) = (h .+ x, x)
accum (generic function with 1 method)
julia> rnn = Flux.Recur(accum, zeros(Int, 1, 1))
Recur(accum)
julia> rnn([2])
1-element Vector{Int64}:
2
julia> rnn([3])
1-element Vector{Int64}:
3
julia> rnn.state
1×1 Matrix{Int64}:
5
julia> out = rnn(reshape(1:10, 1, 1, :)); # применяется к последовательности (признаки, пакет, время)
julia> out |> size
(1, 1, 10)
julia> vec(out)
10-element Vector{Int64}:
1
2
3
4
5
6
7
8
9
10
julia> rnn.state
1×1 Matrix{Int64}:
60
#
Flux.reset!
— Function
reset!(rnn)
Сбрасывает скрытое состояние рекуррентного слоя в исходное значение.
Для слоя rnn
типа Recur
это будет примерно соответствовать следующему выражению:
rnn.state = hidden(rnn.cell)
Примеры
julia> r = Flux.RNNCell(relu, ones(1,1), zeros(1,1), ones(1,1), zeros(1,1)); # вместо этого следует использовать структуру оболочки RNN
julia> y = Flux.Recur(r, ones(1,1));
julia> y.state
1×1 Matrix{Float64}:
1.0
julia> y(ones(1,1)) # relu(1*1 + 1)
1×1 Matrix{Float64}:
2.0
julia> y.state
1×1 Matrix{Float64}:
2.0
julia> Flux.reset!(y)
1×1 Matrix{Float64}:
0.0
julia> y.state
1×1 Matrix{Float64}:
0.0
Нормализация и регуляризация
Эти слои не влияют на структуру сети, но могут ускорять обучение или предотвращать чрезмерное обучение. Некоторые из них содержат обучаемые параметры, а другие — нет.
#
Flux.BatchNorm
— Type
BatchNorm(channels::Integer, λ=identity;
initβ=zeros32, initγ=ones32,
affine=true, track_stats=true, active=nothing,
eps=1f-5, momentum= 0.1f0)
Слой пакетной нормализации. Аргумент channels
должен содержать размер измерения канала в данных (см. ниже).
Для массива с N
измерениями следует вызвать N-1
-е измерение канала. Для пакета векторов признаков это просто измерение данных; для изображений WHCN
это обычное измерение канала.
BatchNorm
вычисляет среднее значение и дисперсию для каждого входного среза D_1×...×D_{N-2}×1×D_N
и соответствующим образом нормализует входные данные.
При affine=true
также применяет сдвиг и коэффициент масштаба к входным данным посредством обучаемых параметров поканального смещения β и масштаба γ.
После нормализации применяется поэлементная активация λ
.
При track_stats=true
на этапе обучения накапливается статистика по средним значениям и дисперсии, которая будет использоваться для повторной нормализации входных данных на этапе проверки.
Во время вывода используйте testmode!
.
Примеры
julia> using Statistics
julia> xs = rand(3, 3, 3, 2); # пакет из 2 изображений по 3 канала в каждом
julia> m = BatchNorm(3);
julia> Flux.trainmode!(m);
julia> isapprox(std(m(xs)), 1, atol=0.1) && std(xs) != std(m(xs))
true
#
Flux.Dropout
— Type
Dropout(p; [dims, rng, active])
Слой, реализующий предотвращение переобучения с заданной вероятностью. Используется в целях регуляризации, то есть для предотвращения чрезмерного обучения.
При обучении каждый вход устанавливается в значение 0
(с вероятностью p
) либо масштабируется в отношении 1 / (1 - p)
с помощью функции NNlib.dropout
. При проверке не действует.
По умолчанию режим активируется автоматически, но им также можно управлять вручную с помощью Flux.testmode!
или путем передачи именованного аргумента active=true
для режима обучения.
По умолчанию каждый вход обрабатывается независимо. При задании именованного аргумента dims
вместо этого случайный выбор делается только по данному измерению. Например, при вызове Dropout(p; dims = 3)
случайным образом обнуляются целые каналы на входе WHCN (это также называется двумерным исключением).
Именованный аргумент rng
позволяет указать пользовательский генератор случайных чисел. (Поддерживается только при выполнении на ЦП.)
Примеры
julia> m = Chain(Dense(ones(3,2)), Dropout(0.4))
Chain(
Dense(2 => 3), # 9 параметров
Dropout(0.4),
)
julia> m(ones(2, 7)) # тестовый режим, не оказывает эффекта
3×7 Matrix{Float64}:
2.0 2.0 2.0 2.0 2.0 2.0 2.0
2.0 2.0 2.0 2.0 2.0 2.0 2.0
2.0 2.0 2.0 2.0 2.0 2.0 2.0
julia> Flux.trainmode!(m) # равносильно использованию в градиенте
Chain(
Dense(2 => 3), # 9 параметров
Dropout(0.4, active=true),
)
julia> m(ones(2, 7))
3×7 Matrix{Float64}:
0.0 0.0 3.33333 0.0 0.0 0.0 0.0
3.33333 0.0 3.33333 0.0 3.33333 0.0 3.33333
3.33333 3.33333 0.0 3.33333 0.0 0.0 3.33333
julia> y = m(ones(2, 10_000));
julia> using Statistics
julia> mean(y) # примерно равно 2,0, как и в режиме проверки
1.9989999999999961
julia> mean(iszero, y) # примерно равно 0,4
0.4003
#
Flux.AlphaDropout
— Type
AlphaDropout(p; [rng, active])
Слой исключения. Используется в самонормализующихся нейронных сетях. Слой AlphaDropout гарантирует сохранение среднего значения и дисперсии активаций.
Если testmode!
имеет значение true, со входом ничего не происходит.
Примеры
julia> using Statistics
julia> x = randn32(1000,1);
julia> m = Chain(Dense(1000 => 1000, selu), AlphaDropout(0.2));
julia> Flux.trainmode!(m);
julia> y = m(x);
julia> isapprox(std(x), std(y), atol=0.2)
true
#
Flux.LayerNorm
— Type
LayerNorm(size..., λ=identity; affine=true, eps=1f-5)
Слой нормализации, предназначенный для использования с рекуррентными скрытыми состояниями. Значением аргумента size
должно быть целое число или их кортеж.
При прямом проходе слой нормализует среднее значение и среднеквадратичное отклонение входа, а затем применяет поэлементную активацию λ
. Вход нормализуется по первым length(size)
измерениям для кортежа size
или по первому измерению для целочисленного значения size
. Размер первых измерений входа должен быть равен size
.
При affine=true
также применяются обучаемый сдвиг и коэффициент масштаба с помощью слоя Scale
.
См. также описание BatchNorm
, InstanceNorm
, GroupNorm
и normalise
.
Примеры
julia> using Statistics
julia> xs = rand(3, 3, 3, 2); # пакет из 2 изображений по 3 канала в каждом
julia> m = LayerNorm(3);
julia> y = m(xs);
julia> isapprox(std(y, dims=1:3), ones(1, 1, 1, 2), atol=0.1) && std(y, dims=1:3) != std(xs, dims=1:3)
true
#
Flux.InstanceNorm
— Type
InstanceNorm(channels::Integer, λ=identity;
initβ=zeros32, initγ=ones32,
affine=false, track_stats=false,
eps=1f-5, momentum=0.1f0)
Слой индивидуальной нормализации. Аргумент channels
должен содержать размер измерения канала в данных (см. ниже).
Для массива с N > 2
измерениями следует вызвать N-1
-е измерение канала. Для изображений WHCN
это обычное измерение канала.
InstanceNorm
вычисляет среднее значение и дисперсию для каждого входного среза D_1×...×D_{N-2}×1×1
и соответствующим образом нормализует входные данные.
При affine=true
также применяет сдвиг и коэффициент масштаба к входным данным посредством обучаемых параметров поканального смещения β
и масштаба γ
.
При track_stats=true
на этапе обучения накапливается статистика по средним значениям и дисперсии, которая будет использоваться для повторной нормализации входных данных на этапе проверки.
Внимание! Для параметров affine
и track_stats
значением по умолчанию было true
в предыдущих версиях Flux (до версии 0.12).
Примеры
julia> using Statistics
julia> xs = rand(3, 3, 3, 2); # пакет из 2 изображений по 3 канала в каждом
julia> m = InstanceNorm(3);
julia> y = m(xs);
julia> isapprox(std(y, dims=1:2), ones(1, 1, 3, 2), atol=0.2) && std(y, dims=1:2) != std(xs, dims=1:2)
true
#
Flux.GroupNorm
— Type
GroupNorm(channels::Int, G::Int, λ = identity;
initβ = zeros32,
initγ = ones32,
affine = true,
eps = 1f-5,
momentum = 0.1f0)
Слой групповой нормализации.
chs
— это количество каналов в измерении каналов входа. Для массива с N измерениями измерение каналов имеет индекс N-1
.
G
— это количество групп, по которым вычисляется статистика. Количество каналов должно быть целым числом, кратным количеству групп.
Аргумент channels
должен содержать размер измерения канала в данных (см. ниже).
Для массива с N > 2
измерениями следует вызвать N-1
-е измерение канала. Для изображений WHCN
это обычное измерение канала.
При affine=true
также применяет сдвиг и коэффициент масштаба к входным данным посредством обучаемых параметров поканального смещения β
и масштаба γ
.
Примеры
julia> using Statistics
julia> xs = rand(3, 3, 4, 2); # пакет из 2 изображений по 4 канала в каждом
julia> m = GroupNorm(4, 2);
julia> y = m(xs);
julia> isapprox(std(y[:, :, 1:2, 1]), 1, atol=0.1) && std(xs[:, :, 1:2, 1]) != std(y[:, :, 1:2, 1])
true
julia> isapprox(std(y[:, :, 3:4, 2]), 1, atol=0.1) && std(xs[:, :, 3:4, 2]) != std(y[:, :, 3:4, 2])
true
#
Flux.normalise
— Function
normalise(x; dims=ndims(x), eps=1e-5)
Нормализует x
к среднему значению 0 и среднеквадратичному отклонению 1 по измерениям, указанным в dims
. По умолчанию dims
— это последнее измерение. eps
— это небольшой член, который добавляется в знаменатель для численной устойчивости.
Примеры
julia> using Statistics
julia> x = [90, 100, 110, 130, 70];
julia> mean(x), std(x; corrected=false)
(100.0, 20.0)
julia> y = Flux.normalise(x)
5-element Vector{Float64}:
-0.49999975000012503
0.0
0.49999975000012503
1.499999250000375
-1.499999250000375
julia> isapprox(std(y; corrected=false), 1, atol=1e-5)
true
julia> x = rand(10:100, 10, 10);
julia> y = Flux.normalise(x, dims=1);
julia> isapprox(std(y; dims=1, corrected=false), ones(1, 10), atol=1e-5)
true
Проверка и обучение
Некоторые нормализационные слои ведут себя по-разному в режиме обучения и вывода (проверки). По умолчанию Flux автоматически определяет, вычисляется ли слой в рамках обучения или вывода.
Автоматическое определение режима обучения или проверки лучше всего работает с Zygote, пакетом по умолчанию для автоматического дифференцирования. С другими пакетами, такими как Tracker, Yota или ForwardDiff, оно может не работать. |
С помощью функций Flux.trainmode!
и Flux.testmode!
можно вручную указать требуемое поведение. При вызове для модели они переводят все ее слои в заданный режим.
#
Flux.testmode!
— Method
testmode!(model, [mode]) -> model
Переводит слой или все слои модели в режим проверки. При этом перестают действовать Dropout
и некоторые другие слои регуляризации.
Если модель была переведена в режим проверки вручную, ее необходимо также вручную перевести обратно в режим обучения на этапе обучения с помощью trainmode!
.
Кроме того, имеется необязательный второй аргумент, который принимает символ :auto
для перевода всех слоев обратно в автоматический режим по умолчанию.
Пример
julia> d = Dropout(0.3)
Dropout(0.3)
julia> testmode!(d) # исключение теперь всегда отключено
Dropout(0.3, active=false)
julia> trainmode!(d) # исключение теперь всегда включено
Dropout(0.3, active=true)
julia> testmode!(d, :auto) # восстановление режима по умолчанию
Dropout(0.3)
#
Flux.testmode!
— Method
testmode!(model, inactive)
Этот метод с двумя аргументами предназначен преимущественно для внутреннего использования. Он выполняет рекурсию по model
, пока метод, например testmode!(d::Dropout, inactive)
, не изменит активность слоя. Пользовательские слои могут поддерживать переключение вручную между testmode!
и trainmode!
путем определения такого метода.
Возможные значения inactive
:
-
true
для тестирования, то естьactive=false
; -
false
для обучения; равносильно xref:./layers.adoc#Flux.trainmode!(m)
; -
:auto
илиnothing
для автоматического обнаружения обучения библиотекой Flux.
compat Этот метод может быть упразднен при внесении следующего критического изменения для отделения доступной пользователю функции testmode!
от внутренней рекурсии.
#
Flux.trainmode!
— Function
trainmode!(model) -> model
Переводит слой или все слои модели в режим обучения. Функция, обратная функции testmode!
. Дополнительные сведения см. в ее описании.
trainmode!(m, active)
Этот метод с двумя аргументами устарел. |
Возможные значения active
:
-
true
для обучения; -
false
для тестирования; равносильноtestmode!
(m)
; -
:auto
илиnothing
для автоматического обнаружения обучения библиотекой Flux.