Документация Engee

Инициализация произвольных весов

Flux инициализирует сверточные слои и рекуррентные ячейки с помощью функции glorot_uniform по умолчанию. Большинство слоев принимают функцию в качестве ключевого слова init, которое заменяет это значение по умолчанию. Например:

julia> conv = Conv((3, 3), 3 => 2, relu; init=Flux.glorot_normal)
Conv((3, 3), 3 => 2, relu)  # 56 параметров

julia> conv.bias
2-element Vector{Float32}:
 0.0
 0.0

Обратите внимание, что init создает массив весов, но не вектор отклонения.

Многие функции инициализации принимают ключевые слова, такие как gain, а также генератор случайных чисел. Чтобы было проще передавать их слоям, существуют методы, которые возвращают функцию:

julia> Dense(4 => 5, tanh; init=Flux.glorot_uniform(gain=2))
Dense(4 => 5, tanh)  # 25 параметров

julia> Dense(4 => 5, tanh; init=Flux.randn32(MersenneTwister(1)))
Dense(4 => 5, tanh)  # 25 параметров

Функции инициализации

# Flux.glorot_uniformFunction

glorot_uniform([rng], size...; gain = 1) -> Array
glorot_uniform([rng]; kw...) -> Function

Возвращает массив Array{Float32} указанного размера size, содержащий случайные числа из равномерного распределения в интервале ], где x = gain * sqrt(6 / (fan_in + fan_out)).

Этот метод описан в работе [1] и также известен как инициализация Ксавье.

Примеры

julia> Flux.glorot_uniform(3, 4) |> summary
"3×4 Matrix{Float32}"

julia> round.(extrema(Flux.glorot_uniform(10, 100)), digits=3)
(-0.232f0, 0.234f0)

julia> round.(extrema(Flux.glorot_uniform(100, 10)), digits=3)
(-0.233f0, 0.233f0)

julia> round.(extrema(Flux.glorot_uniform(100, 100)), digits=3)
(-0.173f0, 0.173f0)

julia> Dense(3 => 2, tanh; init = Flux.glorot_uniform(MersenneTwister(1)))
Dense(3 => 2, tanh)  # 8 параметров

julia> ans.bias
2-element Vector{Float32}:
 0.0
 0.0

Ссылки

[1] Глоро (Glorot), Ксавье (Xavier) и Йошуа Бенжио (Yoshua Bengio). Understanding the difficulty of training deep feedforward neural networks. Материалы тринадцатой международной конференции по вопросам искусственного интеллекта и статистики. 2010 г.

# Flux.glorot_normalFunction

glorot_normal([rng], size...; gain = 1) -> Array
glorot_normal([rng]; kw...) -> Function

Возвращает массив Array{Float32} указанного размера size, содержащий случайные числа из нормального распределения со среднеквадратичным отклонением gain * sqrt(2 / (fan_in + fan_out)), с использованием функции nfan.

Этот метод описан в работе [1] и также известен как инициализация Ксавье.

Примеры

julia> using Statistics

julia> round(std(Flux.glorot_normal(10, 1000)), digits=3)
0.044f0

julia> round(std(Flux.glorot_normal(1000, 10)), digits=3)
0.044f0

julia> round(std(Flux.glorot_normal(1000, 1000)), digits=3)
0.032f0

julia> Dense(10 => 1000, tanh; init = Flux.glorot_normal(gain=100))
Dense(10 => 1000, tanh)  # 11_000 параметров

julia> round(std(ans.weight), sigdigits=3)
4.45f0

Ссылки

[1] Глоро (Glorot), Ксавье (Xavier) и Йошуа Бенжио (Yoshua Bengio). Understanding the difficulty of training deep feedforward neural networks. Материалы тринадцатой международной конференции по вопросам искусственного интеллекта и статистики. 2010 г.

# Flux.kaiming_uniformFunction

kaiming_uniform([rng], size...; gain = √2) -> Array
kaiming_uniform([rng]; kw...) -> Function

