Примитивы нейронной сети из NNlib.jl
Flux повторно экспортирует все функции, экспортируемые пакетом NNlib. В их число входят функции активации, описанные на этой странице. Многие из приведенных на этой странице функций существуют в основном в виде внутренней реализации слоя Flux, но могут использоваться и самостоятельно.
Внимание
Примитивы для слоя MultiHeadAttention
.
#
NNlib.dot_product_attention
— Function
dot_product_attention(query, key, value, [bias]; [fdrop, mask, nheads])
Внимание многоголового скалярного произведения, используемое в архитектурах трансформера.
Входные массивы должны иметь первые два измерения, задаваемые количеством признаков и длиной последовательности, затем произвольное количество пакетных измерений или ни одного.
Возвращает выходной массив внимания размером (v_dim, q_len, batch_size...)
и оценки внимания размером (kv_len, q_len, nheads, batch_size...)
.
Если вам нужны только оценки внимания, см. описание dot_product_attention_scores
.
Аргументы
-
query
: массив запросов размером(qk_dim, q_len, batch_size...)
. -
key
: массив ключей размером(qk_dim, kv_len, batch_size...)
. -
value
: массив значений размером(v_dim, kv_len, batch_size...)
. -
bias
: либоnothing
, либо массив, транслируемый в размер(kv_len, q_len, nheads, batch_size)
. Будет добавлен к оценкам внимания перед применением многопеременной логистической функции (softmax). Значение по умолчанию —nothing
. -
fdrop
: слой или функция предотвращения переобучения, которые будут применяться к оценкам внимания сразу после softmax. Значение по умолчанию —identity
(без предотвращения переобучения). -
mask
: либоnothing
, либо логический массив, транслируемый в размер(kv_len, q_len, nheads, batch_size)
. Маска применяется к оценкам внимания непосредственно перед softmax. См. описаниеmake_causal_mask
для создания причинных масок. Значение по умолчанию —nothing
. -
nheads
: количество голов, на которое будут разделены входные массивы. Значение по умолчанию —1
.
Примеры
q, k, v = rand(10, 20, 2), rand(10, 30, 2), rand(20, 30, 2)
y, α = dot_product_attention(q, k, v)
#
NNlib.dot_product_attention_scores
— Function
dot_product_attention_scores(query, key, [bias]; [fdrop, mask])
Возвращает оценки внимания для dot_product_attention
. Входные массивы должны иметь измерения (num_features ÷ nheads, nheads, sequence_length, batch_size)
.
Дополнительные сведения см. в документе dot_product_attention
.
#
NNlib.make_causal_mask
— Function
make_causal_mask(x, dims=2)
Возвращает логическую квадратную матрицу m
того же типа, что и x
, со стороной size(x, dims)
. Ее элементы заданы таким образом, что m[i, j] == i ≤ j
.
Можно использовать для маскирования оценок внимания в dot_product_attention
.
Многопеременная логистическая функция (softmax)
Flux.logitcrossentropy
во Flux
использует NNlib.logsoftmax
внутренним образом.
#
NNlib.softmax
— Function
softmax(x; dims = 1)
Softmax преобразует входной массив x
в распределения вероятностей, которые в сумме равны 1 по измерениям, указанным с помощью dims
. Функция семантически эквивалентна следующему:
softmax(x; dims = 1) = exp.(x) ./ sum(exp.(x), dims = dims)
с дополнительными операциями, повышающими численную устойчивость.
Для входа матрицы x
она по умолчанию (dims = 1
) будет рассматриваться как пакет векторов, каждый столбец которого независим. Ключевое слово dims = 2
будет рассматривать строки независимо друг от друга и так далее.
См. также описание logsoftmax
.
Примеры
julia> softmax([1, 2, 3])
3-element Vector{Float64}:
0.09003057317038046
0.24472847105479764
0.6652409557748218
julia> softmax([1 2 3; 2 2 2]) # dims=1
2×3 Matrix{Float64}:
0.268941 0.5 0.731059
0.731059 0.5 0.268941
julia> softmax([1 2 3; 2 2 2]; dims=2)
2×3 Matrix{Float64}:
0.0900306 0.244728 0.665241
0.333333 0.333333 0.333333
Обратите внимание, что при использовании Flux.jl softmax
нельзя передавать слоям типа Dense
, которые принимают функцию активации. Активация транслируется через результат, поэтому применяется к отдельным числам. Но softmax
всегда нужно видеть весь столбец.
julia> using Flux
julia> x = randn(Float32, 4, 4, 3, 13);
julia> model = Chain(Conv((4, 4), 3 => 8, tanh), Flux.flatten, Dense(8 => 7), softmax);
julia> model(x) |> size
(7, 13)
julia> Dense(4 => 7, softmax)(x)
ERROR: `softmax(x)` called with a number, but it expects an array.
#
NNlib.logsoftmax
— Function
logsoftmax(x; dims = 1)
Вычисляет логарифм softmax более численно устойчивым способом по сравнению с прямым взятием log.(softmax(xs))
. Обычно используется при вычислении потери перекрестной энтропии.
Функция семантически эквивалентна следующему:
logsoftmax(x; dims = 1) = x .- log.(sum(exp.(x), dims = dims))
См. также описание softmax
.
Подвыборка
AdaptiveMaxPool
, AdaptiveMeanPool
, GlobalMaxPool
, GlobalMeanPool
, MaxPool
и MeanPool
во Flux
используют NNlib.PoolDims
, NNlib.maxpool
и NNlib.meanpool
в качестве своего бэкенда.
#
NNlib.PoolDims
— Type
PoolDims(x_size::NTuple{M}, k::Union{NTuple{L, Int}, Int};
stride=k, padding=0, dilation=1) where {M, L}
Измерения для операции подвыборки, которая может иметь произвольный входной размер, размер ядра, количество шагов, растяжений и каналов. Используется для диспетчеризации эффективных реализаций во время компиляции.
#
NNlib.lpnormpool
— Function
lpnormpool(x, p::Real, k::NTuple{N, Integer}; pad=0, stride=k)
Выполняет операцию подвыборки Lp со значением Lp-нормы p
и размером окна k
на входном тензоре x
, также известную как LPPool в PyTorch. Этот оператор подвыборки взят из документа Learned-Norm Pooling for Deep Feedforward and Recurrent Neural Networks.
Аргументы
-
x
иk
: ожидаетndim(x) ∈ 3:5
length(k) == ndim(x) - 2`, and always
-
p
ограничен0 < p < Inf
. -
pad
: дополнительные сведения см. в описанииpad_zeros
. -
stride
: либо кортеж той же длины, что иk
, либо одно целое число для всех направлений. Значение по умолчанию —k
.
Для всех элементов x
в окне размером k
lpnormpool вычисляет (∑ᵢ xᵢ^p)^(1 / p)
как элемент вывода.
Таким образом, lpnormpool(x, 1, k) ./ prod(k) ≈ meanpool(x, k)
и lpnormpool(x, 2, k).^2 ./ prod(k) ≈ meanpool(x.^2, k)
.
#
NNlib.maxpool
— Function
maxpool(x, k::NTuple{N, Integer}; pad=0, stride=k)
Выполняет операцию подвыборки максимума с размером окна k
во входном тензоре x
.
Аргументы
-
x
иk
: ожидаетndim(x) ∈ 3:5
и всегдаlength(k) == ndim(x) - 2
. -
pad
: дополнительные сведения см. в описанииpad_zeros
. -
stride
: либо кортеж той же длины, что иk
, либо одно целое число для всех направлений. Значение по умолчанию —k
.
#
NNlib.meanpool
— Function
meanpool(x, k::NTuple{N, Integer}; pad=0, stride=k)
Выполняет операцию подвыборки среднего с размером окна k
во входном тензоре x
.
Аргументы
-
x
иk
: ожидаетndim(x) ∈ 3:5
length(k) == ndim(x) - 2`, and always
-
pad
: дополнительные сведения см. в описанииpad_zeros
. -
stride
: либо кортеж той же длины, что иk
, либо одно целое число для всех направлений. Значение по умолчанию —k
.
Заполнение
#
NNlib.pad_circular
— Function
pad_circular(x, pad::Tuple; [dims])
pad_circular(x, pad::Int; [dims])
Заполняет массив x
кругообразно через границу, заключая в оболочку значения с противоположной стороны x
.
pad
может быть кортежем целых чисел (l1, r1, ..., ln, rn)
некоторой длины 2n
, задающим размер левого и правого заполнения для каждого измерения в dims
. Если значение dims
не задано, по умолчанию используются первые n
измерений.
Если pad
является целым числом, он применяется к обеим сторонам каждого измерения в dims
. В данном случае для dims
по умолчанию используются первые ndims(x)-2
измерений (т. е. исключаются измерение канала и пакетное измерение).
Длина заполнения с каждой стороны в любом измерении не должна превышать размер x
в этом измерении, т. е. pad_circular
не может создавать мозаики произвольного размера x
.
См. также описание pad_repeat
, pad_reflect
, pad_symmetric
и pad_constant
.
julia> r = reshape(1:9, 3, 3)
3×3 reshape(::UnitRange{Int64}, 3, 3) with eltype Int64:
1 4 7
2 5 8
3 6 9
julia> pad_circular(r, (1,2,1,2))
6×6 Matrix{Int64}:
9 3 6 9 3 6
7 1 4 7 1 4
8 2 5 8 2 5
9 3 6 9 3 6
7 1 4 7 1 4
8 2 5 8 2 5
#
NNlib.pad_constant
— Function
pad_constant(x, pad::Tuple, val = 0; [dims = :])
pad_constant(x, pad::Int, val = 0; [dims = :])
Заполняет массив x
постоянным значением val
.
pad
может быть кортежем целых чисел. Если он имеет некоторую длину 2 * length(dims)
, которая задает размер левого и правого заполнения для каждого измерения в dims
в виде (l1, r1, ..., ln, rn)
. Если указан с кортежем длиной length(dims)
, применяется симметричное заполнение. Если значение dims
не задано, по умолчанию используются все измерения.
Если pad
является целым числом, он применяется к обеим сторонам каждого измерения в dims
.
См. также описание pad_zeros
, pad_repeat
, pad_reflect
, pad_symmetric
и pad_circular
.
julia> r = reshape(1:4, 2, 2)
2×2 reshape(::UnitRange{Int64}, 2, 2) with eltype Int64:
1 3
2 4
julia> pad_constant(r, (1, 2, 3, 4), 8)
5×9 Matrix{Int64}:
8 8 8 8 8 8 8 8 8
8 8 8 1 3 8 8 8 8
8 8 8 2 4 8 8 8 8
8 8 8 8 8 8 8 8 8
8 8 8 8 8 8 8 8 8
julia> pad_constant(r, 1, 8)
4×4 Matrix{Int64}:
8 8 8 8
8 1 3 8
8 2 4 8
8 8 8 8
julia> r = reshape(1:27, 3, 3, 3)
3×3×3 reshape(::UnitRange{Int64}, 3, 3, 3) with eltype Int64:
[:, :, 1] =
1 4 7
2 5 8
3 6 9
[:, :, 2] =
10 13 16
11 14 17
12 15 18
[:, :, 3] =
19 22 25
20 23 26
21 24 27
julia> pad_constant(r, (2,1), dims = 1) # ассиметричное заполнение
6×3×3 Array{Int64, 3}:
[:, :, 1] =
0 0 0
0 0 0
1 4 7
2 5 8
3 6 9
0 0 0
[:, :, 2] =
0 0 0
0 0 0
10 13 16
11 14 17
12 15 18
0 0 0
[:, :, 3] =
0 0 0
0 0 0
19 22 25
20 23 26
21 24 27
0 0 0
julia> pad_constant(r, (2,1, 3), dims = (1,2)) # заполнение всегда должно быть либо такой же длины, как измерения, либо в два раза больше
ERROR: ArgumentError: Could not parse padding (2, 1, 3) and dims (1, 2)
Stacktrace:
[...]
#
NNlib.pad_reflect
— Function
pad_reflect(x, pad::Tuple; [dims])
pad_reflect(x, pad::Int; [dims])
Заполняет массив x
, отражая его значения через границу.
pad
может быть кортежем целых чисел (l1, r1, ..., ln, rn)
некоторой длины 2n
, задающим размер левого и правого заполнения для каждого измерения в dims
. Если значение dims
не задано, по умолчанию используются первые n
измерений.
Если pad
является целым числом, он применяется к обеим сторонам каждого измерения в dims
. В данном случае для dims
по умолчанию используются первые ndims(x)-2
измерений (т. е. исключаются измерение канала и пакетное измерение).
См. также pad_repeat
, pad_symmetric
, pad_circular
и pad_constant
.
julia> r = reshape(1:9, 3, 3)
3×3 reshape(::UnitRange{Int64}, 3, 3) with eltype Int64:
1 4 7
2 5 8
3 6 9
julia> pad_reflect(r, (1,2,1,2))
6×6 Matrix{Int64}:
5 2 5 8 5 2
4 1 4 7 4 1
5 2 5 8 5 2
6 3 6 9 6 3
5 2 5 8 5 2
4 1 4 7 4 1
#
NNlib.pad_repeat
— Function
pad_repeat(x, pad::Tuple; [dims])
pad_repeat(x, pad::Int; [dims])
Заполняет массив x
, повторяя значения на границе.
pad
может быть кортежем целых чисел (l1, r1, ..., ln, rn)
некоторой длины 2n
, задающим размер левого и правого заполнения для каждого измерения в dims
. Если значение dims
не задано, по умолчанию используются первые n
измерений.
Если pad
является целым числом, он применяется к обеим сторонам каждого измерения в dims
. В данном случае для dims
по умолчанию используются первые ndims(x)-2
измерений (т. е. исключаются измерение канала и пакетное измерение).
См. также pad_reflect
, pad_symmetric
, pad_circular
и pad_constant
.
julia> r = reshape(1:9, 3, 3)
3×3 reshape(::UnitRange{Int64}, 3, 3) with eltype Int64:
1 4 7
2 5 8
3 6 9
julia> pad_repeat(r, (1,2,3,4))
6×10 Matrix{Int64}:
1 1 1 1 4 7 7 7 7 7
1 1 1 1 4 7 7 7 7 7
2 2 2 2 5 8 8 8 8 8
3 3 3 3 6 9 9 9 9 9
3 3 3 3 6 9 9 9 9 9
3 3 3 3 6 9 9 9 9 9
#
NNlib.pad_symmetric
— Function
pad_symmetric(x, pad::Tuple; [dims])
pad_symmetric(x, pad::Int; [dims])
Заполняет массив x
, симметрично отражая его значения через границу, т. е. граничные значения x
присутствуют в значениях заполнения, в отличие от pad_reflect
.
pad
может быть кортежем целых чисел (l1, r1, ..., ln, rn)
некоторой длины 2n
, задающим размер левого и правого заполнения для каждого измерения в dims
. Если значение dims
не задано, по умолчанию используются первые n
измерений.
Если pad
является целым числом, он применяется к обеим сторонам каждого измерения в dims
. В данном случае для dims
по умолчанию используются первые ndims(x)-2
измерений (т. е. исключаются измерение канала и пакетное измерение).
См. также pad_repeat
, pad_reflect
, pad_circular
и pad_constant
.
julia> r = reshape(1:9, 3, 3)
3×3 reshape(::UnitRange{Int64}, 3, 3) with eltype Int64:
1 4 7
2 5 8
3 6 9
julia> pad_symmetric(r, (1,2,1,2))
6×6 Matrix{Int64}:
1 1 4 7 7 4
1 1 4 7 7 4
2 2 5 8 8 5
3 3 6 9 9 6
3 3 6 9 9 6
2 2 5 8 8 5
#
NNlib.pad_zeros
— Function
pad_zeros(x, pad::Tuple; [dims])
pad_zeros(x, pad::Int; [dims])
Заполняет массив x
нулями. Эквивалентна pad_constant
с константой, равной 0.
Свертка
Слои Conv
и CrossCor
во Flux
используют NNlib.DenseConvDims
и NNlib.conv
внутренним образом.
#
NNlib.conv
— Function
conv(x, w; stride = 1, pad = 0, dilation = 1, flipped = false, groups = 1)
Применяет сверточный фильтр w
к входному x
. x
и w
являются трех-, четырех- и пятимерными тензорами в одно-, дву- и трехмерных свертках, соответственно. x
и w
могут иметь вещественные или комплексные типы элементов.
#
NNlib.ConvDims
— Type
ConvDims
Вводит информацию системного уровня об измерениях свертки. Имеет критически важное значение для таких вещей, как im2col!()
, чтобы генерировать эффективный код, и полезна для уменьшения количества передаваемых именованных аргументов.
#
NNlib.depthwiseconv
— Function
depthwiseconv(x, w; stride=1, pad=0, dilation=1, flipped=false)
Операция глубинной свертки с фильтром w
на входном x
. x
и w
являются трех-, четырех- и пятимерными тензорами в одно-, дву- и трехмерных свертках, соответственно.
#
NNlib.DepthwiseConvDims
— Type
DepthwiseConvDims
Конкретный подкласс ConvDims
для глубинной свертки. Отличается в первую очередь тем, что характеризуется Cin, Cmult, а не Cin, Cout. Рекомендуется использовать отдельно от DenseConvDims в первую очередь из-за различий в вычислении каналов.
#
NNlib.DenseConvDims
— Type
DenseConvDims
Конкретный подкласс ConvDims
для нормальной плотной двумерной или трехмерной свертки.
Прекращение переобучения
#
NNlib.dropout
— Function
dropout([rng], A, p; [dims])
Возвращает массив, в котором каждый элемент A
либо заменен нулем с вероятностью p
, либо умножен на 1/(1-p)
.
По умолчанию каждый массив обрабатывается независимо. С помощью ключевого слова dims=1
выбор осуществляется для каждого значения 1-го индекса, т. е. каждая строка матрицы либо нулевая, либо нет.
Необязательный первый аргумент представляет собой используемый генератор случайных чисел.
Примеры
julia> dropout(ones(2, 10), 0.2) 2×10 Matrix{Float64}: 1.25 1.25 0.0 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 1.25 0.0 1.25 1.25 0.0 1.25 1.25 1.25 julia> mean(dropout(ones(10^4, 5), 0.2), dims=1) 1×5 Matrix{Float64}: 0.998 1.00075 0.99125 0.99575 1.00075 julia> dropout(ones(5, 5), 0.7, dims=1) # вся строка та же 5×5 Matrix{Float64}: 3.33333 3.33333 3.33333 3.33333 3.33333 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 3.33333 3.33333 3.33333 3.33333 3.33333 0.0 0.0 0.0 0.0 0.0 julia> mean(dropout(ones(10^4, 5), 0.3, dims=1), dims=1) 1×5 Matrix{Float64}: 1.00571 1.00571 1.00571 1.00571 1.00571
Повышающая дискретизация
Слой Upsample
во Flux
использует NNlib.upsample_nearest
, NNlib.upsample_bilinear
и NNlib.upsample_trilinear
в качестве своего бэкенда. Кроме того, слой PixelShuffle
во Flux
использует NNlib.pixel_shuffle
в качестве своего бэкенда.
#
NNlib.upsample_nearest
— Function
upsample_nearest(x, scale::NTuple{S,Int})
upsample_nearest(x; size::NTuple{S,Int})
Повышает дискретизацию массива x
на целые кратные в первых S
измерениях. Последующие измерения x
не изменяются.
Можно указать либо множители scale
, либо конечный результат size
.
Кроме того, см. описание upsample_bilinear
со сведениями о двух измерениях массива N=4
.
Пример
julia> upsample_nearest([1 2 3; 4 5 6], (2, 3))
4×9 Matrix{Int64}:
1 1 1 2 2 2 3 3 3
1 1 1 2 2 2 3 3 3
4 4 4 5 5 5 6 6 6
4 4 4 5 5 5 6 6 6
julia> ans == upsample_nearest([1 2 3; 4 5 6]; size=(4, 9)) # эквивалентно
true
julia> upsample_nearest([1 2 3; 4 5 6], (2,))
4×3 Matrix{Int64}:
1 2 3
1 2 3
4 5 6
4 5 6
julia> ans == upsample_nearest([1 2 3; 4 5 6], size=(4,))
true
#
NNlib.upsample_linear
— Function
upsample_linear(x::AbstractArray{T,3}, scale::Real; align_corners::Bool = true)
upsample_linear(x::AbstractArray{T,3}; size::Integer, align_corners::Bool = true)
Повышает дискретизацию массива x
на величину, заданную scale
, с помощью линейной интерполяции. В качестве альтернативы использования scale
результирующий массив size
можно указать напрямую с помощью именованного аргумента.
Размер вывода равен (scale*S1, S2, S3)
, где S1, S2, S3 = size(x)
.
#
NNlib.∇upsample_linear
— Function
∇upsample_linear(Δ::AbstractArray{T,3}; size::Integer, align_corners::Bool = true) where T
Аргументы
-
Δ
: входящий массив градиентов, распространяющийся с нижележащих слоев в обратном направлении. -
size
: размер изображения, подвергнутого повышающей дискретизации в первую очередь.
Выводы
-
dx
: подвергнутая понижающей дискретизации версияΔ
.
#
NNlib.upsample_bilinear
— Function
upsample_bilinear(x::AbstractArray{T,4}, scale::NTuple{2,Real}; align_corners::Bool = true)
upsample_bilinear(x::AbstractArray{T,4}; size::NTuple{2,Integer}, align_corners::Bool = true)
Повышает дискретизацию первых двух измерений массива x
на коэффициенты повышения частоты дискретизации, хранящиеся в scale
, с помощью билинейной интерполяции. В качестве альтернативы использования scale
результирующее изображение size
можно указать напрямую с помощью именованного аргумента.
Размер вывода равен (scale[1]*S1, scale[2]*S2, S3, S4)
, где S1, S2, S3, S4 = size(x)
.
Примеры
julia> x = reshape(Float32[1 2 3; 4 5 6], (2,3,1,1))
2×3×1×1 Array{Float32, 4}:
[:, :, 1, 1] =
1.0 2.0 3.0
4.0 5.0 6.0
julia> upsample_bilinear(x, (2, 3))
4×9×1×1 Array{Float32, 4}:
[:, :, 1, 1] =
1.0 1.25 1.5 1.75 2.0 2.25 2.5 2.75 3.0
2.0 2.25 2.5 2.75 3.0 3.25 3.5 3.75 4.0
3.0 3.25 3.5 3.75 4.0 4.25 4.5 4.75 5.0
4.0 4.25 4.5 4.75 5.0 5.25 5.5 5.75 6.0
julia> ans == upsample_bilinear(x; size=(4, 9)) # укажите размер вывода
true
julia> upsample_bilinear(x, (2.5, 3.5)) # допускаются нецелочисленные масштабирующие множители
5×10×1×1 Array{Float32, 4}:
[:, :, 1, 1] =
1.0 1.22222 1.44444 1.66667 1.88889 … 2.33333 2.55556 2.77778 3.0
1.75 1.97222 2.19444 2.41667 2.63889 3.08333 3.30556 3.52778 3.75
2.5 2.72222 2.94444 3.16667 3.38889 3.83333 4.05556 4.27778 4.5
3.25 3.47222 3.69444 3.91667 4.13889 4.58333 4.80556 5.02778 5.25
4.0 4.22222 4.44444 4.66667 4.88889 5.33333 5.55556 5.77778 6.0
#
NNlib.∇upsample_bilinear
— Function
∇upsample_bilinear(Δ::AbstractArray{T,4}; size::NTuple{2,Integer}, align_corners::Bool = true) where T
Аргументы
-
Δ
: входящий массив градиентов, распространяющийся с нижележащих слоев в обратном направлении. -
size
: боковой (W,H) размер изображения, подвергнутого повышающей дискретизации в первую очередь.
Выводы
-
dx
: подвергнутая понижающей дискретизации версияΔ
.
#
NNlib.upsample_trilinear
— Function
upsample_trilinear(x::AbstractArray{T,5}, scale::NTuple{3,Real}; align_corners::Bool = true)
upsample_trilinear(x::AbstractArray{T,5}; size::NTuple{3,Integer}, align_corners::Bool = true)
Повышает дискретизацию первых трех измерений массива x
на коэффициенты повышения частоты дискретизации, хранящийся в scale
, с помощью трилинейной интерполяции. В качестве альтернативы использования scale
результирующее изображение size
можно указать напрямую с помощью именованного аргумента.
Размер вывода равен (scale[1]*S1, scale[2]*S2, scale[3]*S3, S4, S5)
, где S1, S2, S3, S4, S5 = size(x)
.
Примеры
upsample_trilinear(x, (2, 3, 4))
upsample_trilinear(x; size=(4, 9, 11)) # укажите размер вывода
upsample_trilinear(x, (2.5, 3.5, pi)) # допускаются нецелочисленные масштабирующие множители
#
NNlib.∇upsample_trilinear
— Function
∇upsample_trilinear(Δ::AbstractArray{T,5}; size::NTuple{3,Integer}, align_corners::Bool = true) where T
Аргументы
-
Δ
: входящий массив градиентов, распространяющийся с нижележащих слоев в обратном направлении. -
size
: боковой размер и глубина (W,H,D) изображения, подвергнутого повышающей дискретизации в первую очередь.
Выводы
-
dx
: подвергнутая понижающей дискретизации версияΔ
.
#
NNlib.pixel_shuffle
— Function
pixel_shuffle(x, r::Integer)
Операция перестановки пикселей, повышение масштаба на коэффициент r
.
Для четырехмерных массивов, представляющих N
изображение, операция преобразует входной size(x) == (W, H, r^2*C, N)
в вывод размером (r*W, r*H, C, N)
. Для D
-мерных данных она ожидает ndims(x) == D+2
с измерениями канала и пакета и делит количество каналов на r^D
.
Используется в сетях с суперразрешением для повышения дискретизации до высокого разрешения. Справка: Shi et. al., Real-Time Single Image and Video Super-Resolution …, CVPR 2016, https://arxiv.org/abs/1609.05158
Примеры
julia> x = [10i + j + channel/10 for i in 1:2, j in 1:3, channel in 1:4, batch in 1:1]
2×3×4×1 Array{Float64, 4}:
[:, :, 1, 1] =
11.1 12.1 13.1
21.1 22.1 23.1
[:, :, 2, 1] =
11.2 12.2 13.2
21.2 22.2 23.2
[:, :, 3, 1] =
11.3 12.3 13.3
21.3 22.3 23.3
[:, :, 4, 1] =
11.4 12.4 13.4
21.4 22.4 23.4
julia> pixel_shuffle(x, 2) # 4 канала используются для 2-кратного увеличения измерений изображения
4×6×1×1 Array{Float64, 4}:
[:, :, 1, 1] =
11.1 11.3 12.1 12.3 13.1 13.3
11.2 11.4 12.2 12.4 13.2 13.4
21.1 21.3 22.1 22.3 23.1 23.3
21.2 21.4 22.2 22.4 23.2 23.4
julia> y = [i + channel/10 for i in 1:3, channel in 1:6, batch in 1:1]
3×6×1 Array{Float64, 3}:
[:, :, 1] =
1.1 1.2 1.3 1.4 1.5 1.6
2.1 2.2 2.3 2.4 2.5 2.6
3.1 3.2 3.3 3.4 3.5 3.6
julia> pixel_shuffle(y, 2) # одномерное изображение, в котором 6 каналов сокращены до 3
6×3×1 Array{Float64, 3}:
[:, :, 1] =
1.1 1.3 1.5
1.2 1.4 1.6
2.1 2.3 2.5
2.2 2.4 2.6
3.1 3.3 3.5
3.2 3.4 3.6
Пакетные операции
Слой Flux.Bilinear
во Flux
использует NNlib.batched_mul
внутренним образом.
#
NNlib.batched_mul
— Function
batched_mul(A, B) -> C
A ⊠ B # \boxtimes
Пакетное умножение матриц. В результате имеем C[:,:,k...] == A[:,:,k...] * B[:,:,k...]
, где k...
представляет любые индексы в последних измерениях.
Если ndims(A) == ndims(B) == 3
и size(B,3) == 1
, то вместо C[:,:,k] == A[:,:,k] * B[:,:,1]
и аналогично для A
.
Чтобы транспонировать каждую матрицу, примените batched_transpose
к массиву, или batched_adjoint
для сопряженного транспонирования:
julia> A, B = randn(2,5,17), randn(5,9,17);
julia> A ⊠ B |> size
(2, 9, 17)
julia> batched_adjoint(A) |> size
(5, 2, 17)
julia> batched_mul(A, batched_adjoint(randn(9,5,17))) |> size
(2, 9, 17)
julia> A ⊠ randn(5,9,1) |> size
(2, 9, 17)
julia> batched_transpose(A) == PermutedDimsArray(A, (2,1,3))
true
Вместо batched_transpose
можно использовать эквивалентный PermutedDimsArray
. Другие перестановки также обрабатываются BLAS при условии, что пакетный индекс k
не является первым измерением базового массива. Таким образом, PermutedDimsArray(::Array, (1,3,2))
и PermutedDimsArray(::Array, (3,1,2))
вполне подходят.
Однако A = PermutedDimsArray(::Array, (3,2,1))
неприемлемо для BLAS, поскольку пакетное измерение является непрерывным: stride(A,3) == 1
. Это будет скопировано, так как это быстрее, чем выполнение batched_mul_generic!
.
И copy
, и batched_mul_generic!
выдают сообщения @debug
, и при задании, например, ENV["JULIA_DEBUG"] = NNlib
они будут выведены на экран.
batched_mul(A::Array{T,3}, B::Matrix) batched_mul(A::Matrix, B::Array{T,3}) A ⊠ B
Это всегда умножение матрицы на матрицу, но у A
или B
может отсутствовать индекс пакета.
-
Если
B
является матрицей, результат имеет видC[:,:,k] == A[:,:,k] * B[:,:]
для всехk
. -
Если
A
является матрицей, тоC[:,:,k] == A[:,:] * B[:,:,k]
. Это также можно сделать, изменив форму и вызвав*
, напримерA ⊡ B
, используя TensorCore.jl, но здесь это реализовано с помощьюbatched_gemm
вместоgemm
.
julia> randn(16,8,32) ⊠ randn(8,4) |> size
(16, 4, 32)
julia> randn(16,8,32) ⊠ randn(8,4,1) |> size # эквивалентно
(16, 4, 32)
julia> randn(16,8) ⊠ randn(8,4,32) |> size
(16, 4, 32)
См. также описание batched_vec
, где B
рассматривается как пакет векторов A[:,:,k] * B[:,k]
.
#
NNlib.batched_mul!
— Function
batched_mul!(C, A, B) -> C
batched_mul!(C, A, B, α=1, β=0)
Пакетное умножение матриц на месте, функция эквивалентна mul!(C[:,:,k], A[:,:,k], B[:,:,k], α, β)
для всех k
. Если size(B,3) == 1
, каждый пакет использует B[:,:,1]
.
При любой возможности будет вызываться batched_gemm!
. Для вещественных массивов это означает, что для X ∈ [A,B,C]
либо strides(X,1)==1
, либо strides(X,2)==1
. Последнее может быть вызвано с помощью batched_transpose
или с помощью PermutedDimsArray(::Array, (3,1,2))
, к примеру. В отличие от batched_mul
, функция никогда не будет создавать копию.
Для сложных массивов оболочка, созданная с помощью batched_adjoint
, должна быть самой дальней, чтобы ее можно было увидеть. В этом случае принимаемые BLAS массивы с заданным шагом более ограничены, если stride(C,1)==1
, принимается только stride(AorB::BatchedAdjoint,2) == 1
.
#
NNlib.batched_adjoint
— Function
batched_transpose(A::AbstractArray{T,3})
batched_adjoint(A)
Эквивалентна применению транспонирования (transpose
) или сопряжения (adjoint
) к каждой матрице A[:,:,k]
.
Они существуют для того, чтобы контролировать поведение функции batched_mul
, поскольку она работает с такими матричными срезами массива, где ndims(A)==3
.
PermutedDimsArray(A, (2,1,3))
эквивалентен batched_transpose(A)
и также понятен для batched_mul
(и более широко поддерживается в других местах).
BatchedTranspose{T, S} <: AbstractBatchedMatrix{T, 3} BatchedAdjoint{T, S}
Ленивые оболочки, аналогичные Transpose
и Adjoint
, возвращаемые batched_transpose
и т. д.
#
NNlib.batched_transpose
— Function
batched_transpose(A::AbstractArray{T,3})
batched_adjoint(A)
Эквивалентна применению транспонирования (transpose
) или сопряжения (adjoint
) к каждой матрице A[:,:,k]
.
Они существуют для того, чтобы контролировать поведение функции batched_mul
, поскольку она работает с такими матричными срезами массива, где ndims(A)==3
.
PermutedDimsArray(A, (2,1,3))
эквивалентен batched_transpose(A)
и также понятен для batched_mul
(и более широко поддерживается в других местах).
BatchedTranspose{T, S} <: AbstractBatchedMatrix{T, 3} BatchedAdjoint{T, S}
Ленивые оболочки, аналогичные Transpose
и Adjoint
, возвращаемые batched_transpose
и т. д.
#
NNlib.batched_vec
— Function
batched_vec(A::Array{T,3}, B::Matrix)
batched_vec(A::Array{T,3}, b::Vector)
Пакетное матрично-векторное умножение: результат имеет вид C[:,:,k] == A[:,:,k] * B[:,k]
для всех k
, или же C[:,:,k] == A[:,:,k] * b
для b::Vector
.
При тех же типах аргументов batched_mul(A, B)
будет рассматривать B
как фиксированную матрицу, а не как пакет векторов. Изменяет форму, а затем вызывает batched_mul(::Array{T,3}, ::Array{T,3})
.
julia> A, B, b = randn(16,8,32), randn(8,32), randn(8);
julia> batched_vec(A,B) |> size
(16, 32)
julia> batched_vec(A,b) |> size
(16, 32)
Дефрагментация и фрагментация
Слой Flux
во Embedding
использует NNlib.gather
в качестве своего бэкенда.
#
NNlib.gather
— Function
NNlib.gather(src, idx) -> dst
Операция, обратная scatter
. Собирает данные из источника src
и записывает их в место назначения dst
в соответствии с массивом индексов idx
. Для каждого k
в CartesianIndices(idx)
присваивает значения dst
в соответствии со следующим выражением:
dst[:, ... , k] .= src[:, ... , idx[k]...]
Обратите внимание, что если idx
— это вектор, содержащий целые числа, а src
является матрицей, предыдущее выражение упрощается до следующего
dst[:, k] .= src[:, idx[k]]
и k
будет превышать 1:length(idx)
.
Элементы idx
могут быть целыми числами или кортежами целых чисел и могут повторяться. Один столбец src
может быть скопирован в ноль, один или несколько столбцов dst
.
См. описание gather!
со сведениями о версии на месте.
Примеры
julia> NNlib.gather([1,20,300,4000], [2,4,2])
3-element Vector{Int64}:
20
4000
20
julia> NNlib.gather([1 2 3; 4 5 6], [1,3,1,3,1])
2×5 Matrix{Int64}:
1 3 1 3 1
4 6 4 6 4
gather(src, IJK...)
Преобразует кортеж целочисленных векторов IJK
в кортеж CartesianIndex
и вызывает gather
для него: gather(src, CartesianIndex.(IJK...))
.
Примеры
julia> src = reshape([1:15;], 3, 5)
3×5 Matrix{Int64}:
1 4 7 10 13
2 5 8 11 14
3 6 9 12 15
julia> NNlib.gather(src, [1, 2], [2, 4])
2-element Vector{Int64}:
4
11
#
NNlib.gather!
— Function
NNlib.gather!(dst, src, idx)
Операция, обратная scatter!
. Собирает данные из источника src
и записывает их в место назначения dst
в соответствии с массивом индексов idx
. Для каждого k
в CartesianIndices(idx)
присваивает значения dst
в соответствии со следующим выражением:
dst[:, ... , k] .= src[:, ... , idx[k]...]
Обратите внимание, что если idx
— это вектор, содержащий целые числа, а dst
и src
являются матрицами, предыдущее выражение упрощается до следующего
dst[:, k] .= src[:, idx[k]]
и k
будет превышать 1:length(idx)
.
Элементы idx
могут быть целыми числами или кортежами целых чисел и могут повторяться. Один столбец src
может быть скопирован в ноль, один или несколько столбцов dst
.
См. описание gather
со сведениями о выделяющей версии.
#
NNlib.scatter
— Function
NNlib.scatter(op, src, idx; [init, dstsize])
Операция фрагментации, выделяющая целевой массив dst
и вызывающая для него scatter!(op, dst, src, idx)
.
-
Если указано ключевое слово
init
, оно используется для инициализации содержимогоdst
. В противном случае значения инициализации выводятся из оператора редукцииop
для некоторых общих операторов (например,init = 0
дляop = +
). -
Если указано значение
dstsize
, оно будет использоваться для определения размера массива назначения, в противном случае он будет определяться поsrc
иidx
.
Подробные сведения о работе idx
см. в описании scatter!
.
Примеры
julia> NNlib.scatter(+, [10,100,1000], [3,1,2])
3-element Vector{Int64}:
100
1000
10
julia> NNlib.scatter(+, [1 2 3 4; 5 6 7 8], [2,1,1,5])
2×5 Matrix{Int64}:
5 1 0 0 4
13 5 0 0 8
julia> NNlib.scatter(*, [10,200,3000], [1,4,2]; init = 10, dstsize = 6)
6-element Vector{Int64}:
100
30000
10
2000
10
10
#
NNlib.scatter!
— Function
NNlib.scatter!(op, dst, src, idx)
Операция фрагментации, которая записывает данные из источника (src
) в место назначения (dst
) в расположениях индексов (idx
). Во время фрагментации применяется бинарный оператор редукции op
. Для каждого индекса k
в idx
накапливает значения в dst
в соответствии со следующим выражением:
dst[:, ..., idx[k]...] = (op).(dst[:, ..., idx[k]...], src[:, ..., k...])
Аргументы
-
op
: операции, применяемые кdst
иsrc
, например+
,-
,*
,/
,max
,min
иmean
. -
dst
: место назначенияsrc
для агрегирования. Этот аргумент будет изменен. -
src
: исходные данные для агрегирования. -
idx
: сопоставление для агрегирования из источника (индекс) в место назначения (значение). Массивidx
может содержать либо целые числа, либо кортежи.
Примеры
julia> NNlib.scatter!(+, ones(3), [10,100], [1,3])
3-element Vector{Float64}:
11.0
1.0
101.0
julia> NNlib.scatter!(*, fill(0.5, 2, 4), [1 10; 100 1000], [3,2])
2×4 Matrix{Float64}:
0.5 5.0 0.5 0.5
0.5 500.0 50.0 0.5
Дискретизация
#
NNlib.grid_sample
— Function
grid_sample(input::AbstractArray{T, 4}, grid::AbstractArray{T, 4}; padding_mode = :zeros)
При заданных входных данных (input
) вычисляет вывод выборки входных (input
) значения путем в местах расположения пикселей из сетки (grid
). Использует билинейную интерполяцию для вычисления выходных значений.
В данной реализации предполагается, что экстремумы (-1
и 1
) относятся к центральным точкам угловых пикселей входного изображения (т. е. выравнивание углов имеет значение true
).
Аргументы
-
input
: входной массив в форме(W_in, H_in, C, N)
. -
grid
: входная сетка в форме(2, W_out, H_out, N)
. Где для каждой формы(W_out, H_out, N)
сетка содержит координаты(x, y)
, которые определяют места выборки, нормализованные по формеinput
.Таким образом,
x
иy
должны иметь значения в диапазоне[-1, 1]
. Например,(x = -1, y = -1)
— это левый верхний пиксель входного изображения (input
), а(x = 1, y = 1)
— правый нижний пиксель входного изображения (input
).Выходящие за границы значения обрабатываются в соответствии с режимом
padding_mode
. -
padding_mode
: заполнение за границами.:zeros
чтобы использовать0
для мест, расположенных за пределами сетки.:border
чтобы использовать граничные значения для мест, расположенных за пределами сетки. Значение по умолчанию —:zeros
.
Возвращаемые значения
Сетка с выборкой (W_out, H_out, C, N)
из входных данных (input
).
Примеры
В приведенном ниже примере сетка содержит два выходящих за границы расположения выборки, которые обрабатываются по-разному в зависимости от padding_mode
.
julia> x = reshape(collect(1.0:4.0), (2, 2, 1, 1))
2×2×1×1 Array{Float64, 4}:
[:, :, 1, 1] =
1.0 3.0
2.0 4.0
julia> grid = Array{Float64}(undef, 2, 3, 2, 1);
julia> grid[:, 1, 1, 1] .= (-3, -1);
julia> grid[:, 2, 1, 1] .= (0, -1);
julia> grid[:, 3, 1, 1] .= (1, -1);
julia> grid[:, 1, 2, 1] .= (-1, 1);
julia> grid[:, 2, 2, 1] .= (0, 1);
julia> grid[:, 3, 2, 1] .= (3, 1);
julia> grid_sample(x, grid; padding_mode=:zeros)
3×2×1×1 Array{Float64, 4}:
[:, :, 1, 1] =
0.0 3.0
1.5 3.5
2.0 0.0
julia> grid_sample(x, grid; padding_mode=:border)
3×2×1×1 Array{Float64, 4}:
[:, :, 1, 1] =
1.0 3.0
1.5 3.5
2.0 4.0
#
NNlib.∇grid_sample
— Function
∇grid_sample(Δ::AbstractArray{T, 4}, input::AbstractArray{T, 4}, grid::AbstractArray{T, 4}; padding_mode = :zeros) where T
Аргументы
-
Δ
: входной градиент в форме(W_out, H_out, C, N)
(то же самое, что и результат первичного вычисления). -
input
: входные данные из первичного вычисления в форме(W_in, H_in, C, N)
. -
grid
: сетка из первичного вычисления в форме(2, W_out, H_out, N)
. -
padding_mode
: заполнение за границами.:zeros
чтобы использовать0
для мест, расположенных за пределами сетки.:border
чтобы использовать граничные значения для мест, расположенных за пределами сетки. Должно быть таким же, как и при первичном вычислении. Значение по умолчанию —:zeros
.
Возвращаемые значения
Градиенты dinput
(той же формы, что и input
) и dgrid
(той же формы, что и grid
).
Потери
#
NNlib.ctc_loss
— Function
ctc_loss(ŷ, y)
Вычисляет потери временной классификации на основе связей между ŷ
и y
. ŷ
должны быть матрицами классов и времени, т. е. каждая строка представляет класс, а каждый столбец — временной шаг. Кроме того, к ŷ
будет применена функция logsoftmax
, поэтому ŷ
должны быть необработанными значениями активации нейронной сети, а не, например, активациями, переданными через функцию активации softmax
. y
должен быть одномерным массивом меток, связанным с ŷ
. Предполагается, что пустая метка является последней категорией меток в ŷ
, поэтому она эквивалентна size(ŷ, 1)
. Используется для решения задач классификации последовательности в последовательность, таких как распознавание речи и распознавание рукописного ввода, где для решения задачи не требуется точное выравнивание по времени выходных данных (например, букв). См. Graves et al.https://www.cs.toronto.edu/graves/icml_2006.pdf[]https://www.cs.toronto.edu/graves/icml_2006.pdf[(2006)] или Graves (2012) с описанием математических подробностей.
Прочее
#
NNlib.logsumexp
— Function
logsumexp(x; dims = :)
Вычисляет log.(sum(exp.(x); dims))
численно устойчивым способом. Без ключевого слова dims
возвращается скаляр.
См. также описание logsoftmax
.
#
NNlib.glu
— Function
glu(x, dim = 1)
Управляемый линейный блок из статьи Language Modeling with Gated Convolutional Networks.
Вычисляет a .* sigmoid(b)
, где x
делится пополам в заданном измерении dim
, образуя a
и b
.