Возвращает массив Array{Float32} указанного размера size, содержащий случайные числа из равномерного распределения в интервале [-x, x], где x = gain * sqrt(3/fan_in), с использованием функции nfan.

Этот метод описан в работе [1] и также известен как инициализация Хе.

Примеры

julia> round.(extrema(Flux.kaiming_uniform(100, 10)), digits=3)
(-0.774f0, 0.774f0)

julia> round.(extrema(Flux.kaiming_uniform(10, 100)), digits=3)
(-0.245f0, 0.244f0)

julia> round.(extrema(Flux.kaiming_uniform(100, 100)), digits=3)
(-0.245f0, 0.245f0)

Ссылки

[1] Кайминг Хе (Kaiming He) и др. Delving deep into rectifiers: Surpassing human-level performance on imagenet classification. Материалы международной конференции IEEE по вопросам компьютерного зрения. 2015 г.

# Flux.kaiming_normalFunction

kaiming_normal([rng], size...; gain = √2) -> Array
kaiming_normal([rng]; kw...) -> Function

Возвращает массив Array{Float32} указанного размера size, содержащий случайные числа из нормального распределения со среднеквадратичным отклонением gain / sqrt(fan_in), с использованием функции nfan.

Этот метод описан в работе [1] и также известен как инициализация Хе.

Примеры

julia> using Statistics

julia> round(std(Flux.kaiming_normal(10, 1000)), digits=3)
0.045f0

julia> round(std(Flux.kaiming_normal(1000, 10)), digits=3)
0.447f0

julia> round(std(Flux.kaiming_normal(1000, 1000)), digits=3)
0.045f0

Ссылки

[1] Кайминг Хе (Kaiming He) и др. Delving deep into rectifiers: Surpassing human-level performance on imagenet classification. Материалы международной конференции IEEE по вопросам компьютерного зрения. 2015 г.

# Flux.truncated_normalFunction

truncated_normal([rng], size...; mean = 0, std = 1, lo = -2, hi = 2) -> Array
truncated_normal([rng]; kw...) -> Function

Возвращает массив Array{Float32} указанного размера size, каждый элемент которого берется из усеченного нормального распределения. Распределение чисел подчиняется условиям filter(x -> lo<=x<=hi, mean .+ std .* randn(100)).

Значения генерируются путем выборки из Uniform(0, 1) (rand()) с последующим применением обратной интегральной функции распределения усеченного нормального распределения. Этот метод лучше всего работает при lo ≤ mean ≤ hi.

Примеры

julia> using Statistics

julia> Flux.truncated_normal(3, 4) |> summary
"3×4 Matrix{Float32}"

julia> round.(extrema(Flux.truncated_normal(10^6)); digits=3)
(-2.0f0, 2.0f0)

julia> round(std(Flux.truncated_normal(10^6; lo = -100, hi = 100)))
1.0f0

# Flux.orthogonalFunction

orthogonal([rng], size...; gain = 1) -> Array
orthogonal([rng]; kw...) -> Function

Возвращает массив Array{Float32} указанного размера size, представляющий собой (полу-) ортогональную матрицу, как описано в работе [1].

Создать вектор невозможно, то есть значение length(size) == 1 запрещено. Для length(size) > 2 сначала вычисляется ортогональная матрица prod(size[1:(end - 1)]) на size[end], которая затем приводится к исходным измерениям.

Примеры

julia> W = Flux.orthogonal(5, 7);

julia> summary(W)
"5×7 Matrix{Float32}"

julia> W * W' ≈ I(5)
true

julia> W2 = Flux.orthogonal(7, 5);

julia> W2 * W2' ≈ I(7)
false

julia> W2' * W2 ≈ I(5)
true

julia> W3 = Flux.orthogonal(3, 3, 2, 4);

julia> transpose(reshape(W3, :, 4)) * reshape(W3, :, 4) ≈ I(4)
true

Ссылки

[1] Сакс (Saxe), Макклелланд (McClelland), Гангули (Ganguli). Exact solutions to the nonlinear dynamics of learning in deep linear neural networks, ICLR 2014 г., https://arxiv.org/abs/1312.6120

# Flux.sparse_initFunction

sparse_init([rng], rows, cols; sparsity, std = 0.01) -> Array
sparse_init([rng]; kw...) -> Function

Возвращает матрицу Matrix{Float32} размера rows, cols, каждый столбец которой содержит фиксированную долю нулевых элементов, заданных с помощью sparsity. Ненулевые элементы имеют нормальное распределение с нулевым средним значением и среднеквадратичным отклонением std.

Этот метод описан в работе [1].

Примеры

julia> count(iszero, Flux.sparse_init(10, 10, sparsity=1/5))
20

julia> sum(0 .== Flux.sparse_init(10, 11, sparsity=0.9), dims=1)
1×11 Matrix{Int64}:
 9  9  9  9  9  9  9  9  9  9  9

julia> Dense(3 => 10, tanh; init=Flux.sparse_init(sparsity=0.5))
Dense(3 => 10, tanh)  # 40 параметров

julia> count(iszero, ans.weight, dims=1)
1×3 Matrix{Int64}:
 5  5  5

Ссылки

[1] Дж. Мартенс (J Martens), Deep learning via Hessian-free optimization. Материалы 27-й международной конференции по вопросам машинного обучения. 2010 г.

# Flux.identity_initFunction

identity_init(size...; gain=1, shift=0) -> Array
identity_init(; kw...) -> Function

Возвращает массив Array{Float32} указанного размера size, который выдает тождественное отображение при использовании в качестве параметров в большинстве слоев Flux. Для масштабирования тождественности по константе используйте gain.

Эта функция часто бывает полезна в контексте переноса обучения, когда нужно увеличить емкость модели, начав с того же отображения.

Работает следующим образом:

  • одно измерение: вектор (Vector) нулевых значений (zeros) (полезен для смещения тождественности);

  • два измерения: матрица тождественности (полезна для умножения матрицы тождественности);

  • более двух измерений: плотный блочный массив пространственных фильтров средних отводов (полезен для свертки тождественности).

Особенности:

  • Не все слои будут представлять собой тождественное отображение при использовании с этим методом инициализации. К исключениям относятся рекуррентные слои и слои нормализации.

  • Слои должны отвечать условию input_size == output_size, чтобы тождественное отображение было возможным. Если это не так, лишние измерения массива заполняются нулями.

  • Для сверточных слоев, помимо указанной выше особенности, размеры ядер должны быть нечетными и должно применяться заполнение, чтобы выходные карты признаков имели тот же размер, что и входные. Для этого может применяться, например, SamePad.

Для применения циклического сдвига к выходу используйте ключевое слово shift (целое число или кортеж), что эквивалентно Base.circshift(identity_init(size...), shift).

Для согласованности с другими инциализаторами эта функция принимает rng::AbstractRNG в качестве необязательного первого аргумента. Однако он игнорируется, так как результат не является случайным.

Примеры

julia> Flux.identity_init(3,5)
3×5 Matrix{Float32}:
 1.0  0.0  0.0  0.0  0.0
 0.0  1.0  0.0  0.0  0.0
 0.0  0.0  1.0  0.0  0.0

julia> Dense(5 => 3, relu, init=Flux.identity_init)([1,-2,3,-4,5])
3-element Vector{Float32}:
 1.0
 0.0
 3.0

julia> Flux.identity_init(3,3,2; gain=100)
3×3×2 Array{Float32, 3}:
[:, :, 1] =
   0.0  0.0  0.0
 100.0  0.0  0.0
   0.0  0.0  0.0

[:, :, 2] =
 0.0    0.0  0.0
 0.0  100.0  0.0
 0.0    0.0  0.0

julia> x4 = cat([1 2 3; 4 5 6; 7 8 9]; dims=4);

julia> Conv((2,2), 1 => 1, init=Flux.identity_init(gain=10), pad=SamePad())(x4)
3×3×1×1 Array{Float32, 4}:
[:, :, 1, 1] =
 10.0  20.0  30.0
 40.0  50.0  60.0
 70.0  80.0  90.0

# Flux.ones32Function

ones32(size...) = ones(Float32, size...)

Возвращает массив Array{Float32} указанного размера size, заполненный единицами.

# Flux.zeros32Function

zeros32(size...) = zeros(Float32, size...)

Возвращает массив Array{Float32} указанного размера size, заполненный нулями.

# Flux.rand32Function

rand32([rng], size...)

Возвращает массив Array{Float32} указанного размера size, заполненный случайными значениями (rand). Если размер не указан, rand32(rng::AbstractRNG) возвращает функцию.

# Flux.randn32Function

randn32([rng], size...)

Возвращает массив Array{Float32} указанного размера size, заполненный случайными значениями (randn). Если размер не указан, randn32(rng::AbstractRNG) возвращает функцию.

# Flux.create_biasFunction

create_bias(weights, bias, size...)

Возвращает параметр смещения для слоя на основе значения, переданного в ключевом слове конструктора bias=bias.

  • При значении bias == true создается обучаемый массив указанного размера того же типа, что и weights, инициализированный с нулевыми значениями.

  • При значении bias == false возвращается false, что механизм автоматического дифференцирования распознает как невозможность дифференцирования.

  • При bias::AbstractArray используется предоставленный массив, если он имеет правильный размер. Кроме того, eltype изменяется в соответствии с типом элементов weights.

Эти функции вызывают:

# Flux.rng_from_arrayFunction

rng_from_array(x)

Создает экземпляр генератора случайных чисел, наиболее подходящего для x. Текущие значения по умолчанию:

  • x isa CuArray: CUDA.default_rng()

  • x isa AbstractArray: `Random.default_rng()

# Flux.nfanFunction

nfan(n_out, n_in=1) -> Tuple
nfan(dims...)
nfan(dims::Tuple)

Для слоя, характеризуемого измерениями dims, возвращает кортеж (fan_in, fan_out), где fan_in — это число входных нейронов, связанных с выходным, а fan_out — число выходных нейронов, связанных с входным.

Эта функция используется в основном инициализаторами весов, например kaiming_normal.

Примеры

julia> layer = Dense(10, 20);

julia> Flux.nfan(size(layer.weight))
(10, 20)

julia> layer = Conv((3, 3), 2=>10);

julia> Flux.nfan(size(layer.weight))
(18, 90)

Изменение типа всех параметров

Типом элемента (eltype) по умолчанию для моделей является Float32, так как модели часто обучаются или запускаются на графических процессорах. Тип eltype модели m можно изменить на Float64 с помощью макроса f64(m):

# Flux.f64Function

f64(m)

Преобразует eltype параметров модели с плавающей запятой во Float64. Выполняет рекурсию по структурам, помеченным с помощью @functor.

См. также описание f32 и f16.

# Flux.f32Function

f32(m)

Преобразует eltype параметров модели с плавающей запятой во Float32 (тип по умолчанию во Flux). Выполняет рекурсию по структурам, помеченным с помощью @functor.

См. также описание f64 и f16.

# Flux.f16Function

f16(m)

Преобразует eltype параметров модели с плавающей запятой во Float16. Выполняет рекурсию по структурам, помеченным с помощью @functor.

Во многих ЦП поддержка Float16 ограничена. Julia может выполнять преобразование во Float32 для каждой операции, но это происходит медленно.

См. также описание f32 и f64.

Пример

julia> m = Chain(Dense(784, 2048, relu), Dense(2048, 10))  # все Float32
Chain(
  Dense(784 => 2048, relu),             # 1_607_680 параметров
  Dense(2048 => 10),                    # 20_490 параметров
)                   # Всего: 4 массива, 1_628_170 параметров, 6,211 МиБ.

julia> m |> f16  # занимает половину памяти
Chain(
  Dense(784 => 2048, relu),             # 1_607_680 параметров
  Dense(2048 => 10),                    # 20_490 параметров
)                   # Всего: 4 массива, 1_628_170 параметров, 3,106 МиБ.